From 4920d80d41c40896199bd1909cf8065dc5bd4325 Mon Sep 17 00:00:00 2001 From: Dima Khludkov <57712402+dmytrokhl@users.noreply.github.com> Date: Thu, 30 Mar 2023 15:15:41 +0300 Subject: [PATCH 1/9] Fix warnings. --- Cartfile | 2 - .../VGSBlinkCardExpirationDate.swift | 1 - .../VGSBlinkCardController.swift | 6 +- .../VGSBlinkCardHandler.swift | 16 ++-- .../VGSCardIODataMapUtils.swift | 28 +++---- .../VGSCardIOScanController.swift | 8 +- .../VGSCollectSDK/Core/API/APIClient.swift | 2 +- .../Analytics/VGSFormAnanlyticsDetails.swift | 2 +- .../Core/Collector/VGSCollect+network.swift | 2 +- Sources/VGSCollectSDK/Core/Storage.swift | 4 +- ...dHolderNameTokenizationConfiguration.swift | 3 +- .../VGSSSNTokenizationConfiguration.swift | 1 - .../VGSCollectSDK/Core/VGSConfiguration.swift | 4 +- .../Core/CardBrand+default.swift | 6 +- .../VGSPaymentCards/Core/CardType+icon.swift | 2 +- .../Text Field/Mask/MaskedTextField.swift | 14 ++-- .../UIElements/Text Field/State/State.swift | 3 +- .../Text Field/VGSCVCTextField.swift | 1 - .../Text Field/VGSExpDateTextField.swift | 6 +- .../UIElements/Text Field/VGSTextField.swift | 7 +- .../VGSValidationRuleExpirationDate.swift | 2 +- .../Convertors/ExpDateFormatConvertor.swift | 2 - .../Helpers/Mappers/VGSDeepMergeUtils.swift | 4 +- .../VGSFieldNameToSubscriptMapper.swift | 4 +- .../APIClient Tests/ApiClientTests.swift | 2 +- .../TokenizationApiTests.swift | 6 +- .../_CardBrandDataSource.swift | 4 +- .../VGSFieldNameToJSONTests.swift | 4 +- .../File Picker Tests/FilePickerTests.swift | 2 +- .../Text Fields Tests/VGSTextFieldTests.swift | 5 +- .../VGSExpDateSeparateSerializerTests.swift | 20 ++--- ...GSExpDateTokenizationSerializerTests.swift | 4 +- .../Test Helpers/MockedDataProvider.swift | 2 +- .../VGSTokenizationConfigurationTests.swift | 3 - .../VGSTokenizationResponseMappingTests.swift | 2 +- VGSCollectSDK.xcodeproj/project.pbxproj | 79 +++++++++---------- .../xcschemes/FrameworkTests.xcscheme | 2 +- .../xcschemes/VGSBlinkCardCollector.xcscheme | 2 +- .../xcschemes/VGSCardIOCollector.xcscheme | 2 +- .../VGSCardIOCollectorTests.xcscheme | 2 +- .../xcschemes/VGSCollectSDK.xcscheme | 2 +- .../demoapp/AppCollectorConfiguration.swift | 2 +- .../UIColor+Extensions.swift | 16 ++-- .../UIView+Extensions/UIView+Extensions.swift | 15 ++-- demoapp/demoapp/InitialViewController.swift | 4 +- .../CardsDataCollectingViewController.swift | 2 +- .../CollectApplePayDataViewController.swift | 3 +- .../CustomPaymentCardsViewController.swift | 7 +- .../UseCases/FilePickerViewController.swift | 15 +--- ...tPaymentOptIntegrationViewController.swift | 46 +++++------ .../Helpers/CustomBackendAPIClient.swift | 12 ++- .../Models/SavedCardModel.swift | 6 +- .../TableViewCells/PaymentCardCell.swift | 1 - .../VGSPaymentOptionCardTableViewCell.swift | 3 +- .../TestCollectCardsDataFlow.swift | 3 +- .../TestCollectSSNDataFlow.swift | 4 +- .../demoappUITests/TestCollectSSNFlow.swift | 4 +- .../TestCustomCardNumbersDataFlow.swift | 8 +- .../UITestUtils/VGSUITestElement.swift | 46 +++++------ 59 files changed, 222 insertions(+), 248 deletions(-) delete mode 100644 Cartfile diff --git a/Cartfile b/Cartfile deleted file mode 100644 index 3727ec88..00000000 --- a/Cartfile +++ /dev/null @@ -1,2 +0,0 @@ -github "getbouncer/cardscan-ios" "1.0.5048" -github "verygoodsecurity/card.io-iOS-source" "b43a202acd7c7a258930b675348f8c4086f32e5d" \ No newline at end of file diff --git a/Sources/VGSBlinkCardCollector/CardDataMappers/VGSBlinkCardExpirationDate.swift b/Sources/VGSBlinkCardCollector/CardDataMappers/VGSBlinkCardExpirationDate.swift index e806fa1b..e568bc44 100644 --- a/Sources/VGSBlinkCardCollector/CardDataMappers/VGSBlinkCardExpirationDate.swift +++ b/Sources/VGSBlinkCardCollector/CardDataMappers/VGSBlinkCardExpirationDate.swift @@ -1,4 +1,3 @@ - import Foundation #if !COCOAPODS import VGSCollectSDK diff --git a/Sources/VGSBlinkCardCollector/VGSBlinkCardController.swift b/Sources/VGSBlinkCardCollector/VGSBlinkCardController.swift index e134c01d..c356822e 100644 --- a/Sources/VGSBlinkCardCollector/VGSBlinkCardController.swift +++ b/Sources/VGSBlinkCardCollector/VGSBlinkCardController.swift @@ -22,12 +22,12 @@ public class VGSBlinkCardController { /// `VGSBlinkCardControllerDelegate` - handle user interaction with `BlinkCard` scanner. public var delegate: VGSBlinkCardControllerDelegate? { - set { - scanHandler?.delegate = newValue - } get { return scanHandler?.delegate } + set { + scanHandler?.delegate = newValue + } } // MARK: - Initialization diff --git a/Sources/VGSBlinkCardCollector/VGSBlinkCardHandler.swift b/Sources/VGSBlinkCardCollector/VGSBlinkCardHandler.swift index 850446d1..f1cd2ef1 100644 --- a/Sources/VGSBlinkCardCollector/VGSBlinkCardHandler.swift +++ b/Sources/VGSBlinkCardCollector/VGSBlinkCardHandler.swift @@ -3,15 +3,16 @@ // VGSBlinkCardCollector // - import Foundation +#if os(iOS) +import UIKit +#endif + +#if canImport(BlinkCard) import BlinkCard #if !COCOAPODS import VGSCollectSDK #endif -#if os(iOS) -import UIKit -#endif /// BlinkCard wrapper, manages communication between public API and BlinkCard. @available(iOS 13.0, *) @@ -40,15 +41,15 @@ internal class VGSBlinkCardHandler: NSObject, VGSScanHandlerProtocol { /// Setup BlinlCard params and present scanner. func presentScanVC(on viewController: UIViewController, animated: Bool, modalPresentationStyle: UIModalPresentationStyle, completion: (() -> Void)?) { // Create BlinkCard settings - let settings : MBCBlinkCardOverlaySettings = MBCBlinkCardOverlaySettings() + let settings: MBCBlinkCardOverlaySettings = MBCBlinkCardOverlaySettings() settings.enableEditScreen = false // Crate recognizer collection let recognizerList = [cardRecognizer] - let recognizerCollection : MBCRecognizerCollection = MBCRecognizerCollection(recognizers: recognizerList) + let recognizerCollection: MBCRecognizerCollection = MBCRecognizerCollection(recognizers: recognizerList) // Create overlay view controller let blinkCardOverlayViewController = MBCBlinkCardOverlayViewController(settings: settings, recognizerCollection: recognizerCollection, delegate: self) // Create recognizer view controller with wanted overlay view controller - let recognizerRunneViewController : UIViewController = MBCViewControllerFactory.recognizerRunnerViewController(withOverlayViewController: blinkCardOverlayViewController)! + let recognizerRunneViewController: UIViewController = MBCViewControllerFactory.recognizerRunnerViewController(withOverlayViewController: blinkCardOverlayViewController)! recognizerRunneViewController.modalPresentationStyle = modalPresentationStyle self.view = recognizerRunneViewController // Present the recognizer runner view controller @@ -135,3 +136,4 @@ extension VGSBlinkCardHandler: MBCBlinkCardOverlayViewControllerDelegate { delegate?.userDidCancelScan() } } +#endif diff --git a/Sources/VGSCardIOCollector/CardIODataMapper/VGSCardIODataMapUtils.swift b/Sources/VGSCardIOCollector/CardIODataMapper/VGSCardIODataMapUtils.swift index 030eced6..30c2aabc 100644 --- a/Sources/VGSCardIOCollector/CardIODataMapper/VGSCardIODataMapUtils.swift +++ b/Sources/VGSCardIOCollector/CardIODataMapper/VGSCardIODataMapUtils.swift @@ -22,24 +22,24 @@ internal final class VGSCardIODataMapUtils { /// - scannedDataType: `CradIODataType` object, CardIO data type. /// - Returns: `String?`, formatted string or `nil`. internal static func mapCardExpirationData(_ data: VGSCardIOExpirationDate, scannedDataType: CradIODataType) -> String? { - switch scannedDataType { - case .cardNumber, .cvc: - return nil - case .expirationDate: - return mapDefaultExpirationDate(data.month, scannedExpYear: data.year) - case .expirationDateLong: - return mapLongExpirationDate(data.month, scannedExpYear: data.year) - case .expirationMonth: - return mapMonth(data.month) - case .expirationYear: - return mapYear(data.year) - case .expirationYearLong: - return mapYearLong(data.year) + switch scannedDataType { + case .cardNumber, .cvc: + return nil + case .expirationDate: + return mapDefaultExpirationDate(data.month, scannedExpYear: data.year) + case .expirationDateLong: + return mapLongExpirationDate(data.month, scannedExpYear: data.year) + case .expirationMonth: + return mapMonth(data.month) + case .expirationYear: + return mapYear(data.year) + case .expirationYearLong: + return mapYearLong(data.year) case .expirationDateShortYearThenMonth: return mapExpirationDateWithShortYearFirst(data.month, scannedExpYear: data.year) case .expirationDateLongYearThenMonth: return mapLongExpirationDateWithLongYearFirst(data.month, scannedExpYear: data.year) - } + } } // MARK: - Helpers diff --git a/Sources/VGSCardIOCollector/VGSCardIOScanController.swift b/Sources/VGSCardIOCollector/VGSCardIOScanController.swift index 5d934216..975b88ac 100644 --- a/Sources/VGSCardIOCollector/VGSCardIOScanController.swift +++ b/Sources/VGSCardIOCollector/VGSCardIOScanController.swift @@ -25,12 +25,12 @@ public class VGSCardIOScanController { /// `VGSCardIOScanControllerDelegate` - handle user interaction with `Card.io` scanner public var delegate: VGSCardIOScanControllerDelegate? { - set { - scanHandler?.delegate = newValue - } get { return scanHandler?.delegate } + set { + scanHandler?.delegate = newValue + } } /// Defines preferred `AVCaptureDevice.Position`. Deault is `AVCaptureDevice.Position.unspecified` @@ -50,7 +50,7 @@ public class VGSCardIOScanController { /// Defines preferred language for all strings appearing in the CardIO user interface. /// If not set, or if set to nil, defaults to the device's current language setting. - public var languageOrLocale: String? = nil { + public var languageOrLocale: String? { didSet { scanHandler?.languageOrLocale = languageOrLocale } diff --git a/Sources/VGSCollectSDK/Core/API/APIClient.swift b/Sources/VGSCollectSDK/Core/API/APIClient.swift index 02161f65..c3c6c7bd 100644 --- a/Sources/VGSCollectSDK/Core/API/APIClient.swift +++ b/Sources/VGSCollectSDK/Core/API/APIClient.swift @@ -136,7 +136,7 @@ class APIClient { } // Check if routeId is set and should be attached to request url - if case .vaultURL(_) = self.hostURLPolicy, + if case .vaultURL = self.hostURLPolicy, let routeId = routeId { guard let newUrl = APIClient.buildVaultURL(tenantId: self.vaultId, regionalEnvironment: self.environment, routeId: routeId) else { diff --git a/Sources/VGSCollectSDK/Core/Analytics/VGSFormAnanlyticsDetails.swift b/Sources/VGSCollectSDK/Core/Analytics/VGSFormAnanlyticsDetails.swift index 0fa99e4a..8ca4d6a1 100644 --- a/Sources/VGSCollectSDK/Core/Analytics/VGSFormAnanlyticsDetails.swift +++ b/Sources/VGSCollectSDK/Core/Analytics/VGSFormAnanlyticsDetails.swift @@ -8,7 +8,7 @@ import Foundation -///:nodoc: VGSCollect Form Analytics Details +/// :nodoc: VGSCollect Form Analytics Details public struct VGSFormAnanlyticsDetails { public let formId: String public let tenantId: String diff --git a/Sources/VGSCollectSDK/Core/Collector/VGSCollect+network.swift b/Sources/VGSCollectSDK/Core/Collector/VGSCollect+network.swift index 4697dd34..bb9d7cfa 100644 --- a/Sources/VGSCollectSDK/Core/Collector/VGSCollect+network.swift +++ b/Sources/VGSCollectSDK/Core/Collector/VGSCollect+network.swift @@ -145,7 +145,7 @@ extension VGSCollect { userInfo: VGSErrorInfo(key: VGSSDKErrorFileTypeNotSupported, description: "File format is not supported. File is empty.", extraInfo: [:])) - VGSAnalyticsClient.shared.trackFormEvent(self.formAnalyticsDetails, type: .beforeSubmit, status: .failed, extraData: [ "statusCode": error.code, "content": content,"upstream": "custom"]) + VGSAnalyticsClient.shared.trackFormEvent(self.formAnalyticsDetails, type: .beforeSubmit, status: .failed, extraData: [ "statusCode": error.code, "content": content, "upstream": "custom"]) block(.failure(error.code, nil, nil, error)) return } diff --git a/Sources/VGSCollectSDK/Core/Storage.swift b/Sources/VGSCollectSDK/Core/Storage.swift index 900aadf5..da5e33ea 100644 --- a/Sources/VGSCollectSDK/Core/Storage.swift +++ b/Sources/VGSCollectSDK/Core/Storage.swift @@ -22,12 +22,12 @@ internal class Storage { /// TextFields attached to `VGSCollect` instance, with configuration that implements `VGSTextFieldTokenizationConfigurationProtocol`. var tokenizableTextFields: [VGSTextField] { - return textFields.filter{$0.tokenizationParameters != nil} + return textFields.filter {$0.tokenizationParameters != nil} } /// TextFields attached to `VGSCollect` instance, with configuration that DOES NOT implements `VGSTextFieldTokenizationConfigurationProtocol`. var notTokenizibleTextFields: [VGSTextField] { - return textFields.filter{ + return textFields.filter { $0.tokenizationParameters == nil && $0.fieldType.sensitive == false } diff --git a/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSCardHolderNameTokenizationConfiguration.swift b/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSCardHolderNameTokenizationConfiguration.swift index 804fd07f..6a610bb6 100644 --- a/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSCardHolderNameTokenizationConfiguration.swift +++ b/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSCardHolderNameTokenizationConfiguration.swift @@ -16,7 +16,8 @@ public struct VGSCardHolderNameTokenizationParameters: VGSTokenizationParameters /// `VGSCardHolderNameTokenizationConfiguration` - textfield configuration for textfield with type `.cardHolderName`, required for work with tokenization api. public class VGSCardHolderNameTokenizationConfiguration: VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol { - +// swiftlint:disable:previous type_name + /// `VGSCardHolderNameTokenizationParameters` - tokenization configuration parameters. public var tokenizationParameters = VGSCardHolderNameTokenizationParameters() diff --git a/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSSSNTokenizationConfiguration.swift b/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSSSNTokenizationConfiguration.swift index 80d23040..899fa357 100644 --- a/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSSSNTokenizationConfiguration.swift +++ b/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSSSNTokenizationConfiguration.swift @@ -3,7 +3,6 @@ // VGSCollectSDK // - import Foundation /// `VGSSSNTokenizationParameters` - parameters required for tokenization api. diff --git a/Sources/VGSCollectSDK/Core/VGSConfiguration.swift b/Sources/VGSCollectSDK/Core/VGSConfiguration.swift index 1890353c..0897b8b7 100644 --- a/Sources/VGSCollectSDK/Core/VGSConfiguration.swift +++ b/Sources/VGSCollectSDK/Core/VGSConfiguration.swift @@ -70,7 +70,7 @@ public class VGSConfiguration: VGSTextFieldConfigurationProtocol { /// Preferred UIKeyboardType for `VGSTextField`. If not applied, will be set by default depending on field `type` parameter. public var keyboardType: UIKeyboardType? - ///Preferred UIReturnKeyType for `VGSTextField`. + /// Preferred UIReturnKeyType for `VGSTextField`. public var returnKeyType: UIReturnKeyType? /// Preferred UIKeyboardAppearance for textfield. By default is `UIKeyboardAppearance.default`. @@ -89,7 +89,7 @@ public class VGSConfiguration: VGSTextFieldConfigurationProtocol { /// Logs warning when both `.formatPattern` and `.maxInputLength` are used. internal func logWarningForFormatPatternIfNeeded() { if !formatPattern.isNilOrEmpty && maxInputLength != nil { - let message = "Format pattern (\(formatPattern)) and maxInputLength (\(maxInputLength)) can conflict when both are in use!" + let message = "Format pattern (\(formatPattern ?? "")) and maxInputLength (\(maxInputLength ?? 0)) can conflict when both are in use!" let event = VGSLogEvent(level: .warning, text: message, severityLevel: .warning) VGSCollectLogger.shared.forwardLogEvent(event) } diff --git a/Sources/VGSCollectSDK/Core/VGSPaymentCards/Core/CardBrand+default.swift b/Sources/VGSCollectSDK/Core/VGSPaymentCards/Core/CardBrand+default.swift index 20274f75..b774fff5 100644 --- a/Sources/VGSCollectSDK/Core/VGSPaymentCards/Core/CardBrand+default.swift +++ b/Sources/VGSCollectSDK/Core/VGSPaymentCards/Core/CardBrand+default.swift @@ -42,7 +42,7 @@ extension VGSPaymentCards.CardBrand { return "^(384100|384140|384160|606282|637095|637568|60(?!11))\\d*$" case .unknown: return "^\\d*$" - case .custom(brandName: _): + case .custom: return "" } } @@ -77,7 +77,7 @@ extension VGSPaymentCards.CardBrand { return [14, 15, 16, 17, 18, 19] case .unknown: return [16, 17, 18, 19] - case .custom(brandName: _): + case .custom: return [] } } @@ -145,7 +145,7 @@ extension VGSPaymentCards.CardBrand { return "HiperCard" case .unknown: return "Unknown" - case .custom(brandName: _): + case .custom: return "" } } diff --git a/Sources/VGSCollectSDK/Core/VGSPaymentCards/Core/CardType+icon.swift b/Sources/VGSCollectSDK/Core/VGSPaymentCards/Core/CardType+icon.swift index cb183c25..ee6a460a 100644 --- a/Sources/VGSCollectSDK/Core/VGSPaymentCards/Core/CardType+icon.swift +++ b/Sources/VGSCollectSDK/Core/VGSPaymentCards/Core/CardType+icon.swift @@ -63,7 +63,7 @@ extension VGSPaymentCards.CardBrand { resultIcon = UIImage(named: "hipercard", in: bundle, compatibleWith: nil) case .unknown: resultIcon = Self.defaultUnknownBrandIcon - case .custom(brandName: _): + case .custom: resultIcon = Self.defaultUnknownBrandIcon } return resultIcon diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Mask/MaskedTextField.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Mask/MaskedTextField.swift index eb5bfc70..7a7f8254 100755 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Mask/MaskedTextField.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Mask/MaskedTextField.swift @@ -12,8 +12,7 @@ import UIKit /// Defines interface for masked text field delegate. internal protocol MaskedTextFieldDelegate: AnyObject { - func maskedTextField(_ maskedTextField: UITextField, shouldChangeCharactersInRange range: NSRange, - replacementString string: String) -> Bool + func maskedTextField(_ maskedTextField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool } /// :nodoc: Internal wrapper for `UITextField`. @@ -75,21 +74,21 @@ internal class MaskedTextField: UITextField { */ @available(*, deprecated, message: "Don't use this method.") override var text: String? { + get { return nil } set { secureText = newValue } - get { return nil } } /// set/get text just for internal using internal var secureText: String? { + get { + return super.text + } set { super.text = newValue self.updateTextFormat() } - get { - return super.text - } } /// returns textfield text without mask @@ -278,8 +277,7 @@ internal class MaskedTextField: UITextField { // MARK: - UITextFieldDelegate extension MaskedTextField: UITextFieldDelegate { - func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, - replacementString string: String) -> Bool { + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { guard let customTextFieldDelegate = customDelegate else { return true } diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/State/State.swift b/Sources/VGSCollectSDK/UIElements/Text Field/State/State.swift index f877ec5e..2fc4c331 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/State/State.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/State/State.swift @@ -8,7 +8,6 @@ import Foundation import UIKit #endif - /// An object that describes `VGSTextField` state. State attributes are read-only. public class State { @@ -119,7 +118,7 @@ public class CardState: State { - cardBrand: `VGSPaymentCards.CardBrand`, card brand. */ private func getBin(_ cardNumber: String, cardBrand: VGSPaymentCards.CardBrand) -> String { - switch cardBrand{ + switch cardBrand { case .visa, .mastercard, .maestro: /// check min card length allowed guard cardNumber.count >= 16 else { diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/VGSCVCTextField.swift b/Sources/VGSCollectSDK/UIElements/Text Field/VGSCVCTextField.swift index 4c8e5d1b..70217f40 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/VGSCVCTextField.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/VGSCVCTextField.swift @@ -120,7 +120,6 @@ internal extension VGSCVCTextField { return stack } - func updateCVCImage(for cardBrand: VGSPaymentCards.CardBrand) { cvcIconImageView.image = (cvcIconSource == nil) ? cardBrand.cvcIcon : cvcIconSource?(cardBrand) } diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift b/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift index 6b4c5479..0562cd73 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift @@ -44,7 +44,7 @@ public final class VGSExpDateTextField: VGSTextField { } } - ///:nodoc: + /// :nodoc: public override var configuration: VGSConfiguration? { didSet { fieldType = .expDate @@ -127,7 +127,7 @@ extension VGSExpDateTextField: UIPickerViewDelegate, UIPickerViewDataSource { } } -// MARK: - Configuration +// MARK: - Configuration private extension VGSExpDateTextField { @@ -151,7 +151,7 @@ private extension VGSExpDateTextField { } } -// MARK: - Date Picker +// MARK: - Date Picker private extension VGSExpDateTextField { func makePicker() -> UIPickerView { let picker = UIPickerView() diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/VGSTextField.swift b/Sources/VGSCollectSDK/UIElements/Text Field/VGSTextField.swift index 17ce8ea3..fd61038a 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/VGSTextField.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/VGSTextField.swift @@ -25,7 +25,7 @@ public class VGSTextField: UIView { internal var horizontalConstraints = [NSLayoutConstraint]() internal var verticalConstraint = [NSLayoutConstraint]() internal var validationRules = VGSValidationRuleSet() - internal var tokenizationParameters: VGSTokenizationParametersProtocol? = nil + internal var tokenizationParameters: VGSTokenizationParametersProtocol? // MARK: - UI Attributes @@ -284,11 +284,11 @@ internal extension VGSTextField { @objc func addTextFieldObservers() { - //delegates + // delegates textField.delegate = textField textField.customDelegate = self textField.addSomeTarget(self, action: #selector(textFieldDidBeginEditing), for: .editingDidBegin) - //Note: .allEditingEvents doesn't work proparly when set text programatically. Use setText instead! + // Note: .allEditingEvents doesn't work proparly when set text programatically. Use setText instead! textField.addSomeTarget(self, action: #selector(textFieldDidEndEditing), for: .editingDidEnd) textField.addSomeTarget(self, action: #selector(textFieldDidEndEditingOnExit), for: .editingDidEndOnExit) NotificationCenter.default.addObserver(self, selector: #selector(textFieldDidChange), name: UITextField.textDidChangeNotification, object: textField) @@ -385,6 +385,7 @@ internal extension VGSTextField { return !textField.formatPattern.isEmpty } } +// swiftlint:disable file_length // MARK: - MaskedTextFieldDelegate diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleExpirationDate.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleExpirationDate.swift index f1e989b2..98a7aa22 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleExpirationDate.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleExpirationDate.swift @@ -118,7 +118,7 @@ extension VGSValidationRuleCardExpirationDate: VGSRuleValidator { guard let inputMM = Int(mm), (1...12).contains(inputMM), var inputYY = Int(yy) else { return false } - ///convert input year to long format if needed + /// convert input year to long format if needed inputYY = self.dateFormat.yearCharacters == 2 ? (inputYY + 2000) : inputYY if inputYY < todayYY || inputYY > (todayYY + 20) { return false diff --git a/Sources/VGSCollectSDK/Utils/Convertors/ExpDateFormatConvertor.swift b/Sources/VGSCollectSDK/Utils/Convertors/ExpDateFormatConvertor.swift index d7e6a377..da1b01b2 100644 --- a/Sources/VGSCollectSDK/Utils/Convertors/ExpDateFormatConvertor.swift +++ b/Sources/VGSCollectSDK/Utils/Convertors/ExpDateFormatConvertor.swift @@ -29,8 +29,6 @@ internal class ExpDateFormatConvertor: TextFormatConvertor { /// Convert Exp Date String with input `CardExpDateFormat` to Output `CardExpDateFormat` func convert(_ input: String, inputFormat: VGSCardExpDateFormat, outputFormat: VGSCardExpDateFormat) -> String { - - let inputYear = inputFormat.isYearFirst ? String(input.prefix(inputFormat.yearCharacters)) : String(input.suffix(inputFormat.yearCharacters)) let inputMonth = inputFormat.isYearFirst ? input.suffix(inputFormat.monthCharacters) : input.prefix(inputFormat.monthCharacters) let divider = inputFormat.isYearFirst ? String(input.dropLast(inputFormat.monthCharacters)).dropFirst(inputFormat.yearCharacters) : String(input.dropLast(inputFormat.yearCharacters)).dropFirst(inputFormat.monthCharacters) diff --git a/Sources/VGSCollectSDK/Utils/Helpers/Mappers/VGSDeepMergeUtils.swift b/Sources/VGSCollectSDK/Utils/Helpers/Mappers/VGSDeepMergeUtils.swift index 5da424d5..f0852014 100644 --- a/Sources/VGSCollectSDK/Utils/Helpers/Mappers/VGSDeepMergeUtils.swift +++ b/Sources/VGSCollectSDK/Utils/Helpers/Mappers/VGSDeepMergeUtils.swift @@ -27,7 +27,7 @@ final internal class VGSDeepMergeUtils { if let v1 = result[k2] as? JsonData, let v2 = v2 as? JsonData { result[k2] = deepMerge(target: v1, source: v2, mergeArrayPolicy: mergeArrayPolicy) // Try to merge Array1 and Array2. - } else if let array1 = result[k2] as? Array, let array2 = v2 as? Array { + } else if let array1 = result[k2] as? [Any?], let array2 = v2 as? [Any?] { switch mergeArrayPolicy { case .merge: result[k2] = deepArrayMerge(target: array1, source: array2, mergeArrayPolicy: mergeArrayPolicy) @@ -48,7 +48,7 @@ final internal class VGSDeepMergeUtils { /// - source: `Array` object, source to merge. /// - mergeArrayPolicy: `VGSCollectArrayMergePolicy` object, array merge policy. /// - Returns: `Array` object, merged arrays. - static func deepArrayMerge(target: Array, source: Array, mergeArrayPolicy: VGSCollectArrayMergePolicy) -> Array { + static func deepArrayMerge(target: [Any?], source: [Any?], mergeArrayPolicy: VGSCollectArrayMergePolicy) -> [Any?] { var result = target // Iterate through source array. diff --git a/Sources/VGSCollectSDK/Utils/Helpers/Mappers/VGSFieldNameToSubscriptMapper.swift b/Sources/VGSCollectSDK/Utils/Helpers/Mappers/VGSFieldNameToSubscriptMapper.swift index 6ef6cc56..870ead8f 100644 --- a/Sources/VGSCollectSDK/Utils/Helpers/Mappers/VGSFieldNameToSubscriptMapper.swift +++ b/Sources/VGSCollectSDK/Utils/Helpers/Mappers/VGSFieldNameToSubscriptMapper.swift @@ -74,7 +74,9 @@ internal final class VGSFieldNameToSubscriptMapper { let regex = try NSRegularExpression(pattern: regex, options: []) let nsString = text as NSString let results = regex.matches(in: text, - options: [], range: NSMakeRange(0, nsString.length)) + options: [], + range: NSMakeRange(0, nsString.length)) + // swiftlint:disable:previous legacy_constructor return results.map { nsString.substring(with: $0.range)} } catch let error as NSError { print("invalid regex: \(error.localizedDescription)") diff --git a/Tests/FrameworkTests/APIClient Tests/ApiClientTests.swift b/Tests/FrameworkTests/APIClient Tests/ApiClientTests.swift index 53d53ea0..7209d522 100644 --- a/Tests/FrameworkTests/APIClient Tests/ApiClientTests.swift +++ b/Tests/FrameworkTests/APIClient Tests/ApiClientTests.swift @@ -164,7 +164,7 @@ class ApiClientTests: VGSCollectBaseTestCase { textField.configuration = configuration let expectation = XCTestExpectation(description: "Sending data...") - collector.sendData(path: "/post", routeId: routeId) { [weak self]respose in + collector.sendData(path: "/post", routeId: routeId) { [weak self] _ in // check base url not changed and don't include routeid let url = self?.collector.apiClient.baseURL XCTAssertTrue(baseUrl?.absoluteString == url?.absoluteString, "-testBaseUrlNotChangedAfterRouteIdSet url error: \(String(describing: url))") diff --git a/Tests/FrameworkTests/APIClient Tests/TokenizationApiTests.swift b/Tests/FrameworkTests/APIClient Tests/TokenizationApiTests.swift index 523728b0..cf470cb8 100644 --- a/Tests/FrameworkTests/APIClient Tests/TokenizationApiTests.swift +++ b/Tests/FrameworkTests/APIClient Tests/TokenizationApiTests.swift @@ -58,7 +58,7 @@ class TokenizationApiTests: VGSCollectBaseTestCase { let expectation = XCTestExpectation(description: "Sending data...") - collector.tokenizeData() { result in + collector.tokenizeData { result in switch result { case .success(let code, let jsonData, let response): XCTAssertTrue(code == 200) @@ -131,8 +131,8 @@ class TokenizationApiTests: VGSCollectBaseTestCase { someNumberTextField.textField.secureText = someNumber let expectation = XCTestExpectation(description: "Sending data...") - - collector.tokenizeData() { result in + + collector.tokenizeData { result in switch result { case .success(let code, let jsonData, let response): guard let json = jsonData as? [String: String] else { diff --git a/Tests/FrameworkTests/Card Brand Tests/_CardBrandDataSource.swift b/Tests/FrameworkTests/Card Brand Tests/_CardBrandDataSource.swift index f8132f7c..5cb917f0 100644 --- a/Tests/FrameworkTests/Card Brand Tests/_CardBrandDataSource.swift +++ b/Tests/FrameworkTests/Card Brand Tests/_CardBrandDataSource.swift @@ -163,7 +163,7 @@ extension VGSPaymentCards.CardBrand { "6062828888666688"] case .unknown: return [] - case .custom(brandName:_): + case .custom: return [] } } @@ -234,7 +234,7 @@ extension VGSPaymentCards.CardBrand { return ["384100", "3841009", "606282", "6062820", "637568"] case .unknown: return [] - case .custom(brandName: _): + case .custom: return [] } } diff --git a/Tests/FrameworkTests/DeepMergeUtils Tests/VGSFieldNameToJSONTests.swift b/Tests/FrameworkTests/DeepMergeUtils Tests/VGSFieldNameToJSONTests.swift index 455b8974..68a45095 100644 --- a/Tests/FrameworkTests/DeepMergeUtils Tests/VGSFieldNameToJSONTests.swift +++ b/Tests/FrameworkTests/DeepMergeUtils Tests/VGSFieldNameToJSONTests.swift @@ -54,11 +54,11 @@ class VGSFieldNameToJSONTests: XCTestCase { } class VGSFieldNameMapperTestDataProvider { - static func provideTestDataForVGSFieldNameToJSON() -> [VGSFieldNameToJSONTests.VGSFieldNameTestData] { + static func provideTestDataForVGSFieldNameToJSON() -> [VGSFieldNameToJSONTests.VGSFieldNameTestData] { return provideFieldNameTestData(for: "VGSFieldNameToJSONTestData") } - static func provideFieldNameTestData(for fileName: String) -> [VGSFieldNameToJSONTests.VGSFieldNameTestData] { + static func provideFieldNameTestData(for fileName: String) -> [VGSFieldNameToJSONTests.VGSFieldNameTestData] { guard let rootTestJSON = JsonData(jsonFileName: fileName), let testDataJSONArray = rootTestJSON["test_data"] as? [JsonData] else { XCTFail("cannot build data for file VGSFieldNameToJSONTestData") return [] diff --git a/Tests/FrameworkTests/File Picker Tests/FilePickerTests.swift b/Tests/FrameworkTests/File Picker Tests/FilePickerTests.swift index 05b03f67..d258ecc0 100644 --- a/Tests/FrameworkTests/File Picker Tests/FilePickerTests.swift +++ b/Tests/FrameworkTests/File Picker Tests/FilePickerTests.swift @@ -27,7 +27,7 @@ class FilePickerTests: VGSCollectBaseTestCase { // MARK: - Upload file func testUpload() { - //The Bundle for your current class + // The Bundle for your current class let bundle = AssetsBundle.main.iconBundle let testImage = UIImage(named: "visa", in: bundle, compatibleWith: nil)?.jpegData(compressionQuality: 1) diff --git a/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/VGSTextFieldTests.swift b/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/VGSTextFieldTests.swift index 010ea659..1edeb4d6 100644 --- a/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/VGSTextFieldTests.swift +++ b/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/VGSTextFieldTests.swift @@ -101,13 +101,14 @@ class VGSTextFieldTests: VGSCollectBaseTestCase { let testField4 = VGSTextField() let testFields = [testField1, testField2, testField3, testField4] - + // swiftlint:disable identifier_name for i in 0 ..< testFields.count - 1 { let field1 = testFields[i] for j in (i+1) ..< testFields.count { let field2 = testFields[j] - + // swiftlint:enable identifier_name + /// Test positive case with equal input field1.textField.secureText = input1 field2.textField.secureText = input1 diff --git a/Tests/FrameworkTests/SerializersTest/VGSExpDateSeparateSerializerTests.swift b/Tests/FrameworkTests/SerializersTest/VGSExpDateSeparateSerializerTests.swift index b1a7a4b8..0fb484be 100644 --- a/Tests/FrameworkTests/SerializersTest/VGSExpDateSeparateSerializerTests.swift +++ b/Tests/FrameworkTests/SerializersTest/VGSExpDateSeparateSerializerTests.swift @@ -26,18 +26,18 @@ class VGSExpDateSeparateSerializerTests: VGSCollectBaseTestCase { } var jsonFileNameSuffix: String { - switch self { - case .defaultConfiguration: - return "DefaultConfig" - case .customConfiguration: - return "CustomConfig" + switch self { + case .defaultConfiguration: + return "DefaultConfig" + case .customConfiguration: + return "CustomConfig" case .customExpDateOutputConfiguration: return "CustomExpDateOutputConfig" - case .mapWithArrayOverwrite: - return "MapWithArrayOverwrite" - case .mapWithArrayMerge: - return "MapWithArrayMerge" - } + case .mapWithArrayOverwrite: + return "MapWithArrayOverwrite" + case .mapWithArrayMerge: + return "MapWithArrayMerge" + } } } diff --git a/Tests/FrameworkTests/SerializersTest/VGSExpDateTokenizationSerializerTests.swift b/Tests/FrameworkTests/SerializersTest/VGSExpDateTokenizationSerializerTests.swift index 6e465fb2..f1f2c494 100644 --- a/Tests/FrameworkTests/SerializersTest/VGSExpDateTokenizationSerializerTests.swift +++ b/Tests/FrameworkTests/SerializersTest/VGSExpDateTokenizationSerializerTests.swift @@ -99,10 +99,8 @@ class VGSExpDateTokenizationSerializerTests: VGSCollectBaseTestCase { var matchedPayloads = 0 // mapFieldsToTokenizationRequestBodyJSON can produce array of tokenized data in different order. So we need to iterate through payloads and check them one by one to get 2 matches (one is for month, another one is for year). for payload in tokenizedPayloads { - for expectedPayload in test.tokenizedPayloads { - if payload == expectedPayload { + for expectedPayload in test.tokenizedPayloads where payload == expectedPayload { matchedPayloads += 1 - } } } diff --git a/Tests/FrameworkTests/Test Helpers/MockedDataProvider.swift b/Tests/FrameworkTests/Test Helpers/MockedDataProvider.swift index 2529c559..6c7fd54c 100644 --- a/Tests/FrameworkTests/Test Helpers/MockedDataProvider.swift +++ b/Tests/FrameworkTests/Test Helpers/MockedDataProvider.swift @@ -23,7 +23,7 @@ final class MockedDataProvider { } /// Provided mocked data. - private func provideMockedData() -> () { + private func provideMockedData() { #if SWIFT_PACKAGE let bundle = Bundle.module #else diff --git a/Tests/FrameworkTests/TokenizationTests/VGSTokenizationConfigurationTests.swift b/Tests/FrameworkTests/TokenizationTests/VGSTokenizationConfigurationTests.swift index 7dbc37f9..694193cf 100644 --- a/Tests/FrameworkTests/TokenizationTests/VGSTokenizationConfigurationTests.swift +++ b/Tests/FrameworkTests/TokenizationTests/VGSTokenizationConfigurationTests.swift @@ -3,8 +3,6 @@ // FrameworkTests // -import Foundation - import Foundation import XCTest @testable import VGSCollectSDK @@ -14,7 +12,6 @@ class VGSTokenizationConfigurationsTest: VGSCollectBaseTestCase { var textField: VGSTextField! var collector = VGSCollect(id: "testVaultId") - override func tearDown() { super.tearDown() textField = nil diff --git a/Tests/FrameworkTests/TokenizationTests/VGSTokenizationResponseMappingTests.swift b/Tests/FrameworkTests/TokenizationTests/VGSTokenizationResponseMappingTests.swift index 75ce8a44..8d1685cf 100644 --- a/Tests/FrameworkTests/TokenizationTests/VGSTokenizationResponseMappingTests.swift +++ b/Tests/FrameworkTests/TokenizationTests/VGSTokenizationResponseMappingTests.swift @@ -39,7 +39,7 @@ class VGSTokenizationResponseMappingTests: VGSCollectBaseTestCase { guard let fieldName = json["field_name"] as? String, let inputValue = json["value"] as? String, let storage = json["storage"] as? String, - let format = json["format"] as? String else { + let format = json["format"] as? String else { return nil } diff --git a/VGSCollectSDK.xcodeproj/project.pbxproj b/VGSCollectSDK.xcodeproj/project.pbxproj index 8c5e15fa..5263b4d6 100644 --- a/VGSCollectSDK.xcodeproj/project.pbxproj +++ b/VGSCollectSDK.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -99,7 +99,6 @@ 441B26E925DB8D950099AA3A /* APIClient+Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 441B26E825DB8D950099AA3A /* APIClient+Utils.swift */; }; 441B26F025DB956B0099AA3A /* URL+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 441B26EF25DB956B0099AA3A /* URL+Extensions.swift */; }; 441B4E9B293EFD050011EFAC /* VGSCollectHTTPMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 441B4E9A293EFD050011EFAC /* VGSCollectHTTPMethod.swift */; }; - 441B4E9D293EFD2B0011EFAC /* VGSCollectHTTPMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 441B4E9C293EFD2B0011EFAC /* VGSCollectHTTPMethod.swift */; }; 442A39132909718F007CCC58 /* VGSTokenizationTestJSON_DefaultConfig.json in Resources */ = {isa = PBXBuildFile; fileRef = 442A39122909718F007CCC58 /* VGSTokenizationTestJSON_DefaultConfig.json */; }; 442A391729097425007CCC58 /* VGSTokenizationResponseMappingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 442A391629097425007CCC58 /* VGSTokenizationResponseMappingTests.swift */; }; 442BB2C6287314DC001FD26B /* MockedData.plist in Resources */ = {isa = PBXBuildFile; fileRef = 442BB2C5287314DC001FD26B /* MockedData.plist */; }; @@ -1157,7 +1156,7 @@ 326FFAEE24F904430024A4F9 /* Sources */, 326FFAEF24F904430024A4F9 /* Frameworks */, 326FFAF024F904430024A4F9 /* Resources */, - 326FFB0E24F90DB60024A4F9 /* ShellScript */, + 03AA85BF29799568006DC673 /* SwiftLint */, ); buildRules = ( ); @@ -1212,6 +1211,7 @@ FD24954D2330CB49009024E6 /* Sources */, FD24954E2330CB49009024E6 /* Frameworks */, FD24954F2330CB49009024E6 /* Resources */, + 03AA85C029799580006DC673 /* ShellScript */, ); buildRules = ( ); @@ -1230,7 +1230,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1400; - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1420; ORGANIZATIONNAME = VGS; TargetAttributes = { 326FFAF124F904430024A4F9 = { @@ -1326,8 +1326,9 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 03B10C0628E31B1A009B409B /* SwiftLint */ = { + 03AA85BF29799568006DC673 /* SwiftLint */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -1342,29 +1343,48 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if which swiftlint >/dev/null; then\n swiftlint lint --config \"${SRCROOT}/.swiftlint.yml\"\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; + shellScript = "export PATH=\"$PATH:/opt/homebrew/bin\"\nif which swiftlint >/dev/null; then\n swiftlint lint --config \"${SRCROOT}/.swiftlint.yml\"\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; + }; + 03AA85C029799580006DC673 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "export PATH=\"$PATH:/opt/homebrew/bin\"\nif which swiftlint >/dev/null; then\n swiftlint lint --config \"${SRCROOT}/.swiftlint.yml\"\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; }; - 326FFB0E24F90DB60024A4F9 /* ShellScript */ = { + 03B10C0628E31B1A009B409B /* SwiftLint */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( - "$(SRCROOT)/Carthage/Build/iOS/CardIO.framework", ); + name = SwiftLint; outputFileListPaths = ( ); outputPaths = ( - "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/CardIO.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/usr/local/bin/carthage copy-frameworks\n"; + shellScript = "export PATH=\"$PATH:/opt/homebrew/bin\"\nif which swiftlint >/dev/null; then\n swiftlint lint --config \"${SRCROOT}/.swiftlint.yml\"\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; }; 32C89470256C34EC00DC5648 /* SwiftLint */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -1379,7 +1399,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if which swiftlint >/dev/null; then\n swiftlint lint --config \"${SRCROOT}/.swiftlint.yml\"\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; + shellScript = "export PATH=\"$PATH:/opt/homebrew/bin\"\nif which swiftlint >/dev/null; then\n swiftlint lint --config \"${SRCROOT}/.swiftlint.yml\"\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -1448,7 +1468,6 @@ 44ECD60427D9C18C00460FDF /* CheckSumAlgoritmType.swift in Sources */, 3215C4BC260DAF3D00F21259 /* VGSFormatSerializerProtocol.swift in Sources */, 441B4E9B293EFD050011EFAC /* VGSCollectHTTPMethod.swift in Sources */, - 441B4E9D293EFD2B0011EFAC /* VGSCollectHTTPMethod.swift in Sources */, 32093D8625CDA3E6006CD242 /* VGSReadWriteSafeContainer.swift in Sources */, FD3C01C323AFC0980096B4A4 /* VGSTextField+CVC.swift in Sources */, 44F8F51C25DBD1950052647A /* VGSCollectSatelliteUtils.swift in Sources */, @@ -1591,10 +1610,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); INFOPLIST_FILE = VGSBlinkCardCollector/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 13.0; @@ -1624,10 +1639,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); INFOPLIST_FILE = VGSBlinkCardCollector/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 13.0; @@ -1656,13 +1667,9 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); INFOPLIST_FILE = VGSCardIOCollector/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1689,13 +1696,9 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); INFOPLIST_FILE = VGSCardIOCollector/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1810,7 +1813,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MARKETING_VERSION = 1.12.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -1872,7 +1875,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MARKETING_VERSION = 1.12.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -1898,13 +1901,9 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); INFOPLIST_FILE = Sources/VGSCollectSDK/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1934,13 +1933,9 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); INFOPLIST_FILE = Sources/VGSCollectSDK/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/VGSCollectSDK.xcodeproj/xcshareddata/xcschemes/FrameworkTests.xcscheme b/VGSCollectSDK.xcodeproj/xcshareddata/xcschemes/FrameworkTests.xcscheme index 014bd018..e1e5fcfa 100644 --- a/VGSCollectSDK.xcodeproj/xcshareddata/xcschemes/FrameworkTests.xcscheme +++ b/VGSCollectSDK.xcodeproj/xcshareddata/xcschemes/FrameworkTests.xcscheme @@ -1,6 +1,6 @@ internal extension UIColor { - ///:nodoc: System background color (white). + /// :nodoc: System background color (white). static var vgsSystemBackground: UIColor { if #available(iOS 13, *) { return .systemGroupedBackground @@ -39,7 +39,7 @@ internal extension UIColor { return .groupTableViewBackground } - ///:nodoc: Input text color (black). + /// :nodoc: Input text color (black). static var vgsInputBlackTextColor: UIColor { if #available(iOS 13.0, *) { return UIColor {(traits) -> UIColor in @@ -50,7 +50,7 @@ internal extension UIColor { } } - ///:nodoc: Input text color (black). + /// :nodoc: Input text color (black). static var vgsBorderColor: UIColor { if #available(iOS 13.0, *) { return UIColor {(traits) -> UIColor in @@ -61,7 +61,7 @@ internal extension UIColor { } } - ///:nodoc: VGS section title color (with fallback to earlier versions). + /// :nodoc: VGS section title color (with fallback to earlier versions). static var vgsSectionTitleColor: UIColor { if #available(iOS 13.0, *) { return label @@ -70,7 +70,7 @@ internal extension UIColor { } } - ///:nodoc: VGS section background color (with fallback to earlier versions). + /// :nodoc: VGS section background color (with fallback to earlier versions). static var vgsSectionBackgroundColor: UIColor { if #available(iOS 13.0, *) { return UIColor.secondarySystemGroupedBackground @@ -79,7 +79,7 @@ internal extension UIColor { } } - ///:nodoc: + /// :nodoc: static var vgsPaymentOptionBackgroundColor: UIColor { if #available(iOS 13.0, *) { return UIColor.secondarySystemGroupedBackground @@ -88,7 +88,7 @@ internal extension UIColor { } } - ///:nodoc: VGS systemGray2 color (with fallback to earlier versions). + /// :nodoc: VGS systemGray2 color (with fallback to earlier versions). static var vgsSystemGray2Color: UIColor { if #available(iOS 13.0, *) { return UIColor.systemGray2 @@ -97,7 +97,7 @@ internal extension UIColor { } } - ///:nodoc: VGS systemGray color (with fallback to earlier versions). + /// :nodoc: VGS systemGray color (with fallback to earlier versions). static var vgsSystemGrayColor: UIColor { if #available(iOS 13.0, *) { return UIColor.systemGray diff --git a/demoapp/demoapp/Helpers/Extensions/UIKit+Extensions/UIView+Extensions/UIView+Extensions.swift b/demoapp/demoapp/Helpers/Extensions/UIKit+Extensions/UIView+Extensions/UIView+Extensions.swift index cfee03d8..5834bd95 100644 --- a/demoapp/demoapp/Helpers/Extensions/UIKit+Extensions/UIView+Extensions/UIView+Extensions.swift +++ b/demoapp/demoapp/Helpers/Extensions/UIKit+Extensions/UIView+Extensions/UIView+Extensions.swift @@ -37,7 +37,7 @@ internal extension UIView { let constraints = [ centerXAnchor.constraint(equalTo: view.centerXAnchor), - centerYAnchor.constraint(equalTo: view.centerYAnchor), + centerYAnchor.constraint(equalTo: view.centerYAnchor) ] NSLayoutConstraint.activate(constraints) @@ -103,7 +103,7 @@ internal extension UIView { /// no:doc internal extension UIView { - ///:nodoc: System background color (white). + /// :nodoc: System background color (white). var vgsSystemBackground: UIColor { if #available(iOS 13, *) { return .systemGroupedBackground @@ -147,19 +147,19 @@ internal extension UIView { let overlayView: UIView = self.overlayView let activityIndicatorView: UIActivityIndicatorView = self.activityIndicatorView - //add subviews + // add subviews overlayView.addSubview(activityIndicatorView) addSubview(overlayView) - //add overlay constraints + // add overlay constraints overlayView.heightAnchor.constraint(equalTo: heightAnchor).isActive = true overlayView.widthAnchor.constraint(equalTo: widthAnchor).isActive = true - //add indicator constraints + // add indicator constraints activityIndicatorView.centerXAnchor.constraint(equalTo: overlayView.centerXAnchor).isActive = true activityIndicatorView.centerYAnchor.constraint(equalTo: overlayView.centerYAnchor).isActive = true - //animate indicator + // animate indicator activityIndicatorView.startAnimating() } @@ -172,9 +172,10 @@ internal extension UIView { overlayView.alpha = 0.0 activityIndicator.stopAnimating() }) { _ in + // swiftlint:disable:previous multiple_closures_with_trailing_closure activityIndicator.removeFromSuperview() overlayView.removeFromSuperview() - } + } } /// Checks if loader is displayed. diff --git a/demoapp/demoapp/InitialViewController.swift b/demoapp/demoapp/InitialViewController.swift index 1e64d6fb..ad387a4e 100644 --- a/demoapp/demoapp/InitialViewController.swift +++ b/demoapp/demoapp/InitialViewController.swift @@ -26,9 +26,9 @@ class InitialViewController: UITableViewController { })) if let popoverController = alert.popoverPresentationController { - popoverController.sourceView = self.view //to set the source of your alert + popoverController.sourceView = self.view // to set the source of your alert popoverController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0) // you can set this as per your requirement. - popoverController.permittedArrowDirections = [] //to hide the arrow of any particular direction + popoverController.permittedArrowDirections = [] // to hide the arrow of any particular direction } self.present(alert, animated: true, completion: nil) diff --git a/demoapp/demoapp/UseCases/CardsDataCollectingViewController.swift b/demoapp/demoapp/UseCases/CardsDataCollectingViewController.swift index de1cace1..f4a2706f 100644 --- a/demoapp/demoapp/UseCases/CardsDataCollectingViewController.swift +++ b/demoapp/demoapp/UseCases/CardsDataCollectingViewController.swift @@ -142,7 +142,7 @@ class CardsDataCollectingViewController: UIViewController { cardHolderName.textAlignment = .natural // Set max input length - //holderConfiguration.maxInputLength = 32 + // holderConfiguration.maxInputLength = 32 cardHolderName.configuration = holderConfiguration cardHolderName.placeholder = "Cardholder Name" diff --git a/demoapp/demoapp/UseCases/CollectApplePayDataViewController.swift b/demoapp/demoapp/UseCases/CollectApplePayDataViewController.swift index 720470c7..ff14c341 100644 --- a/demoapp/demoapp/UseCases/CollectApplePayDataViewController.swift +++ b/demoapp/demoapp/UseCases/CollectApplePayDataViewController.swift @@ -96,7 +96,7 @@ extension CollectApplePayData: PKPaymentAuthorizationControllerDelegate { func paymentAuthorizationController(_ controller: PKPaymentAuthorizationController, didAuthorizePayment payment: PKPayment, handler completion: @escaping (PKPaymentAuthorizationResult) -> Void) { /// Prepapre payment data required to collect for your use-case - guard let paymentDataDictionary: [String: Any] = try? JSONSerialization.jsonObject(with: payment.token.paymentData, options: .mutableContainers) as? [String : Any] else { + guard let paymentDataDictionary: [String: Any] = try? JSONSerialization.jsonObject(with: payment.token.paymentData, options: .mutableContainers) as? [String: Any] else { print("Error: can't parse payment.token.paymentData") completion(PKPaymentAuthorizationResult(status: .failure, errors: nil)) return @@ -132,4 +132,3 @@ extension CollectApplePayData: PKPaymentAuthorizationControllerDelegate { controller.dismiss(completion: nil) } } - diff --git a/demoapp/demoapp/UseCases/CustomPaymentCardsViewController.swift b/demoapp/demoapp/UseCases/CustomPaymentCardsViewController.swift index 6a35ef69..02b7dfcb 100644 --- a/demoapp/demoapp/UseCases/CustomPaymentCardsViewController.swift +++ b/demoapp/demoapp/UseCases/CustomPaymentCardsViewController.swift @@ -38,7 +38,6 @@ class CustomPaymentCardsViewController: UIViewController { setupUI() setupElementsConfiguration() - // set custom headers vgsCollect.customHeaders = [ "my custome header": "some custom data" @@ -234,19 +233,19 @@ class CustomPaymentCardsViewController: UIViewController { extension CustomPaymentCardsViewController: VGSCardIOScanControllerDelegate { - //When user press Done button on CardIO screen + // When user press Done button on CardIO screen func userDidFinishScan() { scanController.dismissCardScanner(animated: true, completion: { // add actions on scan controller dismiss completion }) } - //When user press Cancel button on CardIO screen + // When user press Cancel button on CardIO screen func userDidCancelScan() { scanController.dismissCardScanner(animated: true, completion: nil) } - //Asks VGSTextField where scanned data with type need to be set. + // Asks VGSTextField where scanned data with type need to be set. func textFieldForScannedData(type: CradIODataType) -> VGSTextField? { switch type { case .expirationDateLong: diff --git a/demoapp/demoapp/UseCases/FilePickerViewController.swift b/demoapp/demoapp/UseCases/FilePickerViewController.swift index 2ef04881..25cec258 100644 --- a/demoapp/demoapp/UseCases/FilePickerViewController.swift +++ b/demoapp/demoapp/UseCases/FilePickerViewController.swift @@ -62,17 +62,6 @@ class FilePickerViewController: UIViewController { return } } - - /// Deprecated -// vgsForm.submitFile(path: "/post", method: .post, extraData: extraData) { [weak self](json, error) in -// if error == nil, let json = json?["json"] { -// self?.stateLabel.text = "Success!!!\n" + (String(data: try! JSONSerialization.data(withJSONObject: json, options: .prettyPrinted), encoding: .utf8)!) -// self?.vgsForm.cleanFiles() -// } else { -// print("Error: \(String(describing: error?.localizedDescription))") -// self?.stateLabel.text = "Something went wrong!" -// } -// } } // Show file picker for specific source type @@ -105,9 +94,9 @@ class FilePickerViewController: UIViewController { alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) if let popoverController = alert.popoverPresentationController { - popoverController.sourceView = self.view //to set the source of your alert + popoverController.sourceView = self.view // to set the source of your alert popoverController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0) // you can set this as per your requirement. - popoverController.permittedArrowDirections = [] //to hide the arrow of any particular direction + popoverController.permittedArrowDirections = [] // to hide the arrow of any particular direction } present(alert, animated: true, completion: nil) diff --git a/demoapp/demoapp/UseCases/PayOptIntegration/CollectPaymentOptIntegrationViewController.swift b/demoapp/demoapp/UseCases/PayOptIntegration/CollectPaymentOptIntegrationViewController.swift index 40a6d3b8..0d6e007c 100644 --- a/demoapp/demoapp/UseCases/PayOptIntegration/CollectPaymentOptIntegrationViewController.swift +++ b/demoapp/demoapp/UseCases/PayOptIntegration/CollectPaymentOptIntegrationViewController.swift @@ -91,7 +91,7 @@ class CollectPayoptIntegrationViewConroller: UIViewController { // // return // return - //state = .fetchingSavedCards(.success(models)) +// state = .fetchingSavedCards(.success(models)) state = .fetchingToken(.isLoading) apiClient.fetchToken {[weak self] token in @@ -199,10 +199,10 @@ class CollectPayoptIntegrationViewConroller: UIViewController { } /// Save fin instrument in shared config AppCollectorConfiguration.shared.savedFinancialInstruments.append(finId) - /// Make deposit request + // Make deposit request // self?.deposit(50, finId: finId) self?.state = .sendingNewCard(.success(finId)) - case .failure(let code, _, _, let error): + case .failure(let code, _, _, let error): print("\(code) + \(String(describing: error))") self?.state = .sendingNewCard(.error(error?.localizedDescription)) return @@ -240,7 +240,7 @@ class CollectPayoptIntegrationViewConroller: UIViewController { /// vgsCollectNewCardFlow.customHeaders = ["Authorization": ""] /// Include all data required for transaction in extradata attribute. - let extraData: [String : Any] = ["fin_id": findId, "amount": amount] + let extraData: [String: Any] = ["fin_id": findId, "amount": amount] /// You should create new route in VGS Dashboard to tokenize CVC. let cvcRouteId = "" @@ -260,9 +260,9 @@ class CollectPayoptIntegrationViewConroller: UIViewController { /// Send deposit request to custom backend private func deposit(_ sum: Int, finId: String) { - // TODO: make API call to custom backend, backend should use fin_id and sum to make transfer via payopt API. + // NOTE: make API call to custom backend, backend should use fin_id and sum to make transfer via payopt API. print("🔼 Send transfer with deposit: \(sum) fin_id: \(finId)") - /// Navigate to completion VC + // Navigate to completion VC // let storyBoard = UIStoryboard(name: "Main", bundle:nil) // let nextViewController = storyBoard.instantiateViewController(withIdentifier: "CompletionViewController") // self.navigationController?.pushViewController(nextViewController, animated: true) @@ -303,19 +303,19 @@ class CollectPayoptIntegrationViewConroller: UIViewController { } func updateSavedCardsUI(with savedCardsRequestState: RequestResult<[SavedCardModel]>) { - switch savedCardsRequestState { - case .success(let fetchedCards): - savedCards = fetchedCards - paymentOptions = fetchedCards.map({return PaymentOption.savedCard($0)}) + [.newCard] - prepareDataSource() - tableView.reloadData() - hideLoader() - case .error(let errorText): - print("Cannot fetch saved cards: \(errorText ?? "Uknown error")") - hideLoader() - case .isLoading: - displayLoader() - } + switch savedCardsRequestState { + case .success(let fetchedCards): + savedCards = fetchedCards + paymentOptions = fetchedCards.map({return PaymentOption.savedCard($0)}) + [.newCard] + prepareDataSource() + tableView.reloadData() + hideLoader() + case .error(let errorText): + print("Cannot fetch saved cards: \(errorText ?? "Uknown error")") + hideLoader() + case .isLoading: + displayLoader() + } } func updateUISendNewCard(_ requestState: RequestResult) { @@ -396,11 +396,11 @@ extension CollectPayoptIntegrationViewConroller: UITableViewDelegate, UITableVie case .savedCard(let savedCardModel): let cell: VGSPaymentOptionCardTableViewCell = tableView.dequeue(cellForRowAt: indexPath) cell.configure(with: savedCardModel.paymentOptionCellViewModel, isEditing: false) - //cell.delegate = self + // cell.delegate = self return cell } - +// swiftlint:disable file_length // if indexPath.section == paymentMethodsDataSource.count - 1, let cell = tableView.dequeueReusableCell(withIdentifier: "AddCardCell", for: indexPath) as? AddCardCell { // cell.title.text = cellData.title @@ -453,9 +453,9 @@ extension CollectPayoptIntegrationViewConroller: UITableViewDelegate, UITableVie let option = paymentOptions[savedCardIndex] switch option { case .savedCard(let previousCard): - //print("savedCardIndex: \(savedCardIndex), index: \(index)") + // print("savedCardIndex: \(savedCardIndex), index: \(index)") if savedCardIndex != index { - //print("unmard card!") + // print("unmard card!") previousCard.isSelected = false } case .newCard: diff --git a/demoapp/demoapp/UseCases/PayOptIntegration/Helpers/CustomBackendAPIClient.swift b/demoapp/demoapp/UseCases/PayOptIntegration/Helpers/CustomBackendAPIClient.swift index af1664ac..6b29b393 100644 --- a/demoapp/demoapp/UseCases/PayOptIntegration/Helpers/CustomBackendAPIClient.swift +++ b/demoapp/demoapp/UseCases/PayOptIntegration/Helpers/CustomBackendAPIClient.swift @@ -28,8 +28,7 @@ final class CustomBackendAPIClient { typealias FetchSavedCardsCompletionFailure = ( _ error: Error?) -> Void /// Main url. - private let baseUrl = URL(string: AppCollectorConfiguration.shared.customBackendBaseUrl)! - + private let baseUrl = URL(string: AppCollectorConfiguration.shared.customBackendBaseUrl)! /// Fetch payment orchestration token from your own backend. /// - Parameters: @@ -42,7 +41,7 @@ final class CustomBackendAPIClient { request.httpMethod = "POST" let task = URLSession.shared.dataTask( with: request, - completionHandler: { (data, response, error) in + completionHandler: { (data, _, _) in guard let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { @@ -85,7 +84,7 @@ final class CustomBackendAPIClient { fetchPaymentInstrument(with: finId, accessToken: accessToken) { savedCard in fetchedSavedCards.append(savedCard) dispatchGroup.leave() - } failure: { error in + } failure: { _ in dispatchGroup.leave() } } @@ -129,7 +128,6 @@ final class CustomBackendAPIClient { }) } - // MARK: - Private /// Sends API request. @@ -144,7 +142,7 @@ final class CustomBackendAPIClient { let requestUrl = url.appendingPathComponent(path) var request = URLRequest(url: requestUrl) request.httpMethod = httpMethod - var requestHeaders: [String:String] = [:] + var requestHeaders: [String: String] = [:] requestHeaders["Content-Type"] = "application/json" if let customerHeaders = headers, customerHeaders.count > 0 { @@ -161,7 +159,7 @@ final class CustomBackendAPIClient { let task = URLSession.shared.dataTask( with: request, - completionHandler: {(data, response, error) in + completionHandler: {(data, _, _) in guard let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { diff --git a/demoapp/demoapp/UseCases/PayOptIntegration/Models/SavedCardModel.swift b/demoapp/demoapp/UseCases/PayOptIntegration/Models/SavedCardModel.swift index c0bf3181..842b5ac2 100644 --- a/demoapp/demoapp/UseCases/PayOptIntegration/Models/SavedCardModel.swift +++ b/demoapp/demoapp/UseCases/PayOptIntegration/Models/SavedCardModel.swift @@ -50,7 +50,7 @@ internal class SavedCardModel { let name = cardJSON[keys.name] as? String, let expYear = cardJSON[keys.expYear] as? Int, let expMonth = cardJSON[keys.expMonth] as? Int, - let brand = cardJSON[keys.brand] as? String , + let brand = cardJSON[keys.brand] as? String, let last4 = cardJSON[keys.last4] as? String else { return nil } @@ -101,10 +101,8 @@ internal extension Array where Element == SavedCardModel { func reorderByIds(_ cardIds: [String]) -> [SavedCardModel] { var orderedArray: [SavedCardModel] = [] cardIds.forEach { id in - for card in self { - if card.id == id { + for card in self where card.id == id { orderedArray.append(card) - } } } diff --git a/demoapp/demoapp/UseCases/PayOptIntegration/Views/TableViewCells/PaymentCardCell.swift b/demoapp/demoapp/UseCases/PayOptIntegration/Views/TableViewCells/PaymentCardCell.swift index 0f9c8ebe..8d8ca3b6 100644 --- a/demoapp/demoapp/UseCases/PayOptIntegration/Views/TableViewCells/PaymentCardCell.swift +++ b/demoapp/demoapp/UseCases/PayOptIntegration/Views/TableViewCells/PaymentCardCell.swift @@ -2,7 +2,6 @@ // PaymentCardCell.swift // demoapp - import UIKit import VGSCollectSDK diff --git a/demoapp/demoapp/UseCases/PayOptIntegration/Views/TableViewCells/VGSPaymentOptionCardTableViewCell.swift b/demoapp/demoapp/UseCases/PayOptIntegration/Views/TableViewCells/VGSPaymentOptionCardTableViewCell.swift index 122eafe6..dd824642 100644 --- a/demoapp/demoapp/UseCases/PayOptIntegration/Views/TableViewCells/VGSPaymentOptionCardTableViewCell.swift +++ b/demoapp/demoapp/UseCases/PayOptIntegration/Views/TableViewCells/VGSPaymentOptionCardTableViewCell.swift @@ -8,7 +8,8 @@ import VGSCollectSDK /// A set of methods to notify about changes in `VGSPaymentOptionCardTableViewCell` cell. internal protocol VGSPaymentOptionCardTableViewCellDelegate: AnyObject { - +// swiftlint:disable:previous type_name + /// Tells the delegate that user tappped removed card. /// - Parameter savedCardCell: `VGSPaymentOptionCardTableViewCell` object, saved card cell. func removeCardDidTap(in savedCardCell: VGSPaymentOptionCardTableViewCell) diff --git a/demoapp/demoappUITests/TestCollectCardsDataFlow.swift b/demoapp/demoappUITests/TestCollectCardsDataFlow.swift index 453ec2e4..f94c42f9 100644 --- a/demoapp/demoappUITests/TestCollectCardsDataFlow.swift +++ b/demoapp/demoappUITests/TestCollectCardsDataFlow.swift @@ -14,6 +14,7 @@ class TestCollectCardsDataFlow: TestCollectBaseTestCase { /// UI elements. enum UIElements { + // swiftlint:disable nesting /// VGSText field. enum VGSTextField { @@ -63,6 +64,7 @@ class TestCollectCardsDataFlow: TestCollectBaseTestCase { /// Upload. static let upload: VGSUITestElement = .init(type: .button, identifier: "UPLOAD") } + // swiftlint:enable nesting } /// Test valid data flow. @@ -103,7 +105,6 @@ class TestCollectCardsDataFlow: TestCollectBaseTestCase { let expDateField = UIElements.VGSTextField.CardDetails.expirationDate.find(in: app) let cvcField = UIElements.VGSTextField.CardDetails.cvc.find(in: app) - cardHolderNameField.tap() cardHolderNameField.typeText("Joe B") diff --git a/demoapp/demoappUITests/TestCollectSSNDataFlow.swift b/demoapp/demoappUITests/TestCollectSSNDataFlow.swift index 755685e8..3bfcc0d0 100644 --- a/demoapp/demoappUITests/TestCollectSSNDataFlow.swift +++ b/demoapp/demoappUITests/TestCollectSSNDataFlow.swift @@ -13,7 +13,8 @@ class TestCollectSSNDataFlow: TestCollectBaseTestCase { /// UI elements. enum UIElements { - + // swiftlint:disable nesting + /// VGSText field. enum VGSTextField { @@ -53,6 +54,7 @@ class TestCollectSSNDataFlow: TestCollectBaseTestCase { /// Masked ssn. static let maskedSSN = "SSN: XXX-XX-8899" } + // swiftlint:enable nesting } /// Verifies correct data flow works for ssn. diff --git a/demoapp/demoappUITests/TestCollectSSNFlow.swift b/demoapp/demoappUITests/TestCollectSSNFlow.swift index aaadd5b1..ced79e31 100644 --- a/demoapp/demoappUITests/TestCollectSSNFlow.swift +++ b/demoapp/demoappUITests/TestCollectSSNFlow.swift @@ -13,7 +13,8 @@ class TestCollectSSNFlow: TestCollectBaseTestCase { /// UI elements. enum UIElements { - + // swiftlint:disable nesting + /// VGSText field. enum VGSTextField { @@ -53,6 +54,7 @@ class TestCollectSSNFlow: TestCollectBaseTestCase { /// Masked ssn. static let maskedSSN = "SSN: XXX-XX-8899" } + // swiftlint:enable nesting } /// Verifies ssn flow work for valid ssn. diff --git a/demoapp/demoappUITests/TestCustomCardNumbersDataFlow.swift b/demoapp/demoappUITests/TestCustomCardNumbersDataFlow.swift index 055d84b9..12fb60fe 100644 --- a/demoapp/demoappUITests/TestCustomCardNumbersDataFlow.swift +++ b/demoapp/demoappUITests/TestCustomCardNumbersDataFlow.swift @@ -2,9 +2,6 @@ // TestCustomCardNumbersDataFlow.swift // demoappUITests // -// Created by Dima on 04.08.2020. -// Copyright © 2020 Very Good Security. All rights reserved. -// import XCTest @@ -13,7 +10,8 @@ class TestCustomCardNumbersDataFlow: TestCollectBaseTestCase { /// UI elements. enum UIElements { - + // swiftlint:disable nesting + /// VGSText field. enum VGSTextField { @@ -96,6 +94,7 @@ class TestCustomCardNumbersDataFlow: TestCollectBaseTestCase { /// Custom brand. static let uknownBrand = "9111 1111 1111 111" } + // swiftlint:enable nesting } /// Tests valid custom brand. @@ -208,7 +207,6 @@ class TestCustomCardNumbersDataFlow: TestCollectBaseTestCase { let expDateField = UIElements.VGSTextField.CardDetails.expirationDate.find(in: app) let cvcField = UIElements.VGSTextField.CardDetails.cvc.find(in: app) - cardHolderNameField.tap() cardHolderNameField.typeText("Joe B") diff --git a/demoapp/demoappUITests/UITestUtils/VGSUITestElement.swift b/demoapp/demoappUITests/UITestUtils/VGSUITestElement.swift index 55255119..d77b5e04 100644 --- a/demoapp/demoappUITests/UITestUtils/VGSUITestElement.swift +++ b/demoapp/demoappUITests/UITestUtils/VGSUITestElement.swift @@ -18,29 +18,29 @@ struct VGSUITestElement { /// - Parameter app: `XCUIApplication` object. /// - Returns: `XCUIElement` object. func find(in app: XCUIApplication) -> XCUIElement { - switch type { - case .label: - return app.staticTexts[identifier] - case .button: - return app.buttons[identifier] - case .table: - return app.tables[identifier] - case .slider: - return app.sliders[identifier] - case .other: - return app.otherElements[identifier] - case .collection: - return app.collectionViews[identifier] - case .image: - return app.images[identifier] - case .textField: - return app.textFields[identifier] - case .secureTextField: - return app.secureTextFields[identifier] - case .tabBar: - return app.tabBars[identifier] - case .navigationBar: - return app.navigationBars[identifier] + switch type { + case .label: + return app.staticTexts[identifier] + case .button: + return app.buttons[identifier] + case .table: + return app.tables[identifier] + case .slider: + return app.sliders[identifier] + case .other: + return app.otherElements[identifier] + case .collection: + return app.collectionViews[identifier] + case .image: + return app.images[identifier] + case .textField: + return app.textFields[identifier] + case .secureTextField: + return app.secureTextFields[identifier] + case .tabBar: + return app.tabBars[identifier] + case .navigationBar: + return app.navigationBars[identifier] } } From b2563ee4e682077c2a5ad78c7c7b37a39eb4ca85 Mon Sep 17 00:00:00 2001 From: Dima Khludkov <57712402+dmytrokhl@users.noreply.github.com> Date: Tue, 25 Apr 2023 14:42:12 +0300 Subject: [PATCH 2/9] Add Combine and Concurrency API support. --- .circleci/config.yml | 12 +- .../Core/Collector/VGSCollect+network.swift | 147 +++++++++- .../Text Field/VGSExpDateTextField.swift | 1 - .../VGSTextField+statePublisher.swift | 86 ++++++ .../APIClient Tests/ApiClientTests.swift | 265 +++++++++++------- .../TokenizationApiTests.swift | 193 ++++++++----- .../Test Helpers/MockedDataProvider.swift | 5 +- .../VGSTextFieldStatePublisherTests.swift | 85 ++++++ VGSCollectSDK.xcodeproj/project.pbxproj | 16 ++ demoapp/demoapp.xcodeproj/project.pbxproj | 4 + .../xcshareddata/xcschemes/demoapp.xcscheme | 2 +- .../xcschemes/demoappUITests.xcscheme | 2 +- demoapp/demoapp/Main.storyboard | 152 +++++++++- .../CardsDataCollectingViewController.swift | 3 +- .../CombineExamplesViewController.swift | 246 ++++++++++++++++ 15 files changed, 1026 insertions(+), 193 deletions(-) create mode 100644 Sources/VGSCollectSDK/UIElements/Text Field/VGSTextField+statePublisher.swift create mode 100644 Tests/FrameworkTests/VGSTextFieldStatePublisherTests/VGSTextFieldStatePublisherTests.swift create mode 100644 demoapp/demoapp/UseCases/CombineExamplesViewController.swift diff --git a/.circleci/config.yml b/.circleci/config.yml index f2d0b42c..83d37963 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,31 +3,31 @@ version: 2 jobs: build-and-test-sdk: macos: - xcode: "14.0" + xcode: "14.2" steps: - checkout - run: name: Run Tests iOS 16 command: > - cd Tests/FrameworkTests/Resources && plutil -insert tokenization_vaultId -string ${tokenization_vaultId} MockedData.plist && cd .. && cd .. && cd .. && xcodebuild test -project VGSCollectSDK.xcodeproj -scheme FrameworkTests -destination 'platform=iOS Simulator,name=iPhone 14,OS=16.0' -testPlan FrameworkTests + cd Tests/FrameworkTests/Resources && plutil -insert tokenization_vaultId -string ${tokenization_vaultId} MockedData.plist && plutil -insert vaultID -string ${vaultID} MockedData.plist && cd .. && cd .. && cd .. && xcodebuild test -project VGSCollectSDK.xcodeproj -scheme FrameworkTests -destination 'platform=iOS Simulator,name=iPhone 14,OS=16.2' -testPlan FrameworkTests build-and-ui-test-demo-app-ios-16-iphone14: macos: - xcode: "14.0" + xcode: "14.2" steps: - checkout - run: - name: Run UI Tests on iPhone 14 iOS 16.0 + name: Run UI Tests on iPhone 14 iOS 16.2 command: > cd demoapp && cd demoapp && plutil -insert vaultID -string ${vaultID} UITestsMockedData.plist && cd .. && pod install && - xcrun instruments -w "iPhone 14 (16.0) [" || true && + xcrun instruments -w "iPhone 14 (16.2) [" || true && xcodebuild test -workspace demoapp.xcworkspace -scheme demoappUITests -sdk iphonesimulator - -destination 'platform=iOS Simulator,name=iPhone 14,OS=16.0' + -destination 'platform=iOS Simulator,name=iPhone 14,OS=16.2' workflows: version: 2 diff --git a/Sources/VGSCollectSDK/Core/Collector/VGSCollect+network.swift b/Sources/VGSCollectSDK/Core/Collector/VGSCollect+network.swift index bb9d7cfa..05fe3acc 100644 --- a/Sources/VGSCollectSDK/Core/Collector/VGSCollect+network.swift +++ b/Sources/VGSCollectSDK/Core/Collector/VGSCollect+network.swift @@ -2,11 +2,9 @@ // VGSCollect+network.swift // VGSCollectSDK // -// Created by Vitalii Obertynskyi on 09.05.2020. -// Copyright © 2020 VGS. All rights reserved. -// import Foundation +import Combine // MARK: - Send data extension VGSCollect { @@ -51,7 +49,7 @@ extension VGSCollect { VGSAnalyticsClient.shared.trackFormEvent(self.formAnalyticsDetails, type: .beforeSubmit, status: .success, extraData: [ "statusCode": 200, "content": content]) // Send request. - apiClient.sendRequest(path: path, method: method, routeId: routeId, value: body) { [weak self](response ) in + apiClient.sendRequest(path: path, method: method, routeId: routeId, value: body) { [weak self](response ) in // Analytics if let strongSelf = self { @@ -80,7 +78,7 @@ extension VGSCollect { - Note: Errors can be returned in the `NSURLErrorDomain` and `VGSCollectSDKErrorDomain`. */ - public func sendFile(path: String, method: VGSCollectHTTPMethod = .post, routeId: String? = nil, extraData: [String: Any]? = nil, completion block: @escaping (VGSResponse) -> Void) { + public func sendFile(path: String, method: VGSCollectHTTPMethod = .post, routeId: String? = nil, extraData: [String: Any]? = nil, requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions(), completion block: @escaping (VGSResponse) -> Void) { var content: [String] = ["file"] if !(extraData?.isEmpty ?? true) { @@ -171,7 +169,7 @@ extension VGSCollect { } /** - Makes tokenization response with data from VGSTextFields. + Send tokenization request with data from VGSTextFields. - Parameters: - routeId: id of VGS Proxy Route, default is `nil`. - completion: response completion block, returns `VGSTokenizationResponse`. @@ -226,3 +224,140 @@ extension VGSCollect { } } } + +// MARK: VGSCollect + async +@available(iOS 13, *) +extension VGSCollect { + /** + Asynchronously send data from VGSTextFields to your organization vault. + + - Parameters: + - path: Inbound rout path for your organization vault. + - method: VGSCollectHTTPMethod, default is `.post`. + - routeId: id of VGS Proxy Route, default is `nil`. + - extraData: Any data you want to send together with data from VGSTextFields , default is `nil`. + - requestOptions: `VGSCollectRequestOptions` object, holds additional request options. Default options are `.nestedJSON`. + - Returns: + - VGSResponse: response completion block, returns `VGSResponse`. + + - Note: + Errors can be returned in the `NSURLErrorDomain` and `VGSCollectSDKErrorDomain`. + */ + public func sendData(path: String, method: VGSCollectHTTPMethod = .post, routeId: String? = nil, extraData: [String: Any]? = nil, requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions()) async -> VGSResponse { + return await withCheckedContinuation { continuation in + //NOTE: We need to use main thread since data will be collected from UI elements + DispatchQueue.main.async { + self.sendData(path: path, method: method, routeId: routeId, extraData: extraData, requestOptions: requestOptions) { response in + continuation.resume(returning: response) + + } + } + } + } + + /** + Asynchronously send file to your organization vault. Only send one file at a time. + + - Parameters: + - path: Inbound rout path for your organization vault. + - method: HTTPMethod, default is `.post`. + - routeId: id of VGS Proxy Route, default is `nil`. + - extraData: Any data you want to send together with data from VGSTextFields , default is `nil`. + - completion: response completion block, returns `VGSResponse`. + + - Note: + Errors can be returned in the `NSURLErrorDomain` and `VGSCollectSDKErrorDomain`. + */ + public func sendFile(path: String, method: VGSCollectHTTPMethod = .post, routeId: String? = nil, extraData: [String: Any]? = nil) async -> VGSResponse { + return await withCheckedContinuation { continuation in + self.sendFile(path: path, method: method, routeId: routeId, extraData: extraData) { response in + continuation.resume(returning: response) + } + } + } + + /** + Asynchronously send tokenization request with data from VGSTextFields. + - Parameters: + - routeId: id of VGS Proxy Route, default is `nil`. + - completion: response completion block, returns `VGSTokenizationResponse`. + - Note: + Errors can be returned in the `NSURLErrorDomain` and `VGSCollectSDKErrorDomain`. + */ + public func tokenizeData(routeId: String? = nil) async -> VGSTokenizationResponse { + return await withCheckedContinuation { continuation in + //NOTE: We need to use main thread since data will be collected from UI elements + DispatchQueue.main.async { + self.tokenizeData {response in + continuation.resume(returning: response) + } + } + } + } +} + +// MARK: VGSCollect + Combine +@available(iOS 13, *) +extension VGSCollect { + /** + Send data from VGSTextFields to your organization vault using the Combine framework. + + - Parameters: + - path: Inbound rout path for your organization vault. + - method: VGSCollectHTTPMethod, default is `.post`. + - routeId: id of VGS Proxy Route, default is `nil`. + - extraData: Any data you want to send together with data from VGSTextFields , default is `nil`. + - requestOptions: `VGSCollectRequestOptions` object, holds additional request options. Default options are `.nestedJSON`. + - Returns: A `Future` publisher that emits a single `VGSResponse`. + + - Note: + Errors can be returned in the `NSURLErrorDomain` and `VGSCollectSDKErrorDomain`. + */ + public func sendDataPublisher(path: String, method: VGSCollectHTTPMethod = .post, routeId: String? = nil, extraData: [String: Any]? = nil, requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions()) -> Future { + return Future { [weak self] completion in + self?.sendData(path: path, method: method, routeId: routeId, extraData: extraData, requestOptions: requestOptions) { response in + completion(.success(response)) + } + } + } + + /** + Send file to your organization vault using the Combine framework. + + - Parameters: + - path: Inbound rout path for your organization vault. + - method: VGSCollectHTTPMethod, default is `.post`. + - routeId: id of VGS Proxy Route, default is `nil`. + - extraData: Any data you want to send together with data from VGSTextFields , default is `nil`. + - requestOptions: `VGSCollectRequestOptions` object, holds additional request options. Default options are `.nestedJSON`. + - Returns: A `Future` publisher that emits a single `VGSResponse`. + + - Note: + Errors can be returned in the `NSURLErrorDomain` and `VGSCollectSDKErrorDomain`. + */ + public func sendFilePublisher(path: String, method: VGSCollectHTTPMethod = .post, routeId: String? = nil, extraData: [String: Any]? = nil, requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions()) -> Future { + return Future { [weak self] completion in + self?.sendFile(path: path, method: method, routeId: routeId, extraData: extraData, requestOptions: requestOptions) { response in + completion(.success(response)) + } + } + } + + /** + Send tokenization request with data from VGSTextFields to your organization vault using the Combine framework. + + - Parameters: + - routeId: id of VGS Proxy Route, default is `nil`. + - Returns: A `Future` publisher that emits a single `VGSTokenizationResponse`. + + - Note: + Errors can be returned in the `NSURLErrorDomain` and `VGSCollectSDKErrorDomain`. + */ + public func tokenizeDataPublisher(routeId: String? = nil) -> Future { + return Future { [weak self] completion in + self?.tokenizeData(routeId: routeId) { response in + completion(.success(response)) + } + } + } +} diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift b/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift index 0562cd73..a91b8084 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift @@ -78,7 +78,6 @@ public final class VGSExpDateTextField: VGSTextField { guard let config = configuration as? VGSExpDateConfiguration else { return } - // setup input source switch config.inputSource { case .datePicker: diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/VGSTextField+statePublisher.swift b/Sources/VGSCollectSDK/UIElements/Text Field/VGSTextField+statePublisher.swift new file mode 100644 index 00000000..1605ab3c --- /dev/null +++ b/Sources/VGSCollectSDK/UIElements/Text Field/VGSTextField+statePublisher.swift @@ -0,0 +1,86 @@ +// +// VGSTextField+statePublisher.swift +// VGSCollectSDK +// + +import Foundation +import Combine + +@available(iOS 13, *) +public extension VGSTextField { + /// `VGSTextFieldStatePublisher` publisher that emits the `State` of a given `VGSTextField`. + var statePublisher: VGSTextFieldStatePublisher { + return VGSTextFieldStatePublisher(self) + } +} + +/// A custom publisher that emits `State` of a given `VGSTextField`. +@available(iOS 13, *) +public struct VGSTextFieldStatePublisher: Publisher { + public typealias Output = State + public typealias Failure = Never + + private unowned let vgsTextField: VGSTextField + + /// Initializer + /// - Parameter vgsTextField: The `VGSTextField` instance to observe for state changes. + init(_ vgsTextField: VGSTextField) { + self.vgsTextField = vgsTextField + } + + /// Attaches a subscriber to the publisher to receive updates on the `VGSTextField` `State`. + /// - Parameter subscriber: The subscriber that will receive state updates. + public func receive(subscriber: S) where S.Input == Output, S.Failure == Failure { + let subscription = VGSTextFieldStateSubscription(subscriber: subscriber, vgsTextField: vgsTextField) + subscriber.receive(subscription: subscription) + } +} + +/// A `VGSTextFieldStateSubscription` subscription that conforms to the `Subscription` and `VGSTextFieldDelegate` protocols. +/// Used by the `VGSTextFieldStatePublisher` to manage the subscribers and deliver updates on the `VGSTextField` `State`. +@available(iOS 13, *) +final class VGSTextFieldStateSubscription: NSObject, Subscription, VGSTextFieldDelegate where S.Input == State, S.Failure == Never { + private var subscriber: S? + private unowned let vgsTextField: VGSTextField + + /// Initializer with a subscriber and a `VGSTextField`. + /// + /// - Parameters: + /// - subscriber: The subscriber attached to the publisher. + /// - vgsTextField: The `VGSTextField` instance to observe for state changes. + init(subscriber: S, vgsTextField: VGSTextField) { + self.subscriber = subscriber + self.vgsTextField = vgsTextField + super.init() + vgsTextField.delegate = self + } + + /// Indicates if the subscriber is ready to receive more values. + /// - Parameter demand: The maximum number of values the subscriber is ready to receive. + func request(_ demand: Subscribers.Demand) { + // Nothing to do here as VGSTextFieldDelegate updates the state on demand. + } + + /// Cancel recieve events. + func cancel() { + subscriber = nil + } + + // MARK: - VGSTextFieldDelegate + + func vgsTextFieldDidBeginEditing(_ textField: VGSTextField) { + _ = subscriber?.receive(textField.state) + } + + func vgsTextFieldDidEndEditing(_ textField: VGSTextField) { + _ = subscriber?.receive(textField.state) + } + + func vgsTextFieldDidChange(_ textField: VGSTextField) { + _ = subscriber?.receive(textField.state) + } + + func vgsTextFieldDidEndEditingOnReturn(_ textField: VGSTextField) { + _ = subscriber?.receive(textField.state) + } +} diff --git a/Tests/FrameworkTests/APIClient Tests/ApiClientTests.swift b/Tests/FrameworkTests/APIClient Tests/ApiClientTests.swift index 7209d522..36db912e 100644 --- a/Tests/FrameworkTests/APIClient Tests/ApiClientTests.swift +++ b/Tests/FrameworkTests/APIClient Tests/ApiClientTests.swift @@ -2,129 +2,128 @@ // ApiClientTests.swift // FrameworkTests // -// Created by Vitalii Obertynskyi on 9/19/19. -// Copyright © 2019 Vitalii Obertynskyi. All rights reserved. -// import XCTest +import Combine @testable import VGSCollectSDK +@available(iOS 13, *) class ApiClientTests: VGSCollectBaseTestCase { var collector: VGSCollect! - + + var cardTextField: VGSCardTextField! + var expDateTextField: VGSTextField! + var cardHolderTextField: VGSTextField! + var numbersTextField: VGSCardTextField! + + let testCardNumber = "41111111111111111" + let testNumbers = "1234567890" + let testNumbersResponse = "123-4567-89" + let testCardHolder = "Joe Business" + let testExpDate = "1125" + let testExpDateResponse = "11/2025" + + let customHeaderKey = "Customheaderkey" + let customHeaderValue = "CustomHeaderValue" + let extraDataKey = "extraKey" + let extraDataValue = "extraValue" + + var cancellables: Set! + override func setUp() { - collector = VGSCollect(id: "tntva5wfdrp", environment: .sandbox) + collector = VGSCollect(id: MockedDataProvider.shared.vaultId, environment: .sandbox) + cancellables = Set() + cardTextField = VGSCardTextField() + expDateTextField = VGSExpDateTextField() + cardHolderTextField = VGSTextField() + numbersTextField = VGSCardTextField() } - + + override func tearDown() { + collector = nil + cardTextField = nil + expDateTextField = nil + cardHolderTextField = nil + numbersTextField = nil + } + func testSendCardToEchoServer() { - /// this test require setting proper inbound routs - - let cardNum = "4111111111111111" - let cardConfig = VGSConfiguration(collector: collector, fieldName: "cardNumber") - cardConfig.type = .cardNumber - let cardTextField = VGSCardTextField(frame: .zero) - cardTextField.configuration = cardConfig - cardTextField.textField.secureText = cardNum - - let someNumber = "1234567890" - let someNumberConfig = VGSConfiguration(collector: collector, fieldName: "not_secured_some_number") - someNumberConfig.type = .none - someNumberConfig.divider = "-" - someNumberConfig.formatPattern = "### #### ##" - let someNumberTextField = VGSCardTextField(frame: .zero) - someNumberTextField.configuration = someNumberConfig - someNumberTextField.textField.secureText = someNumber - - let expDate = "1122" - let expDateConfig = VGSConfiguration(collector: collector, fieldName: "expDate") - expDateConfig.type = .expDate - let expDatTextField = VGSTextField(frame: .zero) - expDatTextField.configuration = expDateConfig - expDatTextField.textField.secureText = expDate - - let cardHolder = "Joe Business" - let cardHolderConfig = VGSConfiguration(collector: collector, fieldName: "not_secured_cardHolder") - cardHolderConfig.type = .cardHolderName - let cardHolderTextField = VGSTextField(frame: .zero) - cardHolderTextField.configuration = cardHolderConfig - cardHolderTextField.textField.secureText = cardHolder - - let customHeaderKey = "Customheaderkey" - let customHeaderValue = "CustomHeaderValue" - collector.customHeaders = [ - customHeaderKey: customHeaderValue - ] - - let extraDataKey = "extraKey" - let extraDataValue = "extraValue" - let extraData = [extraDataKey: extraDataValue] - - let expectation = XCTestExpectation(description: "Sending data...") + self.configureCardTextFields() + + collector.customHeaders = [ + customHeaderKey: customHeaderValue + ] + + let extraData = [extraDataKey: extraDataValue] + + let expectation = XCTestExpectation(description: "Sending data...") - collector.sendData(path: "post", method: .post, extraData: extraData) { result in - switch result { - case .success(let code, let data, let response): - XCTAssertTrue(code == 200) - XCTAssertNotNil(data) - XCTAssertNotNil(response) - - guard let data = data, let jsonData = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { - XCTFail("Error: code=\(code): wrong data format") - expectation.fulfill() - return - } - - if let json = jsonData["json"] as? [String: String] { - XCTAssertTrue(json[extraDataKey] == extraDataValue) - XCTAssertNotNil(json["cardNumber"]) - XCTAssertTrue(json["cardNumber"] != cardNum) - XCTAssertTrue(json["expDate"] != "11/22") - XCTAssertTrue(json["not_secured_cardHolder"] == cardHolder) - XCTAssertTrue(json["not_secured_some_number"] == "123-4567-89") - } else { - XCTFail("Error: code=\(code): wrong json format") - } - - if let headers = jsonData["headers"] as? [String: String] { - XCTAssertTrue(headers[customHeaderKey] == customHeaderValue) - } else { - XCTFail("Error: code=\(code): wrong json format") - } - case .failure(let code, _, _, let error): - XCTFail("Error: code=\(code):\(String(describing: error?.localizedDescription))") - } + collector.sendData(path: "post", method: .post, extraData: extraData) { [weak self] result in + self?.validateSendDataResponseResults(result) expectation.fulfill() } wait(for: [expectation], timeout: 60.0) } + + func testAsyncSendCardToEchoServer() { + self.configureCardTextFields() + collector.customHeaders = [ + customHeaderKey: customHeaderValue + ] + let extraData = [extraDataKey: extraDataValue] + let expectation = XCTestExpectation(description: "Sending data...") + Task { + let result = await collector.sendData(path: "post", method: .post, extraData: extraData) + validateSendDataResponseResults(result) + expectation.fulfill() + } + wait(for: [expectation], timeout: 60.0) + } + + func testCardSendPublisherToEchoServer() { + self.configureCardTextFields() + collector.customHeaders = [ + customHeaderKey: customHeaderValue + ] + let extraData = [extraDataKey: extraDataValue] + let expectation = XCTestExpectation(description: "Sending data...") + collector.sendDataPublisher(path: "post", method: .post, extraData: extraData) + .sink {[weak self] result in + self?.validateSendDataResponseResults(result) + expectation.fulfill() + } + .store(in: &cancellables) + + wait(for: [expectation], timeout: 60) + } - func testWrongTanentId() { - let form = VGSCollect(id: "wrongId") - let conf = VGSConfiguration(collector: form, fieldName: "cardField") - conf.type = .cardNumber - let field = VGSTextField(frame: .zero) - field.configuration = conf - field.textField.secureText = "5252" - - let expectation = XCTestExpectation(description: "Sending data...") - - form.sendData(path: "post") { result in - switch result { - case .success: - break - case .failure(let code, let data, _, _): - XCTAssertNotNil(data) - XCTAssertTrue(code >= 400) - } - expectation.fulfill() + func testWrongTanentId() { + let form = VGSCollect(id: "wrongId") + let conf = VGSConfiguration(collector: form, fieldName: "cardField") + conf.type = .cardNumber + let field = VGSTextField() + field.configuration = conf + field.textField.secureText = "5252" + + let expectation = XCTestExpectation(description: "Sending data...") + + form.sendData(path: "post") { result in + switch result { + case .success: + break + case .failure(let code, let data, _, _): + XCTAssertNotNil(data) + XCTAssertTrue(code >= 400) } - wait(for: [expectation], timeout: 60.0) + expectation.fulfill() } + wait(for: [expectation], timeout: 60.0) + } func testWrongPath() { let conf = VGSConfiguration(collector: collector, fieldName: "cardField") conf.type = .cardNumber - let field = VGSTextField(frame: .zero) + let field = VGSTextField() field.configuration = conf field.textField.secureText = "5252" @@ -172,4 +171,66 @@ class ApiClientTests: VGSCollectBaseTestCase { } wait(for: [expectation], timeout: 60.0) } + + private func configureCardTextFields() { + /// this test requires setting proper inbound routs + let cardNum = testCardNumber + let cardConfig = VGSConfiguration(collector: collector, fieldName: "cardNumber") + cardConfig.type = .cardNumber + cardTextField.configuration = cardConfig + cardTextField.textField.secureText = cardNum + + let someNumber = testNumbers + let someNumberConfig = VGSConfiguration(collector: collector, fieldName: "not_secured_some_number") + someNumberConfig.type = .none + someNumberConfig.divider = "-" + someNumberConfig.formatPattern = "### #### ##" + numbersTextField.configuration = someNumberConfig + numbersTextField.textField.secureText = someNumber + + let expDate = testExpDate + let expDateConfig = VGSConfiguration(collector: collector, fieldName: "expDate") + expDateConfig.type = .expDate + expDateTextField.configuration = expDateConfig + expDateTextField.textField.secureText = expDate + + let cardHolder = testCardHolder + let cardHolderConfig = VGSConfiguration(collector: collector, fieldName: "not_secured_cardHolder") + cardHolderConfig.type = .cardHolderName + cardHolderTextField.configuration = cardHolderConfig + cardHolderTextField.textField.secureText = cardHolder + } + + private func validateSendDataResponseResults(_ result: VGSResponse) { + switch result { + case .success(let code, let data, let response): + XCTAssertTrue(code == 200) + XCTAssertNotNil(data) + XCTAssertNotNil(response) + + guard let data = data, let jsonData = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { + XCTFail("Error: code=\(code): wrong data format") + return + } + + if let json = jsonData["json"] as? [String: String] { + XCTAssertTrue(json[extraDataKey] == extraDataValue) + XCTAssertNotNil(json["cardNumber"]) + XCTAssertTrue(json["cardNumber"] != testCardNumber) + XCTAssertTrue(json["expDate"] != testExpDateResponse) + XCTAssertTrue(json["not_secured_cardHolder"] == testCardHolder) + XCTAssertTrue(json["not_secured_some_number"] == testNumbersResponse) + } else { + XCTFail("Error: code=\(code): wrong json format") + } + + if let headers = jsonData["headers"] as? [String: String] { + XCTAssertTrue(headers[customHeaderKey] == customHeaderValue) + } else { + XCTFail("Error: code=\(code): wrong json format") + } + case .failure(let code, _, _, let error): + XCTFail("Error: code=\(code):\(String(describing: error?.localizedDescription))") + } + } } diff --git a/Tests/FrameworkTests/APIClient Tests/TokenizationApiTests.swift b/Tests/FrameworkTests/APIClient Tests/TokenizationApiTests.swift index cf470cb8..d86f1d2a 100644 --- a/Tests/FrameworkTests/APIClient Tests/TokenizationApiTests.swift +++ b/Tests/FrameworkTests/APIClient Tests/TokenizationApiTests.swift @@ -4,85 +4,81 @@ // import XCTest +import Combine @testable import VGSCollectSDK +@available(iOS 13, *) class TokenizationApiTests: VGSCollectBaseTestCase { var collector: VGSCollect! + + var cardTextField: VGSCardTextField! + var expDateTextField: VGSTextField! + var cvcTextField: VGSCVCTextField! + var cardHolderTextField: VGSTextField! + var numbersTextField: VGSCardTextField! + + let testCardNumber = "41111111111111111" + let testCVC = "123" + let testNumbers = "1234567890" + let testNumbersResponse = "123-4567-89" + let testCardHolder = "Joe Business" + let testExpDate = "1125" + let testExpDateResponse = "11/2025" + + var cancellables: Set! override func setUp() { collector = VGSCollect(id: MockedDataProvider.shared.tokenizationVaultId, environment: .sandbox) + cancellables = Set() + cardTextField = VGSCardTextField() + cvcTextField = VGSCVCTextField() + expDateTextField = VGSExpDateTextField() + cardHolderTextField = VGSTextField() + numbersTextField = VGSCardTextField() + } + + override func tearDown() { + collector = nil + cancellables = nil + cardTextField = nil + expDateTextField = nil + cvcTextField = nil + cardHolderTextField = nil + numbersTextField = nil } - func testSendCardToTokenizationAPI() { - /// this test require setting tokenzation url as upstream host - - /// Tokenizable fields - let cardNum = "4111111111111111" - let cardConfig = VGSCardNumberTokenizationConfiguration(collector: collector, fieldName: "cardNumber") - cardConfig.type = .cardNumber - let cardTextField = VGSCardTextField() - cardTextField.configuration = cardConfig - cardTextField.textField.secureText = cardNum - - let expDate = "1125" - let expDateConfig = VGSExpDateTokenizationConfiguration(collector: collector, fieldName: "expDate") - expDateConfig.tokenizationParameters.format = VGSVaultAliasFormat.UUID.rawValue - expDateConfig.inputDateFormat = .shortYear - expDateConfig.outputDateFormat = .longYear - let expDatTextField = VGSTextField() - expDatTextField.configuration = expDateConfig - expDatTextField.textField.secureText = expDate - - let cvc = "123" - let cvcConfig = VGSCVCTokenizationConfiguration(collector: collector, fieldName: "cvc") - let cvcTextField = VGSCVCTextField() - cvcTextField.configuration = cvcConfig - cvcTextField.textField.secureText = cvc - - /// Not Tokenizable fields - let cardHolder = "Joe Business" - let cardHolderConfig = VGSConfiguration(collector: collector, fieldName: "not_secured_cardHolder") - cardHolderConfig.type = .cardHolderName - let cardHolderTextField = VGSTextField() - cardHolderTextField.configuration = cardHolderConfig - cardHolderTextField.textField.secureText = cardHolder - - let someNumber = "1234567890" - let someNumberConfig = VGSConfiguration(collector: collector, fieldName: "not_secured_some_number") - someNumberConfig.type = .none - someNumberConfig.divider = "-" - someNumberConfig.formatPattern = "### #### ##" - let someNumberTextField = VGSCardTextField() - someNumberTextField.configuration = someNumberConfig - someNumberTextField.textField.secureText = someNumber - - let expectation = XCTestExpectation(description: "Sending data...") - - collector.tokenizeData { result in - switch result { - case .success(let code, let jsonData, let response): - XCTAssertTrue(code == 200) - XCTAssertNotNil(jsonData) - XCTAssertNotNil(response) - - guard let json = jsonData as? [String: String] else { - XCTFail("Error: code=\(code): wrong data format") - expectation.fulfill() - return - } - - XCTAssertNotNil(json["cardNumber"]) - XCTAssertTrue(json["cardNumber"] != cardNum) - XCTAssertTrue(json["cvc"] != cvc) - XCTAssertTrue(json["expDate"] != "11/2025") - XCTAssertTrue(json["not_secured_cardHolder"] == cardHolder) - XCTAssertTrue(json["not_secured_some_number"] == "123-4567-89") - case .failure(let code, _, _, let error): - XCTFail("Error: code=\(code):\(String(describing: error?.localizedDescription))") - } - expectation.fulfill() - } - wait(for: [expectation], timeout: 60.0) + func testSendCardToTokenizationAPI() { + configureCardTextFields() + let expectation = XCTestExpectation(description: "Sending data...") + collector.tokenizeData { [weak self] result in + self?.validateTokenizeDataResponseResults(result) + expectation.fulfill() + } + wait(for: [expectation], timeout: 60.0) + } + + func testAsyncTokenizeCardToEchoServer() { + self.configureCardTextFields() + let expectation = XCTestExpectation(description: "Sending data...") + Task { + let result = await collector.tokenizeData() + self.validateTokenizeDataResponseResults(result) + expectation.fulfill() + } + wait(for: [expectation], timeout: 60) + } + + func testCardSendPublisherToEchoServer() { + self.configureCardTextFields() + let expectation = XCTestExpectation(description: "Sending data...") + collector.tokenizeDataPublisher() + .sink {[weak self] result in + self?.validateTokenizeDataResponseResults(result) + expectation.fulfill() + } + .store(in: &cancellables) + + wait(for: [expectation], timeout: 60) } func testNotTokenizableFieldsTokenization() { @@ -155,4 +151,61 @@ class TokenizationApiTests: VGSCollectBaseTestCase { } wait(for: [expectation], timeout: 60.0) } + + private func configureCardTextFields() { + /// this test requires setting proper inbound routs + let cardNum = testCardNumber + let cardConfig = VGSCardNumberTokenizationConfiguration(collector: collector, fieldName: "cardNumber") + cardConfig.type = .cardNumber + cardTextField.configuration = cardConfig + cardTextField.textField.secureText = cardNum + + let expDate = testExpDate + let expDateConfig = VGSExpDateTokenizationConfiguration(collector: collector, fieldName: "expDate") + expDateConfig.tokenizationParameters.format = VGSVaultAliasFormat.UUID.rawValue + expDateConfig.inputDateFormat = .shortYear + expDateConfig.outputDateFormat = .longYear + expDateTextField.configuration = expDateConfig + expDateTextField.textField.secureText = expDate + + let cvc = testCVC + let cvcConfig = VGSCVCTokenizationConfiguration(collector: collector, fieldName: "cvc") + cvcTextField.configuration = cvcConfig + cvcTextField.textField.secureText = cvc + + /// Not Tokenizable fields + let cardHolder = testCardHolder + let cardHolderConfig = VGSConfiguration(collector: collector, fieldName: "not_secured_cardHolder") + cardHolderConfig.type = .cardHolderName + cardHolderTextField.configuration = cardHolderConfig + cardHolderTextField.textField.secureText = cardHolder + + let someNumber = testNumbers + let someNumberConfig = VGSConfiguration(collector: collector, fieldName: "not_secured_some_number") + someNumberConfig.type = .none + someNumberConfig.divider = "-" + someNumberConfig.formatPattern = "### #### ##" + numbersTextField.configuration = someNumberConfig + numbersTextField.textField.secureText = someNumber + } + + private func validateTokenizeDataResponseResults(_ result: VGSTokenizationResponse) { + switch result { + case .success(let code, let jsonData, let response): + guard let json = jsonData as? [String: String] else { + XCTFail("Error: code=\(code): wrong data format") + return + } + XCTAssertTrue(code == 200) + XCTAssertNotNil(jsonData) + XCTAssertNotNil(response) + XCTAssertTrue(json["cardNumber"] != testCardNumber) + XCTAssertTrue(json["cvc"] != testCVC) + XCTAssertTrue(json["expDate"] != testExpDateResponse) + XCTAssertTrue(json["not_secured_cardHolder"] == testCardHolder) + XCTAssertTrue(json["not_secured_some_number"] == testNumbersResponse) + case .failure(let code, _, _, let error): + XCTFail("Error: code=\(code):\(String(describing: error?.localizedDescription))") + } + } } diff --git a/Tests/FrameworkTests/Test Helpers/MockedDataProvider.swift b/Tests/FrameworkTests/Test Helpers/MockedDataProvider.swift index 6c7fd54c..88a2aa48 100644 --- a/Tests/FrameworkTests/Test Helpers/MockedDataProvider.swift +++ b/Tests/FrameworkTests/Test Helpers/MockedDataProvider.swift @@ -11,9 +11,10 @@ import Foundation /// Mocked data provider. final class MockedDataProvider { + /// Mocked tokenization vault id. + var vaultId: String = "" /// Mocked tokenization vault id. var tokenizationVaultId: String = "" - /// Shared instance. static let shared = MockedDataProvider() @@ -35,7 +36,7 @@ final class MockedDataProvider { assertionFailure("Mocked data not found!") return } - + vaultId = dictionary["vaultID"] as? String ?? "" tokenizationVaultId = dictionary["tokenization_vaultId"] as? String ?? "" } else { assertionFailure("Mocked data not found!") diff --git a/Tests/FrameworkTests/VGSTextFieldStatePublisherTests/VGSTextFieldStatePublisherTests.swift b/Tests/FrameworkTests/VGSTextFieldStatePublisherTests/VGSTextFieldStatePublisherTests.swift new file mode 100644 index 00000000..2d3c3c74 --- /dev/null +++ b/Tests/FrameworkTests/VGSTextFieldStatePublisherTests/VGSTextFieldStatePublisherTests.swift @@ -0,0 +1,85 @@ +// +// VGSTextFieldStatePublisherTests.swift +// FrameworkTests +// + +import XCTest +import Combine +@testable import VGSCollectSDK + +@available(iOS 13.0, *) +class VGSTextFieldStatePublisherTests: XCTestCase { + + var collector: VGSCollect! + private var cancellableSet: Set = [] + + override func setUp() { + collector = VGSCollect(id: "vaultId") + cancellableSet = [] + } + + func testVGSTextFieldStatePublisher() { + let exp = expectation(description: "VGSTextField State Publisher Test") + let config = VGSConfiguration(collector: collector, fieldName: "name") + config.type = .cardHolderName + + let textField = VGSTextField() + textField.configuration = config + var states: [State] = [] + + textField.statePublisher + .prepend(textField.state) // Emit the initial state + .sink { state in + states.append(state) + if states.count == 3 { + exp.fulfill() + } + } + .store(in: &cancellableSet) + + textField.setText("Test Text") + textField.cleanText() + + waitForExpectations(timeout: 1.0) + + XCTAssertEqual(states[0].isValid, false) + XCTAssertEqual(states[0].isDirty, false) + XCTAssertEqual(states[1].isValid, true) + XCTAssertEqual(states[1].isDirty, true) + XCTAssertEqual(states[2].isValid, false) + XCTAssertEqual(states[2].isDirty, true) + } + + func testVGSCardTextFieldStatePublisher() { + let exp = expectation(description: "VGSCardTextField State Publisher Test") + + let config = VGSConfiguration.init(collector: collector, fieldName: "card_num") + config.type = .cardNumber + config.isRequired = true + let cardTextField = VGSCardTextField() + cardTextField.configuration = config + + var states: [CardState] = [] + cardTextField.statePublisher + .prepend(cardTextField.state) // Emit the initial state + .compactMap { $0 as? CardState } + .sink { cardState in + states.append(cardState) + if states.count == 2 { + exp.fulfill() + } + } + .store(in: &cancellableSet) + + cardTextField.setText("4000 0000 0000 0002") // Invalid Visa card number + + waitForExpectations(timeout: 1.0) + + XCTAssertEqual(states[0].isValid, false) + XCTAssertEqual(states[0].isDirty, false) + XCTAssertEqual(states[0].cardBrand, VGSPaymentCards.CardBrand.unknown) + XCTAssertEqual(states[1].isValid, true) + XCTAssertEqual(states[1].isDirty, true) + XCTAssertEqual(states[1].cardBrand, VGSPaymentCards.CardBrand.visa) + } +} diff --git a/VGSCollectSDK.xcodeproj/project.pbxproj b/VGSCollectSDK.xcodeproj/project.pbxproj index 5263b4d6..3fc33ff6 100644 --- a/VGSCollectSDK.xcodeproj/project.pbxproj +++ b/VGSCollectSDK.xcodeproj/project.pbxproj @@ -8,6 +8,8 @@ /* Begin PBXBuildFile section */ 0313A1202975A22700DB2F2C /* VGSTokenizationConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0313A11F2975A22700DB2F2C /* VGSTokenizationConfigurationTests.swift */; }; + 031795D629DF00EA00BD1215 /* VGSTextFieldStatePublisherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031795D529DF00EA00BD1215 /* VGSTextFieldStatePublisherTests.swift */; }; + 033C979729D5BDC60088E045 /* VGSTextField+statePublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033C979629D5BDC60088E045 /* VGSTextField+statePublisher.swift */; }; 0351799B2858B3B700394BFC /* VGSTextFieldTokenizationProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0351799A2858B3B700394BFC /* VGSTextFieldTokenizationProtocol.swift */; }; 0351799D2858B64600394BFC /* VGSCVCTokenizationConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0351799C2858B64600394BFC /* VGSCVCTokenizationConfiguration.swift */; }; 035179A1285920F100394BFC /* VGSCardTokenizationConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035179A0285920F100394BFC /* VGSCardTokenizationConfiguration.swift */; }; @@ -195,6 +197,8 @@ /* Begin PBXFileReference section */ 0313A11F2975A22700DB2F2C /* VGSTokenizationConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSTokenizationConfigurationTests.swift; sourceTree = ""; }; + 031795D529DF00EA00BD1215 /* VGSTextFieldStatePublisherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSTextFieldStatePublisherTests.swift; sourceTree = ""; }; + 033C979629D5BDC60088E045 /* VGSTextField+statePublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VGSTextField+statePublisher.swift"; sourceTree = ""; }; 0351799A2858B3B700394BFC /* VGSTextFieldTokenizationProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSTextFieldTokenizationProtocol.swift; sourceTree = ""; }; 0351799C2858B64600394BFC /* VGSCVCTokenizationConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSCVCTokenizationConfiguration.swift; sourceTree = ""; }; 035179A0285920F100394BFC /* VGSCardTokenizationConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSCardTokenizationConfiguration.swift; sourceTree = ""; }; @@ -414,6 +418,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 031795D429DF00D800BD1215 /* VGSTextFieldStatePublisherTests */ = { + isa = PBXGroup; + children = ( + 031795D529DF00EA00BD1215 /* VGSTextFieldStatePublisherTests.swift */, + ); + path = VGSTextFieldStatePublisherTests; + sourceTree = ""; + }; 035179992858B39100394BFC /* TokenizationConfiguration */ = { isa = PBXGroup; children = ( @@ -987,6 +999,7 @@ 44D521092681B7F5005AB588 /* FrameworkTests.xctestplan */, FDF696E42346461D00063507 /* StorageTests.swift */, FD24955D2330CC62009024E6 /* VGSCollectTests.swift */, + 031795D429DF00D800BD1215 /* VGSTextFieldStatePublisherTests */, 44D5210B2681B803005AB588 /* Resources */, 3213001A24190BE50062FEF0 /* VGSCollectTest+Validation.swift */, 32059CD22417EACC003E9481 /* UtilsTest.swift */, @@ -1093,6 +1106,7 @@ 321FE73925DE45FC00B138E9 /* VGSCVCTextField.swift */, FD3C01C223AFC0980096B4A4 /* VGSTextField+CVC.swift */, FD1B44652327D9B0009AA04A /* VGSTextField+state.swift */, + 033C979629D5BDC60088E045 /* VGSTextField+statePublisher.swift */, FDD42A3C233F67BA0005D631 /* VGSTextField+UIBuilder.swift */, FD362EDE2401659100B4A640 /* VGSTextFieldDelegate.swift */, ); @@ -1445,6 +1459,7 @@ 3219D73D2404279700F4A7E5 /* VGSError.swift in Sources */, FD1B44662327D9B0009AA04A /* VGSTextField+state.swift in Sources */, 32C894DD256D4AE400DC5648 /* UIDevice+extension.swift in Sources */, + 033C979729D5BDC60088E045 /* VGSTextField+statePublisher.swift in Sources */, 32093D7E25CD9F88006CD242 /* VGSCollectRequestLogger.swift in Sources */, FD3C01C423AFCEEE0096B4A4 /* Enums.swift in Sources */, 441B26D425DB88C50099AA3A /* APIHostURLPolicy.swift in Sources */, @@ -1537,6 +1552,7 @@ FD790B9A243BB432006A30CB /* _CardBrandDataSource.swift in Sources */, 44F8F52F25DBE8770052647A /* VGSCollectSatelliteUtilsTests.swift in Sources */, FD1BE48923462F21006D8658 /* CVVTextFieldTests.swift in Sources */, + 031795D629DF00EA00BD1215 /* VGSTextFieldStatePublisherTests.swift in Sources */, 3215C4E92611B50A00F21259 /* VGSExpDateSeparateSerializerTests.swift in Sources */, FD1BE48723462F1A006D8658 /* CardNumerTextFieldTests.swift in Sources */, 038EDA0D286F2EFF00AF3CF2 /* TokenizationApiTests.swift in Sources */, diff --git a/demoapp/demoapp.xcodeproj/project.pbxproj b/demoapp/demoapp.xcodeproj/project.pbxproj index 35a95d5a..1af5cd1d 100644 --- a/demoapp/demoapp.xcodeproj/project.pbxproj +++ b/demoapp/demoapp.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 00A95AF26E4AD1DA30D2AD0C /* libPods-demoappTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 218005F91E53ACAA92DB30A8 /* libPods-demoappTests.a */; }; 0351799F2858D53C00394BFC /* CardsDataTokenizationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0351799E2858D53C00394BFC /* CardsDataTokenizationViewController.swift */; }; + 03B992D829C8A5BF00B10A70 /* CombineExamplesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B992D729C8A5BF00B10A70 /* CombineExamplesViewController.swift */; }; 03DBB7B4292FBFDA00F4DCA2 /* CollectApplePayDataViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03DBB7B3292FBFDA00F4DCA2 /* CollectApplePayDataViewController.swift */; }; 322196DE24D19CE900A66EC9 /* InitialViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 322196DD24D19CE900A66EC9 /* InitialViewController.swift */; }; 3258CB3D24D1B79000C0CC8D /* TestCollectCardsDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3258CB3C24D1B79000C0CC8D /* TestCollectCardsDataFlow.swift */; }; @@ -78,6 +79,7 @@ /* Begin PBXFileReference section */ 0351799E2858D53C00394BFC /* CardsDataTokenizationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsDataTokenizationViewController.swift; sourceTree = ""; }; + 03B992D729C8A5BF00B10A70 /* CombineExamplesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CombineExamplesViewController.swift; sourceTree = ""; }; 03DBB7B3292FBFDA00F4DCA2 /* CollectApplePayDataViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectApplePayDataViewController.swift; sourceTree = ""; }; 03DBB7B5292FC41600F4DCA2 /* demoapp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = demoapp.entitlements; sourceTree = ""; }; 218005F91E53ACAA92DB30A8 /* libPods-demoappTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-demoappTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -344,6 +346,7 @@ 44D8691526205F670014645F /* CustomDataCollectingViewController.swift */, 44D8691926205F670014645F /* FilePickerViewController.swift */, 03DBB7B3292FBFDA00F4DCA2 /* CollectApplePayDataViewController.swift */, + 03B992D729C8A5BF00B10A70 /* CombineExamplesViewController.swift */, ); path = UseCases; sourceTree = ""; @@ -703,6 +706,7 @@ 44D8691B26205F670014645F /* CardsDataCollectingViewController.swift in Sources */, 03DBB7B4292FBFDA00F4DCA2 /* CollectApplePayDataViewController.swift in Sources */, 449FFCD728A63DC300FE4A1F /* PaymentOptionModel.swift in Sources */, + 03B992D829C8A5BF00B10A70 /* CombineExamplesViewController.swift in Sources */, 449FFCC428A5186A00FE4A1F /* VGSRoundedCheckboxTheme.swift in Sources */, FD12B9782304616C00B670DD /* AppDelegate.swift in Sources */, 449FFCC628A518E800FE4A1F /* VGSPaymentOptionItemContainerView.swift in Sources */, diff --git a/demoapp/demoapp.xcodeproj/xcshareddata/xcschemes/demoapp.xcscheme b/demoapp/demoapp.xcodeproj/xcshareddata/xcschemes/demoapp.xcscheme index b87986f0..c60672dd 100644 --- a/demoapp/demoapp.xcodeproj/xcshareddata/xcschemes/demoapp.xcscheme +++ b/demoapp/demoapp.xcodeproj/xcshareddata/xcschemes/demoapp.xcscheme @@ -1,6 +1,6 @@ - + + + + + + + + + + + + + + + @@ -403,7 +423,7 @@ - + @@ -898,7 +918,7 @@ - + @@ -1293,6 +1313,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demoapp/demoapp/UseCases/CardsDataCollectingViewController.swift b/demoapp/demoapp/UseCases/CardsDataCollectingViewController.swift index f4a2706f..fee3cfcb 100644 --- a/demoapp/demoapp/UseCases/CardsDataCollectingViewController.swift +++ b/demoapp/demoapp/UseCases/CardsDataCollectingViewController.swift @@ -43,7 +43,8 @@ class CardsDataCollectingViewController: UIViewController { "my custome header": "some custom data" ] - // Observing text fields. The call back return all textfields with updated states. You also can use VGSTextFieldDelegate + // Observing text fields. The call back return all textfields with updated states. + // You also can use VGSTextFieldDelegate instead. vgsCollect.observeStates = { [weak self] form in self?.consoleMessage = "" diff --git a/demoapp/demoapp/UseCases/CombineExamplesViewController.swift b/demoapp/demoapp/UseCases/CombineExamplesViewController.swift new file mode 100644 index 00000000..27099d00 --- /dev/null +++ b/demoapp/demoapp/UseCases/CombineExamplesViewController.swift @@ -0,0 +1,246 @@ +// +// CombineExamplesViewController.swift +// demoapp +// + +import UIKit +import VGSCollectSDK +import Combine + +/// A class that demonstrates how to collect data from VGSTextFields and upload it to VGS +class CombineExamplesViewController: UIViewController { + + @IBOutlet weak var cardDataStackView: UIStackView! + @IBOutlet weak var consoleStatusLabel: UILabel! + @IBOutlet weak var consoleLabel: UILabel! + + @IBOutlet weak var uploadButton: UIButton! + + var cancellables = Set() + + // Init VGS Collector + var vgsCollect = VGSCollect(id: AppCollectorConfiguration.shared.vaultId, environment: AppCollectorConfiguration.shared.environment) + + // VGS UI Elements + var cardNumber = VGSCardTextField() + var expCardDate = VGSExpDateTextField() + var cvcCardNum = VGSCVCTextField() + var cardHolderName = VGSTextField() + + /// BlinkCard Card Scanner + var scanController: VGSBlinkCardController? + + var consoleMessage: String = "" { + didSet { consoleLabel.text = consoleMessage } + } + + override func viewDidLoad() { + super.viewDidLoad() + setupUI() + setupElementsConfiguration() + + /// Track textfield state changes + cardHolderName.statePublisher.sink { [weak self] state in + self?.cardHolderName.borderColor = state.isValid ? .lightGray : .red + }.store(in: &cancellables) + + /// Map State to CardState to get access for card attributes + cardNumber.statePublisher.compactMap { state -> CardState? in + return state as? CardState + }.sink { [weak self] cardState in + self?.cardNumber.borderColor = cardState.isValid ? .lightGray : .red + }.store(in: &cancellables) + + expCardDate.statePublisher.sink { [weak self] state in + self?.expCardDate.borderColor = state.isValid ? .lightGray : .red + }.store(in: &cancellables) + + cvcCardNum.statePublisher.sink { [weak self] state in + self?.cvcCardNum.borderColor = state.isValid ? .lightGray : .red + }.store(in: &cancellables) + +// /// Enable Upload Button when all fields are valid +// Publishers.CombineLatest4(cardHolderName.statePublisher, +// cardNumber.statePublisher, +// expCardDate.statePublisher, +// cvcCardNum.statePublisher) +// .map { state1, state2, state3, state4 in +// return state1.isValid && state2.isValid && state3.isValid && state4.isValid +// } +// .sink { [weak self] allValid in +// self?.uploadButton.isEnabled = allValid +// }.store(in: &cancellables) + + // set custom headers + vgsCollect.customHeaders = [ + "my custome header": "some custom data" + ] + + // Init VGSBlinkCardController with BlinkCard license key + if let licenseKey = AppCollectorConfiguration.shared.blinkCardLicenseKey { + scanController = VGSBlinkCardController(licenseKey: licenseKey, delegate: self, onError: { errorCode in + print("BlinkCard license error, code: \(errorCode)") + }) + } else { + print("⚠️ VGSBlinkCardController not initialized. Check license key!") + } + + // // If you need to set your own card brand icons + // + // VGSPaymentCards.visa.brandIcon = UIImage(named: "my visa icon") + // VGSPaymentCards.unknown.brandIcon = UIImage(named: "my unknown brand icon") + + } + + override func awakeFromNib() { + super.awakeFromNib() + + let view = self.view + if UITestsMockedDataProvider.isRunningUITest { + view?.accessibilityIdentifier = "CombineExamplesViewController.Screen.RootView" + } + } + + // MARK: - Init UI + private func setupUI() { + + cardDataStackView.addArrangedSubview(cardHolderName) + cardDataStackView.addArrangedSubview(cardNumber) + cardDataStackView.addArrangedSubview(expCardDate) + cardDataStackView.addArrangedSubview(cvcCardNum) + + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(hideKeyboard)) + consoleLabel.addGestureRecognizer(tapGesture) + consoleLabel.isUserInteractionEnabled = true + view.addGestureRecognizer(tapGesture) + } + + @objc + func hideKeyboard() { + view.endEditing(true) + consoleLabel.endEditing(true) + } + + private func setupElementsConfiguration() { + + let cardConfiguration = VGSConfiguration(collector: vgsCollect, fieldName: "card_number") + cardConfiguration.type = .cardNumber + cardNumber.configuration = cardConfiguration + cardNumber.placeholder = "4111 1111 1111 1111" + cardNumber.textAlignment = .natural + cardNumber.cardIconLocation = .right + +// cardNumber.becomeFirstResponder() + /// Use `VGSExpDateConfiguration` if you need to convert output date format + let expDateConfiguration = VGSExpDateConfiguration(collector: vgsCollect, fieldName: "card_expirationDate") + expDateConfiguration.type = .expDate + expDateConfiguration.inputDateFormat = .shortYear + expDateConfiguration.outputDateFormat = .longYear + + /// Default .expDate format is "##/##" + expDateConfiguration.formatPattern = "##/##" + + /// Update validation rules + expDateConfiguration.validationRules = VGSValidationRuleSet(rules: [ + VGSValidationRuleCardExpirationDate(dateFormat: .shortYear, error: VGSValidationErrorType.expDate.rawValue) + ]) + + expCardDate.configuration = expDateConfiguration + expCardDate.placeholder = "MM/YY" + expCardDate.monthPickerFormat = .longSymbols + + let cvcConfiguration = VGSConfiguration(collector: vgsCollect, fieldName: "card_cvc") + cvcConfiguration.type = .cvc + + cvcCardNum.configuration = cvcConfiguration + cvcCardNum.isSecureTextEntry = true + cvcCardNum.placeholder = "CVC" + cvcCardNum.tintColor = .lightGray + + let holderConfiguration = VGSConfiguration(collector: vgsCollect, fieldName: "cardHolder_name") + holderConfiguration.type = .cardHolderName + holderConfiguration.keyboardType = .namePhonePad + /// Required to be not empty + + cardHolderName.textAlignment = .natural + // Set max input length + // holderConfiguration.maxInputLength = 32 + cardHolderName.configuration = holderConfiguration + cardHolderName.placeholder = "Cardholder Name" + + vgsCollect.textFields.forEach { textField in + textField.textColor = UIColor.inputBlackTextColor + textField.font = .systemFont(ofSize: 22) + textField.padding = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) + textField.tintColor = .lightGray + } + } + + // Upload data from TextFields to VGS + @IBAction func uploadAction(_ sender: Any) { + // hide kayboard + hideKeyboard() + + // check if textfields are valid + vgsCollect.textFields.forEach { textField in + textField.borderColor = textField.state.isValid ? .lightGray : .red + } + + // send extra data + var extraData = [String: Any]() + extraData["customKey"] = "Custom Value" + + vgsCollect.sendDataPublisher(path: "/post", extraData: extraData).sink( + receiveCompletion: { completion in + switch completion { + case .finished: + break + case .failure(let error): + print("Error: \(error.localizedDescription)") + } + }, + receiveValue: { response in + print("Response: \(response)") + } + ).store(in: &cancellables) + } + + // Start BlinkCard scanning + @IBAction func scanAction(_ sender: Any) { + guard let scanController = scanController else { + print("⚠️ VGSBlinkCardController not initialized. Check license key!") + return + } + scanController.presentCardScanner(on: self, animated: true, modalPresentationStyle: .fullScreen, completion: nil) + } +} + +extension CombineExamplesViewController: VGSBlinkCardControllerDelegate { + func textFieldForScannedData(type: VGSBlinkCardDataType) -> VGSTextField? { + // match VGSTextField with scanned data + switch type { + case .expirationDateLong: + return expCardDate + case .cardNumber: + return cardNumber + case .cvc: + return cvcCardNum + case .name: + return cardHolderName + default: + return nil + } + } + + func userDidFinishScan() { + scanController?.dismissCardScanner(animated: true, completion: { + // add actions on scan controller dismiss completion + }) + } + + func userDidCancelScan() { + scanController?.dismissCardScanner(animated: true, completion: { + // add actions on scan controller dismiss completion + }) + } +} From 588987327769473d63d1b7fc52c1b7899304aa1e Mon Sep 17 00:00:00 2001 From: Donald Rodriguez Gutierrez <129230521+DonaldRG@users.noreply.github.com> Date: Thu, 27 Apr 2023 08:27:03 -0600 Subject: [PATCH 3/9] Add VGSDateTeextField. --- .circleci/config.yml | 2 +- .../Core/Collector/VGSCollect.swift | 6 +- Sources/VGSCollectSDK/Core/Enums.swift | 16 +- .../VGSDateTokenizationConfiguration.swift | 108 +++++ .../VGSExpDateTokenizationConfiguration.swift | 28 +- Sources/VGSCollectSDK/Core/VGSDate.swift | 84 ++++ .../Core/VGSDateConfiguration.swift | 132 ++++++ .../Core/VGSExpDateConfiguration.swift | 33 +- .../Core/VGSCustomPaymentCardModel.swift | 2 +- .../Text Field/VGSDateTextField.swift | 361 ++++++++++++++++ .../Text Field/VGSExpDateTextField.swift | 3 +- .../UIElements/Text Field/VGSTextField.swift | 18 +- .../AnyType/VGSValidationRuleLength.swift | 2 +- .../VGSValidationRuleLengthMatch.swift | 2 +- .../AnyType/VGSValidationRulePattern.swift | 2 +- .../Card/VGSValidationRuleLuhnCheck.swift | 2 +- .../Card/VGSValidationRulePaymentCard.swift | 4 +- .../Validation/Date/VGSDateFormat.swift | 181 ++++++++ .../Date/VGSValidationRuleDateRange.swift | 76 ++++ .../VGSValidationRuleExpirationDate.swift | 4 +- .../Validation/VGSValidationError.swift | 3 + .../Validation/VGSValidationRule.swift | 4 +- .../Convertors/DateFormatConvertor.swift | 75 ++++ .../Convertors/ExpDateFormatConvertor.swift | 152 ++++--- .../Convertors/VGSTextFormatConvertable.swift | 31 ++ .../VGSDateSeparateSerializer.swift | 32 ++ .../ConvertorsTests/DateConvertorTests.swift | 309 ++++++++++++++ Tests/FrameworkTests/Core/DateTests.swift | 53 +++ .../VGSDateSerialization_CustomConfig.json | 44 ++ ...rialization_CustomExpDateOutputConfig.json | 44 ++ .../VGSDateSerialization_DefaultConfig.json | 44 ++ ...GSDateSerialization_MapWithArrayMerge.json | 72 ++++ ...teSerialization_MapWithArrayOverwrite.json | 53 +++ ...kenizationSerialization_DefaultConfig.json | 85 ++++ .../Text Fields Tests/DateTextFieldTest.swift | 225 ++++++++++ .../VGSDateFormatTests.swift | 178 ++++++++ .../ValidationRuleDateTests.swift | 204 +++++++++ .../SerializersDataProvider.swift | 47 +++ .../VGSDateSeparateSerializerTests.swift | 256 ++++++++++++ .../VGSDateTokenizationSerializerTests.swift | 135 ++++++ .../VGSExpDateSeparateSerializerTests.swift | 387 ++++++++++-------- .../VGSExpDateSerializersDataProvider.swift | 59 --- ...GSExpDateTokenizationSerializerTests.swift | 192 ++++----- VGSCollectSDK.xcodeproj/project.pbxproj | 140 ++++++- demoapp/demoapp.xcodeproj/project.pbxproj | 8 +- demoapp/demoapp/Main.storyboard | 282 +++++++++---- .../DateValidationViewController.swift | 186 +++++++++ 47 files changed, 3838 insertions(+), 528 deletions(-) create mode 100644 Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSDateTokenizationConfiguration.swift create mode 100644 Sources/VGSCollectSDK/Core/VGSDate.swift create mode 100644 Sources/VGSCollectSDK/Core/VGSDateConfiguration.swift create mode 100644 Sources/VGSCollectSDK/UIElements/Text Field/VGSDateTextField.swift create mode 100644 Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSDateFormat.swift create mode 100644 Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleDateRange.swift create mode 100644 Sources/VGSCollectSDK/Utils/Convertors/DateFormatConvertor.swift create mode 100644 Sources/VGSCollectSDK/Utils/Convertors/VGSTextFormatConvertable.swift create mode 100644 Sources/VGSCollectSDK/Utils/Helpers/Serializers/VGSDateSeparateSerializer.swift create mode 100644 Tests/FrameworkTests/ConvertorsTests/DateConvertorTests.swift create mode 100644 Tests/FrameworkTests/Core/DateTests.swift create mode 100644 Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_CustomConfig.json create mode 100644 Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_CustomExpDateOutputConfig.json create mode 100644 Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_DefaultConfig.json create mode 100644 Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_MapWithArrayMerge.json create mode 100644 Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_MapWithArrayOverwrite.json create mode 100644 Tests/FrameworkTests/Resources/DateTokenizationJSON/VGSDateTokenizationSerialization_DefaultConfig.json create mode 100644 Tests/FrameworkTests/Satellite Tests/Text Fields Tests/DateTextFieldTest.swift create mode 100644 Tests/FrameworkTests/Satellite Tests/Text Fields Tests/VGSDateFormatTests.swift create mode 100644 Tests/FrameworkTests/Satellite Tests/Text Fields Tests/ValidationRuleDateTests.swift create mode 100644 Tests/FrameworkTests/SerializersTest/SerializersDataProvider.swift create mode 100644 Tests/FrameworkTests/SerializersTest/VGSDateSeparateSerializerTests.swift create mode 100644 Tests/FrameworkTests/SerializersTest/VGSDateTokenizationSerializerTests.swift delete mode 100644 Tests/FrameworkTests/SerializersTest/VGSExpDateSerializersDataProvider.swift create mode 100644 demoapp/demoapp/UseCases/DateValidationViewController.swift diff --git a/.circleci/config.yml b/.circleci/config.yml index 83d37963..7c89195e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -34,4 +34,4 @@ workflows: build-and-test: jobs: - build-and-test-sdk - - build-and-ui-test-demo-app-ios-16-iphone14 + - build-and-ui-test-demo-app-ios-16-iphone14 \ No newline at end of file diff --git a/Sources/VGSCollectSDK/Core/Collector/VGSCollect.swift b/Sources/VGSCollectSDK/Core/Collector/VGSCollect.swift index b2bbddfc..bbeea0bf 100644 --- a/Sources/VGSCollectSDK/Core/Collector/VGSCollect.swift +++ b/Sources/VGSCollectSDK/Core/Collector/VGSCollect.swift @@ -52,9 +52,9 @@ public class VGSCollect { return storage.textFields } - // MARK: - Initialzation + // MARK: - Initialization - /// Initialzation. + /// Initialization. /// /// - Parameters: /// - id: `String` object, your organization vault id. @@ -72,7 +72,7 @@ public class VGSCollect { } } - /// Initialzation. + /// Initialization. /// /// - Parameters: /// - id: `String` object, your organization vault id. diff --git a/Sources/VGSCollectSDK/Core/Enums.swift b/Sources/VGSCollectSDK/Core/Enums.swift index 4f4aa6a3..e4e92a1c 100644 --- a/Sources/VGSCollectSDK/Core/Enums.swift +++ b/Sources/VGSCollectSDK/Core/Enums.swift @@ -32,6 +32,9 @@ public enum FieldType: Int, CaseIterable { /// Field type that requires Expiration Date input formatting and validation. case expDate + /// Field type that requires Date input formatting and validation. + case date + /// Field type that requires Credit Card CVC input formatting and validation. case cvc @@ -64,6 +67,8 @@ internal extension FieldType { return DateFormatPattern.shortYear.rawValue case .ssn: return "###-##-####" + case .date: + return VGSDateFormat.default.formatPattern default: return "" } @@ -71,7 +76,7 @@ internal extension FieldType { var defaultDivider: String { switch self { - case .expDate: + case .expDate, .date: return "/" case .ssn: return "-" @@ -86,6 +91,8 @@ internal extension FieldType { return "^(?:4[0-9]{12}(?:[0-9]{3})?|[25][1-7][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})$" case .expDate: return "^(0[1-9]|1[0-2])\\/?([0-9]{4}|[0-9]{2})$" + case .date: + return "^([0-9]{4}|[0-9]{2})\\/?([0-9]{2})\\/?([0-9]{4}|[0-9]{2})$" case .cardHolderName: return "^([a-zA-Z0-9\\ \\,\\.\\-\\']{2,})$" case .ssn: @@ -100,7 +107,7 @@ internal extension FieldType { var keyboardType: UIKeyboardType { switch self { - case .cardNumber, .cvc, .expDate, .ssn: + case .cardNumber, .cvc, .expDate, .date, .ssn: return .asciiCapableNumberPad default: return .alphabet @@ -115,6 +122,9 @@ internal extension FieldType { case .expDate: rules.add(rule: VGSValidationRulePattern(pattern: self.defaultRegex, error: VGSValidationErrorType.pattern.rawValue)) rules.add(rule: VGSValidationRuleCardExpirationDate(error: VGSValidationErrorType.expDate.rawValue)) + case .date: + rules.add(rule: VGSValidationRulePattern(pattern: self.defaultRegex, error: VGSValidationErrorType.pattern.rawValue)) + rules.add(rule: VGSValidationRuleDateRange(error: VGSValidationErrorType.date.rawValue)) case .cardNumber: rules.add(rule: VGSValidationRulePaymentCard(error: VGSValidationErrorType.cardNumber.rawValue)) case .cvc: @@ -137,6 +147,8 @@ internal extension FieldType { return "card-security-code" case .expDate: return "card-expiration-date" + case .date: + return "date" case .ssn: return "ssn" case .none: diff --git a/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSDateTokenizationConfiguration.swift b/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSDateTokenizationConfiguration.swift new file mode 100644 index 00000000..c9878863 --- /dev/null +++ b/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSDateTokenizationConfiguration.swift @@ -0,0 +1,108 @@ +// +// VGSDateTokenizationConfiguration.swift +// VGSCollectSDK +// + +import Foundation + +/// `VGSDateTokenizationParameters` - parameters required for tokenization API +public struct VGSDateTokenizationParameters: VGSTokenizationParametersProtocol { + + /// Vault storage type. + public var storage: String = VGSVaultStorageType.PERSISTENT.rawValue + + /// Data alies format. + public var format: String = VGSVaultAliasFormat.UUID.rawValue +} + +/// Class responsible for configuration `VGSDateTextField` or `VGSTextField` with `fieldType = .date`. +/// Extends `VGSConfiguration`. Required to work with tokenization API. +public final class VGSDateTokenizationConfiguration: VGSConfiguration, VGSDateConfigurationProtocol, VGSTextFieldTokenizationConfigurationProtocol, VGSFormatSerializableProtocol { + + // MARK: - Properties + /// Start date used to fill out the date picker + private var datePickerStartDate: VGSDate = VGSDateConfiguration.minValidPickerStartDate + + /// End date used to fill out the date picker + private var datePickerEndDate: VGSDate = VGSDateConfiguration.maxValidPickerEndDate + + /// Get the list of years from `datePickerStartDate` to `datePickerEndDate`. + /// In case any of the dates are not set, it will use the default + /// values `minValidStartDate` and `maxValidEndDate` respectively + internal var years: [Int] { + Array(datePickerStartDate.year...datePickerEndDate.year) + } + + // MARK: - Constructor + /// Initialization + /// Date configuration initializer, if no `datePickerStartDate` is provided, + /// a default date will be used adding 100 years to the current date. + /// Similar approach will be used if `datePickerEndDate` is not provided, + /// it will be calculated removing 100 years from current date. + /// + /// - Parameters: + /// - vgs: `VGSCollect` instance. + /// - fieldName: associated `fieldName`. + /// - datePickerStartDate: optional `VGSDate` instance. + /// - datePickerEndDate: optional `VGSDate` instance. + public init(collector vgs: VGSCollect, + fieldName: String, + datePickerStartDate: VGSDate? = nil, + datePickerEndDate: VGSDate? = nil) { + /// Setup custom picker start date + if let startDate = datePickerStartDate { + self.datePickerStartDate = startDate + } + /// Setup custom picker end date + if let endDate = datePickerEndDate { + self.datePickerEndDate = endDate + } + /// Super initializer + super.init(collector: vgs, fieldName: fieldName) + } + + // MARK: - Overridden methods and properties + public override var type: FieldType { + get { return .date } + set {} + } + + // MARK: - VGSDateConfigurationProtocol implementation + public var inputSource: VGSTextFieldInputSource = .datePicker + public var inputDateFormat: VGSDateFormat? + public var outputDateFormat: VGSDateFormat? + + // MARK: - VGSFormatSerializableProtocol implementation + public var serializers: [VGSFormatSerializerProtocol] = [] + func serialize(_ content: String) -> [String: Any] { + return DateFormatConvertor.serialize(content, serializers: serializers, outputFormat: outputDateFormat) + } + internal var shouldSerialize: Bool { + return !serializers.isEmpty + } + + // MARK: - VGSDateTokenizationParameters implementation + public var tokenizationParameters = VGSDateTokenizationParameters() + internal var tokenizationConfiguration: VGSTokenizationParametersProtocol { + return tokenizationParameters + } +} + +// MARK: - `TextFormatConvertable` implementation +extension VGSDateTokenizationConfiguration: VGSTextFormatConvertable { + + /// :nodoc: + var inputFormat: InputConvertableFormat? { + return inputDateFormat + } + + /// :nodoc: + var outputFormat: OutputConvertableFormat? { + return outputDateFormat + } + + /// :nodoc: + var convertor: TextFormatConvertor { + return DateFormatConvertor() + } +} diff --git a/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSExpDateTokenizationConfiguration.swift b/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSExpDateTokenizationConfiguration.swift index 679b35de..9efaba4c 100644 --- a/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSExpDateTokenizationConfiguration.swift +++ b/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSExpDateTokenizationConfiguration.swift @@ -49,7 +49,7 @@ public final class VGSExpDateTokenizationConfiguration: VGSConfiguration, VGSExp // MARK: - `VGSExpDateConfiguration` implementation /// Serialize Expiration Date internal func serialize(_ content: String) -> [String: Any] { - return ExpDateFormatConvertor.serialize(content, serializers: serializers, outputFormat: outputFormat) + return ExpDateFormatConvertor.serialize(content, serializers: serializers, outputFormat: outputDateFormat) } /// Returns if Content should be Serialized @@ -58,18 +58,18 @@ public final class VGSExpDateTokenizationConfiguration: VGSConfiguration, VGSExp } } -/// Implement `FormatConvertable` protocol. -extension VGSExpDateTokenizationConfiguration: FormatConvertable { - - internal var outputFormat: VGSCardExpDateFormat? { - return outputDateFormat - } - - internal var inputFormat: VGSCardExpDateFormat? { - return inputDateFormat - } +/// Implement `TextFormatConvertable` protocol. +extension VGSExpDateTokenizationConfiguration: VGSTextFormatConvertable { + + var inputFormat: InputConvertableFormat? { + return inputDateFormat + } + + var outputFormat: OutputConvertableFormat? { + return outputDateFormat + } - internal var convertor: TextFormatConvertor { - return ExpDateFormatConvertor() - } + internal var convertor: TextFormatConvertor { + return ExpDateFormatConvertor() + } } diff --git a/Sources/VGSCollectSDK/Core/VGSDate.swift b/Sources/VGSCollectSDK/Core/VGSDate.swift new file mode 100644 index 00000000..315e8dbd --- /dev/null +++ b/Sources/VGSCollectSDK/Core/VGSDate.swift @@ -0,0 +1,84 @@ +// +// VGSDate.swift +// VGSCollectSDK +// + +import Foundation + +/// `Struct` that represents a date including `year`, `month` and `day`. It doesn't include `hours`, `minutes` or `seconds`. +public struct VGSDate { + + // MARK: - Properties + public var day: Int + public var month: Int + public var year: Int + + /// Get the day formatted value, for example if the day is `1` it is returned as `01` + public var dayFormatted: String { + return String(format: "%02d", day) + } + + /// Get the month formatted value, for example if the month is `3` it is returned as `03` + public var monthFormatted: String { + return String(format: "%02d", month) + } + + // MARK: - Initialization + /// Create a new instance of a `VGSDate` object, if the date is not valid, it returns `nil` + /// - Parameters: + /// - day: `Int`. Represents the day in the date. + /// - month: `Int`. Represents the month in the date. + /// - year: `Int`. Represents the year in the date. + /// - Returns: `VGSDate`, date reference or nil if the date is invalid. + public init?(day: Int, month: Int, year: Int) { + // Make sure it is a valid date + guard DateComponents( + calendar: Calendar(identifier: .gregorian), + year: year, + month: month, + day: day + ).isValidDate else { + let message = "Invalid day, month or year to create date at VGSDate initializer" + let event = VGSLogEvent(level: .warning, text: message, severityLevel: .error) + VGSCollectLogger.shared.forwardLogEvent(event) + return nil + } + // Save date data + self.day = day + self.month = month + self.year = year + } +} + +// MARK: - Equatable and Comparable implementation +extension VGSDate: Comparable { + + /// :nodoc: + public static func == (lhs: Self, rhs: Self) -> Bool { + return lhs.year == rhs.year && + lhs.month == rhs.month && + lhs.day == rhs.day + } + + /// :nodoc: + public static func < (lhs: VGSDate, rhs: VGSDate) -> Bool { + // Check year + if lhs.year < rhs.year { + return true + } + // If the year is equal, check month + else if lhs.year == rhs.year { + // Check month + if lhs.month < rhs.month { + return true + } + // If the month is equal, check day + else if lhs.month == rhs.month { + // Check day + return lhs.day < rhs.day + } + } + // The date at left is not less than date at right + return false + } +} diff --git a/Sources/VGSCollectSDK/Core/VGSDateConfiguration.swift b/Sources/VGSCollectSDK/Core/VGSDateConfiguration.swift new file mode 100644 index 00000000..5b7b15d4 --- /dev/null +++ b/Sources/VGSCollectSDK/Core/VGSDateConfiguration.swift @@ -0,0 +1,132 @@ +// +// VGSDateConfiguration.swift +// VGSCollectSDK +// + +import Foundation + +/// Define the methods and properties the date configuration must have +public protocol VGSDateConfigurationProtocol { + + /// Input source type. + var inputSource: VGSTextFieldInputSource {get set} + + /// Input date format to convert. + var inputDateFormat: VGSDateFormat? {get set} + + /// Output date format to convert. + var outputDateFormat: VGSDateFormat? {get set} +} + +/// Class responsible for configuration `VGSDateTextField` or `VGSTextField` with `fieldType = .date`. Extends `VGSConfiguration` +public final class VGSDateConfiguration: VGSConfiguration, VGSDateConfigurationProtocol, VGSFormatSerializableProtocol { + + // MARK: - Properties + /// Start date used to fill out the date picker + private var datePickerStartDate: VGSDate = VGSDateConfiguration.minValidPickerStartDate + + /// End date used to fill out the date picker + private var datePickerEndDate: VGSDate = VGSDateConfiguration.maxValidPickerEndDate + + /// Get the list of years from `datePickerStartDate` to `datePickerEndDate`. + /// In case any of the dates are not set, it will use the default + /// values `minValidStartDate` and `maxValidEndDate` respectively + internal var years: [Int] { + Array(datePickerStartDate.year...datePickerEndDate.year) + } + + // MARK: - Constructor + /// Initialization + /// Date configuration initializer, if no `datePickerStartDate` is provided, + /// a default date will be used adding 100 years to the current date. + /// Similar approach will be used if `datePickerEndDate` is not provided, + /// it will be calculated removing 100 years from current date. + /// + /// - Parameters: + /// - vgs: `VGSCollect` instance. + /// - fieldName: associated `fieldName`. + /// - datePickerStartDate: optional `VGSDate` instance. + /// - datePickerEndDate: optional `VGSDate` instance. + public init(collector vgs: VGSCollect, + fieldName: String, + datePickerStartDate: VGSDate? = nil, + datePickerEndDate: VGSDate? = nil) { + /// Setup custom picker start date + if let startDate = datePickerStartDate { + self.datePickerStartDate = startDate + } + /// Setup custom picker end date + if let endDate = datePickerEndDate { + self.datePickerEndDate = endDate + } + /// Super initializer + super.init(collector: vgs, fieldName: fieldName) + } + + // MARK: - Overridden methods and properties + public override var type: FieldType { + get { return .date } + set {} + } + + // MARK: - VGSDateConfigurationProtocol implementation + public var inputSource: VGSTextFieldInputSource = .datePicker + public var inputDateFormat: VGSDateFormat? + public var outputDateFormat: VGSDateFormat? + + // MARK: - VGSFormatSerializableProtocol implementation + public var serializers: [VGSFormatSerializerProtocol] = [] + func serialize(_ content: String) -> [String: Any] { + return DateFormatConvertor.serialize(content, serializers: serializers, outputFormat: outputDateFormat) + } + internal var shouldSerialize: Bool { + return !serializers.isEmpty + } +} + +// MARK: - Static properties and methods +extension VGSDateConfiguration { + + /// Amount of years used to calculate the minimun and maximun date picker default dates + public static var validYearsCount = 100 + + /// Minimun date picker start date, current year minus `validYearsCount` + public static let minValidPickerStartDate = VGSDate( + day: 1, + month: 1, + year: Calendar.currentYear - validYearsCount + )! + + /// Maximun date picker valid end date, current year plus `validYearsCount` + public static var maxValidPickerEndDate = VGSDate( + day: 1, + month: 1, + year: Calendar.currentYear + validYearsCount + )! + + /// Get the array of years used as default when no start date or end date are defined + internal static var defaultYears: [Int] = { + let startYear = VGSDateConfiguration.minValidPickerStartDate.year + let endYear = VGSDateConfiguration.maxValidPickerEndDate.year + return Array(startYear...endYear) + }() +} + +// MARK: - `TextFormatConvertable` implementation +extension VGSDateConfiguration: VGSTextFormatConvertable { + + /// :nodoc: + var inputFormat: InputConvertableFormat? { + return inputDateFormat + } + + /// :nodoc: + var outputFormat: OutputConvertableFormat? { + return outputDateFormat + } + + /// :nodoc: + var convertor: TextFormatConvertor { + return DateFormatConvertor() + } +} diff --git a/Sources/VGSCollectSDK/Core/VGSExpDateConfiguration.swift b/Sources/VGSCollectSDK/Core/VGSExpDateConfiguration.swift index 9f441a29..9efb0006 100644 --- a/Sources/VGSCollectSDK/Core/VGSExpDateConfiguration.swift +++ b/Sources/VGSCollectSDK/Core/VGSExpDateConfiguration.swift @@ -51,7 +51,7 @@ public final class VGSExpDateConfiguration: VGSConfiguration, VGSExpDateConfigur // MARK: - `VGSExpDateConfiguration` implementation /// Serialize Expiration Date internal func serialize(_ content: String) -> [String: Any] { - return ExpDateFormatConvertor.serialize(content, serializers: serializers, outputFormat: outputFormat) + return ExpDateFormatConvertor.serialize(content, serializers: serializers, outputFormat: outputDateFormat) } /// Returns if Content should be Serialized @@ -60,18 +60,21 @@ public final class VGSExpDateConfiguration: VGSConfiguration, VGSExpDateConfigur } } -/// Implement `FormatConvertable` protocol. -extension VGSExpDateConfiguration: FormatConvertable { - - internal var outputFormat: VGSCardExpDateFormat? { - return outputDateFormat - } - - internal var inputFormat: VGSCardExpDateFormat? { - return inputDateFormat - } - - internal var convertor: TextFormatConvertor { - return ExpDateFormatConvertor() - } +/// Implement `TextFormatConvertable` protocol. +extension VGSExpDateConfiguration: VGSTextFormatConvertable { + + /// :nodoc: + var inputFormat: InputConvertableFormat? { + return inputDateFormat + } + + /// :nodoc: + var outputFormat: OutputConvertableFormat? { + return outputDateFormat + } + + /// :nodoc: + var convertor: TextFormatConvertor { + return ExpDateFormatConvertor() + } } diff --git a/Sources/VGSCollectSDK/Core/VGSPaymentCards/Core/VGSCustomPaymentCardModel.swift b/Sources/VGSCollectSDK/Core/VGSPaymentCards/Core/VGSCustomPaymentCardModel.swift index 23a1ac4e..f9ceb826 100644 --- a/Sources/VGSCollectSDK/Core/VGSPaymentCards/Core/VGSCustomPaymentCardModel.swift +++ b/Sources/VGSCollectSDK/Core/VGSPaymentCards/Core/VGSCustomPaymentCardModel.swift @@ -42,7 +42,7 @@ public struct VGSCustomPaymentCardModel: VGSPaymentCardModelProtocol { /// Image, associated with CVC for Payment Card Brand. public var cvcIcon: UIImage? - // MARK: - Initialzation + // MARK: - Initialization /// Initializer. /// - Parameters: diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/VGSDateTextField.swift b/Sources/VGSCollectSDK/UIElements/Text Field/VGSDateTextField.swift new file mode 100644 index 00000000..906c5f6a --- /dev/null +++ b/Sources/VGSCollectSDK/UIElements/Text Field/VGSDateTextField.swift @@ -0,0 +1,361 @@ +// +// VGSDateTextField.swift +// VGSCollectSDK +// + +import UIKit + +/// An object that displays an editable text area. Can be use instead of a `VGSTextField` when need to show picker view with a Date. It support to define a range of valid dates to select from. +public final class VGSDateTextField: VGSTextField { + + // MARK: - Inner objects + /// Available month Label formats in `UIPickerView` + public enum MonthFormat { + /// Short month name, e.g.: `Jan` + case shortSymbols + /// Long month name, e.g.: `January` + case longSymbols + /// Month number: e.g.: `01` + case numbers + } + + // MARK: - Properties + /// UIPickerView month label format + public var monthPickerFormat: MonthFormat = .shortSymbols { + didSet { + updateMonthsDataSource() + } + } + /// UIPickerView components order, it is based on the input format of the configuration + internal var pickerDateFormat: VGSDateFormat? + /// Visual day data source + internal var daysDataSource = [String]() + /// Visual month data source + internal var monthsDataSource = [String]() + /// Visual year data source + internal var yearsDataSource = [String]() + /// Valid days range, it is updated when the Month or Year are selected + internal lazy var days = [Int]() + /// Valid months range + internal lazy var months = Array(1...12) + /// Valid years range, it is updated when the configuration is set + internal lazy var years = [Int]() + /// Store the components index in the picker + private let pickerComponent = (left: 0, center: 1, right: 2) + + // MARK: - Properties + /// `UIPickerView` reference + internal lazy var picker: UIPickerView = { + let picker = UIPickerView() + picker.delegate = self + picker.dataSource = self + return picker + }() + + // MARK: - Overridden methods and properties + public override var configuration: VGSConfiguration? { + didSet { + fieldType = .date + } + } + + override func mainInitialization() { + super.mainInitialization() + setupDatePicker() + } + + override func setupField(with configuration: VGSConfiguration) { + super.setupField(with: configuration) + guard let config = configuration as? VGSDateConfigurationProtocol else { + return + } + + // setup input source + switch config.inputSource { + case .datePicker: + setupDatePicker() + case .keyboard: + setupKeyboard(with: configuration) + } + } +} + +// MARK: - UIPickerViewDelegate and UIPickerViewDataSource implementation +extension VGSDateTextField: UIPickerViewDelegate, UIPickerViewDataSource { + + /// :nodoc: Picker view dataSource implementation. + public func numberOfComponents(in pickerView: UIPickerView) -> Int { + return 3 + } + + /// :nodoc: Picker view dataSource implementation. + public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { + switch component { + case pickerComponent.left: + switch pickerDateFormat { + case .ddmmyyyy: + return daysDataSource.count + case .mmddyyyy: + return monthsDataSource.count + case .yyyymmdd: + return yearsDataSource.count + default: + // Default format: .mmddyyyy + return monthsDataSource.count + } + + case pickerComponent.center: + switch pickerDateFormat { + case .ddmmyyyy, .yyyymmdd: + return monthsDataSource.count + case .mmddyyyy: + return daysDataSource.count + default: + // Default format: .mmddyyyy + return daysDataSource.count + } + + case pickerComponent.right: + switch pickerDateFormat { + case .ddmmyyyy, .mmddyyyy: + return yearsDataSource.count + case .yyyymmdd: + return daysDataSource.count + default: + // Default format: .mmddyyyy + return yearsDataSource.count + } + + default: + // This should never happend + assertionFailure("No valid component index for picker") + return 0 + } + } + + /// :nodoc: Picker view delegate implementation. + public func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { + + switch component { + case pickerComponent.left: + switch pickerDateFormat { + case .ddmmyyyy: + return daysDataSource[row] + case .mmddyyyy: + return monthsDataSource[row] + case .yyyymmdd: + return yearsDataSource[row] + default: + // Default format: .mmddyyyy + return monthsDataSource[row] + } + + case pickerComponent.center: + switch pickerDateFormat { + case .ddmmyyyy, .yyyymmdd: + return monthsDataSource[row] + case .mmddyyyy: + return daysDataSource[row] + default: + // Default format: .mmddyyyy + return daysDataSource[row] + } + + case pickerComponent.right: + switch pickerDateFormat { + case .ddmmyyyy, .mmddyyyy: + return yearsDataSource[row] + case .yyyymmdd: + return daysDataSource[row] + default: + // Default format: .mmddyyyy + return yearsDataSource[row] + } + + default: + // This should never happend + assertionFailure("No valid component index for picker") + return "" + } + } + + /// :nodoc: Picker view delegate implementation. + public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { + switch component { + case pickerComponent.left: + if pickerDateFormat == .mmddyyyy || pickerDateFormat == .yyyymmdd { + updateDaysDataSource() + } + + case pickerComponent.center: + if pickerDateFormat == .ddmmyyyy || pickerDateFormat == .yyyymmdd { + updateDaysDataSource() + } + + case pickerComponent.right: + if pickerDateFormat == .ddmmyyyy || pickerDateFormat == .mmddyyyy { + updateDaysDataSource() + } + default: + // This should never happend + assertionFailure("No valid component index for picker") + } + + // Update text selection + updateTextFieldWithDatePickerSelection() + } +} + +// MARK: - Private methods +private extension VGSDateTextField { + + var pickerDayComponent: Int { + switch pickerDateFormat { + case .ddmmyyyy: + return pickerComponent.left + case .mmddyyyy: + return pickerComponent.center + case .yyyymmdd: + return pickerComponent.right + default: + // Default format: .mmddyyyy + return pickerComponent.center + } + } + + var pickerMonthComponent: Int { + switch pickerDateFormat { + case .ddmmyyyy, .yyyymmdd: + return pickerComponent.center + case .mmddyyyy: + return pickerComponent.left + default: + // Default format: .mmddyyyy + return pickerComponent.left + } + } + + var pickerYearComponent: Int { + switch pickerDateFormat { + case .ddmmyyyy, .mmddyyyy: + return pickerComponent.right + case .yyyymmdd: + return pickerComponent.left + default: + // Default format: .mmddyyyy + return pickerComponent.right + } + } + + func updateMonthsDataSource() { + switch monthPickerFormat { + case .shortSymbols: + monthsDataSource = DateFormatter().shortMonthSymbols + case .longSymbols: + monthsDataSource = DateFormatter().monthSymbols + case .numbers: + monthsDataSource = months.map { (String(format: "%02d", $0)) } + } + } + + func updateDaysDataSource() { + /// Make sure it has valid data for months and years + guard months.count > 0, years.count > 0 else { + return + } + /// Get month and year + var day = 0 + if days.count > 0 { + day = days[picker.selectedRow(inComponent: pickerDayComponent)] + } + let month = months[picker.selectedRow(inComponent: pickerMonthComponent)] + let year = years[picker.selectedRow(inComponent: pickerYearComponent)] + + /// Get amount of days in selected month and year + let dateComponents = DateComponents(year: year, month: month) + let calendar = Calendar(identifier: .gregorian) + let date = calendar.date(from: dateComponents)! + + // Get range of days in month + if let range = calendar.range(of: .day, in: .month, for: date) { + days = range.map { $0 } + } + daysDataSource = days.map { String($0) } + + // Reload days + picker.reloadComponent(pickerDayComponent) + + // If the day is not valid in the month and year, update it to the last one in the days collection + if day >= days.count { + picker.selectRow(days.count - 1, inComponent: pickerDayComponent, animated: true) + } + } + + func updateYearsDataSource() { + /// Make sure the configuration is valid + if let config = configuration as? VGSDateConfiguration { + years = config.years + } else if let tokenizationConfig = configuration as? VGSDateTokenizationConfiguration { + years = tokenizationConfig.years + } else { + years = VGSDateConfiguration.defaultYears + } + yearsDataSource = years.map { String($0) } + } + + func updateTextFieldWithDatePickerSelection() { + /// Get date components + let day = days[picker.selectedRow(inComponent: pickerDayComponent)] + let month = months[picker.selectedRow(inComponent: pickerMonthComponent)] + let year = years[picker.selectedRow(inComponent: pickerYearComponent)] + + /// Get input date format, if not set, use the default + var inputDateFormat = VGSDateFormat.default + if let config = configuration as? VGSDateConfigurationProtocol, + let fieldDateFormat = config.inputDateFormat { + inputDateFormat = fieldDateFormat + } + + /// Create the date string and update the display text + if let date = VGSDate(day: day, month: month, year: year) { + self.setText(inputDateFormat.mapDatePickerDataForFieldFormat(date)) + } + } + + func scrollToCurrentMonthAndYear(animated: Bool) { + let currentMonthIndex = Calendar.currentMonth - 1 + let currentYearIndex = Calendar.currentYear - 1 + picker.selectRow(currentMonthIndex, inComponent: pickerMonthComponent, animated: animated) + picker.selectRow(currentYearIndex, inComponent: pickerYearComponent, animated: animated) + } + + /// Setup date picker configuration + func setupDatePicker() { + textField.inputView = picker + updateMonthsDataSource() + updateYearsDataSource() + updateDaysDataSource() + + // If the date format change, reload the picker component + if let config = configuration as? VGSDateConfigurationProtocol, + let fieldDateFormat = config.inputDateFormat { + // Update the picker format only if it is different + if pickerDateFormat != fieldDateFormat { + pickerDateFormat = fieldDateFormat + picker.reloadAllComponents() + } + } + scrollToCurrentMonthAndYear(animated: false) + textField.inputAccessoryView = UIView() + } + + /// Setup keyboard configuration + func setupKeyboard(with configuration: VGSConfiguration) { + textField.keyboardType = configuration.keyboardType ?? configuration.type.keyboardType + textField.returnKeyType = configuration.returnKeyType ?? .default + textField.keyboardAppearance = configuration.keyboardAppearance ?? .default + // Remove date picker if any + textField.inputView = nil + textField.inputAccessoryView = nil + } +} diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift b/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift index a91b8084..6e500e7b 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift @@ -181,7 +181,8 @@ private extension VGSExpDateTextField { let inputDateFormat: VGSCardExpDateFormat /// Check if specific `.inputFormat` is set in field configuration - if let config = configuration as? VGSExpDateConfiguration, let fieldDateFormat = config.inputFormat { + if let config = configuration as? VGSExpDateConfiguration, + let fieldDateFormat = config.inputFormat as? VGSCardExpDateFormat { inputDateFormat = fieldDateFormat } else { /// Default format could be mm/yy or mm/yyyy. In other case `.inputDateFormat` should be specified diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/VGSTextField.swift b/Sources/VGSCollectSDK/UIElements/Text Field/VGSTextField.swift index fd61038a..b6ce1663 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/VGSTextField.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/VGSTextField.swift @@ -10,6 +10,7 @@ import UIKit #endif +// swiftlint:disable file_length /// An object that displays an editable text area in user interface. public class VGSTextField: UIView { @@ -168,13 +169,16 @@ public class VGSTextField: UIView { public func isContentEqual(_ textField: VGSTextField) -> Bool { return self.textField.getSecureRawText == textField.textField.getSecureRawText } - - internal func getOutputText() -> String? { - if let config = configuration as? FormatConvertable, let input = textField.getSecureTextWithDivider, let outputFormat = config.outputFormat, let inputFormat = config.inputFormat { - return config.convertor.convert(input, inputFormat: inputFormat, outputFormat: outputFormat) + + internal func getOutputText() -> String? { + if let config = configuration as? VGSTextFormatConvertable, + let input = textField.getSecureTextWithDivider, + let inputFormat = config.inputFormat, + let outputFormat = config.outputFormat { + return config.convertor.convert(input, inputFormat: inputFormat, outputFormat: outputFormat) + } + return textField.getSecureTextWithDivider } - return textField.getSecureTextWithDivider - } /// Field Configuration internal func setupField(with configuration: VGSConfiguration) { @@ -385,7 +389,6 @@ internal extension VGSTextField { return !textField.formatPattern.isEmpty } } -// swiftlint:disable file_length // MARK: - MaskedTextFieldDelegate @@ -422,3 +425,4 @@ extension UIView { layer.cornerRadius = 4 } } +// swiftlint:enable file_length diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRuleLength.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRuleLength.swift index 1381b28e..8b2fa615 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRuleLength.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRuleLength.swift @@ -22,7 +22,7 @@ public struct VGSValidationRuleLength: VGSValidationRuleProtocol { /// Validation Error public let error: VGSValidationError - /// Initialzation + /// Initialization /// /// - Parameters: /// - error:`VGSValidationError` - error on failed validation relust. diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRuleLengthMatch.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRuleLengthMatch.swift index 547c370a..7efdfc31 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRuleLengthMatch.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRuleLengthMatch.swift @@ -19,7 +19,7 @@ public struct VGSValidationRuleLengthMatch: VGSValidationRuleProtocol { /// Validation Error public let error: VGSValidationError - /// Initialzation + /// Initialization /// /// - Parameters: /// - error:`VGSValidationError` - error on failed validation relust. diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRulePattern.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRulePattern.swift index 30b2cd23..c79e8ac8 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRulePattern.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRulePattern.swift @@ -19,7 +19,7 @@ public struct VGSValidationRulePattern: VGSValidationRuleProtocol { /// Validation Error public let error: VGSValidationError - /// Initialzation + /// Initialization /// /// - Parameters: /// - error:`VGSValidationError` - error on failed validation relust. diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Card/VGSValidationRuleLuhnCheck.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Card/VGSValidationRuleLuhnCheck.swift index 950dbf2e..49424366 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Card/VGSValidationRuleLuhnCheck.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Card/VGSValidationRuleLuhnCheck.swift @@ -16,7 +16,7 @@ public struct VGSValidationRuleLuhnCheck: VGSValidationRuleProtocol { /// Validation Error public var error: VGSValidationError - /// Initialzation + /// Initialization /// /// - Parameters: /// - error:`VGSValidationError` - error on failed validation relust. diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Card/VGSValidationRulePaymentCard.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Card/VGSValidationRulePaymentCard.swift index 620fc99f..77884d15 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Card/VGSValidationRulePaymentCard.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Card/VGSValidationRulePaymentCard.swift @@ -21,7 +21,7 @@ public struct VGSValidationRulePaymentCard: VGSValidationRuleProtocol { /// Turn on/off validation of cards that are not defined in SDK - `CardBrand.unknown` public var validateUnknownCardBrand = false - /// Initialzation + /// Initialization /// /// - Parameters: /// - error:`VGSValidationError` - error on failed validation relust. @@ -29,7 +29,7 @@ public struct VGSValidationRulePaymentCard: VGSValidationRuleProtocol { self.error = error } - /// Initialzation + /// Initialization /// /// - Parameters: /// - error:`VGSValidationError` - error on failed validation relust. diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSDateFormat.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSDateFormat.swift new file mode 100644 index 00000000..54c70463 --- /dev/null +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSDateFormat.swift @@ -0,0 +1,181 @@ +// +// VGSDateFormat.swift +// VGSCollectSDK +// + +/// Format used to validate a VGS date text input +public enum VGSDateFormat: InputConvertableFormat, OutputConvertableFormat { + case mmddyyyy + case ddmmyyyy + case yyyymmdd + + /// Initializer + /// - Parameter name: String object, date format name. + internal init?(name: String) { + switch name { + case "mmddyyyy": + self = .mmddyyyy + return + case "ddmmyyyy": + self = .ddmmyyyy + return + case "yyyymmdd": + self = .yyyymmdd + return + default: + print("WRONG name!: \(name)") + return nil + } + } + + /// Amount of expected characters for day date component + internal var daysCharacters: Int { + return 2 + } + + /// Amount of expected characters for month date component + internal var monthCharacters: Int { + return 2 + } + + /// Amount of expected characters for year date component + internal var yearCharacters: Int { + return 4 + } + + /// Amount of expected dividers in the formatted date + internal var dividerCharacters: Int { + return 2 + } + + /// Get the formatted date to be used as a string representation based + /// in the selected date format. + /// + /// - Returns: `String`, formatted date + internal func mapDatePickerDataForFieldFormat(_ date: VGSDate) -> String { + /// Day and month values + let dayString = String(format: "%02d", date.day) + let monthString = String(format: "%02d", date.month) + + /// Return the string of the date based on the format + switch self { + case .mmddyyyy: + return "\(monthString)\(dayString)\(date.year)" + case .ddmmyyyy: + return "\(dayString)\(monthString)\(date.year)" + case .yyyymmdd: + return "\(date.year)\(monthString)\(dayString)" + } + } + + /// Get the formatted date including the divider + internal func formatDate(_ date: VGSDate, divider: String) -> String { + /// Day and month values + let dayString = String(format: "%02d", date.day) + let monthString = String(format: "%02d", date.month) + + /// Return the string of the date based on the format + switch self { + case .mmddyyyy: + return "\(monthString)\(divider)\(dayString)\(divider)\(date.year)" + case .ddmmyyyy: + return "\(dayString)\(divider)\(monthString)\(divider)\(date.year)" + case .yyyymmdd: + return "\(date.year)\(divider)\(monthString)\(divider)\(dayString)" + } + } + + /// Format and validate an input string and try to convert it to `VGSDate` + /// - Parameter input: `String` object, input data. + /// - Returns: `VGSDate?`, date reference or `nil`. + internal func dateFromInput(_ input: String?) -> VGSDate? { + /// Make sure if is a valid input string + guard let input = input else { + return nil + } + /// Check the amount of chars per date component are correct + let expectedCount = daysCharacters + monthCharacters + yearCharacters + guard input.count == expectedCount else { + return nil + } + // Format the date + switch self { + case .mmddyyyy: + /// Get month, day and year + let month = Int(input.prefix(monthCharacters)) + let day = Int(input.prefix(monthCharacters + daysCharacters).dropFirst(monthCharacters)) + let year = Int(input.suffix(yearCharacters)) + /// Make sure the data is good to create the date + if let month = month, let day = day, let year = year { + return VGSDate(day: day, month: month, year: year) + } + + case .ddmmyyyy: + /// Get day, month and year + let day = Int(input.prefix(daysCharacters)) + let month = Int(input.prefix(daysCharacters + monthCharacters).dropFirst(daysCharacters)) + let year = Int(input.suffix(yearCharacters)) + /// Make sure the data is good to create the date + if let day = day, let month = month, let year = year { + return VGSDate(day: day, month: month, year: year) + } + + case .yyyymmdd: + /// Get year, month and day + let year = Int(input.prefix(yearCharacters)) + let month = Int(input.prefix(yearCharacters + monthCharacters).dropFirst(yearCharacters)) + let day = Int(input.suffix(daysCharacters)) + /// Make sure the data is good to create the date + if let year = year, let month = month, let day = day { + return VGSDate(day: day, month: month, year: year) + } + } + // By default return nil, no valid date + return nil + } + + /// Date format used for display in UI + public var displayFormat: String { + switch self { + case .mmddyyyy: + return "mm-dd-yyyy" + case .ddmmyyyy: + return "dd-mm-yyyy" + case .yyyymmdd: + return "yyyy-mm-dd" + } + } + + /// Date format pattern used to display in the text field + internal var formatPattern: String { + switch self { + case .mmddyyyy, .ddmmyyyy: + return "##-##-####" + case .yyyymmdd: + return "####-##-##" + } + } + + // MARK: - Static properties and methods + /// Default format + static public let `default`: VGSDateFormat = .mmddyyyy + + /// Search the separator used in the input + /// - Parameter input: `String` object, input data. + /// - Returns: `String`, divider reference or empty string. + static internal func dividerInInput(_ input: String) -> String { + /// Remove all digits + let dividers = input.components(separatedBy: CharacterSet.decimalDigits).split(separator: "") + /// There must be only 2 dividers + if dividers.count == 2, + let first = dividers.first?.first, + let second = dividers.last?.first { + /// The dividers must be the same + if String(first) == String(second) { + return String(first) + } + } + /// If no divider found, return empty + return "" + } +} diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleDateRange.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleDateRange.swift new file mode 100644 index 00000000..5a6905b4 --- /dev/null +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleDateRange.swift @@ -0,0 +1,76 @@ +// +// VGSDateRangeValidationRule.swift +// VGSCollectSDK +// + +import Foundation + +/// Validation rule used to validate the date input in objects +/// like `VGSDateTextField`, `VGSTextField` and `VGSExpDateTextField` +public struct VGSValidationRuleDateRange: VGSValidationRuleProtocol { + + // MARK: - Properties + /// Store the start date, it can be null + internal let startDate: VGSDate? + + /// Store the end date, it can be null + internal let endDate: VGSDate? + + /// Date format used to validate the rule + public let dateFormat: VGSDateFormat + + /// Error used in case the validation is invalid + public let error: VGSValidationError + + // MARK: - Constructor + /// Initialization + /// + /// - Parameters: + /// - dateFormat: Format used to validate the rule, defaults to `VGSDateFormat.default`. + /// - error: Error used in case there is an error with the validation rule. + /// - startDate: optional `VGSDate` instance. + /// - endDate: optional `VGSDate` instance. + public init(dateFormat: VGSDateFormat = VGSDateFormat.default, + error: VGSValidationError, + start: VGSDate? = nil, + end: VGSDate? = nil) { + self.dateFormat = dateFormat + self.error = error + self.startDate = start + self.endDate = end + } +} + +// MARK: - VGSRuleValidator implementation +extension VGSValidationRuleDateRange: VGSRuleValidator { + + /// :nodoc: + internal func validate(input: String?) -> Bool { + /// Must have valid input + guard let input = input else { + return false + } + + /// Format input date match selected format + guard let inputDate = dateFormat.dateFromInput(input) else { + return false + } + + /// When startDate and endDate are set, validate that startDate `<=` inputDate `<=` endDate + if let startDate = startDate, let endDate = endDate { + return startDate <= inputDate && inputDate <= endDate + } + + /// When startDate is set, validate that startDate `<=` inputDate + if let startDate = startDate { + return startDate <= inputDate + } + + /// When endDate is set, validate that inputDate `<=` endDate + if let endDate = endDate { + return inputDate <= endDate + } + + return true + } +} diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleExpirationDate.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleExpirationDate.swift index 98a7aa22..749d4f0e 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleExpirationDate.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleExpirationDate.swift @@ -9,7 +9,7 @@ import Foundation /// Payment Card Expiration Date Format -public enum VGSCardExpDateFormat { +public enum VGSCardExpDateFormat: InputConvertableFormat, OutputConvertableFormat { /// Exp.Date in format mm/yy: 01/22 case shortYear @@ -88,7 +88,7 @@ public struct VGSValidationRuleCardExpirationDate: VGSValidationRuleProtocol { /// Validation Error public let error: VGSValidationError - /// Initialzation + /// Initialization /// /// - Parameters: /// - error:`VGSValidationError` - error on failed validation relust. diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/VGSValidationError.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/VGSValidationError.swift index aa36c81d..5305f02d 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/VGSValidationError.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/VGSValidationError.swift @@ -24,6 +24,9 @@ public enum VGSValidationErrorType: String { /// Default Validation error for `VGSValidationRuleCardExpirationDate` case expDate = "EXPIRATION_DATE_VALIDATION_ERROR" + + /// Default Validation error for `VGSValidationRuleDateRange` + case date = "DATE_VALIDATION_ERROR" /// Default Validation error for `VGSValidationRulePaymentCard` case cardNumber = "CARD_NUMBER_VALIDATION_ERROR" diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/VGSValidationRule.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/VGSValidationRule.swift index 1afc01bc..7f9e92cb 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/VGSValidationRule.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/VGSValidationRule.swift @@ -20,10 +20,10 @@ public struct VGSValidationRuleSet { internal var rules = [AnyValidationRule]() - /// Initialzation + /// Initialization public init() { } - /// Initialzation + /// Initialization /// /// - Parameters: /// - rules: array of validation rules diff --git a/Sources/VGSCollectSDK/Utils/Convertors/DateFormatConvertor.swift b/Sources/VGSCollectSDK/Utils/Convertors/DateFormatConvertor.swift new file mode 100644 index 00000000..b6d85832 --- /dev/null +++ b/Sources/VGSCollectSDK/Utils/Convertors/DateFormatConvertor.swift @@ -0,0 +1,75 @@ +// +// DateFormatConvertor.swift +// VGSCollectSDK +// + +import Foundation + +/// Date format convertor +internal class DateFormatConvertor: TextFormatConvertor { + + /// Convert date string with input `VGSDateFormat` to output `VGSDateFormat` + func convert(_ input: String, + inputFormat: InputConvertableFormat, + outputFormat: OutputConvertableFormat) -> String { + /// Make sure the input and output formats are references to `VGSCardExpDateFormat` + guard let inputFormat = inputFormat as? VGSDateFormat, + let outputFormat = outputFormat as? VGSDateFormat else { + let text = "CANNOT CONVERT DATE FORMAT! NOT VALID INPUT OR OUTPUT FORMATS. WILL USE ORIGINAL(INPUT) DATE FORMAT!" + let event = VGSLogEvent(level: .warning, text: text, severityLevel: .warning) + VGSCollectLogger.shared.forwardLogEvent(event) + return input + } + + // Get digits + let result = input.digits + // Get output + if let inputDate = inputFormat.dateFromInput(result) { + /// Store the dividers + let divider = VGSDateFormat.dividerInInput(input) + // Return output date including the divider + return outputFormat.formatDate(inputDate, divider: divider) + } + + // Error, no valid input + let text = "CANNOT CONVERT DATE FORMAT! NOT VALID INPUT OR OUTPUT FORMATS. WILL USE ORIGINAL(INPUT) DATE FORMAT!" + let event = VGSLogEvent(level: .warning, text: text, severityLevel: .warning) + VGSCollectLogger.shared.forwardLogEvent(event) + return input + } + + /// Serializes date + /// - Parameters: + /// - content: `String` object, content to serialize + /// - serializers: `[VGSFormatSerializerProtocol]` object, an array of serializers. + /// - outputFormat: `VGSDateFormat` object, output date format, + /// - Returns: `[String: Any]` object, json with serialized data. + static internal func serialize(_ content: String, + serializers: [VGSFormatSerializerProtocol], + outputFormat: VGSDateFormat?) -> [String: Any] { + var result = [String: Any]() + for serializer in serializers { + if let serializer = serializer as? VGSDateSeparateSerializer { + /// Remove dividers + let dateDigitsString = content.digits + + /// Get output date format, or default if not set + let outputDateFormat = outputFormat ?? .default + + /// Check output date components length + if let outputDate = outputDateFormat.dateFromInput(dateDigitsString) { + /// Set result for specific field names + result[serializer.dayFieldName] = outputDate.dayFormatted + result[serializer.monthFieldName] = outputDate.monthFormatted + result[serializer.yearFieldName] = String(outputDate.year) + } else { + // Error, no valid output + let text = "CANNOT SERIALIZE DATE! NOT VALID OUTPUT FORMATS OR INPUT. WILL USE ORIGINAL(INPUT) DATE FORMAT!" + let event = VGSLogEvent(level: .warning, text: text, severityLevel: .warning) + VGSCollectLogger.shared.forwardLogEvent(event) + } + } + } + return result + } +} diff --git a/Sources/VGSCollectSDK/Utils/Convertors/ExpDateFormatConvertor.swift b/Sources/VGSCollectSDK/Utils/Convertors/ExpDateFormatConvertor.swift index da1b01b2..b6174a1c 100644 --- a/Sources/VGSCollectSDK/Utils/Convertors/ExpDateFormatConvertor.swift +++ b/Sources/VGSCollectSDK/Utils/Convertors/ExpDateFormatConvertor.swift @@ -11,89 +11,85 @@ import Foundation import UIKit #endif -internal protocol FormatConvertable { - /// Input text format - var inputFormat: VGSCardExpDateFormat? { get } - /// Output text format - var outputFormat: VGSCardExpDateFormat? { get } - /// Text convertor object - var convertor: TextFormatConvertor { get } -} - -internal protocol TextFormatConvertor { - func convert(_ input: String, inputFormat: VGSCardExpDateFormat, outputFormat: VGSCardExpDateFormat) -> String -} - /// Card Expiration date format convertor internal class ExpDateFormatConvertor: TextFormatConvertor { - - /// Convert Exp Date String with input `CardExpDateFormat` to Output `CardExpDateFormat` - func convert(_ input: String, inputFormat: VGSCardExpDateFormat, outputFormat: VGSCardExpDateFormat) -> String { - let inputYear = inputFormat.isYearFirst ? String(input.prefix(inputFormat.yearCharacters)) : String(input.suffix(inputFormat.yearCharacters)) - let inputMonth = inputFormat.isYearFirst ? input.suffix(inputFormat.monthCharacters) : input.prefix(inputFormat.monthCharacters) - let divider = inputFormat.isYearFirst ? String(input.dropLast(inputFormat.monthCharacters)).dropFirst(inputFormat.yearCharacters) : String(input.dropLast(inputFormat.yearCharacters)).dropFirst(inputFormat.monthCharacters) - - let dateFormatter = DateFormatter() - dateFormatter.calendar = Calendar(identifier: .gregorian) - dateFormatter.dateFormat = inputFormat.dateYearFormat - dateFormatter.locale = Locale(identifier: "en_US") - if let date = dateFormatter.date(from: inputYear) { - dateFormatter.dateFormat = outputFormat.dateYearFormat - let outputYear = dateFormatter.string(from: date) - let output = outputFormat.isYearFirst ? String(outputYear + divider + inputMonth) : - String(inputMonth + divider + outputYear) - return output + /// Convert Exp Date String with input `CardExpDateFormat` to Output `CardExpDateFormat` + func convert(_ input: String, inputFormat: InputConvertableFormat, outputFormat: OutputConvertableFormat) -> String { + /// Make sure the input and output formats are references to `VGSCardExpDateFormat` + guard let inputFormat = inputFormat as? VGSCardExpDateFormat, + let outputFormat = outputFormat as? VGSCardExpDateFormat else { + let text = "CANNOT CONVERT DATE FORMAT! NOT VALID INPUT OR OUTPUT FORMATS. WILL USE ORIGINAL(INPUT) DATE FORMAT!" + let event = VGSLogEvent(level: .warning, text: text, severityLevel: .warning) + VGSCollectLogger.shared.forwardLogEvent(event) + return input + } + /// Get input data + let inputYear = inputFormat.isYearFirst ? String(input.prefix(inputFormat.yearCharacters)) : String(input.suffix(inputFormat.yearCharacters)) + let inputMonth = inputFormat.isYearFirst ? input.suffix(inputFormat.monthCharacters) : input.prefix(inputFormat.monthCharacters) + let divider = inputFormat.isYearFirst ? String(input.dropLast(inputFormat.monthCharacters)).dropFirst(inputFormat.yearCharacters) : String(input.dropLast(inputFormat.yearCharacters)).dropFirst(inputFormat.monthCharacters) + + let dateFormatter = DateFormatter() + dateFormatter.calendar = Calendar(identifier: .gregorian) + dateFormatter.dateFormat = inputFormat.dateYearFormat + dateFormatter.locale = Locale(identifier: "en_US") + + if let date = dateFormatter.date(from: inputYear) { + dateFormatter.dateFormat = outputFormat.dateYearFormat + let outputYear = dateFormatter.string(from: date) + let output = outputFormat.isYearFirst ? String(outputYear + divider + inputMonth) : + String(inputMonth + divider + outputYear) + return output + } + let text = "CANNOT CONVERT DATE FORMAT! NOT VALID INPUT YEAR - \(inputYear). WILL USE ORIGINAL(INPUT) DATE FORMAT!" + let event = VGSLogEvent(level: .warning, text: text, severityLevel: .warning) + VGSCollectLogger.shared.forwardLogEvent(event) + + return input } - let text = "CANNOT CONVERT DATE FORMAT! NOT VALID INPUT YEAR - \(inputYear). WILL USE ORIGINAL(INPUT) DATE FORMAT!" - let event = VGSLogEvent(level: .warning, text: text, severityLevel: .warning) - VGSCollectLogger.shared.forwardLogEvent(event) - return input - } - - /// Serializes expiration date. - /// - Parameters: - /// - content: `String` object, content to serialize - /// - serializers: `[VGSFormatSerializerProtocol]` object, an array of serializers. - /// - outputFormat: `VGSCardExpDateFormat` object, output date format, - /// - Returns: `[String: Any]` object, json with serialized data. - static internal func serialize(_ content: String, serializers: [VGSFormatSerializerProtocol], outputFormat: VGSCardExpDateFormat?) -> [String: Any] { - var result = [String: Any]() - for serializer in serializers { - if let serializer = serializer as? VGSExpDateSeparateSerializer { - /// remove dividers - var dateDigitsString = content.digits - - /// get output date format, if not set - use default - let outputDateFormat = outputFormat ?? .shortYear - /// check output date components length - let outputMonthDigits = outputDateFormat.monthCharacters - let outputYearDigits = outputDateFormat.yearCharacters - - let mth: String - let year: String - if outputDateFormat.isYearFirst { - /// take month digitis - year = String(dateDigitsString.prefix(outputYearDigits)) - /// remove month digits - dateDigitsString = String(dateDigitsString.dropFirst(outputYearDigits)) - /// take year digitis - mth = String(dateDigitsString.prefix(outputMonthDigits)) - } else { - /// take month digitis - mth = String(dateDigitsString.prefix(outputMonthDigits)) - /// remove month digits - dateDigitsString = String(dateDigitsString.dropFirst(outputMonthDigits)) - /// take year digitis - year = String(dateDigitsString.prefix(outputYearDigits)) + /// Serializes expiration date. + /// - Parameters: + /// - content: `String` object, content to serialize + /// - serializers: `[VGSFormatSerializerProtocol]` object, an array of serializers. + /// - outputFormat: `VGSCardExpDateFormat` object, output date format, + /// - Returns: `[String: Any]` object, json with serialized data. + static internal func serialize(_ content: String, serializers: [VGSFormatSerializerProtocol], outputFormat: VGSCardExpDateFormat?) -> [String: Any] { + var result = [String: Any]() + for serializer in serializers { + if let serializer = serializer as? VGSExpDateSeparateSerializer { + /// remove dividers + var dateDigitsString = content.digits + + /// get output date format, if not set - use default + let outputDateFormat = outputFormat ?? .shortYear + /// check output date components length + let outputMonthDigits = outputDateFormat.monthCharacters + let outputYearDigits = outputDateFormat.yearCharacters + + let mth: String + let year: String + if outputDateFormat.isYearFirst { + /// take month digitis + year = String(dateDigitsString.prefix(outputYearDigits)) + /// remove month digits + dateDigitsString = String(dateDigitsString.dropFirst(outputYearDigits)) + /// take year digitis + mth = String(dateDigitsString.prefix(outputMonthDigits)) + } else { + /// take month digitis + mth = String(dateDigitsString.prefix(outputMonthDigits)) + /// remove month digits + dateDigitsString = String(dateDigitsString.dropFirst(outputMonthDigits)) + /// take year digitis + year = String(dateDigitsString.prefix(outputYearDigits)) + } + + /// set result for specific fieldnames + result[serializer.monthFieldName] = mth + result[serializer.yearFieldName] = year + } } - - /// set result for specific fieldnames - result[serializer.monthFieldName] = mth - result[serializer.yearFieldName] = year - } + return result } - return result - } } diff --git a/Sources/VGSCollectSDK/Utils/Convertors/VGSTextFormatConvertable.swift b/Sources/VGSCollectSDK/Utils/Convertors/VGSTextFormatConvertable.swift new file mode 100644 index 00000000..2a8242e5 --- /dev/null +++ b/Sources/VGSCollectSDK/Utils/Convertors/VGSTextFormatConvertable.swift @@ -0,0 +1,31 @@ +// +// VGSTextFormatConvertable.swift +// VGSCollectSDK +// + +import Foundation + +/// Base protocol describing the input format to conver a string value +protocol InputConvertableFormat { } + +/// Base protocol describing the output format to conver a string value +protocol OutputConvertableFormat { } + +/// Base protocol to implements the method to convert an `input` string +/// with input `InputConvertableFormat` to output `OutputConvertableFormat` +protocol TextFormatConvertor { + func convert(_ input: String, + inputFormat: InputConvertableFormat, + outputFormat: OutputConvertableFormat) -> String +} + +/// Base protocol to implement the input and output formats and +/// the convertor for input strings +protocol VGSTextFormatConvertable { + /// Input text format + var inputFormat: InputConvertableFormat? { get } + /// Output text format + var outputFormat: OutputConvertableFormat? { get } + /// Text convertor object + var convertor: TextFormatConvertor { get } +} diff --git a/Sources/VGSCollectSDK/Utils/Helpers/Serializers/VGSDateSeparateSerializer.swift b/Sources/VGSCollectSDK/Utils/Helpers/Serializers/VGSDateSeparateSerializer.swift new file mode 100644 index 00000000..737aeaa9 --- /dev/null +++ b/Sources/VGSCollectSDK/Utils/Helpers/Serializers/VGSDateSeparateSerializer.swift @@ -0,0 +1,32 @@ +// +// VGSDateSeparateSerializer.swift +// VGSCollectSDK +// + +import Foundation + +public struct VGSDateSeparateSerializer: VGSFormatSerializerProtocol { + + // MARK: - Properties + /// Field Name that will be used as a JSON key with day value from date string on send request. + public let dayFieldName: String + + /// Field Name that will be used as a JSON key with month value from date string on send request. + public let monthFieldName: String + + /// Field Name that will be used as a JSON key with year value from date string on send request. + public let yearFieldName: String + + // MARK: - Initialization + /// Initialization + /// + /// - Parameters: + /// - dayFielddName: key, that should be associated with day value in request JSON. + /// - monthFieldName: key, that should be associated with month value in request JSON. + /// - yearFieldName: key, that should be associated with year value in request JSON. + public init(dayFieldName: String, monthFieldName: String, yearFieldName: String) { + self.dayFieldName = dayFieldName + self.monthFieldName = monthFieldName + self.yearFieldName = yearFieldName + } +} diff --git a/Tests/FrameworkTests/ConvertorsTests/DateConvertorTests.swift b/Tests/FrameworkTests/ConvertorsTests/DateConvertorTests.swift new file mode 100644 index 00000000..289bdf02 --- /dev/null +++ b/Tests/FrameworkTests/ConvertorsTests/DateConvertorTests.swift @@ -0,0 +1,309 @@ +// +// DateConvertorTests.swift +// FrameworkTests +// + +import XCTest +@testable import VGSCollectSDK + +class DateConvertorTests: VGSCollectBaseTestCase { + + // MARK: - Properties + private var collector: VGSCollect! + private var textField: VGSDateTextField! + + // MARK: - Inner objects + struct TestDataType { + let input: String + let output: String + } + + // MARK: - Overrides + override func setUp() { + super.setUp() + + collector = VGSCollect(id: "any") + textField = VGSDateTextField() + } + + override func tearDown() { + collector = nil + textField = nil + } + + // MARK: - Tests + /// Test to convert a date from default format + func testConvertDate() { + /// Setup configuration + let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") + textField.configuration = config + + /// Test dates + let testDates: [TestDataType] = [ + TestDataType(input: "12/10/2021", output: "12/10/2021"), + TestDataType(input: "01/04/2050", output: "01/04/2050"), + TestDataType(input: "05/07/2100", output: "05/07/2100") + ] + + /// Assert: Test dates output + for date in testDates { + textField.setText(date.input) + XCTAssertEqual(textField.getOutputText(), date.output) + } + } + + /// Test to convert a date from ddmmyyy to ddmmyyy + func testConvertDate_ddmmyyyy_to_ddmmyyyy() { + /// Setup configuration + let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") + config.formatPattern = VGSDateFormat.ddmmyyyy.formatPattern + config.inputDateFormat = .ddmmyyyy + config.outputDateFormat = .ddmmyyyy + textField.configuration = config + + /// Test dates + let testDates: [TestDataType] = [ + TestDataType(input: "12/10/2021", output: "12/10/2021"), + TestDataType(input: "01/04/2050", output: "01/04/2050"), + TestDataType(input: "05/07/2100", output: "05/07/2100") + ] + + /// Assert: Test dates + for date in testDates { + textField.setText(date.input) + XCTAssertEqual(textField.getOutputText(), date.output) + } + } + + /// Test to convert a date from ddmmyyy to mmddyyyy + func testConvertDate_ddmmyyyy_to_mmddyyyy() { + /// Setup configuration + let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") + config.formatPattern = VGSDateFormat.ddmmyyyy.formatPattern + config.inputDateFormat = .ddmmyyyy + config.outputDateFormat = .mmddyyyy + textField.configuration = config + + /// Test dates + let testDates: [TestDataType] = [ + TestDataType(input: "12/10/2021", output: "10/12/2021"), + TestDataType(input: "01/04/2050", output: "04/01/2050"), + TestDataType(input: "05/07/2100", output: "07/05/2100") + ] + + /// Assert: Test dates + for date in testDates { + textField.setText(date.input) + XCTAssertEqual(textField.getOutputText(), date.output) + } + } + + /// Test to convert a date from ddmmyyy to yyyymmdd + func testConvertDate_ddmmyyyy_to_yyyymmdd() { + /// Setup configuration + let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") + config.formatPattern = VGSDateFormat.ddmmyyyy.formatPattern + config.inputDateFormat = .ddmmyyyy + config.outputDateFormat = .yyyymmdd + textField.configuration = config + + /// Test dates + let testDates: [TestDataType] = [ + TestDataType(input: "12/10/2021", output: "2021/10/12"), + TestDataType(input: "01/04/2050", output: "2050/04/01"), + TestDataType(input: "05/07/2100", output: "2100/07/05") + ] + + /// Assert: Test dates + for date in testDates { + textField.setText(date.input) + XCTAssertEqual(textField.getOutputText(), date.output) + } + } + + /// Test to convert a date from mmddyyyy to mmddyyyy + func testConvertDate_mmddyyyy_to_mmddyyyy() { + /// Setup configuration + let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") + config.formatPattern = VGSDateFormat.mmddyyyy.formatPattern + config.inputDateFormat = .mmddyyyy + config.outputDateFormat = .mmddyyyy + textField.configuration = config + + /// Test dates + let testDates: [TestDataType] = [ + TestDataType(input: "10/12/2021", output: "10/12/2021"), + TestDataType(input: "04/01/2050", output: "04/01/2050"), + TestDataType(input: "07/05/2100", output: "07/05/2100") + ] + + /// Assert: Test dates + for date in testDates { + textField.setText(date.input) + XCTAssertEqual(textField.getOutputText(), date.output) + } + } + + /// Test to convert a date from mmddyyyy to ddmmyyy + func testConvertDate_mmddyyyy_to_ddmmyyy() { + /// Setup configuration + let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") + config.formatPattern = VGSDateFormat.mmddyyyy.formatPattern + config.inputDateFormat = .mmddyyyy + config.outputDateFormat = .ddmmyyyy + textField.configuration = config + + /// Test dates + let testDates: [TestDataType] = [ + TestDataType(input: "10/12/2021", output: "12/10/2021"), + TestDataType(input: "04/01/2050", output: "01/04/2050"), + TestDataType(input: "07/05/2100", output: "05/07/2100") + ] + + /// Assert: Test dates + for date in testDates { + textField.setText(date.input) + XCTAssertEqual(textField.getOutputText(), date.output) + } + } + + /// Test to convert a date from mmddyyyy to yyyymmdd + func testConvertDate_mmddyyyy_to_yyyymmdd() { + /// Setup configuration + let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") + config.formatPattern = VGSDateFormat.mmddyyyy.formatPattern + config.inputDateFormat = .mmddyyyy + config.outputDateFormat = .yyyymmdd + textField.configuration = config + + /// Test dates + let testDates: [TestDataType] = [ + TestDataType(input: "10/12/2021", output: "2021/10/12"), + TestDataType(input: "04/01/2050", output: "2050/04/01"), + TestDataType(input: "07/05/2100", output: "2100/07/05") + ] + + /// Assert: Test dates + for date in testDates { + textField.setText(date.input) + XCTAssertEqual(textField.getOutputText(), date.output) + } + } + + /// Test to convert a date from yyyymmdd to yyyymmdd + func testConvertDate_yyyymmdd_to_yyyymmdd() { + /// Setup configuration + let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") + config.formatPattern = VGSDateFormat.yyyymmdd.formatPattern + config.inputDateFormat = .yyyymmdd + config.outputDateFormat = .yyyymmdd + textField.configuration = config + + /// Test dates + let testDates: [TestDataType] = [ + TestDataType(input: "2021/10/12", output: "2021/10/12"), + TestDataType(input: "2050/04/01", output: "2050/04/01"), + TestDataType(input: "2100/07/05", output: "2100/07/05") + ] + + /// Assert: Test dates + for date in testDates { + textField.setText(date.input) + XCTAssertEqual(textField.getOutputText(), date.output) + } + } + + /// Test to convert a date from yyyymmdd to mmddyyyy + func testConvertDate_yyyymmdd_to_mmddyyyy() { + /// Setup configuration + let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") + config.formatPattern = VGSDateFormat.yyyymmdd.formatPattern + config.inputDateFormat = .yyyymmdd + config.outputDateFormat = .mmddyyyy + textField.configuration = config + + /// Test dates + let testDates: [TestDataType] = [ + TestDataType(input: "2021/10/12", output: "10/12/2021"), + TestDataType(input: "2050/04/01", output: "04/01/2050"), + TestDataType(input: "2100/07/05", output: "07/05/2100") + ] + + /// Assert: Test dates + for date in testDates { + textField.setText(date.input) + XCTAssertEqual(textField.getOutputText(), date.output) + } + } + + /// Test to convert a date from yyyymmdd to ddmmyyy + func testConvertDate_yyyymmdd_to_ddmmyyy() { + /// Setup configuration + let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") + config.formatPattern = VGSDateFormat.yyyymmdd.formatPattern + config.inputDateFormat = .yyyymmdd + config.outputDateFormat = .ddmmyyyy + textField.configuration = config + + /// Test dates + let testDates: [TestDataType] = [ + TestDataType(input: "2021/10/12", output: "12/10/2021"), + TestDataType(input: "2050/04/01", output: "01/04/2050"), + TestDataType(input: "2100/07/05", output: "05/07/2100") + ] + + /// Assert: Test dates + for date in testDates { + textField.setText(date.input) + XCTAssertEqual(textField.getOutputText(), date.output) + } + } + + /// Test to convert a date with an empty divider + func testConvertDateEmptyDivider() { + /// Setup configuration + let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") + config.formatPattern = VGSDateFormat.ddmmyyyy.formatPattern + config.divider = "" + config.inputDateFormat = .ddmmyyyy + config.outputDateFormat = .ddmmyyyy + textField.configuration = config + + /// Test dates + let testDates: [TestDataType] = [ + TestDataType(input: "12/10/2021", output: "12102021"), + TestDataType(input: "01/04/2050", output: "01042050"), + TestDataType(input: "05/07/2100", output: "05072100") + ] + + /// Assert: Test dates + for date in testDates { + textField.setText(date.input) + XCTAssertEqual(textField.getOutputText(), date.output) + } + } + + /// Test to convert a date with a custom divider + func testConvertDateCustomDivider() { + /// Setup configuration + let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") + config.formatPattern = VGSDateFormat.ddmmyyyy.formatPattern + config.divider = "-/-" + config.inputDateFormat = .ddmmyyyy + config.outputDateFormat = .ddmmyyyy + textField.configuration = config + + /// Test dates + let testDates: [TestDataType] = [ + TestDataType(input: "12/10/2021", output: "12-/-10-/-2021"), + TestDataType(input: "01/04/2050", output: "01-/-04-/-2050"), + TestDataType(input: "05/07/2100", output: "05-/-07-/-2100") + ] + + /// Assert: Test dates + for date in testDates { + textField.setText(date.input) + XCTAssertEqual(textField.getOutputText(), date.output) + } + } +} diff --git a/Tests/FrameworkTests/Core/DateTests.swift b/Tests/FrameworkTests/Core/DateTests.swift new file mode 100644 index 00000000..3f2bba9d --- /dev/null +++ b/Tests/FrameworkTests/Core/DateTests.swift @@ -0,0 +1,53 @@ +// +// DateTests.swift +// FrameworkTests +// + +import XCTest +@testable import VGSCollectSDK + +class DateTests: VGSCollectBaseTestCase { + + // MARK: - Tests + /// Test date initialization + func testDateInitialization() { + /// Valid date + let validDate = VGSDate(day: 1, month: 1, year: 2010) + XCTAssertNotNil(validDate) + + /// Invalid date + let invalidDate = VGSDate(day: 50, month: 50, year: 2) + XCTAssertNil(invalidDate) + } + + /// Test date formatted + func testFormatters() { + /// Date + let date = VGSDate(day: 2, month: 6, year: 2010) + XCTAssertNotNil(date) + + /// Validate formatted month and day + XCTAssertEqual(date?.dayFormatted, "02") + XCTAssertEqual(date?.monthFormatted, "06") + } + + /// Test date comparable + func testDateComparable() { + /// Dates + let dateA = VGSDate(day: 12, month: 5, year: 2010)! + var dateB = VGSDate(day: 12, month: 5, year: 2010)! + + /// Validate equals + XCTAssertEqual(dateA, dateB) + + /// Validate not equals + dateB.year = 2011 + XCTAssertNotEqual(dateA, dateB) + + /// Validate less than + XCTAssertLessThan(dateA, dateB) + + /// Validate greater than + XCTAssertGreaterThan(dateB, dateA) + } +} diff --git a/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_CustomConfig.json b/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_CustomConfig.json new file mode 100644 index 00000000..71caacf9 --- /dev/null +++ b/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_CustomConfig.json @@ -0,0 +1,44 @@ +{ + "test_data":[ + { + "monthFieldName":"month", + "dayFieldName":"day", + "yearFieldName":"year", + "fieldValue":"2030-/-01-/-15", + "expectedResult":{ + "month":"01", + "day":"15", + "year":"2030" + }, + "comment":"Single key fieldNames." + }, + { + "monthFieldName":"date.month", + "dayFieldName":"date.day", + "yearFieldName":"date.year", + "fieldValue":"2026-/-10-/-18", + "expectedResult":{ + "date":{ + "month":"10", + "day":"18", + "year":"2026" + } + }, + "comment":"Map to dot JSON" + }, + { + "monthFieldName":"date.month", + "dayFieldName":"day", + "yearFieldName":"year", + "fieldValue":"2015-/-05-/-25", + "expectedResult":{ + "date":{ + "month":"05" + }, + "day":"25", + "year":"2015" + }, + "comment":"Map to dot JSON with single key" + } + ] +} \ No newline at end of file diff --git a/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_CustomExpDateOutputConfig.json b/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_CustomExpDateOutputConfig.json new file mode 100644 index 00000000..7e07148a --- /dev/null +++ b/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_CustomExpDateOutputConfig.json @@ -0,0 +1,44 @@ +{ + "test_data":[ + { + "monthFieldName":"month", + "dayFieldName":"day", + "yearFieldName":"year", + "fieldValue":"2030-/-01-/-15", + "expectedResult":{ + "month":"01", + "day":"15", + "year":"2030" + }, + "comment":"Single key fieldNames." + }, + { + "monthFieldName":"date.month", + "dayFieldName":"date.day", + "yearFieldName":"date.year", + "fieldValue":"2033-/-10-/-18", + "expectedResult":{ + "date":{ + "month":"10", + "day":"18", + "year":"2033" + } + }, + "comment":"Map to dot JSON" + }, + { + "monthFieldName":"date.month", + "dayFieldName":"day", + "yearFieldName":"year", + "fieldValue":"2025-/-05-/-25", + "expectedResult":{ + "date":{ + "month":"05" + }, + "day":"25", + "year":"2025" + }, + "comment":"Map to dot JSON with single key" + } + ] +} \ No newline at end of file diff --git a/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_DefaultConfig.json b/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_DefaultConfig.json new file mode 100644 index 00000000..2e0e4613 --- /dev/null +++ b/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_DefaultConfig.json @@ -0,0 +1,44 @@ +{ + "test_data":[ + { + "monthFieldName":"month", + "dayFieldName":"day", + "yearFieldName":"year", + "fieldValue":"01/02/2030", + "expectedResult":{ + "month":"01", + "day":"02", + "year":"2030" + }, + "comment":"Single key fieldNames." + }, + { + "monthFieldName":"date.month", + "dayFieldName":"date.day", + "yearFieldName":"date.year", + "fieldValue":"10/02/2033", + "expectedResult":{ + "date":{ + "month":"10", + "day":"02", + "year":"2033" + } + }, + "comment":"Map to dot JSON" + }, + { + "monthFieldName":"date.month", + "dayFieldName":"day", + "yearFieldName":"year", + "fieldValue":"05/15/2025", + "expectedResult":{ + "date":{ + "month":"05" + }, + "day":"15", + "year":"2025" + }, + "comment":"Map to dot JSON with single key" + } + ] +} \ No newline at end of file diff --git a/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_MapWithArrayMerge.json b/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_MapWithArrayMerge.json new file mode 100644 index 00000000..6ea8d9b7 --- /dev/null +++ b/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_MapWithArrayMerge.json @@ -0,0 +1,72 @@ +{ + "test_data":[ + { + "monthFieldName":"card_data[0].month", + "dayFieldName":"card_data[0].day", + "yearFieldName":"card_data[0].year", + "fieldValue":"01/30/2020", + "expectedResult":{ + "card_data":[ + { + "user_id":"123", + "month":"01", + "day":"30", + "year":"2020" + } + ] + }, + "comment":"Map to array with JSON." + }, + { + "monthFieldName":"card_data[1].month", + "dayFieldName":"card_data[1].day", + "yearFieldName":"card_data[1].year", + "fieldValue":"01/30/2020", + "expectedResult":{ + "card_data":[ + { + "user_id":"123" + }, + { + "month":"01", + "day":"30", + "year":"2020" + } + ] + }, + "comment":"Map to array with JSON adjusting array capacity." + }, + { + "monthFieldName":"card_data[2]", + "dayFieldName":"card_data[3]", + "yearFieldName":"card_data[4]", + "fieldValue":"01/30/2020", + "expectedResult":{ + "card_data":[ + { + "user_id":"123" + }, + null, + "01", + "30", + "2020" + ] + }, + "comment":"Map to array with primitive values and adjusting array capacity." + }, + { + "monthFieldName":"card_data.month", + "dayFieldName":"card_data.day", + "yearFieldName":"card_data.year", + "fieldValue":"10/30/2020", + "expectedResult":{ + "card_data":{ + "month":"10", + "day":"30", + "year":"2020" + } + }, + "comment":"Map to nested JSON. Merge fieldData as JSON with more priority as extra data array." + } + ] +} \ No newline at end of file diff --git a/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_MapWithArrayOverwrite.json b/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_MapWithArrayOverwrite.json new file mode 100644 index 00000000..50532ab9 --- /dev/null +++ b/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_MapWithArrayOverwrite.json @@ -0,0 +1,53 @@ +{ + "test_data":[ + { + "monthFieldName":"card_data[0].month", + "dayFieldName":"card_data[0].day", + "yearFieldName":"card_data[0].year", + "fieldValue":"01/30/2020", + "expectedResult":{ + "card_data":[ + { + "month":"01", + "day":"30", + "year":"2020" + } + ] + }, + "comment":"Map to array with JSON." + }, + { + "monthFieldName":"card_data[1].month", + "dayFieldName":"card_data[1].day", + "yearFieldName":"card_data[1].year", + "fieldValue":"01/30/2020", + "expectedResult":{ + "card_data":[ + null, + { + "month":"01", + "day":"30", + "year":"2020" + } + ] + }, + "comment":"Map to array with JSON adjusting array capacity." + }, + { + "monthFieldName":"card_data[0].month", + "dayFieldName":"card_data[0].day", + "yearFieldName":"card_data[0].year", + "fieldValue":"01/12/2035", + "expectedResult":{ + "card_data":[ + { + "month":"01", + "day":"12", + "year":"2035" + } + ] + }, + "comment":"Map to nested JSON." + } + ] +} \ No newline at end of file diff --git a/Tests/FrameworkTests/Resources/DateTokenizationJSON/VGSDateTokenizationSerialization_DefaultConfig.json b/Tests/FrameworkTests/Resources/DateTokenizationJSON/VGSDateTokenizationSerialization_DefaultConfig.json new file mode 100644 index 00000000..2e95ea84 --- /dev/null +++ b/Tests/FrameworkTests/Resources/DateTokenizationJSON/VGSDateTokenizationSerialization_DefaultConfig.json @@ -0,0 +1,85 @@ +{ + "test_data":[ + { + "monthFieldName":"month", + "dayFieldName":"day", + "yearFieldName":"year", + "fieldValue":"04/26/2016", + "outputFormat":"mmddyyyy", + "expectedResult":{ + "data":[ + { + "format":"UUID", + "value":"04", + "storage":"PERSISTENT" + }, + { + "format":"UUID", + "value":"26", + "storage":"PERSISTENT" + }, + { + "value":"2016", + "storage":"PERSISTENT", + "format":"UUID" + } + ] + }, + "comment":"Serialized date mmddyyyy." + }, + { + "monthFieldName":"month", + "dayFieldName":"day", + "yearFieldName":"year", + "fieldValue":"04/26/2016", + "outputFormat":"ddmmyyyy", + "expectedResult":{ + "data":[ + { + "format":"UUID", + "value":"04", + "storage":"PERSISTENT" + }, + { + "format":"UUID", + "value":"26", + "storage":"PERSISTENT" + }, + { + "value":"2016", + "storage":"PERSISTENT", + "format":"UUID" + } + ] + }, + "comment":"Serialized date ddmmyyyy." + }, + { + "monthFieldName":"month", + "dayFieldName":"day", + "yearFieldName":"year", + "fieldValue":"04/26/2016", + "outputFormat":"yyyymmdd", + "expectedResult":{ + "data":[ + { + "format":"UUID", + "value":"04", + "storage":"PERSISTENT" + }, + { + "format":"UUID", + "value":"26", + "storage":"PERSISTENT" + }, + { + "value":"2016", + "storage":"PERSISTENT", + "format":"UUID" + } + ] + }, + "comment":"Serialized date yyyymmdd." + } + ] +} diff --git a/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/DateTextFieldTest.swift b/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/DateTextFieldTest.swift new file mode 100644 index 00000000..8b48fb37 --- /dev/null +++ b/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/DateTextFieldTest.swift @@ -0,0 +1,225 @@ +// +// DateTextField.swift +// VGSCollectSDK +// + +import XCTest +@testable import VGSCollectSDK + +class DateTextFieldTest: VGSCollectBaseTestCase { + + // MARK: - Properties + private var collector: VGSCollect! + private var textField: VGSDateTextField! + + // MARK: - Overrides + override func setUp() { + super.setUp() + + collector = VGSCollect(id: "any") + textField = VGSDateTextField() + + let config = VGSConfiguration(collector: collector, fieldName: "textField") + config.formatPattern = VGSDateFormat.default.formatPattern + textField.configuration = config + } + + override func tearDown() { + collector = nil + textField = nil + } + + // MARK: - Tests + /// Test when different month formats are selected + func testMonthFormat() { + /// Define the first month `January` for each month format + let firstLongAr = "يناير" + var validLongMonth = "January" + var validShortMonth = "Jan" + + /// For Arabic long and short month is the same. + if Locale.current.languageCode == "ar" { + validLongMonth = firstLongAr + validShortMonth = firstLongAr + } + + /// Asserts + textField.monthPickerFormat = .longSymbols + XCTAssertEqual(textField.monthsDataSource.first, validLongMonth) + textField.monthPickerFormat = .shortSymbols + XCTAssertEqual(textField.monthsDataSource.first, validShortMonth) + textField.monthPickerFormat = .numbers + XCTAssertEqual(textField.monthsDataSource.last, "12") + } + + /// Test when a valid date is selected using the default start and end date range + func testSelectDateWithDefaultDateRange() { + /// Select month + let monthSelected = 0 + textField.picker.selectRow(monthSelected, inComponent: 0, animated: false) + textField.pickerView(textField.picker, didSelectRow: monthSelected, inComponent: 0) + + /// Select day + let daySelected = 8 + textField.picker.selectRow(daySelected, inComponent: 1, animated: false) + textField.pickerView(textField.picker, didSelectRow: daySelected, inComponent: 1) + + /// Select year + let yearSelected = 61 + textField.picker.selectRow(yearSelected, inComponent: 2, animated: false) + textField.pickerView(textField.picker, didSelectRow: yearSelected, inComponent: 2) + + /// Get selected date + let currentValue = textField.textField.secureText + let monthComponent = currentValue?.components(separatedBy: "-").first ?? "0" + let dayComponent = currentValue?.components(separatedBy: "-")[1] ?? "0" + let yearComponent = currentValue?.components(separatedBy: "-").last ?? "0" + + /// Asserts: Validate the selected date is correct + XCTAssertEqual(Int(monthComponent), monthSelected + 1) + XCTAssertEqual(Int(dayComponent), daySelected + 1) + XCTAssertEqual(Int(yearComponent), (Calendar.currentYear - VGSDateConfiguration.validYearsCount) + yearSelected) + } + + /// Test when an invalid date is selected using the default start and end date range + func testSelectWrongDateWithDefaultDateRange() { + /// Select month + let monthSelected = 0 + textField.picker.selectRow(monthSelected, inComponent: 0, animated: false) + textField.pickerView(textField.picker, didSelectRow: monthSelected, inComponent: 0) + + /// Select day + let daySelected = 8 + textField.picker.selectRow(daySelected, inComponent: 1, animated: false) + textField.pickerView(textField.picker, didSelectRow: daySelected, inComponent: 1) + + /// Select invalid year, outside valid default range + let yearSelected = VGSDateConfiguration.validYearsCount * 3 + textField.picker.selectRow(yearSelected, inComponent: 2, animated: false) + textField.pickerView(textField.picker, didSelectRow: yearSelected, inComponent: 2) + + /// Get selected date + let currentValue = textField.textField.secureText + let monthComponent = currentValue?.components(separatedBy: "-").first ?? "0" + let dayComponent = currentValue?.components(separatedBy: "-")[1] ?? "0" + let yearComponent = currentValue?.components(separatedBy: "-").last ?? "0" + + /// Asserts: Selecting invalid day, month or year should be ignored + XCTAssertEqual(Int(monthComponent), monthSelected + 1) + XCTAssertEqual(Int(dayComponent), daySelected + 1) + XCTAssertEqual(Int(yearComponent), Calendar.currentYear - VGSDateConfiguration.validYearsCount) + } + + /// Test when a valid date is selected with a configuration that has custom start and end dates + func testSelectDateWithCustomDateRange() { + /// Define custom dates + let startDate = VGSDate(day: 1, month: 1, year: 2000)! + let endDate = VGSDate(day: 1, month: 1, year: 2030)! + + /// Setup custom configuration + let customConfig = VGSDateConfiguration( + collector: collector, + fieldName: "textField", + datePickerStartDate: startDate, + datePickerEndDate: endDate + ) + textField.configuration = customConfig + + /// Select month + let monthSelected = 6 + textField.picker.selectRow(monthSelected, inComponent: 0, animated: false) + textField.pickerView(textField.picker, didSelectRow: monthSelected, inComponent: 0) + + /// Select day + let daySelected = 15 + textField.picker.selectRow(daySelected, inComponent: 1, animated: false) + textField.pickerView(textField.picker, didSelectRow: daySelected, inComponent: 1) + + /// Select year, exactly the middle between start and end dates + let yearSelected = (endDate.year - startDate.year) / 2 + textField.picker.selectRow(yearSelected, inComponent: 2, animated: false) + textField.pickerView(textField.picker, didSelectRow: yearSelected, inComponent: 2) + + /// Get current date + let currentValue = textField.textField.secureText + let monthComponent = currentValue?.components(separatedBy: "-").first ?? "0" + let dayComponent = currentValue?.components(separatedBy: "-")[1] ?? "0" + let yearComponent = currentValue?.components(separatedBy: "-").last ?? "0" + + /// Asserts: The selected year should be the same selected in the textField + XCTAssertEqual(Int(monthComponent), monthSelected + 1) + XCTAssertEqual(Int(dayComponent), daySelected + 1) + XCTAssertEqual(Int(yearComponent), startDate.year + yearSelected) + XCTAssertEqual(Int(yearComponent), endDate.year - yearSelected) + } + + /// Test when an invalid date is selected with a configuration that has custom start and end dates + func testSelectWrongDateWithCustomDateRange() { + /// Define custom dates + let startDate = VGSDate(day: 1, month: 1, year: 2000)! + let endDate = VGSDate(day: 1, month: 1, year: 2030)! + + /// Setup custom configuration + let customConfig = VGSDateConfiguration( + collector: collector, + fieldName: "textField", + datePickerStartDate: startDate, + datePickerEndDate: endDate + ) + textField.configuration = customConfig + + /// Select month + let monthSelected = 6 + textField.picker.selectRow(monthSelected, inComponent: 0, animated: false) + textField.pickerView(textField.picker, didSelectRow: monthSelected, inComponent: 0) + + /// Select invalid day, outside the custom range + let daySelected = 50 + textField.picker.selectRow(daySelected, inComponent: 1, animated: false) + textField.pickerView(textField.picker, didSelectRow: daySelected, inComponent: 1) + + /// Select year + let yearSelected = 5 + textField.picker.selectRow(yearSelected, inComponent: 2, animated: false) + textField.pickerView(textField.picker, didSelectRow: yearSelected, inComponent: 2) + + /// Get current date + let currentValue = textField.textField.secureText + let monthComponent = currentValue?.components(separatedBy: "-").first ?? "0" + let dayComponent = currentValue?.components(separatedBy: "-")[1] ?? "0" + let yearComponent = currentValue?.components(separatedBy: "-").last ?? "0" + + /// Asserts: Selecting invalid day, month or year should be ignored + XCTAssertEqual(Int(monthComponent), monthSelected + 1) + XCTAssertEqual(Int(dayComponent), 1) + XCTAssertEqual(Int(yearComponent), startDate.year + yearSelected) + } + + /// Test when the keyboard configuration is selected in the configuration + func testDateKeyboardConfiguration() { + /// Setup custom configuration with keyboard + let customConfig = VGSDateConfiguration(collector: collector, fieldName: "textField") + customConfig.inputSource = .keyboard + customConfig.keyboardType = .namePhonePad + customConfig.returnKeyType = .go + customConfig.keyboardAppearance = .dark + textField.configuration = customConfig + + /// Asserts + XCTAssertTrue(textField.textField.keyboardType == customConfig.keyboardType, "Wrong keyboardType!") + XCTAssertTrue(textField.textField.returnKeyType == customConfig.returnKeyType, "Wrong returnKeyType!") + XCTAssertTrue(textField.textField.keyboardAppearance == customConfig.keyboardAppearance, "Wrong keyboardAppearance!") + } + + /// Test when the picker configuration is selected in the configuration + func testDateDatePickerConfiguration() { + /// Setup custom configuration with date picker + let customConfig = VGSDateConfiguration(collector: collector, fieldName: "textField") + customConfig.inputSource = .datePicker + textField.configuration = customConfig + + /// Asserts + XCTAssertTrue(textField.textField.inputView != nil, "Date picker not set!") + XCTAssertTrue(textField.textField.inputView is UIPickerView, "Wrong date picker view!") + } +} diff --git a/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/VGSDateFormatTests.swift b/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/VGSDateFormatTests.swift new file mode 100644 index 00000000..6d7faec8 --- /dev/null +++ b/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/VGSDateFormatTests.swift @@ -0,0 +1,178 @@ +// +// VGSDateFormatTests.swift +// FrameworkTests +// + +import XCTest +@testable import VGSCollectSDK + +class VGSDateFormatTests: VGSCollectBaseTestCase { + + // MARK: - Tests + /// Test date format initialization + func testDateFormatInitialization() { + /// Date format mmddyyyy + let mmddyyyyFormat = VGSDateFormat(name: "mmddyyyy") + XCTAssertEqual(mmddyyyyFormat, .mmddyyyy) + + /// Date format ddmmyyyy + let ddmmyyyyFormat = VGSDateFormat(name: "ddmmyyyy") + XCTAssertEqual(ddmmyyyyFormat, .ddmmyyyy) + + /// Date format yyyymmdd + let yyyymmddFormat = VGSDateFormat(name: "yyyymmdd") + XCTAssertEqual(yyyymmddFormat, .yyyymmdd) + + /// Invalid format + let invalidFormat = VGSDateFormat(name: "any") + XCTAssertNil(invalidFormat) + } + + /// Test the amount of expected characters for each part of the date + func testAmountOfCharacters() { + /// Expected values + let expectedDays = 2 + let expectedMonths = 2 + let expectedYears = 4 + let expectedDivider = 2 + + /// Days + XCTAssertEqual(VGSDateFormat.mmddyyyy.daysCharacters, expectedDays) + XCTAssertEqual(VGSDateFormat.ddmmyyyy.daysCharacters, expectedDays) + XCTAssertEqual(VGSDateFormat.yyyymmdd.daysCharacters, expectedDays) + + /// Months + XCTAssertEqual(VGSDateFormat.mmddyyyy.monthCharacters, expectedMonths) + XCTAssertEqual(VGSDateFormat.ddmmyyyy.monthCharacters, expectedMonths) + XCTAssertEqual(VGSDateFormat.yyyymmdd.monthCharacters, expectedMonths) + + /// Years + XCTAssertEqual(VGSDateFormat.mmddyyyy.yearCharacters, expectedYears) + XCTAssertEqual(VGSDateFormat.ddmmyyyy.yearCharacters, expectedYears) + XCTAssertEqual(VGSDateFormat.yyyymmdd.yearCharacters, expectedYears) + + /// Divider + XCTAssertEqual(VGSDateFormat.mmddyyyy.dividerCharacters, expectedDivider) + XCTAssertEqual(VGSDateFormat.ddmmyyyy.dividerCharacters, expectedDivider) + XCTAssertEqual(VGSDateFormat.yyyymmdd.dividerCharacters, expectedDivider) + } + + /// Test when the map picker data is formatted + func testMapDatePickerDataForFieldFormat() { + /// Expected date + let date = VGSDate(day: 2, month: 5, year: 2016)! + + /// mmddyyyy + XCTAssertEqual(VGSDateFormat.mmddyyyy.mapDatePickerDataForFieldFormat(date), "05022016") + + /// ddmmyyyy + XCTAssertEqual(VGSDateFormat.ddmmyyyy.mapDatePickerDataForFieldFormat(date), "02052016") + + /// yyyymmdd + XCTAssertEqual(VGSDateFormat.yyyymmdd.mapDatePickerDataForFieldFormat(date), "20160502") + } + + /// Test when the format date is called + func testFormatDate() { + /// Expected date + let date = VGSDate(day: 2, month: 5, year: 2016)! + + /// Divider A + var divider = "_" + XCTAssertEqual(VGSDateFormat.mmddyyyy.formatDate(date, divider: divider), "05\(divider)02\(divider)2016") + XCTAssertEqual(VGSDateFormat.ddmmyyyy.formatDate(date, divider: divider), "02\(divider)05\(divider)2016") + XCTAssertEqual(VGSDateFormat.yyyymmdd.formatDate(date, divider: divider), "2016\(divider)05\(divider)02") + + /// Divider B + divider = "+_+" + XCTAssertEqual(VGSDateFormat.mmddyyyy.formatDate(date, divider: divider), "05\(divider)02\(divider)2016") + XCTAssertEqual(VGSDateFormat.ddmmyyyy.formatDate(date, divider: divider), "02\(divider)05\(divider)2016") + XCTAssertEqual(VGSDateFormat.yyyymmdd.formatDate(date, divider: divider), "2016\(divider)05\(divider)02") + + /// Divider C + divider = "/" + XCTAssertEqual(VGSDateFormat.mmddyyyy.formatDate(date, divider: divider), "05\(divider)02\(divider)2016") + XCTAssertEqual(VGSDateFormat.ddmmyyyy.formatDate(date, divider: divider), "02\(divider)05\(divider)2016") + XCTAssertEqual(VGSDateFormat.yyyymmdd.formatDate(date, divider: divider), "2016\(divider)05\(divider)02") + + /// Divider C + divider = "..." + XCTAssertEqual(VGSDateFormat.mmddyyyy.formatDate(date, divider: divider), "05\(divider)02\(divider)2016") + XCTAssertEqual(VGSDateFormat.ddmmyyyy.formatDate(date, divider: divider), "02\(divider)05\(divider)2016") + XCTAssertEqual(VGSDateFormat.yyyymmdd.formatDate(date, divider: divider), "2016\(divider)05\(divider)02") + } + + /// Test when a date is created from an input string + func testDateFromInput() { + /// Expected date + let date = VGSDate(day: 2, month: 5, year: 2016)! + + /// mmddyyyy + XCTAssertEqual(VGSDateFormat.mmddyyyy.dateFromInput("05022016"), date) + + /// ddmmyyyy + XCTAssertEqual(VGSDateFormat.ddmmyyyy.dateFromInput("02052016"), date) + + /// yyyymmdd + XCTAssertEqual(VGSDateFormat.yyyymmdd.dateFromInput("20160502"), date) + + /// Invalid input + XCTAssertNil(VGSDateFormat.mmddyyyy.dateFromInput("any")) + } + + /// Test the display format + func testDisplayFormat() { + /// mmddyyyy + XCTAssertEqual(VGSDateFormat.mmddyyyy.displayFormat, "mm-dd-yyyy") + + /// ddmmyyyy + XCTAssertEqual(VGSDateFormat.ddmmyyyy.displayFormat, "dd-mm-yyyy") + + /// yyyymmdd + XCTAssertEqual(VGSDateFormat.yyyymmdd.displayFormat, "yyyy-mm-dd") + } + + /// Test format pattern + func testFormatPattern() { + /// mmddyyyy + XCTAssertEqual(VGSDateFormat.mmddyyyy.formatPattern, "##-##-####") + + /// ddmmyyyy + XCTAssertEqual(VGSDateFormat.ddmmyyyy.formatPattern, "##-##-####") + + /// yyyymmdd + XCTAssertEqual(VGSDateFormat.yyyymmdd.formatPattern, "####-##-##") + } + + /// Test to get the divider in an input date string + func testDividerInInput() { + /// Divider A + var divider = "_" + XCTAssertEqual(VGSDateFormat.dividerInInput("05\(divider)02\(divider)2016"), divider) + XCTAssertEqual(VGSDateFormat.dividerInInput("02\(divider)05\(divider)2016"), divider) + XCTAssertEqual(VGSDateFormat.dividerInInput("2016\(divider)05\(divider)02"), divider) + + /// Divider B + divider = "+_+" + XCTAssertEqual(VGSDateFormat.dividerInInput("05\(divider)02\(divider)2016"), divider) + XCTAssertEqual(VGSDateFormat.dividerInInput("02\(divider)05\(divider)2016"), divider) + XCTAssertEqual(VGSDateFormat.dividerInInput("2016\(divider)05\(divider)02"), divider) + + /// Divider C + divider = "/" + XCTAssertEqual(VGSDateFormat.dividerInInput("05\(divider)02\(divider)2016"), divider) + XCTAssertEqual(VGSDateFormat.dividerInInput("02\(divider)05\(divider)2016"), divider) + XCTAssertEqual(VGSDateFormat.dividerInInput("2016\(divider)05\(divider)02"), divider) + + /// Divider C + divider = "..." + XCTAssertEqual(VGSDateFormat.dividerInInput("05\(divider)02\(divider)2016"), divider) + XCTAssertEqual(VGSDateFormat.dividerInInput("02\(divider)05\(divider)2016"), divider) + XCTAssertEqual(VGSDateFormat.dividerInInput("2016\(divider)05\(divider)02"), divider) + + /// Invalid input + XCTAssertEqual(VGSDateFormat.dividerInInput("05|02-2016"), "") + XCTAssertEqual(VGSDateFormat.dividerInInput("05-02*2016"), "") + XCTAssertEqual(VGSDateFormat.dividerInInput("05-..-022016"), "") + } +} diff --git a/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/ValidationRuleDateTests.swift b/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/ValidationRuleDateTests.swift new file mode 100644 index 00000000..736adccd --- /dev/null +++ b/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/ValidationRuleDateTests.swift @@ -0,0 +1,204 @@ +// +// ValidationRuleDateTests.swift +// FrameworkTests +// + +import XCTest +@testable import VGSCollectSDK + +class ValidationRuleDateTests: VGSCollectBaseTestCase { + + // MARK: - Constants + /// Default error + private let error = "date_error" + + // MARK: - Properties + private var collector: VGSCollect! + private var textField: VGSTextField! + private var config: VGSConfiguration! + + // MARK: - Overrides + override func setUp() { + super.setUp() + + collector = VGSCollect(id: "any") + textField = VGSTextField() + config = VGSConfiguration(collector: collector, fieldName: "test_field") + config.type = .date + } + + override func tearDown() { + collector = nil + textField = nil + config = nil + } + + // MARK: - Tests + /// Test date validation rule with default configuration + func testDateRule() { + /// Test validation success + textField.configuration = config + textField.textField.secureText = "10102004" + XCTAssertTrue(textField.state.isValid) + XCTAssertEqual(textField.state.validationErrors.count, 0) + + /// Test invalid format + textField.textField.secureText = "102024" + XCTAssertFalse(textField.state.isValid) + XCTAssertEqual(textField.state.validationErrors.count, 1) + + /// Test invalid date, in this case month is `50` + textField.textField.secureText = "50012024" + XCTAssertFalse(textField.state.isValid) + XCTAssertEqual(textField.state.validationErrors.count, 1) + } + + /// Test each of the date formats + func testRuleDateFormats() { + /// Use `ddmmyyy` format + config.validationRules = VGSValidationRuleSet(rules: [ + VGSValidationRuleDateRange( + dateFormat: .ddmmyyyy, + error: error + ) + ]) + + /// Test validation success + textField.configuration = config + textField.textField.secureText = "20111984" + XCTAssertTrue(textField.state.isValid) + XCTAssertEqual(textField.state.validationErrors.count, 0) + + /// Test validation fails + textField.configuration = config + textField.textField.secureText = "19841120" + XCTAssertFalse(textField.state.isValid) + XCTAssertEqual(textField.state.validationErrors.count, 1) + + /// Use `mmddyyyy` format + config.validationRules = VGSValidationRuleSet(rules: [ + VGSValidationRuleDateRange( + dateFormat: .mmddyyyy, + error: error + ) + ]) + + // Test validation success + textField.configuration = config + textField.textField.secureText = "11201984" + XCTAssertTrue(textField.state.isValid) + XCTAssertEqual(textField.state.validationErrors.count, 0) + + /// Test validation fails + textField.configuration = config + textField.textField.secureText = "19842011" + XCTAssertFalse(textField.state.isValid) + XCTAssertEqual(textField.state.validationErrors.count, 1) + + /// Use `yyyymmdd` format + config.validationRules = VGSValidationRuleSet(rules: [ + VGSValidationRuleDateRange( + dateFormat: .yyyymmdd, + error: error + ) + ]) + + // Test validation success + textField.configuration = config + textField.textField.secureText = "19841120" + XCTAssertTrue(textField.state.isValid) + XCTAssertEqual(textField.state.validationErrors.count, 0) + + /// Test validation fails + textField.configuration = config + textField.textField.secureText = "20111984" + XCTAssertFalse(textField.state.isValid) + XCTAssertEqual(textField.state.validationErrors.count, 1) + } + + /// Test when start date and end date are set + func testRuleWithStartAndEndDate() { + /// Setup start and end dates + let startDate = VGSDate(day: 10, month: 11, year: 2015) + let endDate = VGSDate(day: 08, month: 12, year: 2030) + + /// Use default format + config.validationRules = VGSValidationRuleSet(rules: [ + VGSValidationRuleDateRange( + error: error, + start: startDate, + end: endDate + ) + ]) + + /// Test validation success + textField.configuration = config + textField.textField.secureText = "10122020" + XCTAssertTrue(textField.state.isValid) + XCTAssertEqual(textField.state.validationErrors.count, 0) + + /// Test validation fails, date before start date + textField.configuration = config + textField.textField.secureText = "1012215" + XCTAssertFalse(textField.state.isValid) + XCTAssertEqual(textField.state.validationErrors.count, 1) + + /// Test validation fails, date after end date + textField.configuration = config + textField.textField.secureText = "12102030" + XCTAssertFalse(textField.state.isValid) + XCTAssertEqual(textField.state.validationErrors.count, 1) + } + + /// Test when only start date is set + func testRuleWithStartDate() { + /// Setup start date + let startDate = VGSDate(day: 10, month: 11, year: 2015) + + /// Use default format + config.validationRules = VGSValidationRuleSet(rules: [ + VGSValidationRuleDateRange( + error: error, + start: startDate + ) + ]) + + /// Test validation success + textField.configuration = config + textField.textField.secureText = "10122020" + XCTAssertTrue(textField.state.isValid) + XCTAssertEqual(textField.state.validationErrors.count, 0) + + /// Test validation fails, date before start date + textField.configuration = config + textField.textField.secureText = "1012215" + XCTAssertFalse(textField.state.isValid) + XCTAssertEqual(textField.state.validationErrors.count, 1) + } + + /// Test when only end date is set + func testRuleWithEndDate() { + /// Setup end date + let endDate = VGSDate(day: 08, month: 12, year: 2030) + + /// Use default format + config.validationRules = VGSValidationRuleSet(rules: [ + VGSValidationRuleDateRange( + error: error, + end: endDate + ) + ]) + + /// Test validation success + textField.configuration = config + textField.textField.secureText = "10122020" + XCTAssertTrue(textField.state.isValid) + XCTAssertEqual(textField.state.validationErrors.count, 0) + + /// Test validation fails, date after end date + textField.configuration = config + textField.textField.secureText = "12102030" + XCTAssertFalse(textField.state.isValid) + XCTAssertEqual(textField.state.validationErrors.count, 1) + } +} diff --git a/Tests/FrameworkTests/SerializersTest/SerializersDataProvider.swift b/Tests/FrameworkTests/SerializersTest/SerializersDataProvider.swift new file mode 100644 index 00000000..1baa750b --- /dev/null +++ b/Tests/FrameworkTests/SerializersTest/SerializersDataProvider.swift @@ -0,0 +1,47 @@ +// +// SerializersDataProvider.swift +// FrameworkTests +// + +import XCTest +@testable import VGSCollectSDK + +/// Define the methods required to parse test JSON data +protocol TestJSONDataProtocol { + init?(json: JsonData) +} + +/// Class with the methods required to read and parse JSON files for testing +final class SerializersDataProvider { + + /// Method that reads and parse `JSON` file with data for testing. It define an abstract + /// parameter that must implement the `TestJSONDataProtocol` + /// + /// - Parameters: + /// - fileName: `String` with the name of the `JSON` file to read the data from. + /// - rootName: `String` with the name of the root node of the `JSON` file, by defaul it is defined as `test_data` + static func provideTestData(for fileName: String, rootNodeName: String = "test_data") -> [T] { + /// Read json data from file + guard let rootTestJSON = JsonData(jsonFileName: fileName) else { + XCTFail("Cannot build data for file \(fileName)") + return [] + } + + /// Get root node + guard let testDataJSONArray = rootTestJSON[rootNodeName] as? [JsonData] else { + XCTFail("\(rootNodeName) JSON array not found in \(fileName)") + return [] + } + + /// Parse test data + var testData = [T]() + for json in testDataJSONArray { + if let testItem = T(json: json) { + testData.append(testItem) + } else { + XCTFail("Cannot build test data for JSON: \(json)") + } + } + return testData + } +} diff --git a/Tests/FrameworkTests/SerializersTest/VGSDateSeparateSerializerTests.swift b/Tests/FrameworkTests/SerializersTest/VGSDateSeparateSerializerTests.swift new file mode 100644 index 00000000..663a0e4b --- /dev/null +++ b/Tests/FrameworkTests/SerializersTest/VGSDateSeparateSerializerTests.swift @@ -0,0 +1,256 @@ +// +// VGSDateSeparateSerializerTests.swift +// FrameworkTests +// + +import XCTest +@testable import VGSCollectSDK + +class VGSDateSeparateSerializerTests: VGSCollectBaseTestCase { + + // MARK: - Properties + private var collector: VGSCollect! + private var textField: VGSDateTextField! + + // MARK: - Inner objects + /// Define the file names with JSON data for testing + private enum TestFlow { + case defaultConfig + case customConfig + case customExpDateOutputConfig + case mapWithArrayOverwrite + case mapWithArrayMerge + + /// Name of the JSON file + var jsonFileName: String { + return "VGSDateSerialization_" + jsonFileNameSuffix + } + + /// JSON file name + private var jsonFileNameSuffix: String { + switch self { + case .defaultConfig: + return "DefaultConfig" + case .customConfig: + return "CustomConfig" + case .customExpDateOutputConfig: + return "CustomExpDateOutputConfig" + case .mapWithArrayOverwrite: + return "MapWithArrayOverwrite" + case .mapWithArrayMerge: + return "MapWithArrayMerge" + } + } + } + + /// Store the JSON data for testing + private struct TestJSONData: TestJSONDataProtocol { + + // MARK: - Properties + let fieldValue: String + let monthFieldName: String + let dayFieldName: String + let yearFieldName: String + let submitJSON: JsonData + + /// Initializer + init?(json: JsonData) { + guard let submitJSON = json["expectedResult"] as? JsonData else { + XCTFail("Cannot parse test data.") + return nil + } + self.fieldValue = json["fieldValue"] as? String ?? "" + self.monthFieldName = json["monthFieldName"] as? String ?? "" + self.dayFieldName = json["dayFieldName"] as? String ?? "" + self.yearFieldName = json["yearFieldName"] as? String ?? "" + self.submitJSON = submitJSON + } + } + + // MARK: - Overrides + override func setUp() { + super.setUp() + + collector = VGSCollect(id: "any") + textField = VGSDateTextField() + } + + override func tearDown() { + collector = nil + textField = nil + } + + // MARK: - Tests + /// Test default configuration + func testSplitDateSerializerWithDefaultConfig() { + /// Get JSON test data + let fileName = TestFlow.defaultConfig.jsonFileName + let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) + + /// Prepare configuration + let config = VGSDateConfiguration(collector: collector, fieldName: "date") + config.formatPattern = VGSDateFormat.default.formatPattern + + /// Run test for each case from JSON + for test in testData { + /// Prepare serializer + config.serializers = [ + VGSDateSeparateSerializer( + dayFieldName: test.dayFieldName, + monthFieldName: test.monthFieldName, + yearFieldName: test.yearFieldName + ) + ] + /// Update configuration + textField.configuration = config + /// Setup test value + textField.setText(test.fieldValue) + /// Get JSON from collector using serializer + let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSON, extraData: nil) + /// Assert: Test JSON content should be equals to the JSON from the collector + XCTAssertTrue(NSDictionary(dictionary: submitJSON).isEqual(to: test.submitJSON)) + } + } + + /// Test custom configuration + func testSplitDateSerializerWithCustomConfig() { + /// Get JSON test data + let fileName = TestFlow.customConfig.jsonFileName + let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) + + /// Prepare configuration + let config = VGSDateConfiguration(collector: collector, fieldName: "card.date") + config.formatPattern = VGSDateFormat.default.formatPattern + config.inputDateFormat = .yyyymmdd + config.outputDateFormat = .ddmmyyyy + config.divider = "-/-" + + /// Run test for each case from JSON + for test in testData { + /// Prepare serializer + config.serializers = [ + VGSDateSeparateSerializer( + dayFieldName: test.dayFieldName, + monthFieldName: test.monthFieldName, + yearFieldName: test.yearFieldName + ) + ] + /// Update configuration + textField.configuration = config + /// Setup test value + textField.setText(test.fieldValue) + /// Get JSON from collector using serializer + let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSON, extraData: nil) + /// Assert: Test JSON content should be equals to the JSON from the collector + XCTAssertTrue(NSDictionary(dictionary: submitJSON).isEqual(to: test.submitJSON)) + } + } + + /// Test custom output format. + func testSplitCustomDateOutputSerializerWithCustomConfig() { + /// Get JSON test data + let fileName = TestFlow.customExpDateOutputConfig.jsonFileName + let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) + + /// Prepare configuration + let config = VGSDateConfiguration(collector: collector, fieldName: "card.date") + config.formatPattern = VGSDateFormat.default.formatPattern + config.inputDateFormat = .yyyymmdd + config.outputDateFormat = .ddmmyyyy + config.divider = "-/-" + + /// Run test for each case from JSON + for test in testData { + /// Prepare serializer + config.serializers = [ + VGSDateSeparateSerializer( + dayFieldName: test.dayFieldName, + monthFieldName: test.monthFieldName, + yearFieldName: test.yearFieldName + ) + ] + /// Update configuration + textField.configuration = config + /// Setup test value + textField.setText(test.fieldValue) + /// Get JSON from collector using serializer + let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSON, extraData: nil) + /// Assert: Test JSON content should be equals to the JSON from the collector + XCTAssertTrue(NSDictionary(dictionary: submitJSON).isEqual(to: test.submitJSON)) + } + } + + /// Test map with array merge. + func testSplitExpDateSerializersMapWithArray() { + /// Get JSON test data + let fileName = TestFlow.mapWithArrayMerge.jsonFileName + let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) + + /// Prepare configuration + let config = VGSDateConfiguration(collector: collector, fieldName: "date") + config.formatPattern = VGSDateFormat.default.formatPattern + config.inputDateFormat = .mmddyyyy + config.outputDateFormat = .mmddyyyy + config.divider = "/" + + /// Setup extra data + let extraData = ["card_data": [["user_id": "123"]]] + + /// Run test for each case from JSON + for test in testData { + /// Prepare serializer + config.serializers = [ + VGSDateSeparateSerializer( + dayFieldName: test.dayFieldName, + monthFieldName: test.monthFieldName, + yearFieldName: test.yearFieldName + ) + ] + /// Update configuration + textField.configuration = config + /// Setup test value + textField.setText(test.fieldValue) + /// Get JSON from collector using serializer + let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSONWithArrayMerge, extraData: extraData) + /// Assert: Test JSON content should be equals to the JSON from the collector + XCTAssertTrue(NSDictionary(dictionary: submitJSON).isEqual(to: test.submitJSON)) + } + } + + /// Test map with array overwrite. + func testSplitExpDateSerializersMapWithArrayOverwrite() { + /// Get JSON test data + let fileName = TestFlow.mapWithArrayOverwrite.jsonFileName + let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) + + /// Prepare configuration + let config = VGSDateConfiguration(collector: collector, fieldName: "date") + config.formatPattern = VGSDateFormat.default.formatPattern + config.inputDateFormat = .mmddyyyy + config.outputDateFormat = .mmddyyyy + config.divider = "/" + + /// Setup extra data + let extraData = ["card_data": [["month": "3", "year": "2033"]]] + + /// Run test for each case from JSON + for test in testData { + /// Prepare serializer + config.serializers = [ + VGSDateSeparateSerializer( + dayFieldName: test.dayFieldName, + monthFieldName: test.monthFieldName, + yearFieldName: test.yearFieldName + ) + ] + /// Update configuration + textField.configuration = config + /// Setup test value + textField.setText(test.fieldValue) + /// Get JSON from collector using serializer + let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSONWithArrayOverwrite, extraData: extraData) + /// Assert: Test JSON content should be equals to the JSON from the collector + XCTAssertTrue(NSDictionary(dictionary: submitJSON).isEqual(to: test.submitJSON)) + } + } +} diff --git a/Tests/FrameworkTests/SerializersTest/VGSDateTokenizationSerializerTests.swift b/Tests/FrameworkTests/SerializersTest/VGSDateTokenizationSerializerTests.swift new file mode 100644 index 00000000..75ffb216 --- /dev/null +++ b/Tests/FrameworkTests/SerializersTest/VGSDateTokenizationSerializerTests.swift @@ -0,0 +1,135 @@ +// +// VGSDateTokenizationSerializerTests.swift +// FrameworkTests +// + +import XCTest +@testable import VGSCollectSDK + +class VGSDateTokenizationSerializerTests: VGSCollectBaseTestCase { + + // MARK: - Properties + private var collector: VGSCollect! + private var textField: VGSDateTextField! + + // MARK: - Inner objects + /// Define the file names with JSON data for testing + private enum TestFlow { + case defaultConfig + + /// Name of the JSON file + var jsonFileName: String { + return "VGSDateTokenizationSerialization_" + jsonFileNameSuffix + } + + /// JSON file name + private var jsonFileNameSuffix: String { + switch self { + case .defaultConfig: + return "DefaultConfig" + } + } + } + + /// Store the JSON data for testing + private struct TestJSONData: TestJSONDataProtocol { + + // MARK: - Properties + let fieldValue: String + let monthFieldName: String + let dayFieldName: String + let yearFieldName: String + let submitJSON: JsonData + let outputFormat: VGSDateFormat + let comment: String + let tokenizedPayloads: [JsonData] + + /// Initializer + init?(json: JsonData) { + guard let submitJSON = json["expectedResult"] as? JsonData else { + XCTFail("Cannot parse test data.") + return nil + } + guard let formatName = json["outputFormat"] as? String, + let format = VGSDateFormat(name: formatName) else { + XCTFail("Cannot parse output format from test json") + return nil + } + self.fieldValue = json["fieldValue"] as? String ?? "" + self.monthFieldName = json["monthFieldName"] as? String ?? "" + self.dayFieldName = json["dayFieldName"] as? String ?? "" + self.yearFieldName = json["yearFieldName"] as? String ?? "" + self.submitJSON = submitJSON + self.outputFormat = format + self.comment = json["comment"] as? String ?? "" + guard let tokenizedPayloads = submitJSON["data"] as? [JsonData] else { + XCTFail("Invalid payload") + return nil + } + self.tokenizedPayloads = tokenizedPayloads + } + } + + // MARK: - Overrides + override func setUp() { + super.setUp() + + collector = VGSCollect(id: "any") + textField = VGSDateTextField() + } + + override func tearDown() { + collector = nil + textField = nil + } + + // MARK: - Tests + /// Test default configuration + func testSplitDateSerializerWithDefaultConfig() { + /// Get JSON test data + let fileName = TestFlow.defaultConfig.jsonFileName + let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) + + /// Prepare configuration + let config = VGSDateTokenizationConfiguration(collector: collector, fieldName: "date") + config.inputDateFormat = VGSDateFormat.default + config.formatPattern = VGSDateFormat.default.formatPattern + + /// Run test for each case from JSON + for test in testData { + /// Prepare serializer + config.serializers = [ + VGSDateSeparateSerializer( + dayFieldName: test.dayFieldName, + monthFieldName: test.monthFieldName, + yearFieldName: test.yearFieldName + ) + ] + config.outputDateFormat = test.outputFormat + /// Update configuration + textField.configuration = config + /// Setup test value + textField.setText(test.fieldValue) + /// Get JSON from collector using serializer + let submitJSON = collector.mapFieldsToTokenizationRequestBodyJSON(collector.textFields) + + /// Get payloads + guard let tokenizedPayloads = submitJSON["data"] as? [JsonData] else { + XCTFail("Cannot find tokenized data array.") + return + } + var matchedPayloads = 0 + /// mapFieldsToTokenizationRequestBodyJSON can produce array of tokenized data in different + /// order. So we need to iterate through payloads and check them one by one to get 3 matches + /// (one is for month, one for day and another one for year). + for payload in tokenizedPayloads { + for expectedPayload in test.tokenizedPayloads where payload == expectedPayload { + matchedPayloads += 1 + } + } + + /// Assert: Should be at least 3 matches of payloads + XCTAssertEqual(matchedPayloads, 3) + } + } +} diff --git a/Tests/FrameworkTests/SerializersTest/VGSExpDateSeparateSerializerTests.swift b/Tests/FrameworkTests/SerializersTest/VGSExpDateSeparateSerializerTests.swift index 0fb484be..554ce30e 100644 --- a/Tests/FrameworkTests/SerializersTest/VGSExpDateSeparateSerializerTests.swift +++ b/Tests/FrameworkTests/SerializersTest/VGSExpDateSeparateSerializerTests.swift @@ -11,175 +11,242 @@ import XCTest @testable import VGSCollectSDK class VGSExpDateSeparateSerializerTests: VGSCollectBaseTestCase { - var collector: VGSCollect! - var textField: VGSExpDateTextField! - - enum TestFlow { - case defaultConfiguration - case customConfiguration - case customExpDateOutputConfiguration - case mapWithArrayOverwrite - case mapWithArrayMerge - - var jsonFileName: String { - return "VGSExpDateSerialization_" + jsonFileNameSuffix - } - - var jsonFileNameSuffix: String { - switch self { - case .defaultConfiguration: - return "DefaultConfig" - case .customConfiguration: - return "CustomConfig" - case .customExpDateOutputConfiguration: - return "CustomExpDateOutputConfig" - case .mapWithArrayOverwrite: - return "MapWithArrayOverwrite" - case .mapWithArrayMerge: - return "MapWithArrayMerge" - } - } - } - - struct TestJSONData { - let fieldValue: String - let monthFieldName: String - let yearFieldName: String - let submitJSON: JsonData - init?(json: JsonData) { - guard let submitJSON = json["expectedResult"] as? JsonData else { - XCTFail("Cannot parse test data.") - return nil - } - self.fieldValue = json["fieldValue"] as? String ?? "" - self.monthFieldName = json["monthFieldName"] as? String ?? "" - self.yearFieldName = json["yearFieldName"] as? String ?? "" - self.submitJSON = submitJSON + // MARK: - Properties + private var collector: VGSCollect! + private var textField: VGSExpDateTextField! + + // MARK: - Inner objects + /// Define the file names with JSON data for testing + private enum TestFlow { + case defaultConfig + case customConfig + case customExpDateOutputConfig + case mapWithArrayOverwrite + case mapWithArrayMerge + + /// Name of the JSON file + var jsonFileName: String { + return "VGSExpDateSerialization_" + jsonFileNameSuffix + } + + /// JSON file name + var jsonFileNameSuffix: String { + switch self { + case .defaultConfig: + return "DefaultConfig" + case .customConfig: + return "CustomConfig" + case .customExpDateOutputConfig: + return "CustomExpDateOutputConfig" + case .mapWithArrayOverwrite: + return "MapWithArrayOverwrite" + case .mapWithArrayMerge: + return "MapWithArrayMerge" + } + } } - } - - // MARK: - Override - - override func setUp() { - super.setUp() - collector = VGSCollect(id: "any") - textField = VGSExpDateTextField() - } - - override func tearDown() { - collector = nil - textField = nil - } - - // MARK: - Tests - - /// Test default configuration. - func testSplitExpDateSerializerWithDefaultConfig() { - let fileName = TestFlow.defaultConfiguration.jsonFileName - let testData = VGSExpDateSerializersDataProvider.provideTestData(for: fileName) - let config = VGSExpDateConfiguration(collector: collector, fieldName: "expDate") - config.formatPattern = "##/##" + /// Store the JSON data for testing + private struct TestJSONData: TestJSONDataProtocol { + + // MARK: - Properties + let fieldValue: String + let monthFieldName: String + let yearFieldName: String + let submitJSON: JsonData + + /// Initializer + init?(json: JsonData) { + guard let submitJSON = json["expectedResult"] as? JsonData else { + XCTFail("Cannot parse test data.") + return nil + } + self.fieldValue = json["fieldValue"] as? String ?? "" + self.monthFieldName = json["monthFieldName"] as? String ?? "" + self.yearFieldName = json["yearFieldName"] as? String ?? "" + self.submitJSON = submitJSON + } + } - for test in testData { - config.serializers = [VGSExpDateSeparateSerializer(monthFieldName: test.monthFieldName, yearFieldName: test.yearFieldName)] - textField.configuration = config - textField.setText(test.fieldValue) - - let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSON, extraData: nil) - XCTAssertTrue(submitJSON == test.submitJSON, "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") + // MARK: - Override + override func setUp() { + super.setUp() + + collector = VGSCollect(id: "any") + textField = VGSExpDateTextField() + } + + override func tearDown() { + collector = nil + textField = nil } - } - - /// Test custom exp date configuration. - func testSplitExpDateSerializerWithCustomConfig() { - let fileName = TestFlow.customConfiguration.jsonFileName - let testData = VGSExpDateSerializersDataProvider.provideTestData(for: fileName) - let config = VGSExpDateConfiguration(collector: collector, fieldName: "card.expDate") - config.formatPattern = "##/##" - config.inputDateFormat = .shortYear - config.outputDateFormat = .longYear - config.divider = "-/-" + // MARK: - Tests + /// Test default configuration. + func testSplitExpDateSerializerWithDefaultConfig() { + /// Get JSON test data + let fileName = TestFlow.defaultConfig.jsonFileName + let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) + + /// Prepare configuration + let config = VGSExpDateConfiguration(collector: collector, fieldName: "expDate") + config.formatPattern = "##/##" + + /// Run test for each case from JSON + for test in testData { + /// Prepare serializer + config.serializers = [ + VGSExpDateSeparateSerializer( + monthFieldName: test.monthFieldName, + yearFieldName: test.yearFieldName + ) + ] + /// Update configuration + textField.configuration = config + /// Setup test value + textField.setText(test.fieldValue) + /// Get JSON from collector using serializer + let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSON, extraData: nil) + /// Assert: Test JSON content should be equals to the JSON from the collector + XCTAssertTrue(submitJSON == test.submitJSON, + "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") + } + } - for test in testData { - config.serializers = [VGSExpDateSeparateSerializer(monthFieldName: test.monthFieldName, yearFieldName: test.yearFieldName)] - textField.configuration = config - textField.setText(test.fieldValue) - - let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSON, extraData: nil) - XCTAssertTrue(submitJSON == test.submitJSON, "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") - + /// Test custom exp date configuration. + func testSplitExpDateSerializerWithCustomConfig() { + /// Get JSON test data + let fileName = TestFlow.customConfig.jsonFileName + let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) + + /// Prepare configuration + let config = VGSExpDateConfiguration(collector: collector, fieldName: "card.expDate") + config.formatPattern = "##/##" + config.inputDateFormat = .shortYear + config.outputDateFormat = .longYear + config.divider = "-/-" + + /// Run test for each case from JSON + for test in testData { + /// Prepare serializer + config.serializers = [ + VGSExpDateSeparateSerializer( + monthFieldName: test.monthFieldName, + yearFieldName: test.yearFieldName + ) + ] + /// Update configuration + textField.configuration = config + /// Setup test value + textField.setText(test.fieldValue) + /// Get JSON from collector using serializer + let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSON, extraData: nil) + /// Assert: Test JSON content should be equals to the JSON from the collector + XCTAssertTrue(submitJSON == test.submitJSON, + "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") + } } - } - - /// Test custom exp date output format. - func testSplitCustomExpDateOutputSerializerWithCustomConfig() { - let fileName = TestFlow.customExpDateOutputConfiguration.jsonFileName - let testData = VGSExpDateSerializersDataProvider.provideTestData(for: fileName) - let config = VGSExpDateConfiguration(collector: collector, fieldName: "card.expDate") - config.formatPattern = "####/##" - config.inputDateFormat = .longYearThenMonth - config.outputDateFormat = .shortYearThenMonth - config.divider = "-/-" + /// Test custom exp date output format. + func testSplitCustomExpDateOutputSerializerWithCustomConfig() { + /// Get JSON test data + let fileName = TestFlow.customExpDateOutputConfig.jsonFileName + let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) + + /// Prepare configuration + let config = VGSExpDateConfiguration(collector: collector, fieldName: "card.expDate") + config.formatPattern = "####/##" + config.inputDateFormat = .longYearThenMonth + config.outputDateFormat = .shortYearThenMonth + config.divider = "-/-" + + /// Run test for each case from JSON + for test in testData { + /// Prepare serializer + config.serializers = [ + VGSExpDateSeparateSerializer( + monthFieldName: test.monthFieldName, + yearFieldName: test.yearFieldName + ) + ] + /// Update configuration + textField.configuration = config + /// Setup test value + textField.setText(test.fieldValue) + /// Get JSON from collector using serializer + let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSON, extraData: nil) + /// Assert: Test JSON content should be equals to the JSON from the collector + XCTAssertTrue(submitJSON == test.submitJSON, + "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") + } + } - for test in testData { - config.serializers = [VGSExpDateSeparateSerializer(monthFieldName: test.monthFieldName, yearFieldName: test.yearFieldName)] - textField.configuration = config - textField.setText(test.fieldValue) - - let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSON, extraData: nil) - XCTAssertTrue(submitJSON == test.submitJSON, "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") - + /// Test map with array merge. + func testSplitExpDateSerializersMapWithArray() { + /// Get JSON test data + let fileName = TestFlow.mapWithArrayMerge.jsonFileName + let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) + + /// Prepare configuration + let config = VGSExpDateConfiguration(collector: collector, fieldName: "expDate") + config.formatPattern = "##/##" + + /// Setup extra data + let extraData = ["card_data": [["user_id": "123"]]] + + /// Run test for each case from JSON + for test in testData { + /// Prepare serializer + config.serializers = [ + VGSExpDateSeparateSerializer( + monthFieldName: test.monthFieldName, + yearFieldName: test.yearFieldName + ) + ] + /// Update configuration + textField.configuration = config + /// Setup test value + textField.setText(test.fieldValue) + /// Get JSON from collector using serializer + let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSONWithArrayMerge, extraData: extraData) + /// Assert: Test JSON content should be equals to the JSON from the collector + XCTAssertTrue(submitJSON == test.submitJSON, + "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") + } + } + + /// Test map with array overwrite. + func testSplitExpDateSerializersMapWithArrayOverwrite() { + /// Get JSON test data + let fileName = TestFlow.mapWithArrayOverwrite.jsonFileName + let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) + + /// Prepare configuration + let config = VGSExpDateConfiguration(collector: collector, fieldName: "expDate") + config.formatPattern = "##/##" + + /// Setup extra data + let extraData = ["card_data": [["month": "3", "year": "2033"]]] + + /// Run test for each case from JSON + for test in testData { + /// Prepare serializer + config.serializers = [ + VGSExpDateSeparateSerializer( + monthFieldName: test.monthFieldName, + yearFieldName: test.yearFieldName + ) + ] + /// Update configuration + textField.configuration = config + /// Setup test value + textField.setText(test.fieldValue) + /// Get JSON from collector using serializer + let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSONWithArrayOverwrite, extraData: extraData) + /// Assert: Test JSON content should be equals to the JSON from the collector + XCTAssertTrue(submitJSON == test.submitJSON, + "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") + } } - } - - /// Test map with array merge. - func testSplitExpDateSerializersMapWithArray() { - let fileName = TestFlow.mapWithArrayMerge.jsonFileName - let testData = VGSExpDateSerializersDataProvider.provideTestData(for: fileName) - - let config = VGSExpDateConfiguration(collector: collector, fieldName: "expDate") - config.formatPattern = "##/##" - - let extraData = ["card_data": - [ - ["user_id": "123"] - ]] - - for test in testData { - config.serializers = [VGSExpDateSeparateSerializer(monthFieldName: test.monthFieldName, yearFieldName: test.yearFieldName)] - textField.configuration = config - textField.setText(test.fieldValue) - - let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSONWithArrayMerge, extraData: extraData) - XCTAssertTrue(submitJSON == test.submitJSON, "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") - } - } - - /// Test map with array overwrite. - func testSplitExpDateSerializersMapWithArrayOverwrite() { - let fileName = TestFlow.mapWithArrayOverwrite.jsonFileName - let testData = VGSExpDateSerializersDataProvider.provideTestData(for: fileName) - - let config = VGSExpDateConfiguration(collector: collector, fieldName: "expDate") - config.formatPattern = "##/##" - - let extraData = ["card_data": - [ - ["month": "3", - "year": "2033"] - ]] - - for test in testData { - config.serializers = [VGSExpDateSeparateSerializer(monthFieldName: test.monthFieldName, yearFieldName: test.yearFieldName)] - textField.configuration = config - textField.setText(test.fieldValue) - - let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSONWithArrayOverwrite, extraData: extraData) - XCTAssertTrue(submitJSON == test.submitJSON, "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") - } - } } diff --git a/Tests/FrameworkTests/SerializersTest/VGSExpDateSerializersDataProvider.swift b/Tests/FrameworkTests/SerializersTest/VGSExpDateSerializersDataProvider.swift deleted file mode 100644 index effde585..00000000 --- a/Tests/FrameworkTests/SerializersTest/VGSExpDateSerializersDataProvider.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// VGSExpDateSerializersDataProvider.swift -// FrameworkTests -// -// Copyright © 2021 VGS. All rights reserved. -// - -import Foundation -import XCTest -@testable import VGSCollectSDK - -final class VGSExpDateSerializersDataProvider { - - static func provideTestData(for fileName: String) -> [VGSExpDateSeparateSerializerTests.TestJSONData] { - guard let rootTestJSON = JsonData(jsonFileName: fileName) else { - XCTFail("cannot build data for file \(fileName)") - return [] - } - - guard let testDataJSONArray = rootTestJSON["test_data"] as? [JsonData] else { - XCTFail("test_data JSON array not found in \(fileName)") - return [] - } - - var testData = [VGSExpDateSeparateSerializerTests.TestJSONData]() - - for json in testDataJSONArray { - if let testItem = VGSExpDateSeparateSerializerTests.TestJSONData(json: json) { - testData.append(testItem) - } else { - XCTFail("Cannot build test data for json: \(json)") - } - } - return testData - } - - static func provideTokenizationTestData(for fileName: String) -> [VGSExpDateTokenizationSerializerTests.TestJSONData] { - guard let rootTestJSON = JsonData(jsonFileName: fileName) else { - XCTFail("cannot build data for file \(fileName)") - return [] - } - - guard let testDataJSONArray = rootTestJSON["test_data"] as? [JsonData] else { - XCTFail("test_data JSON array not found in \(fileName)") - return [] - } - - var testData = [VGSExpDateTokenizationSerializerTests.TestJSONData]() - - for json in testDataJSONArray { - if let testItem = VGSExpDateTokenizationSerializerTests.TestJSONData(json: json) { - testData.append(testItem) - } else { - XCTFail("Cannot build test data for json: \(json)") - } - } - return testData - } -} diff --git a/Tests/FrameworkTests/SerializersTest/VGSExpDateTokenizationSerializerTests.swift b/Tests/FrameworkTests/SerializersTest/VGSExpDateTokenizationSerializerTests.swift index f1f2c494..8339d219 100644 --- a/Tests/FrameworkTests/SerializersTest/VGSExpDateTokenizationSerializerTests.swift +++ b/Tests/FrameworkTests/SerializersTest/VGSExpDateTokenizationSerializerTests.swift @@ -7,105 +7,105 @@ import XCTest @testable import VGSCollectSDK class VGSExpDateTokenizationSerializerTests: VGSCollectBaseTestCase { - var collector: VGSCollect! - var textField: VGSExpDateTextField! - - enum TestFlow { - case defaultConfiguration - - var jsonFileName: String { - return "VGSExpDateTokenizationSerialization_" + jsonFileNameSuffix + var collector: VGSCollect! + var textField: VGSExpDateTextField! + + enum TestFlow { + case defaultConfiguration + + var jsonFileName: String { + return "VGSExpDateTokenizationSerialization_" + jsonFileNameSuffix + } + + var jsonFileNameSuffix: String { + switch self { + case .defaultConfiguration: + return "DefaultConfig" + } + } } - - var jsonFileNameSuffix: String { - switch self { - case .defaultConfiguration: - return "DefaultConfig" - } + + struct TestJSONData: TestJSONDataProtocol { + let fieldValue: String + let monthFieldName: String + let yearFieldName: String + let submitJSON: JsonData + let outputFormat: VGSCardExpDateFormat + let comment: String + let tokenizedPayloads: [JsonData] + + init?(json: JsonData) { + guard let submitJSON = json["expectedResult"] as? JsonData else { + XCTFail("Cannot parse test data.") + return nil + } + guard let formatName = json["outputFormat"] as? String, + let format = VGSCardExpDateFormat(name: formatName) else { + XCTFail("Cannot parse output format from test json") + return nil + } + self.fieldValue = json["fieldValue"] as? String ?? "" + self.monthFieldName = json["monthFieldName"] as? String ?? "" + self.yearFieldName = json["yearFieldName"] as? String ?? "" + self.submitJSON = submitJSON + self.outputFormat = format + self.comment = json["comment"] as? String ?? "" + guard let tokenizedPayloads = submitJSON["data"] as? [JsonData] else { + XCTFail("Invalid payload") + return nil + } + self.tokenizedPayloads = tokenizedPayloads + } } - } - - struct TestJSONData { - let fieldValue: String - let monthFieldName: String - let yearFieldName: String - let submitJSON: JsonData - let outputFormat: VGSCardExpDateFormat - let comment: String - let tokenizedPayloads: [JsonData] - - init?(json: JsonData) { - guard let submitJSON = json["expectedResult"] as? JsonData else { - XCTFail("Cannot parse test data.") - return nil - } - guard let formatName = json["outputFormat"] as? String, - let format = VGSCardExpDateFormat(name: formatName) else { - XCTFail("Cannot parse output format from test json") - return nil - } - self.fieldValue = json["fieldValue"] as? String ?? "" - self.monthFieldName = json["monthFieldName"] as? String ?? "" - self.yearFieldName = json["yearFieldName"] as? String ?? "" - self.submitJSON = submitJSON - self.outputFormat = format - self.comment = json["comment"] as? String ?? "" - guard let tokenizedPayloads = submitJSON["data"] as? [JsonData] else { - XCTFail("Invalid payload") - return nil - } - self.tokenizedPayloads = tokenizedPayloads + + // MARK: - Override + + override func setUp() { + super.setUp() + collector = VGSCollect(id: "any") + textField = VGSExpDateTextField() } - } - - // MARK: - Override - - override func setUp() { - super.setUp() - collector = VGSCollect(id: "any") - textField = VGSExpDateTextField() - } - - override func tearDown() { - collector = nil - textField = nil - } - - // MARK: - Tests - - /// Test default configuration. - func testSplitExpDateSerializerWithDefaultConfig() { - let fileName = TestFlow.defaultConfiguration.jsonFileName - let testData = VGSExpDateSerializersDataProvider.provideTokenizationTestData(for: fileName) - - let config = VGSExpDateTokenizationConfiguration(collector: collector, fieldName: "expDate") - config.formatPattern = "##/##" - config.inputDateFormat = .shortYear - - for test in testData { - config.serializers = [VGSExpDateSeparateSerializer(monthFieldName: test.monthFieldName, yearFieldName: test.yearFieldName)] - config.outputDateFormat = test.outputFormat - textField.configuration = config - - textField.setText(test.fieldValue) - - let submitJSON = collector.mapFieldsToTokenizationRequestBodyJSON(collector.textFields) - - guard let tokenizedPayloads = submitJSON["data"] as? [JsonData] else { - XCTFail("Cannot find tokenized data array.") - return - } - - var matchedPayloads = 0 - // mapFieldsToTokenizationRequestBodyJSON can produce array of tokenized data in different order. So we need to iterate through payloads and check them one by one to get 2 matches (one is for month, another one is for year). - for payload in tokenizedPayloads { - for expectedPayload in test.tokenizedPayloads where payload == expectedPayload { - matchedPayloads += 1 + + override func tearDown() { + collector = nil + textField = nil + } + + // MARK: - Tests + + /// Test default configuration. + func testSplitExpDateSerializerWithDefaultConfig() { + let fileName = TestFlow.defaultConfiguration.jsonFileName + let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) + + let config = VGSExpDateTokenizationConfiguration(collector: collector, fieldName: "expDate") + config.formatPattern = "##/##" + config.inputDateFormat = .shortYear + + for test in testData { + config.serializers = [VGSExpDateSeparateSerializer(monthFieldName: test.monthFieldName, yearFieldName: test.yearFieldName)] + config.outputDateFormat = test.outputFormat + textField.configuration = config + + textField.setText(test.fieldValue) + + let submitJSON = collector.mapFieldsToTokenizationRequestBodyJSON(collector.textFields) + + guard let tokenizedPayloads = submitJSON["data"] as? [JsonData] else { + XCTFail("Cannot find tokenized data array.") + return + } + + var matchedPayloads = 0 + // mapFieldsToTokenizationRequestBodyJSON can produce array of tokenized data in different order. So we need to iterate through payloads and check them one by one to get 2 matches (one is for month, another one is for year). + for payload in tokenizedPayloads { + for expectedPayload in test.tokenizedPayloads where payload == expectedPayload { + matchedPayloads += 1 + } + } + + // Should be at least 2 matches of payloads. + XCTAssertTrue(matchedPayloads == 2, "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON) \nComment: \(test.comment)") } - } - - // Should be at least 2 matches of payloads. - XCTAssertTrue(matchedPayloads == 2, "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON) \nComment: \(test.comment)") } - } } diff --git a/VGSCollectSDK.xcodeproj/project.pbxproj b/VGSCollectSDK.xcodeproj/project.pbxproj index 3fc33ff6..d75d9df9 100644 --- a/VGSCollectSDK.xcodeproj/project.pbxproj +++ b/VGSCollectSDK.xcodeproj/project.pbxproj @@ -109,7 +109,6 @@ 443FDDC225DD4B2B006932C4 /* VGSCollectBaseTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 443FDDC125DD4B2B006932C4 /* VGSCollectBaseTestCase.swift */; }; 44447F7725F74CCC00D4CE68 /* VGSFieldNameMapUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44447F7625F74CCC00D4CE68 /* VGSFieldNameMapUtilsTests.swift */; }; 44447F8025F7651100D4CE68 /* JSONData+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44447F7F25F7651100D4CE68 /* JSONData+Extensions.swift */; }; - 4459728A26135BE600139EAA /* VGSExpDateSerializersDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4459728926135BE600139EAA /* VGSExpDateSerializersDataProvider.swift */; }; 4479453E25F8C032006CB371 /* VGSCollect+fieldNameMapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4479453D25F8C032006CB371 /* VGSCollect+fieldNameMapping.swift */; }; 4479456525F8EB93006CB371 /* VGSCollectFieldNameMappingPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4479456425F8EB93006CB371 /* VGSCollectFieldNameMappingPolicy.swift */; }; 449C89D525F0AB9F00BE009F /* VGSDeepMergeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 449C89D425F0AB9F00BE009F /* VGSDeepMergeUtils.swift */; }; @@ -147,6 +146,29 @@ 44ECD60627D9E87000460FDF /* CardIcon.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 44ECD60527D9E87000460FDF /* CardIcon.xcassets */; }; 44F8F51C25DBD1950052647A /* VGSCollectSatelliteUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44F8F51B25DBD1950052647A /* VGSCollectSatelliteUtils.swift */; }; 44F8F52F25DBE8770052647A /* VGSCollectSatelliteUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44F8F52325DBE7E40052647A /* VGSCollectSatelliteUtilsTests.swift */; }; + A01CE3F729E5D67E0059700F /* VGSDateTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = A01CE3F629E5D67E0059700F /* VGSDateTextField.swift */; }; + A0752C7329EF373400337C99 /* VGSTextFormatConvertable.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0752C7229EF373400337C99 /* VGSTextFormatConvertable.swift */; }; + A0752C7529EF376100337C99 /* VGSDateSeparateSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0752C7429EF376100337C99 /* VGSDateSeparateSerializer.swift */; }; + A0752C7829EF3C9200337C99 /* DateTextFieldTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0752C7629EF3AC300337C99 /* DateTextFieldTest.swift */; }; + A08DA9F329F1B03A00DA62A5 /* VGSDateTokenizationConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = A08DA9F229F1B03A00DA62A5 /* VGSDateTokenizationConfiguration.swift */; }; + A08DA9FC29F1CE0B00DA62A5 /* VGSDateTokenizationSerializerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A08DA9FB29F1CE0B00DA62A5 /* VGSDateTokenizationSerializerTests.swift */; }; + A08DA9FD29F1D1E000DA62A5 /* VGSDateTokenizationSerialization_DefaultConfig.json in Resources */ = {isa = PBXBuildFile; fileRef = A08DA9F929F1CC2A00DA62A5 /* VGSDateTokenizationSerialization_DefaultConfig.json */; }; + A08DA9FF29F1D4D500DA62A5 /* VGSDateFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = A08DA9FE29F1D4D500DA62A5 /* VGSDateFormat.swift */; }; + A08DAA0129F1D52A00DA62A5 /* VGSDateFormatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A08DAA0029F1D52A00DA62A5 /* VGSDateFormatTests.swift */; }; + A08E91B529F04600007EDA49 /* ValidationRuleDateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A08E91B429F04600007EDA49 /* ValidationRuleDateTests.swift */; }; + A093FE1729F0AA76002C6ABC /* VGSDateSeparateSerializerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A093FE1629F0AA76002C6ABC /* VGSDateSeparateSerializerTests.swift */; }; + A093FE1E29F0BD38002C6ABC /* VGSDateSerialization_CustomExpDateOutputConfig.json in Resources */ = {isa = PBXBuildFile; fileRef = A093FE1929F0BD38002C6ABC /* VGSDateSerialization_CustomExpDateOutputConfig.json */; }; + A093FE1F29F0BD38002C6ABC /* VGSDateSerialization_CustomConfig.json in Resources */ = {isa = PBXBuildFile; fileRef = A093FE1A29F0BD38002C6ABC /* VGSDateSerialization_CustomConfig.json */; }; + A093FE2029F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayMerge.json in Resources */ = {isa = PBXBuildFile; fileRef = A093FE1B29F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayMerge.json */; }; + A093FE2129F0BD38002C6ABC /* VGSDateSerialization_DefaultConfig.json in Resources */ = {isa = PBXBuildFile; fileRef = A093FE1C29F0BD38002C6ABC /* VGSDateSerialization_DefaultConfig.json */; }; + A093FE2229F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayOverwrite.json in Resources */ = {isa = PBXBuildFile; fileRef = A093FE1D29F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayOverwrite.json */; }; + A093FE2429F0BDC7002C6ABC /* SerializersDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A093FE2329F0BDC7002C6ABC /* SerializersDataProvider.swift */; }; + A0988FA129F9739600FAFA67 /* VGSValidationRuleDateRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0988FA029F9739600FAFA67 /* VGSValidationRuleDateRange.swift */; }; + A0BCC67229F064D4009F1118 /* DateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0BCC67129F064D4009F1118 /* DateTests.swift */; }; + A0BCC67429F06CF6009F1118 /* DateConvertorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0BCC67329F06CF6009F1118 /* DateConvertorTests.swift */; }; + A0C1F09A29EE30AB00EE8447 /* VGSDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0C1F09829EE30AB00EE8447 /* VGSDate.swift */; }; + A0C1F09C29EE30AB00EE8447 /* VGSDateConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0C1F09929EE30AB00EE8447 /* VGSDateConfiguration.swift */; }; + A0C1F0A329EE319D00EE8447 /* DateFormatConvertor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0C1F0A129EE319D00EE8447 /* DateFormatConvertor.swift */; }; FD05F9472316CE5A000EAF52 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD05F9392316CE5A000EAF52 /* Storage.swift */; }; FD05F94A2316CE5A000EAF52 /* VGSConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD05F93C2316CE5A000EAF52 /* VGSConfiguration.swift */; }; FD05F94C2316CE5A000EAF52 /* VGSCollectSDK.h in Headers */ = {isa = PBXBuildFile; fileRef = FD05F93F2316CE5A000EAF52 /* VGSCollectSDK.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -298,7 +320,6 @@ 443FDDC125DD4B2B006932C4 /* VGSCollectBaseTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSCollectBaseTestCase.swift; sourceTree = ""; }; 44447F7625F74CCC00D4CE68 /* VGSFieldNameMapUtilsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSFieldNameMapUtilsTests.swift; sourceTree = ""; }; 44447F7F25F7651100D4CE68 /* JSONData+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSONData+Extensions.swift"; sourceTree = ""; }; - 4459728926135BE600139EAA /* VGSExpDateSerializersDataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSExpDateSerializersDataProvider.swift; sourceTree = ""; }; 4479453D25F8C032006CB371 /* VGSCollect+fieldNameMapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VGSCollect+fieldNameMapping.swift"; sourceTree = ""; }; 4479456425F8EB93006CB371 /* VGSCollectFieldNameMappingPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSCollectFieldNameMappingPolicy.swift; sourceTree = ""; }; 449C89D425F0AB9F00BE009F /* VGSDeepMergeUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSDeepMergeUtils.swift; sourceTree = ""; }; @@ -337,6 +358,29 @@ 44ECD60527D9E87000460FDF /* CardIcon.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = CardIcon.xcassets; sourceTree = ""; }; 44F8F51B25DBD1950052647A /* VGSCollectSatelliteUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSCollectSatelliteUtils.swift; sourceTree = ""; }; 44F8F52325DBE7E40052647A /* VGSCollectSatelliteUtilsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSCollectSatelliteUtilsTests.swift; sourceTree = ""; }; + A01CE3F629E5D67E0059700F /* VGSDateTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSDateTextField.swift; sourceTree = ""; }; + A0752C7229EF373400337C99 /* VGSTextFormatConvertable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VGSTextFormatConvertable.swift; sourceTree = ""; }; + A0752C7429EF376100337C99 /* VGSDateSeparateSerializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VGSDateSeparateSerializer.swift; sourceTree = ""; }; + A0752C7629EF3AC300337C99 /* DateTextFieldTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTextFieldTest.swift; sourceTree = ""; }; + A08DA9F229F1B03A00DA62A5 /* VGSDateTokenizationConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSDateTokenizationConfiguration.swift; sourceTree = ""; }; + A08DA9F929F1CC2A00DA62A5 /* VGSDateTokenizationSerialization_DefaultConfig.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = VGSDateTokenizationSerialization_DefaultConfig.json; sourceTree = ""; }; + A08DA9FB29F1CE0B00DA62A5 /* VGSDateTokenizationSerializerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSDateTokenizationSerializerTests.swift; sourceTree = ""; }; + A08DA9FE29F1D4D500DA62A5 /* VGSDateFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSDateFormat.swift; sourceTree = ""; }; + A08DAA0029F1D52A00DA62A5 /* VGSDateFormatTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSDateFormatTests.swift; sourceTree = ""; }; + A08E91B429F04600007EDA49 /* ValidationRuleDateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidationRuleDateTests.swift; sourceTree = ""; }; + A093FE1629F0AA76002C6ABC /* VGSDateSeparateSerializerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSDateSeparateSerializerTests.swift; sourceTree = ""; }; + A093FE1929F0BD38002C6ABC /* VGSDateSerialization_CustomExpDateOutputConfig.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = VGSDateSerialization_CustomExpDateOutputConfig.json; sourceTree = ""; }; + A093FE1A29F0BD38002C6ABC /* VGSDateSerialization_CustomConfig.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = VGSDateSerialization_CustomConfig.json; sourceTree = ""; }; + A093FE1B29F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayMerge.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = VGSDateSerialization_MapWithArrayMerge.json; sourceTree = ""; }; + A093FE1C29F0BD38002C6ABC /* VGSDateSerialization_DefaultConfig.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = VGSDateSerialization_DefaultConfig.json; sourceTree = ""; }; + A093FE1D29F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayOverwrite.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = VGSDateSerialization_MapWithArrayOverwrite.json; sourceTree = ""; }; + A093FE2329F0BDC7002C6ABC /* SerializersDataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SerializersDataProvider.swift; sourceTree = ""; }; + A0988FA029F9739600FAFA67 /* VGSValidationRuleDateRange.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VGSValidationRuleDateRange.swift; sourceTree = ""; }; + A0BCC67129F064D4009F1118 /* DateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTests.swift; sourceTree = ""; }; + A0BCC67329F06CF6009F1118 /* DateConvertorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateConvertorTests.swift; sourceTree = ""; }; + A0C1F09829EE30AB00EE8447 /* VGSDate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VGSDate.swift; sourceTree = ""; }; + A0C1F09929EE30AB00EE8447 /* VGSDateConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VGSDateConfiguration.swift; sourceTree = ""; }; + A0C1F0A129EE319D00EE8447 /* DateFormatConvertor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateFormatConvertor.swift; sourceTree = ""; }; FD05F9392316CE5A000EAF52 /* Storage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = ""; }; FD05F93A2316CE5A000EAF52 /* Enums.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Enums.swift; sourceTree = ""; }; FD05F93B2316CE5A000EAF52 /* VGSCollect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VGSCollect.swift; sourceTree = ""; }; @@ -434,6 +478,7 @@ 035179A0285920F100394BFC /* VGSCardTokenizationConfiguration.swift */, 035179A22859BABC00394BFC /* VGSSSNTokenizationConfiguration.swift */, 035179A42859BB7D00394BFC /* VGSExpDateTokenizationConfiguration.swift */, + A08DA9F229F1B03A00DA62A5 /* VGSDateTokenizationConfiguration.swift */, 035179A62859BCC400394BFC /* VGSCardHolderNameTokenizationConfiguration.swift */, 035179A82859BD5500394BFC /* VGSTokenizationConfiguration.swift */, ); @@ -478,6 +523,13 @@ path = CardDataMappers; sourceTree = ""; }; + 24A3321F33CCBCFBF0C01580 /* Pods */ = { + isa = PBXGroup; + children = ( + ); + path = Pods; + sourceTree = ""; + }; 32093D7225CD9F88006CD242 /* Loggers */ = { isa = PBXGroup; children = ( @@ -506,6 +558,7 @@ children = ( 3215C4BB260DAF3D00F21259 /* VGSFormatSerializerProtocol.swift */, 3215C4C7260DAF9400F21259 /* VGSExpDateSeparateSerializer.swift */, + A0752C7429EF376100337C99 /* VGSDateSeparateSerializer.swift */, ); path = Serializers; sourceTree = ""; @@ -513,10 +566,12 @@ 3215C4E72611B4B900F21259 /* SerializersTest */ = { isa = PBXGroup; children = ( + A093FE2329F0BDC7002C6ABC /* SerializersDataProvider.swift */, + A093FE1629F0AA76002C6ABC /* VGSDateSeparateSerializerTests.swift */, + A08DA9FB29F1CE0B00DA62A5 /* VGSDateTokenizationSerializerTests.swift */, 3215C4E82611B50A00F21259 /* VGSExpDateSeparateSerializerTests.swift */, - 4459728926135BE600139EAA /* VGSExpDateSerializersDataProvider.swift */, - 44168FBE2632945D0088E515 /* VGSExpirationDateTextFieldUtilsTests.swift */, 44EAE09D28FE8B2700FC6BBB /* VGSExpDateTokenizationSerializerTests.swift */, + 44168FBE2632945D0088E515 /* VGSExpirationDateTextFieldUtilsTests.swift */, ); path = SerializersTest; sourceTree = ""; @@ -524,6 +579,8 @@ 322F94B925BABE82001CDF12 /* Convertors */ = { isa = PBXGroup; children = ( + A0752C7229EF373400337C99 /* VGSTextFormatConvertable.swift */, + A0C1F0A129EE319D00EE8447 /* DateFormatConvertor.swift */, 322F94BA25BABE97001CDF12 /* ExpDateFormatConvertor.swift */, ); path = Convertors; @@ -533,6 +590,7 @@ isa = PBXGroup; children = ( 322F94D625BAC3E0001CDF12 /* ExpDateConvertorTests.swift */, + A0BCC67329F06CF6009F1118 /* DateConvertorTests.swift */, ); path = ConvertorsTests; sourceTree = ""; @@ -540,6 +598,8 @@ 324B5E6224A235BC0036867E /* Date */ = { isa = PBXGroup; children = ( + A0988FA029F9739600FAFA67 /* VGSValidationRuleDateRange.swift */, + A08DA9FE29F1D4D500DA62A5 /* VGSDateFormat.swift */, 324B5E7424A23FA60036867E /* VGSValidationRuleExpirationDate.swift */, ); path = Date; @@ -777,10 +837,12 @@ 44D5210B2681B803005AB588 /* Resources */ = { isa = PBXGroup; children = ( - 442A391129097167007CCC58 /* VGSTokenizationJSONs */, + A093FE1829F0ACA2002C6ABC /* DateSplitSerializerTestJSONs */, + A08DA9F829F1CC2A00DA62A5 /* DateTokenizationJSON */, + 44D521152681B803005AB588 /* ExpDateSplitSerializerTestJSONs */, 44EAE09A28FE65B900FC6BBB /* ExpDateTokenizationJSON */, 44D5210C2681B803005AB588 /* TestJSONs */, - 44D521152681B803005AB588 /* ExpDateSplitSerializerTestJSONs */, + 442A391129097167007CCC58 /* VGSTokenizationJSONs */, 442BB2C5287314DC001FD26B /* MockedData.plist */, ); path = Resources; @@ -832,11 +894,11 @@ 44D521152681B803005AB588 /* ExpDateSplitSerializerTestJSONs */ = { isa = PBXGroup; children = ( - 44D521162681B803005AB588 /* VGSExpDateSerialization_DefaultConfig.json */, + 44D5211A2681B803005AB588 /* VGSExpDateSerialization_CustomConfig.json */, 44D521172681B803005AB588 /* VGSExpDateSerialization_CustomExpDateOutputConfig.json */, - 44D521182681B803005AB588 /* VGSExpDateSerialization_MapWithArrayOverwrite.json */, + 44D521162681B803005AB588 /* VGSExpDateSerialization_DefaultConfig.json */, 44D521192681B803005AB588 /* VGSExpDateSerialization_MapWithArrayMerge.json */, - 44D5211A2681B803005AB588 /* VGSExpDateSerialization_CustomConfig.json */, + 44D521182681B803005AB588 /* VGSExpDateSerialization_MapWithArrayOverwrite.json */, ); path = ExpDateSplitSerializerTestJSONs; sourceTree = ""; @@ -899,6 +961,34 @@ path = "Satellite Tests"; sourceTree = ""; }; + A08DA9F829F1CC2A00DA62A5 /* DateTokenizationJSON */ = { + isa = PBXGroup; + children = ( + A08DA9F929F1CC2A00DA62A5 /* VGSDateTokenizationSerialization_DefaultConfig.json */, + ); + path = DateTokenizationJSON; + sourceTree = ""; + }; + A093FE1829F0ACA2002C6ABC /* DateSplitSerializerTestJSONs */ = { + isa = PBXGroup; + children = ( + A093FE1A29F0BD38002C6ABC /* VGSDateSerialization_CustomConfig.json */, + A093FE1929F0BD38002C6ABC /* VGSDateSerialization_CustomExpDateOutputConfig.json */, + A093FE1C29F0BD38002C6ABC /* VGSDateSerialization_DefaultConfig.json */, + A093FE1B29F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayMerge.json */, + A093FE1D29F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayOverwrite.json */, + ); + path = DateSplitSerializerTestJSONs; + sourceTree = ""; + }; + A0BCC67029F064C0009F1118 /* Core */ = { + isa = PBXGroup; + children = ( + A0BCC67129F064D4009F1118 /* DateTests.swift */, + ); + path = Core; + sourceTree = ""; + }; FD05F9372316CE5A000EAF52 /* VGSCollectSDK */ = { isa = PBXGroup; children = ( @@ -922,9 +1012,11 @@ 44ECD5F427D9C18C00460FDF /* VGSPaymentCards */, 035179992858B39100394BFC /* TokenizationConfiguration */, FD05F93A2316CE5A000EAF52 /* Enums.swift */, + A0C1F09829EE30AB00EE8447 /* VGSDate.swift */, FD05F9392316CE5A000EAF52 /* Storage.swift */, FD05F93C2316CE5A000EAF52 /* VGSConfiguration.swift */, 322F94B025BABD9D001CDF12 /* VGSExpDateConfiguration.swift */, + A0C1F09929EE30AB00EE8447 /* VGSDateConfiguration.swift */, 3219D73C2404279700F4A7E5 /* VGSError.swift */, 327C9E132407EF92004C641C /* VGSErrorInfo.swift */, 327C9E152407F43A004C641C /* VGSErrorInfoKey.swift */, @@ -952,6 +1044,7 @@ 03B10BB028E20A3A009B409B /* VGSBlinkCardCollector */, FD12B9B02304619100B670DD /* Products */, 32CFC72324EBF3B500457B17 /* Frameworks */, + 24A3321F33CCBCFBF0C01580 /* Pods */, ); sourceTree = ""; }; @@ -987,6 +1080,7 @@ FD2495522330CB49009024E6 /* FrameworkTests */ = { isa = PBXGroup; children = ( + A0BCC67029F064C0009F1118 /* Core */, 442A391529097408007CCC58 /* TokenizationTests */, 44447F7D25F7648700D4CE68 /* Test Helpers */, 449C89E225F0AFAE00BE009F /* DeepMergeUtils Tests */, @@ -1078,6 +1172,7 @@ children = ( FD24956F2330E834009024E6 /* CardNumerTextFieldTests.swift */, FDAAB6AA249A8844001F5C1A /* ExpDateTextField.swift */, + A0752C7629EF3AC300337C99 /* DateTextFieldTest.swift */, FDE8907C2333A1D400FA170D /* CVVTextFieldTests.swift */, 3270D3F0248155B200004E3B /* SSNTextFieldTests.swift */, FDE8907A2333A16A00FA170D /* ExpDateTextFieldTests.swift */, @@ -1088,6 +1183,8 @@ FDF696E023463ACA00063507 /* TextFielsStyleUI.swift */, FDA680DE239844FC00372817 /* CardTextFieldTests.swift */, 324B5E7924A3A34F0036867E /* ValidationRulesTest.swift */, + A08DAA0029F1D52A00DA62A5 /* VGSDateFormatTests.swift */, + A08E91B429F04600007EDA49 /* ValidationRuleDateTests.swift */, 32AFB93624FFD218007FFCAE /* VGSTextFieldTests.swift */, 441A727C272AAEEA0036BECB /* TextFieldMaxInputLengthTests.swift */, ); @@ -1102,6 +1199,7 @@ FD2495622330E313009024E6 /* Validation */, FDD398ED247D776600B55057 /* VGSCardTextField.swift */, FD8B62462497CD580097C9AB /* VGSExpDateTextField.swift */, + A01CE3F629E5D67E0059700F /* VGSDateTextField.swift */, FD05F9442316CE5A000EAF52 /* VGSTextField.swift */, 321FE73925DE45FC00B138E9 /* VGSCVCTextField.swift */, FD3C01C223AFC0980096B4A4 /* VGSTextField+CVC.swift */, @@ -1321,13 +1419,19 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + A093FE1F29F0BD38002C6ABC /* VGSDateSerialization_CustomConfig.json in Resources */, 44D521212681B803005AB588 /* VGSExpDateSerialization_MapWithArrayOverwrite.json in Resources */, 44D5211C2681B803005AB588 /* FlatPolicyTestJSONs.json in Resources */, 44D521202681B803005AB588 /* VGSExpDateSerialization_CustomExpDateOutputConfig.json in Resources */, 442BB2C6287314DC001FD26B /* MockedData.plist in Resources */, 44D5210A2681B7F6005AB588 /* FrameworkTests.xctestplan in Resources */, + A093FE2229F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayOverwrite.json in Resources */, + A093FE1E29F0BD38002C6ABC /* VGSDateSerialization_CustomExpDateOutputConfig.json in Resources */, + A093FE2029F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayMerge.json in Resources */, 44D521232681B803005AB588 /* VGSExpDateSerialization_CustomConfig.json in Resources */, + A08DA9FD29F1D1E000DA62A5 /* VGSDateTokenizationSerialization_DefaultConfig.json in Resources */, 44D5211F2681B803005AB588 /* VGSExpDateSerialization_DefaultConfig.json in Resources */, + A093FE2129F0BD38002C6ABC /* VGSDateSerialization_DefaultConfig.json in Resources */, 44D5211D2681B803005AB588 /* OverwriteArraysTestJSONs.json in Resources */, 442A39132909718F007CCC58 /* VGSTokenizationTestJSON_DefaultConfig.json in Resources */, 44EAE09C28FE666200FC6BBB /* VGSExpDateTokenizationSerialization_DefaultConfig.json in Resources */, @@ -1454,6 +1558,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + A0752C7329EF373400337C99 /* VGSTextFormatConvertable.swift in Sources */, 324B5E7124A23E670036867E /* VGSValidationRuleLength.swift in Sources */, FDD42A3D233F67BA0005D631 /* VGSTextField+UIBuilder.swift in Sources */, 3219D73D2404279700F4A7E5 /* VGSError.swift in Sources */, @@ -1462,6 +1567,7 @@ 033C979729D5BDC60088E045 /* VGSTextField+statePublisher.swift in Sources */, 32093D7E25CD9F88006CD242 /* VGSCollectRequestLogger.swift in Sources */, FD3C01C423AFCEEE0096B4A4 /* Enums.swift in Sources */, + A08DA9F329F1B03A00DA62A5 /* VGSDateTokenizationConfiguration.swift in Sources */, 441B26D425DB88C50099AA3A /* APIHostURLPolicy.swift in Sources */, 44ECD60227D9C18C00460FDF /* CardType+icon.swift in Sources */, 449C8A3825F2513300BE009F /* VGSFieldNameToSubscriptMapper.swift in Sources */, @@ -1472,20 +1578,24 @@ 32093D7A25CD9F88006CD242 /* VGSCollectLoggingConfiguration.swift in Sources */, 44ECD5FF27D9C18C00460FDF /* VGSPaymentCards.swift in Sources */, FD05F94A2316CE5A000EAF52 /* VGSConfiguration.swift in Sources */, + A0C1F0A329EE319D00EE8447 /* DateFormatConvertor.swift in Sources */, 324B5E6F24A23D530036867E /* VGSValidationRule.swift in Sources */, 324B5E7524A23FA60036867E /* VGSValidationRuleExpirationDate.swift in Sources */, 441B26F025DB956B0099AA3A /* URL+Extensions.swift in Sources */, 0351799B2858B3B700394BFC /* VGSTextFieldTokenizationProtocol.swift in Sources */, + A0988FA129F9739600FAFA67 /* VGSValidationRuleDateRange.swift in Sources */, 441B26DD25DB88DB0099AA3A /* VGSResponse.swift in Sources */, 325AB9CB2420C5410024134B /* VGSFilePickerControllerDelegate.swift in Sources */, 328B5C7023C8DA2600A39515 /* String+extension.swift in Sources */, 32093D7D25CD9F88006CD242 /* VGSCollectLogEvent.swift in Sources */, 44ECD60427D9C18C00460FDF /* CheckSumAlgoritmType.swift in Sources */, 3215C4BC260DAF3D00F21259 /* VGSFormatSerializerProtocol.swift in Sources */, + A0752C7529EF376100337C99 /* VGSDateSeparateSerializer.swift in Sources */, 441B4E9B293EFD050011EFAC /* VGSCollectHTTPMethod.swift in Sources */, 32093D8625CDA3E6006CD242 /* VGSReadWriteSafeContainer.swift in Sources */, FD3C01C323AFC0980096B4A4 /* VGSTextField+CVC.swift in Sources */, 44F8F51C25DBD1950052647A /* VGSCollectSatelliteUtils.swift in Sources */, + A0C1F09C29EE30AB00EE8447 /* VGSDateConfiguration.swift in Sources */, 326FFB0424F90B940024A4F9 /* CrardScannerInteractionProtocol.swift in Sources */, 44ECD5FE27D9C18C00460FDF /* VGSPaymentCardModel.swift in Sources */, FD8B62472497CD580097C9AB /* VGSExpDateTextField.swift in Sources */, @@ -1503,6 +1613,7 @@ FD05F9472316CE5A000EAF52 /* Storage.swift in Sources */, 449C8A4025F2521900BE009F /* VGSFieldNameSubscriptType.swift in Sources */, 3259B39D263079AD008EECE0 /* VGSExpirationDateTextFieldUtils.swift in Sources */, + A01CE3F729E5D67E0059700F /* VGSDateTextField.swift in Sources */, 4479453E25F8C032006CB371 /* VGSCollect+fieldNameMapping.swift in Sources */, 441B26D625DB88C50099AA3A /* APICustomHostStatus.swift in Sources */, 441B26D225DB88C50099AA3A /* APIClient.swift in Sources */, @@ -1518,10 +1629,12 @@ 324B5E9D24A64A600036867E /* VGSValidationRulePaymentCard.swift in Sources */, 327C9E142407EF92004C641C /* VGSErrorInfo.swift in Sources */, 32F4B7F424C881FA006086F3 /* Calendar+extension.swift in Sources */, + A08DA9FF29F1D4D500DA62A5 /* VGSDateFormat.swift in Sources */, 32F23A6D24B60E1100E389F7 /* VGSValidationRuleLengthMatch.swift in Sources */, 321300172417F2B70062FEF0 /* VGSTextField.swift in Sources */, 328A574023FADC3500714675 /* VGSFilePickerConfiguration.swift in Sources */, 449C89DC25F0ABB000BE009F /* Collection+Extensions.swift in Sources */, + A0C1F09A29EE30AB00EE8447 /* VGSDate.swift in Sources */, 328A574223FADD3D00714675 /* VGSFilePickerController+internal.swift in Sources */, 32093D7B25CD9F88006CD242 /* VGSCollectLogger.swift in Sources */, FD1489FF232D4F8000FD7781 /* MaskedTextField.swift in Sources */, @@ -1559,7 +1672,9 @@ FDF696E3234643F300063507 /* LuhnTests.swift in Sources */, 44C23A7925F7B7EF000EA556 /* VGSFieldNameToJSONTests.swift in Sources */, 3270D3F1248155B200004E3B /* SSNTextFieldTests.swift in Sources */, + A08DAA0129F1D52A00DA62A5 /* VGSDateFormatTests.swift in Sources */, 44D520AE2672218A005AB588 /* VGSFlatJSONStructMappingTests.swift in Sources */, + A0752C7829EF3C9200337C99 /* DateTextFieldTest.swift in Sources */, FDF696E123463ACB00063507 /* TextFielsStyleUI.swift in Sources */, 442A391729097425007CCC58 /* VGSTokenizationResponseMappingTests.swift in Sources */, 3213005B241FA0BE0062FEF0 /* VGSCollectTest+Validation.swift in Sources */, @@ -1573,10 +1688,13 @@ FDA680DF239844FC00372817 /* CardTextFieldTests.swift in Sources */, 44447F8025F7651100D4CE68 /* JSONData+Extensions.swift in Sources */, 32F23A7924B752E200E389F7 /* PaymentCardsTest.swift in Sources */, + A0BCC67229F064D4009F1118 /* DateTests.swift in Sources */, FDAAB6AD249A9257001F5C1A /* FileInfoTest.swift in Sources */, 44168FBF2632945D0088E515 /* VGSExpirationDateTextFieldUtilsTests.swift in Sources */, 327C9E172407FC58004C641C /* VGSErrorInfo.swift in Sources */, FDAAB6AB249A8844001F5C1A /* ExpDateTextField.swift in Sources */, + A093FE1729F0AA76002C6ABC /* VGSDateSeparateSerializerTests.swift in Sources */, + A093FE2429F0BDC7002C6ABC /* SerializersDataProvider.swift in Sources */, FDF696E52346461D00063507 /* StorageTests.swift in Sources */, FD1BE48823462F1E006D8658 /* ExpDateTextFieldTests.swift in Sources */, FD790B97243BB403006A30CB /* CardBrandTest.swift in Sources */, @@ -1584,17 +1702,19 @@ 32AFB93724FFD218007FFCAE /* VGSTextFieldTests.swift in Sources */, 0313A1202975A22700DB2F2C /* VGSTokenizationConfigurationTests.swift in Sources */, 449C89E925F0AFF400BE009F /* VGSDeepMergeUtilsTests.swift in Sources */, + A0BCC67429F06CF6009F1118 /* DateConvertorTests.swift in Sources */, 322F94D725BAC3E0001CDF12 /* ExpDateConvertorTests.swift in Sources */, FD4ED0E52373666500AEAD24 /* TextFieldSecurity.swift in Sources */, + A08DA9FC29F1CE0B00DA62A5 /* VGSDateTokenizationSerializerTests.swift in Sources */, FD24955E2330CC62009024E6 /* VGSCollectTests.swift in Sources */, 324B5E7B24A3A5880036867E /* ValidationRulesTest.swift in Sources */, 44447F7725F74CCC00D4CE68 /* VGSFieldNameMapUtilsTests.swift in Sources */, 442BB2C82873158A001FD26B /* MockedDataProvider.swift in Sources */, 4404600F256801890064BEA0 /* APIHostnameValidatorTests.swift in Sources */, + A08E91B529F04600007EDA49 /* ValidationRuleDateTests.swift in Sources */, 3299585D23DF043D0018FA50 /* MaskedTextFieldTest.swift in Sources */, 324CDEE323FB12E200653890 /* FilePickerTests.swift in Sources */, 443FDDC225DD4B2B006932C4 /* VGSCollectBaseTestCase.swift in Sources */, - 4459728A26135BE600139EAA /* VGSExpDateSerializersDataProvider.swift in Sources */, 327C9E182407FC62004C641C /* VGSErrorInfoKey.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/demoapp/demoapp.xcodeproj/project.pbxproj b/demoapp/demoapp.xcodeproj/project.pbxproj index 1af5cd1d..3a5c6e16 100644 --- a/demoapp/demoapp.xcodeproj/project.pbxproj +++ b/demoapp/demoapp.xcodeproj/project.pbxproj @@ -52,6 +52,7 @@ 44D8691C26205F670014645F /* SSNCollectingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44D8691426205F670014645F /* SSNCollectingViewController.swift */; }; 44D8691D26205F670014645F /* CustomDataCollectingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44D8691526205F670014645F /* CustomDataCollectingViewController.swift */; }; 44D8692026205F670014645F /* FilePickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44D8691926205F670014645F /* FilePickerViewController.swift */; }; + A01CE3F529E5C50D0059700F /* DateValidationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A01CE3F429E5C50D0059700F /* DateValidationViewController.swift */; }; C8CBAAC0A0A75BF9CF5A7FA4 /* Pods_demoapp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DAC2D9D525DA573788F57B /* Pods_demoapp.framework */; }; FD12B9782304616C00B670DD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD12B9772304616C00B670DD /* AppDelegate.swift */; }; FD12B97F2304616E00B670DD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FD12B97E2304616E00B670DD /* Assets.xcassets */; }; @@ -130,6 +131,7 @@ 7D9EC63EB636126947A436E7 /* libPods-demoappUITests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-demoappUITests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 971F95F0CD23156BC2F071A3 /* Pods-demoappUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-demoappUITests.release.xcconfig"; path = "Target Support Files/Pods-demoappUITests/Pods-demoappUITests.release.xcconfig"; sourceTree = ""; }; 9E14BE9AC3107988B3A45EBF /* Pods-demoapp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-demoapp.release.xcconfig"; path = "Target Support Files/Pods-demoapp/Pods-demoapp.release.xcconfig"; sourceTree = ""; }; + A01CE3F429E5C50D0059700F /* DateValidationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateValidationViewController.swift; sourceTree = ""; }; B96EAC87AAF5BF889451003A /* Pods-demoapp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-demoapp.debug.xcconfig"; path = "Target Support Files/Pods-demoapp/Pods-demoapp.debug.xcconfig"; sourceTree = ""; }; C0DAC2D9D525DA573788F57B /* Pods_demoapp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_demoapp.framework; sourceTree = BUILT_PRODUCTS_DIR; }; FD12B9742304616C00B670DD /* demoapp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = demoapp.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -347,6 +349,7 @@ 44D8691926205F670014645F /* FilePickerViewController.swift */, 03DBB7B3292FBFDA00F4DCA2 /* CollectApplePayDataViewController.swift */, 03B992D729C8A5BF00B10A70 /* CombineExamplesViewController.swift */, + A01CE3F429E5C50D0059700F /* DateValidationViewController.swift */, ); path = UseCases; sourceTree = ""; @@ -719,6 +722,7 @@ 44D8692026205F670014645F /* FilePickerViewController.swift in Sources */, 446FE1D625D557080021C7C0 /* UIDevice+Extensions.swift in Sources */, 44D8691C26205F670014645F /* SSNCollectingViewController.swift in Sources */, + A01CE3F529E5C50D0059700F /* DateValidationViewController.swift in Sources */, 44D8691D26205F670014645F /* CustomDataCollectingViewController.swift in Sources */, 449FFCBE28A517E200FE4A1F /* UITableView+Extensions.swift in Sources */, 0351799F2858D53C00394BFC /* CardsDataTokenizationViewController.swift in Sources */, @@ -911,7 +915,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 35; - DEVELOPMENT_TEAM = 4445Y664U5; + DEVELOPMENT_TEAM = 7S7622HN85; INFOPLIST_FILE = demoapp/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.1; LD_RUNPATH_SEARCH_PATHS = ( @@ -937,7 +941,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 35; - DEVELOPMENT_TEAM = 4445Y664U5; + DEVELOPMENT_TEAM = 7S7622HN85; INFOPLIST_FILE = demoapp/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.1; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/demoapp/demoapp/Main.storyboard b/demoapp/demoapp/Main.storyboard index 4b2159ea..d971ec2d 100644 --- a/demoapp/demoapp/Main.storyboard +++ b/demoapp/demoapp/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -100,14 +100,14 @@ - + - + - - + - + - + - - + - + - + - - + - + - + - - + - + + + + + + + + + + + + + + + @@ -423,7 +443,7 @@ - + @@ -918,7 +938,7 @@ - + @@ -1313,25 +1333,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - + - + - + - - - + - + - + - + - - - - - - - - - - - + + + + + + + + + + - + - - - - - - - - - - + + + + + + + + + + - - + + - - - - + + + + - + - + diff --git a/demoapp/demoapp/UseCases/DateValidationViewController.swift b/demoapp/demoapp/UseCases/DateValidationViewController.swift new file mode 100644 index 00000000..11f20738 --- /dev/null +++ b/demoapp/demoapp/UseCases/DateValidationViewController.swift @@ -0,0 +1,186 @@ +// +// DateValidationViewController.swift +// demoapp +// + +import UIKit +import VGSCollectSDK + +class DateValidationViewController: UIViewController { + + // MARK: - Outlets + @IBOutlet weak var containerStackView: UIStackView! + @IBOutlet weak var consoleStatusLabel: UILabel! + @IBOutlet weak var consoleLabel: UILabel! + + // MARK: - Properties + /// Init VGS Collector + var vgsCollect = VGSCollect( + id: AppCollectorConfiguration.shared.vaultId, + environment: AppCollectorConfiguration.shared.environment + ) + /// VGS UI Elements + var dateField = VGSDateTextField() + var consoleMessage: String = "" { + didSet { + consoleLabel.text = consoleMessage + } + } + + // MARK: - View life cycle + override func viewDidLoad() { + super.viewDidLoad() + + /// Configuration + setupUI() + setupElementsConfiguration() + + /// Set custom headers + vgsCollect.customHeaders = [ + "my custome header": "some custom data" + ] + + /// Observe VGSTextFields changes + vgsCollect.observeStates = { [weak self] form in + + self?.consoleMessage = "" + self?.consoleStatusLabel.text = "STATE" + + form.forEach({ textField in + self?.consoleMessage.append(textField.state.description) + self?.consoleMessage.append("\n") + }) + } + } +} + +// MARK: - Private methods +private extension DateValidationViewController { + + func setupUI() { + containerStackView.addArrangedSubview(dateField) + let tapGesture = UITapGestureRecognizer( + target: self, + action: #selector(hideKeyboard) + ) + consoleLabel.addGestureRecognizer(tapGesture) + consoleLabel.isUserInteractionEnabled = true + view.addGestureRecognizer(tapGesture) + } + + @objc + func hideKeyboard() { + view.endEditing(true) + consoleLabel.endEditing(true) + } + + func setupElementsConfiguration() { + + /// Start and end dates + let startDate = VGSDate(day: 1, month: 1, year: 2010) + let endDate = VGSDate(day: 20, month: 12, year: 2025) + + // Date format + let inputDateFormat = VGSDateFormat.mmddyyyy + + /// Create configuration + let dateFieldConfiguration = VGSDateConfiguration( + collector: vgsCollect, + fieldName: "date_field", + datePickerStartDate: startDate, + datePickerEndDate: endDate + ) + dateFieldConfiguration.inputDateFormat = inputDateFormat + dateFieldConfiguration.outputDateFormat = .yyyymmdd + dateFieldConfiguration.inputSource = .datePicker + dateFieldConfiguration.divider = "-" + dateFieldConfiguration.formatPattern = "##/##/####" + + /// Setup validation rules, it is important to set the same start and + /// end date used in the configuration + dateFieldConfiguration.validationRules = VGSValidationRuleSet( + rules: [ + VGSValidationRuleDateRange( + dateFormat: inputDateFormat, + error: VGSValidationErrorType.date.rawValue, + start: startDate, + end: endDate + ) + ] + ) + + /// Update configuration in the text field + dateField.configuration = dateFieldConfiguration + dateField.placeholder = "MM-DD-YYYY" + dateField.monthPickerFormat = .longSymbols + + /// Add logging + vgsCollect.textFields.forEach { textField in + textField.textColor = UIColor.inputBlackTextColor + textField.font = .systemFont(ofSize: 22) + textField.padding = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) + textField.tintColor = .lightGray + /// Implement VGSTextFieldDelegate methods + textField.delegate = self + } + } + + // Upload data from TextFields to VGS + @IBAction func uploadAction(_ sender: Any) { + // Hide kayboard + hideKeyboard() + + // Check if textfields are valid + vgsCollect.textFields.forEach { textField in + textField.borderColor = textField.state.isValid ? .lightGray : .red + } + + // Send extra data + var extraData = [String: Any]() + extraData["customKey"] = "Custom Value" + + /// New sendRequest func + vgsCollect.sendData(path: "/post", extraData: extraData) { [weak self] (response) in + self?.consoleStatusLabel.text = "RESPONSE" + switch response { + case .success(_, let data, _): + if let data = data, let jsonData = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] { + // swiftlint:disable force_try + let response = ( + String(data: try! JSONSerialization.data(withJSONObject: jsonData["json"]!, + options: .prettyPrinted), encoding: .utf8)! + ) + self?.consoleLabel.text = "Success: \n\(response)" + print(response) + // swiftlint:enable force_try + } + return + + case .failure(let code, _, _, let error): + switch code { + case 400..<499: + // Wrong request. This also can happend when your Routs not setup yet or your is wrong + self?.consoleLabel.text = "Error: Wrong Request, code: \(code)" + + case VGSErrorType.inputDataIsNotValid.rawValue: + if let error = error as? VGSError { + self?.consoleLabel.text = "Error: Input data is not valid. Details:\n \(error)" + } + + default: + self?.consoleLabel.text = "Error: Something went wrong. Code: \(code)" + } + print("Submit request error: \(code), \(String(describing: error))") + return + } + } + } +} + +// MARK: - VGSTextFieldDelegate implementation +extension DateValidationViewController: VGSTextFieldDelegate { + + func vgsTextFieldDidChange(_ textField: VGSTextField) { + textField.borderColor = textField.state.isValid ? .gray : .red + } +} From 92c1e5099afd272725b02d3af48fa845dc2433fa Mon Sep 17 00:00:00 2001 From: Dmytro Khludkov Date: Mon, 12 Jun 2023 17:18:05 +0300 Subject: [PATCH 4/9] Add VGSDateTextField. --- .circleci/config.yml | 2 +- .../Core/Collector/VGSCollect.swift | 6 +- Sources/VGSCollectSDK/Core/Enums.swift | 16 +- .../VGSDateTokenizationConfiguration.swift | 108 ----- .../VGSExpDateTokenizationConfiguration.swift | 28 +- Sources/VGSCollectSDK/Core/VGSDate.swift | 84 ---- .../Core/VGSDateConfiguration.swift | 132 ------ .../Core/VGSExpDateConfiguration.swift | 33 +- .../Core/VGSCustomPaymentCardModel.swift | 2 +- .../Text Field/VGSDateTextField.swift | 361 ---------------- .../Text Field/VGSExpDateTextField.swift | 3 +- .../UIElements/Text Field/VGSTextField.swift | 18 +- .../AnyType/VGSValidationRuleLength.swift | 2 +- .../VGSValidationRuleLengthMatch.swift | 2 +- .../AnyType/VGSValidationRulePattern.swift | 2 +- .../Card/VGSValidationRuleLuhnCheck.swift | 2 +- .../Card/VGSValidationRulePaymentCard.swift | 4 +- .../Validation/Date/VGSDateFormat.swift | 181 -------- .../Date/VGSValidationRuleDateRange.swift | 76 ---- .../VGSValidationRuleExpirationDate.swift | 4 +- .../Validation/VGSValidationError.swift | 3 - .../Validation/VGSValidationRule.swift | 4 +- .../Convertors/DateFormatConvertor.swift | 75 ---- .../Convertors/ExpDateFormatConvertor.swift | 152 +++---- .../Convertors/VGSTextFormatConvertable.swift | 31 -- .../VGSDateSeparateSerializer.swift | 32 -- .../ConvertorsTests/DateConvertorTests.swift | 309 -------------- Tests/FrameworkTests/Core/DateTests.swift | 53 --- .../VGSDateSerialization_CustomConfig.json | 44 -- ...rialization_CustomExpDateOutputConfig.json | 44 -- .../VGSDateSerialization_DefaultConfig.json | 44 -- ...GSDateSerialization_MapWithArrayMerge.json | 72 ---- ...teSerialization_MapWithArrayOverwrite.json | 53 --- ...kenizationSerialization_DefaultConfig.json | 85 ---- .../Text Fields Tests/DateTextFieldTest.swift | 225 ---------- .../VGSDateFormatTests.swift | 178 -------- .../ValidationRuleDateTests.swift | 204 --------- .../SerializersDataProvider.swift | 47 --- .../VGSDateSeparateSerializerTests.swift | 256 ------------ .../VGSDateTokenizationSerializerTests.swift | 135 ------ .../VGSExpDateSeparateSerializerTests.swift | 387 ++++++++---------- .../VGSExpDateSerializersDataProvider.swift | 59 +++ ...GSExpDateTokenizationSerializerTests.swift | 192 ++++----- VGSCollectSDK.xcodeproj/project.pbxproj | 140 +------ demoapp/demoapp.xcodeproj/project.pbxproj | 8 +- demoapp/demoapp/Main.storyboard | 282 ++++--------- .../DateValidationViewController.swift | 186 --------- 47 files changed, 528 insertions(+), 3838 deletions(-) delete mode 100644 Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSDateTokenizationConfiguration.swift delete mode 100644 Sources/VGSCollectSDK/Core/VGSDate.swift delete mode 100644 Sources/VGSCollectSDK/Core/VGSDateConfiguration.swift delete mode 100644 Sources/VGSCollectSDK/UIElements/Text Field/VGSDateTextField.swift delete mode 100644 Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSDateFormat.swift delete mode 100644 Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleDateRange.swift delete mode 100644 Sources/VGSCollectSDK/Utils/Convertors/DateFormatConvertor.swift delete mode 100644 Sources/VGSCollectSDK/Utils/Convertors/VGSTextFormatConvertable.swift delete mode 100644 Sources/VGSCollectSDK/Utils/Helpers/Serializers/VGSDateSeparateSerializer.swift delete mode 100644 Tests/FrameworkTests/ConvertorsTests/DateConvertorTests.swift delete mode 100644 Tests/FrameworkTests/Core/DateTests.swift delete mode 100644 Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_CustomConfig.json delete mode 100644 Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_CustomExpDateOutputConfig.json delete mode 100644 Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_DefaultConfig.json delete mode 100644 Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_MapWithArrayMerge.json delete mode 100644 Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_MapWithArrayOverwrite.json delete mode 100644 Tests/FrameworkTests/Resources/DateTokenizationJSON/VGSDateTokenizationSerialization_DefaultConfig.json delete mode 100644 Tests/FrameworkTests/Satellite Tests/Text Fields Tests/DateTextFieldTest.swift delete mode 100644 Tests/FrameworkTests/Satellite Tests/Text Fields Tests/VGSDateFormatTests.swift delete mode 100644 Tests/FrameworkTests/Satellite Tests/Text Fields Tests/ValidationRuleDateTests.swift delete mode 100644 Tests/FrameworkTests/SerializersTest/SerializersDataProvider.swift delete mode 100644 Tests/FrameworkTests/SerializersTest/VGSDateSeparateSerializerTests.swift delete mode 100644 Tests/FrameworkTests/SerializersTest/VGSDateTokenizationSerializerTests.swift create mode 100644 Tests/FrameworkTests/SerializersTest/VGSExpDateSerializersDataProvider.swift delete mode 100644 demoapp/demoapp/UseCases/DateValidationViewController.swift diff --git a/.circleci/config.yml b/.circleci/config.yml index 7c89195e..83d37963 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -34,4 +34,4 @@ workflows: build-and-test: jobs: - build-and-test-sdk - - build-and-ui-test-demo-app-ios-16-iphone14 \ No newline at end of file + - build-and-ui-test-demo-app-ios-16-iphone14 diff --git a/Sources/VGSCollectSDK/Core/Collector/VGSCollect.swift b/Sources/VGSCollectSDK/Core/Collector/VGSCollect.swift index bbeea0bf..b2bbddfc 100644 --- a/Sources/VGSCollectSDK/Core/Collector/VGSCollect.swift +++ b/Sources/VGSCollectSDK/Core/Collector/VGSCollect.swift @@ -52,9 +52,9 @@ public class VGSCollect { return storage.textFields } - // MARK: - Initialization + // MARK: - Initialzation - /// Initialization. + /// Initialzation. /// /// - Parameters: /// - id: `String` object, your organization vault id. @@ -72,7 +72,7 @@ public class VGSCollect { } } - /// Initialization. + /// Initialzation. /// /// - Parameters: /// - id: `String` object, your organization vault id. diff --git a/Sources/VGSCollectSDK/Core/Enums.swift b/Sources/VGSCollectSDK/Core/Enums.swift index e4e92a1c..4f4aa6a3 100644 --- a/Sources/VGSCollectSDK/Core/Enums.swift +++ b/Sources/VGSCollectSDK/Core/Enums.swift @@ -32,9 +32,6 @@ public enum FieldType: Int, CaseIterable { /// Field type that requires Expiration Date input formatting and validation. case expDate - /// Field type that requires Date input formatting and validation. - case date - /// Field type that requires Credit Card CVC input formatting and validation. case cvc @@ -67,8 +64,6 @@ internal extension FieldType { return DateFormatPattern.shortYear.rawValue case .ssn: return "###-##-####" - case .date: - return VGSDateFormat.default.formatPattern default: return "" } @@ -76,7 +71,7 @@ internal extension FieldType { var defaultDivider: String { switch self { - case .expDate, .date: + case .expDate: return "/" case .ssn: return "-" @@ -91,8 +86,6 @@ internal extension FieldType { return "^(?:4[0-9]{12}(?:[0-9]{3})?|[25][1-7][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})$" case .expDate: return "^(0[1-9]|1[0-2])\\/?([0-9]{4}|[0-9]{2})$" - case .date: - return "^([0-9]{4}|[0-9]{2})\\/?([0-9]{2})\\/?([0-9]{4}|[0-9]{2})$" case .cardHolderName: return "^([a-zA-Z0-9\\ \\,\\.\\-\\']{2,})$" case .ssn: @@ -107,7 +100,7 @@ internal extension FieldType { var keyboardType: UIKeyboardType { switch self { - case .cardNumber, .cvc, .expDate, .date, .ssn: + case .cardNumber, .cvc, .expDate, .ssn: return .asciiCapableNumberPad default: return .alphabet @@ -122,9 +115,6 @@ internal extension FieldType { case .expDate: rules.add(rule: VGSValidationRulePattern(pattern: self.defaultRegex, error: VGSValidationErrorType.pattern.rawValue)) rules.add(rule: VGSValidationRuleCardExpirationDate(error: VGSValidationErrorType.expDate.rawValue)) - case .date: - rules.add(rule: VGSValidationRulePattern(pattern: self.defaultRegex, error: VGSValidationErrorType.pattern.rawValue)) - rules.add(rule: VGSValidationRuleDateRange(error: VGSValidationErrorType.date.rawValue)) case .cardNumber: rules.add(rule: VGSValidationRulePaymentCard(error: VGSValidationErrorType.cardNumber.rawValue)) case .cvc: @@ -147,8 +137,6 @@ internal extension FieldType { return "card-security-code" case .expDate: return "card-expiration-date" - case .date: - return "date" case .ssn: return "ssn" case .none: diff --git a/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSDateTokenizationConfiguration.swift b/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSDateTokenizationConfiguration.swift deleted file mode 100644 index c9878863..00000000 --- a/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSDateTokenizationConfiguration.swift +++ /dev/null @@ -1,108 +0,0 @@ -// -// VGSDateTokenizationConfiguration.swift -// VGSCollectSDK -// - -import Foundation - -/// `VGSDateTokenizationParameters` - parameters required for tokenization API -public struct VGSDateTokenizationParameters: VGSTokenizationParametersProtocol { - - /// Vault storage type. - public var storage: String = VGSVaultStorageType.PERSISTENT.rawValue - - /// Data alies format. - public var format: String = VGSVaultAliasFormat.UUID.rawValue -} - -/// Class responsible for configuration `VGSDateTextField` or `VGSTextField` with `fieldType = .date`. -/// Extends `VGSConfiguration`. Required to work with tokenization API. -public final class VGSDateTokenizationConfiguration: VGSConfiguration, VGSDateConfigurationProtocol, VGSTextFieldTokenizationConfigurationProtocol, VGSFormatSerializableProtocol { - - // MARK: - Properties - /// Start date used to fill out the date picker - private var datePickerStartDate: VGSDate = VGSDateConfiguration.minValidPickerStartDate - - /// End date used to fill out the date picker - private var datePickerEndDate: VGSDate = VGSDateConfiguration.maxValidPickerEndDate - - /// Get the list of years from `datePickerStartDate` to `datePickerEndDate`. - /// In case any of the dates are not set, it will use the default - /// values `minValidStartDate` and `maxValidEndDate` respectively - internal var years: [Int] { - Array(datePickerStartDate.year...datePickerEndDate.year) - } - - // MARK: - Constructor - /// Initialization - /// Date configuration initializer, if no `datePickerStartDate` is provided, - /// a default date will be used adding 100 years to the current date. - /// Similar approach will be used if `datePickerEndDate` is not provided, - /// it will be calculated removing 100 years from current date. - /// - /// - Parameters: - /// - vgs: `VGSCollect` instance. - /// - fieldName: associated `fieldName`. - /// - datePickerStartDate: optional `VGSDate` instance. - /// - datePickerEndDate: optional `VGSDate` instance. - public init(collector vgs: VGSCollect, - fieldName: String, - datePickerStartDate: VGSDate? = nil, - datePickerEndDate: VGSDate? = nil) { - /// Setup custom picker start date - if let startDate = datePickerStartDate { - self.datePickerStartDate = startDate - } - /// Setup custom picker end date - if let endDate = datePickerEndDate { - self.datePickerEndDate = endDate - } - /// Super initializer - super.init(collector: vgs, fieldName: fieldName) - } - - // MARK: - Overridden methods and properties - public override var type: FieldType { - get { return .date } - set {} - } - - // MARK: - VGSDateConfigurationProtocol implementation - public var inputSource: VGSTextFieldInputSource = .datePicker - public var inputDateFormat: VGSDateFormat? - public var outputDateFormat: VGSDateFormat? - - // MARK: - VGSFormatSerializableProtocol implementation - public var serializers: [VGSFormatSerializerProtocol] = [] - func serialize(_ content: String) -> [String: Any] { - return DateFormatConvertor.serialize(content, serializers: serializers, outputFormat: outputDateFormat) - } - internal var shouldSerialize: Bool { - return !serializers.isEmpty - } - - // MARK: - VGSDateTokenizationParameters implementation - public var tokenizationParameters = VGSDateTokenizationParameters() - internal var tokenizationConfiguration: VGSTokenizationParametersProtocol { - return tokenizationParameters - } -} - -// MARK: - `TextFormatConvertable` implementation -extension VGSDateTokenizationConfiguration: VGSTextFormatConvertable { - - /// :nodoc: - var inputFormat: InputConvertableFormat? { - return inputDateFormat - } - - /// :nodoc: - var outputFormat: OutputConvertableFormat? { - return outputDateFormat - } - - /// :nodoc: - var convertor: TextFormatConvertor { - return DateFormatConvertor() - } -} diff --git a/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSExpDateTokenizationConfiguration.swift b/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSExpDateTokenizationConfiguration.swift index 9efaba4c..679b35de 100644 --- a/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSExpDateTokenizationConfiguration.swift +++ b/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSExpDateTokenizationConfiguration.swift @@ -49,7 +49,7 @@ public final class VGSExpDateTokenizationConfiguration: VGSConfiguration, VGSExp // MARK: - `VGSExpDateConfiguration` implementation /// Serialize Expiration Date internal func serialize(_ content: String) -> [String: Any] { - return ExpDateFormatConvertor.serialize(content, serializers: serializers, outputFormat: outputDateFormat) + return ExpDateFormatConvertor.serialize(content, serializers: serializers, outputFormat: outputFormat) } /// Returns if Content should be Serialized @@ -58,18 +58,18 @@ public final class VGSExpDateTokenizationConfiguration: VGSConfiguration, VGSExp } } -/// Implement `TextFormatConvertable` protocol. -extension VGSExpDateTokenizationConfiguration: VGSTextFormatConvertable { - - var inputFormat: InputConvertableFormat? { - return inputDateFormat - } - - var outputFormat: OutputConvertableFormat? { - return outputDateFormat - } +/// Implement `FormatConvertable` protocol. +extension VGSExpDateTokenizationConfiguration: FormatConvertable { + + internal var outputFormat: VGSCardExpDateFormat? { + return outputDateFormat + } - internal var convertor: TextFormatConvertor { - return ExpDateFormatConvertor() - } + internal var inputFormat: VGSCardExpDateFormat? { + return inputDateFormat + } + + internal var convertor: TextFormatConvertor { + return ExpDateFormatConvertor() + } } diff --git a/Sources/VGSCollectSDK/Core/VGSDate.swift b/Sources/VGSCollectSDK/Core/VGSDate.swift deleted file mode 100644 index 315e8dbd..00000000 --- a/Sources/VGSCollectSDK/Core/VGSDate.swift +++ /dev/null @@ -1,84 +0,0 @@ -// -// VGSDate.swift -// VGSCollectSDK -// - -import Foundation - -/// `Struct` that represents a date including `year`, `month` and `day`. It doesn't include `hours`, `minutes` or `seconds`. -public struct VGSDate { - - // MARK: - Properties - public var day: Int - public var month: Int - public var year: Int - - /// Get the day formatted value, for example if the day is `1` it is returned as `01` - public var dayFormatted: String { - return String(format: "%02d", day) - } - - /// Get the month formatted value, for example if the month is `3` it is returned as `03` - public var monthFormatted: String { - return String(format: "%02d", month) - } - - // MARK: - Initialization - /// Create a new instance of a `VGSDate` object, if the date is not valid, it returns `nil` - /// - Parameters: - /// - day: `Int`. Represents the day in the date. - /// - month: `Int`. Represents the month in the date. - /// - year: `Int`. Represents the year in the date. - /// - Returns: `VGSDate`, date reference or nil if the date is invalid. - public init?(day: Int, month: Int, year: Int) { - // Make sure it is a valid date - guard DateComponents( - calendar: Calendar(identifier: .gregorian), - year: year, - month: month, - day: day - ).isValidDate else { - let message = "Invalid day, month or year to create date at VGSDate initializer" - let event = VGSLogEvent(level: .warning, text: message, severityLevel: .error) - VGSCollectLogger.shared.forwardLogEvent(event) - return nil - } - // Save date data - self.day = day - self.month = month - self.year = year - } -} - -// MARK: - Equatable and Comparable implementation -extension VGSDate: Comparable { - - /// :nodoc: - public static func == (lhs: Self, rhs: Self) -> Bool { - return lhs.year == rhs.year && - lhs.month == rhs.month && - lhs.day == rhs.day - } - - /// :nodoc: - public static func < (lhs: VGSDate, rhs: VGSDate) -> Bool { - // Check year - if lhs.year < rhs.year { - return true - } - // If the year is equal, check month - else if lhs.year == rhs.year { - // Check month - if lhs.month < rhs.month { - return true - } - // If the month is equal, check day - else if lhs.month == rhs.month { - // Check day - return lhs.day < rhs.day - } - } - // The date at left is not less than date at right - return false - } -} diff --git a/Sources/VGSCollectSDK/Core/VGSDateConfiguration.swift b/Sources/VGSCollectSDK/Core/VGSDateConfiguration.swift deleted file mode 100644 index 5b7b15d4..00000000 --- a/Sources/VGSCollectSDK/Core/VGSDateConfiguration.swift +++ /dev/null @@ -1,132 +0,0 @@ -// -// VGSDateConfiguration.swift -// VGSCollectSDK -// - -import Foundation - -/// Define the methods and properties the date configuration must have -public protocol VGSDateConfigurationProtocol { - - /// Input source type. - var inputSource: VGSTextFieldInputSource {get set} - - /// Input date format to convert. - var inputDateFormat: VGSDateFormat? {get set} - - /// Output date format to convert. - var outputDateFormat: VGSDateFormat? {get set} -} - -/// Class responsible for configuration `VGSDateTextField` or `VGSTextField` with `fieldType = .date`. Extends `VGSConfiguration` -public final class VGSDateConfiguration: VGSConfiguration, VGSDateConfigurationProtocol, VGSFormatSerializableProtocol { - - // MARK: - Properties - /// Start date used to fill out the date picker - private var datePickerStartDate: VGSDate = VGSDateConfiguration.minValidPickerStartDate - - /// End date used to fill out the date picker - private var datePickerEndDate: VGSDate = VGSDateConfiguration.maxValidPickerEndDate - - /// Get the list of years from `datePickerStartDate` to `datePickerEndDate`. - /// In case any of the dates are not set, it will use the default - /// values `minValidStartDate` and `maxValidEndDate` respectively - internal var years: [Int] { - Array(datePickerStartDate.year...datePickerEndDate.year) - } - - // MARK: - Constructor - /// Initialization - /// Date configuration initializer, if no `datePickerStartDate` is provided, - /// a default date will be used adding 100 years to the current date. - /// Similar approach will be used if `datePickerEndDate` is not provided, - /// it will be calculated removing 100 years from current date. - /// - /// - Parameters: - /// - vgs: `VGSCollect` instance. - /// - fieldName: associated `fieldName`. - /// - datePickerStartDate: optional `VGSDate` instance. - /// - datePickerEndDate: optional `VGSDate` instance. - public init(collector vgs: VGSCollect, - fieldName: String, - datePickerStartDate: VGSDate? = nil, - datePickerEndDate: VGSDate? = nil) { - /// Setup custom picker start date - if let startDate = datePickerStartDate { - self.datePickerStartDate = startDate - } - /// Setup custom picker end date - if let endDate = datePickerEndDate { - self.datePickerEndDate = endDate - } - /// Super initializer - super.init(collector: vgs, fieldName: fieldName) - } - - // MARK: - Overridden methods and properties - public override var type: FieldType { - get { return .date } - set {} - } - - // MARK: - VGSDateConfigurationProtocol implementation - public var inputSource: VGSTextFieldInputSource = .datePicker - public var inputDateFormat: VGSDateFormat? - public var outputDateFormat: VGSDateFormat? - - // MARK: - VGSFormatSerializableProtocol implementation - public var serializers: [VGSFormatSerializerProtocol] = [] - func serialize(_ content: String) -> [String: Any] { - return DateFormatConvertor.serialize(content, serializers: serializers, outputFormat: outputDateFormat) - } - internal var shouldSerialize: Bool { - return !serializers.isEmpty - } -} - -// MARK: - Static properties and methods -extension VGSDateConfiguration { - - /// Amount of years used to calculate the minimun and maximun date picker default dates - public static var validYearsCount = 100 - - /// Minimun date picker start date, current year minus `validYearsCount` - public static let minValidPickerStartDate = VGSDate( - day: 1, - month: 1, - year: Calendar.currentYear - validYearsCount - )! - - /// Maximun date picker valid end date, current year plus `validYearsCount` - public static var maxValidPickerEndDate = VGSDate( - day: 1, - month: 1, - year: Calendar.currentYear + validYearsCount - )! - - /// Get the array of years used as default when no start date or end date are defined - internal static var defaultYears: [Int] = { - let startYear = VGSDateConfiguration.minValidPickerStartDate.year - let endYear = VGSDateConfiguration.maxValidPickerEndDate.year - return Array(startYear...endYear) - }() -} - -// MARK: - `TextFormatConvertable` implementation -extension VGSDateConfiguration: VGSTextFormatConvertable { - - /// :nodoc: - var inputFormat: InputConvertableFormat? { - return inputDateFormat - } - - /// :nodoc: - var outputFormat: OutputConvertableFormat? { - return outputDateFormat - } - - /// :nodoc: - var convertor: TextFormatConvertor { - return DateFormatConvertor() - } -} diff --git a/Sources/VGSCollectSDK/Core/VGSExpDateConfiguration.swift b/Sources/VGSCollectSDK/Core/VGSExpDateConfiguration.swift index 9efb0006..9f441a29 100644 --- a/Sources/VGSCollectSDK/Core/VGSExpDateConfiguration.swift +++ b/Sources/VGSCollectSDK/Core/VGSExpDateConfiguration.swift @@ -51,7 +51,7 @@ public final class VGSExpDateConfiguration: VGSConfiguration, VGSExpDateConfigur // MARK: - `VGSExpDateConfiguration` implementation /// Serialize Expiration Date internal func serialize(_ content: String) -> [String: Any] { - return ExpDateFormatConvertor.serialize(content, serializers: serializers, outputFormat: outputDateFormat) + return ExpDateFormatConvertor.serialize(content, serializers: serializers, outputFormat: outputFormat) } /// Returns if Content should be Serialized @@ -60,21 +60,18 @@ public final class VGSExpDateConfiguration: VGSConfiguration, VGSExpDateConfigur } } -/// Implement `TextFormatConvertable` protocol. -extension VGSExpDateConfiguration: VGSTextFormatConvertable { - - /// :nodoc: - var inputFormat: InputConvertableFormat? { - return inputDateFormat - } - - /// :nodoc: - var outputFormat: OutputConvertableFormat? { - return outputDateFormat - } - - /// :nodoc: - var convertor: TextFormatConvertor { - return ExpDateFormatConvertor() - } +/// Implement `FormatConvertable` protocol. +extension VGSExpDateConfiguration: FormatConvertable { + + internal var outputFormat: VGSCardExpDateFormat? { + return outputDateFormat + } + + internal var inputFormat: VGSCardExpDateFormat? { + return inputDateFormat + } + + internal var convertor: TextFormatConvertor { + return ExpDateFormatConvertor() + } } diff --git a/Sources/VGSCollectSDK/Core/VGSPaymentCards/Core/VGSCustomPaymentCardModel.swift b/Sources/VGSCollectSDK/Core/VGSPaymentCards/Core/VGSCustomPaymentCardModel.swift index f9ceb826..23a1ac4e 100644 --- a/Sources/VGSCollectSDK/Core/VGSPaymentCards/Core/VGSCustomPaymentCardModel.swift +++ b/Sources/VGSCollectSDK/Core/VGSPaymentCards/Core/VGSCustomPaymentCardModel.swift @@ -42,7 +42,7 @@ public struct VGSCustomPaymentCardModel: VGSPaymentCardModelProtocol { /// Image, associated with CVC for Payment Card Brand. public var cvcIcon: UIImage? - // MARK: - Initialization + // MARK: - Initialzation /// Initializer. /// - Parameters: diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/VGSDateTextField.swift b/Sources/VGSCollectSDK/UIElements/Text Field/VGSDateTextField.swift deleted file mode 100644 index 906c5f6a..00000000 --- a/Sources/VGSCollectSDK/UIElements/Text Field/VGSDateTextField.swift +++ /dev/null @@ -1,361 +0,0 @@ -// -// VGSDateTextField.swift -// VGSCollectSDK -// - -import UIKit - -/// An object that displays an editable text area. Can be use instead of a `VGSTextField` when need to show picker view with a Date. It support to define a range of valid dates to select from. -public final class VGSDateTextField: VGSTextField { - - // MARK: - Inner objects - /// Available month Label formats in `UIPickerView` - public enum MonthFormat { - /// Short month name, e.g.: `Jan` - case shortSymbols - /// Long month name, e.g.: `January` - case longSymbols - /// Month number: e.g.: `01` - case numbers - } - - // MARK: - Properties - /// UIPickerView month label format - public var monthPickerFormat: MonthFormat = .shortSymbols { - didSet { - updateMonthsDataSource() - } - } - /// UIPickerView components order, it is based on the input format of the configuration - internal var pickerDateFormat: VGSDateFormat? - /// Visual day data source - internal var daysDataSource = [String]() - /// Visual month data source - internal var monthsDataSource = [String]() - /// Visual year data source - internal var yearsDataSource = [String]() - /// Valid days range, it is updated when the Month or Year are selected - internal lazy var days = [Int]() - /// Valid months range - internal lazy var months = Array(1...12) - /// Valid years range, it is updated when the configuration is set - internal lazy var years = [Int]() - /// Store the components index in the picker - private let pickerComponent = (left: 0, center: 1, right: 2) - - // MARK: - Properties - /// `UIPickerView` reference - internal lazy var picker: UIPickerView = { - let picker = UIPickerView() - picker.delegate = self - picker.dataSource = self - return picker - }() - - // MARK: - Overridden methods and properties - public override var configuration: VGSConfiguration? { - didSet { - fieldType = .date - } - } - - override func mainInitialization() { - super.mainInitialization() - setupDatePicker() - } - - override func setupField(with configuration: VGSConfiguration) { - super.setupField(with: configuration) - guard let config = configuration as? VGSDateConfigurationProtocol else { - return - } - - // setup input source - switch config.inputSource { - case .datePicker: - setupDatePicker() - case .keyboard: - setupKeyboard(with: configuration) - } - } -} - -// MARK: - UIPickerViewDelegate and UIPickerViewDataSource implementation -extension VGSDateTextField: UIPickerViewDelegate, UIPickerViewDataSource { - - /// :nodoc: Picker view dataSource implementation. - public func numberOfComponents(in pickerView: UIPickerView) -> Int { - return 3 - } - - /// :nodoc: Picker view dataSource implementation. - public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { - switch component { - case pickerComponent.left: - switch pickerDateFormat { - case .ddmmyyyy: - return daysDataSource.count - case .mmddyyyy: - return monthsDataSource.count - case .yyyymmdd: - return yearsDataSource.count - default: - // Default format: .mmddyyyy - return monthsDataSource.count - } - - case pickerComponent.center: - switch pickerDateFormat { - case .ddmmyyyy, .yyyymmdd: - return monthsDataSource.count - case .mmddyyyy: - return daysDataSource.count - default: - // Default format: .mmddyyyy - return daysDataSource.count - } - - case pickerComponent.right: - switch pickerDateFormat { - case .ddmmyyyy, .mmddyyyy: - return yearsDataSource.count - case .yyyymmdd: - return daysDataSource.count - default: - // Default format: .mmddyyyy - return yearsDataSource.count - } - - default: - // This should never happend - assertionFailure("No valid component index for picker") - return 0 - } - } - - /// :nodoc: Picker view delegate implementation. - public func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { - - switch component { - case pickerComponent.left: - switch pickerDateFormat { - case .ddmmyyyy: - return daysDataSource[row] - case .mmddyyyy: - return monthsDataSource[row] - case .yyyymmdd: - return yearsDataSource[row] - default: - // Default format: .mmddyyyy - return monthsDataSource[row] - } - - case pickerComponent.center: - switch pickerDateFormat { - case .ddmmyyyy, .yyyymmdd: - return monthsDataSource[row] - case .mmddyyyy: - return daysDataSource[row] - default: - // Default format: .mmddyyyy - return daysDataSource[row] - } - - case pickerComponent.right: - switch pickerDateFormat { - case .ddmmyyyy, .mmddyyyy: - return yearsDataSource[row] - case .yyyymmdd: - return daysDataSource[row] - default: - // Default format: .mmddyyyy - return yearsDataSource[row] - } - - default: - // This should never happend - assertionFailure("No valid component index for picker") - return "" - } - } - - /// :nodoc: Picker view delegate implementation. - public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { - switch component { - case pickerComponent.left: - if pickerDateFormat == .mmddyyyy || pickerDateFormat == .yyyymmdd { - updateDaysDataSource() - } - - case pickerComponent.center: - if pickerDateFormat == .ddmmyyyy || pickerDateFormat == .yyyymmdd { - updateDaysDataSource() - } - - case pickerComponent.right: - if pickerDateFormat == .ddmmyyyy || pickerDateFormat == .mmddyyyy { - updateDaysDataSource() - } - default: - // This should never happend - assertionFailure("No valid component index for picker") - } - - // Update text selection - updateTextFieldWithDatePickerSelection() - } -} - -// MARK: - Private methods -private extension VGSDateTextField { - - var pickerDayComponent: Int { - switch pickerDateFormat { - case .ddmmyyyy: - return pickerComponent.left - case .mmddyyyy: - return pickerComponent.center - case .yyyymmdd: - return pickerComponent.right - default: - // Default format: .mmddyyyy - return pickerComponent.center - } - } - - var pickerMonthComponent: Int { - switch pickerDateFormat { - case .ddmmyyyy, .yyyymmdd: - return pickerComponent.center - case .mmddyyyy: - return pickerComponent.left - default: - // Default format: .mmddyyyy - return pickerComponent.left - } - } - - var pickerYearComponent: Int { - switch pickerDateFormat { - case .ddmmyyyy, .mmddyyyy: - return pickerComponent.right - case .yyyymmdd: - return pickerComponent.left - default: - // Default format: .mmddyyyy - return pickerComponent.right - } - } - - func updateMonthsDataSource() { - switch monthPickerFormat { - case .shortSymbols: - monthsDataSource = DateFormatter().shortMonthSymbols - case .longSymbols: - monthsDataSource = DateFormatter().monthSymbols - case .numbers: - monthsDataSource = months.map { (String(format: "%02d", $0)) } - } - } - - func updateDaysDataSource() { - /// Make sure it has valid data for months and years - guard months.count > 0, years.count > 0 else { - return - } - /// Get month and year - var day = 0 - if days.count > 0 { - day = days[picker.selectedRow(inComponent: pickerDayComponent)] - } - let month = months[picker.selectedRow(inComponent: pickerMonthComponent)] - let year = years[picker.selectedRow(inComponent: pickerYearComponent)] - - /// Get amount of days in selected month and year - let dateComponents = DateComponents(year: year, month: month) - let calendar = Calendar(identifier: .gregorian) - let date = calendar.date(from: dateComponents)! - - // Get range of days in month - if let range = calendar.range(of: .day, in: .month, for: date) { - days = range.map { $0 } - } - daysDataSource = days.map { String($0) } - - // Reload days - picker.reloadComponent(pickerDayComponent) - - // If the day is not valid in the month and year, update it to the last one in the days collection - if day >= days.count { - picker.selectRow(days.count - 1, inComponent: pickerDayComponent, animated: true) - } - } - - func updateYearsDataSource() { - /// Make sure the configuration is valid - if let config = configuration as? VGSDateConfiguration { - years = config.years - } else if let tokenizationConfig = configuration as? VGSDateTokenizationConfiguration { - years = tokenizationConfig.years - } else { - years = VGSDateConfiguration.defaultYears - } - yearsDataSource = years.map { String($0) } - } - - func updateTextFieldWithDatePickerSelection() { - /// Get date components - let day = days[picker.selectedRow(inComponent: pickerDayComponent)] - let month = months[picker.selectedRow(inComponent: pickerMonthComponent)] - let year = years[picker.selectedRow(inComponent: pickerYearComponent)] - - /// Get input date format, if not set, use the default - var inputDateFormat = VGSDateFormat.default - if let config = configuration as? VGSDateConfigurationProtocol, - let fieldDateFormat = config.inputDateFormat { - inputDateFormat = fieldDateFormat - } - - /// Create the date string and update the display text - if let date = VGSDate(day: day, month: month, year: year) { - self.setText(inputDateFormat.mapDatePickerDataForFieldFormat(date)) - } - } - - func scrollToCurrentMonthAndYear(animated: Bool) { - let currentMonthIndex = Calendar.currentMonth - 1 - let currentYearIndex = Calendar.currentYear - 1 - picker.selectRow(currentMonthIndex, inComponent: pickerMonthComponent, animated: animated) - picker.selectRow(currentYearIndex, inComponent: pickerYearComponent, animated: animated) - } - - /// Setup date picker configuration - func setupDatePicker() { - textField.inputView = picker - updateMonthsDataSource() - updateYearsDataSource() - updateDaysDataSource() - - // If the date format change, reload the picker component - if let config = configuration as? VGSDateConfigurationProtocol, - let fieldDateFormat = config.inputDateFormat { - // Update the picker format only if it is different - if pickerDateFormat != fieldDateFormat { - pickerDateFormat = fieldDateFormat - picker.reloadAllComponents() - } - } - scrollToCurrentMonthAndYear(animated: false) - textField.inputAccessoryView = UIView() - } - - /// Setup keyboard configuration - func setupKeyboard(with configuration: VGSConfiguration) { - textField.keyboardType = configuration.keyboardType ?? configuration.type.keyboardType - textField.returnKeyType = configuration.returnKeyType ?? .default - textField.keyboardAppearance = configuration.keyboardAppearance ?? .default - // Remove date picker if any - textField.inputView = nil - textField.inputAccessoryView = nil - } -} diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift b/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift index 6e500e7b..a91b8084 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift @@ -181,8 +181,7 @@ private extension VGSExpDateTextField { let inputDateFormat: VGSCardExpDateFormat /// Check if specific `.inputFormat` is set in field configuration - if let config = configuration as? VGSExpDateConfiguration, - let fieldDateFormat = config.inputFormat as? VGSCardExpDateFormat { + if let config = configuration as? VGSExpDateConfiguration, let fieldDateFormat = config.inputFormat { inputDateFormat = fieldDateFormat } else { /// Default format could be mm/yy or mm/yyyy. In other case `.inputDateFormat` should be specified diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/VGSTextField.swift b/Sources/VGSCollectSDK/UIElements/Text Field/VGSTextField.swift index b6ce1663..fd61038a 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/VGSTextField.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/VGSTextField.swift @@ -10,7 +10,6 @@ import UIKit #endif -// swiftlint:disable file_length /// An object that displays an editable text area in user interface. public class VGSTextField: UIView { @@ -169,16 +168,13 @@ public class VGSTextField: UIView { public func isContentEqual(_ textField: VGSTextField) -> Bool { return self.textField.getSecureRawText == textField.textField.getSecureRawText } - - internal func getOutputText() -> String? { - if let config = configuration as? VGSTextFormatConvertable, - let input = textField.getSecureTextWithDivider, - let inputFormat = config.inputFormat, - let outputFormat = config.outputFormat { - return config.convertor.convert(input, inputFormat: inputFormat, outputFormat: outputFormat) - } - return textField.getSecureTextWithDivider + + internal func getOutputText() -> String? { + if let config = configuration as? FormatConvertable, let input = textField.getSecureTextWithDivider, let outputFormat = config.outputFormat, let inputFormat = config.inputFormat { + return config.convertor.convert(input, inputFormat: inputFormat, outputFormat: outputFormat) } + return textField.getSecureTextWithDivider + } /// Field Configuration internal func setupField(with configuration: VGSConfiguration) { @@ -389,6 +385,7 @@ internal extension VGSTextField { return !textField.formatPattern.isEmpty } } +// swiftlint:disable file_length // MARK: - MaskedTextFieldDelegate @@ -425,4 +422,3 @@ extension UIView { layer.cornerRadius = 4 } } -// swiftlint:enable file_length diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRuleLength.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRuleLength.swift index 8b2fa615..1381b28e 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRuleLength.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRuleLength.swift @@ -22,7 +22,7 @@ public struct VGSValidationRuleLength: VGSValidationRuleProtocol { /// Validation Error public let error: VGSValidationError - /// Initialization + /// Initialzation /// /// - Parameters: /// - error:`VGSValidationError` - error on failed validation relust. diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRuleLengthMatch.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRuleLengthMatch.swift index 7efdfc31..547c370a 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRuleLengthMatch.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRuleLengthMatch.swift @@ -19,7 +19,7 @@ public struct VGSValidationRuleLengthMatch: VGSValidationRuleProtocol { /// Validation Error public let error: VGSValidationError - /// Initialization + /// Initialzation /// /// - Parameters: /// - error:`VGSValidationError` - error on failed validation relust. diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRulePattern.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRulePattern.swift index c79e8ac8..30b2cd23 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRulePattern.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/AnyType/VGSValidationRulePattern.swift @@ -19,7 +19,7 @@ public struct VGSValidationRulePattern: VGSValidationRuleProtocol { /// Validation Error public let error: VGSValidationError - /// Initialization + /// Initialzation /// /// - Parameters: /// - error:`VGSValidationError` - error on failed validation relust. diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Card/VGSValidationRuleLuhnCheck.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Card/VGSValidationRuleLuhnCheck.swift index 49424366..950dbf2e 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Card/VGSValidationRuleLuhnCheck.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Card/VGSValidationRuleLuhnCheck.swift @@ -16,7 +16,7 @@ public struct VGSValidationRuleLuhnCheck: VGSValidationRuleProtocol { /// Validation Error public var error: VGSValidationError - /// Initialization + /// Initialzation /// /// - Parameters: /// - error:`VGSValidationError` - error on failed validation relust. diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Card/VGSValidationRulePaymentCard.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Card/VGSValidationRulePaymentCard.swift index 77884d15..620fc99f 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Card/VGSValidationRulePaymentCard.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Card/VGSValidationRulePaymentCard.swift @@ -21,7 +21,7 @@ public struct VGSValidationRulePaymentCard: VGSValidationRuleProtocol { /// Turn on/off validation of cards that are not defined in SDK - `CardBrand.unknown` public var validateUnknownCardBrand = false - /// Initialization + /// Initialzation /// /// - Parameters: /// - error:`VGSValidationError` - error on failed validation relust. @@ -29,7 +29,7 @@ public struct VGSValidationRulePaymentCard: VGSValidationRuleProtocol { self.error = error } - /// Initialization + /// Initialzation /// /// - Parameters: /// - error:`VGSValidationError` - error on failed validation relust. diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSDateFormat.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSDateFormat.swift deleted file mode 100644 index 54c70463..00000000 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSDateFormat.swift +++ /dev/null @@ -1,181 +0,0 @@ -// -// VGSDateFormat.swift -// VGSCollectSDK -// - -/// Format used to validate a VGS date text input -public enum VGSDateFormat: InputConvertableFormat, OutputConvertableFormat { - case mmddyyyy - case ddmmyyyy - case yyyymmdd - - /// Initializer - /// - Parameter name: String object, date format name. - internal init?(name: String) { - switch name { - case "mmddyyyy": - self = .mmddyyyy - return - case "ddmmyyyy": - self = .ddmmyyyy - return - case "yyyymmdd": - self = .yyyymmdd - return - default: - print("WRONG name!: \(name)") - return nil - } - } - - /// Amount of expected characters for day date component - internal var daysCharacters: Int { - return 2 - } - - /// Amount of expected characters for month date component - internal var monthCharacters: Int { - return 2 - } - - /// Amount of expected characters for year date component - internal var yearCharacters: Int { - return 4 - } - - /// Amount of expected dividers in the formatted date - internal var dividerCharacters: Int { - return 2 - } - - /// Get the formatted date to be used as a string representation based - /// in the selected date format. - /// - /// - Returns: `String`, formatted date - internal func mapDatePickerDataForFieldFormat(_ date: VGSDate) -> String { - /// Day and month values - let dayString = String(format: "%02d", date.day) - let monthString = String(format: "%02d", date.month) - - /// Return the string of the date based on the format - switch self { - case .mmddyyyy: - return "\(monthString)\(dayString)\(date.year)" - case .ddmmyyyy: - return "\(dayString)\(monthString)\(date.year)" - case .yyyymmdd: - return "\(date.year)\(monthString)\(dayString)" - } - } - - /// Get the formatted date including the divider - internal func formatDate(_ date: VGSDate, divider: String) -> String { - /// Day and month values - let dayString = String(format: "%02d", date.day) - let monthString = String(format: "%02d", date.month) - - /// Return the string of the date based on the format - switch self { - case .mmddyyyy: - return "\(monthString)\(divider)\(dayString)\(divider)\(date.year)" - case .ddmmyyyy: - return "\(dayString)\(divider)\(monthString)\(divider)\(date.year)" - case .yyyymmdd: - return "\(date.year)\(divider)\(monthString)\(divider)\(dayString)" - } - } - - /// Format and validate an input string and try to convert it to `VGSDate` - /// - Parameter input: `String` object, input data. - /// - Returns: `VGSDate?`, date reference or `nil`. - internal func dateFromInput(_ input: String?) -> VGSDate? { - /// Make sure if is a valid input string - guard let input = input else { - return nil - } - /// Check the amount of chars per date component are correct - let expectedCount = daysCharacters + monthCharacters + yearCharacters - guard input.count == expectedCount else { - return nil - } - // Format the date - switch self { - case .mmddyyyy: - /// Get month, day and year - let month = Int(input.prefix(monthCharacters)) - let day = Int(input.prefix(monthCharacters + daysCharacters).dropFirst(monthCharacters)) - let year = Int(input.suffix(yearCharacters)) - /// Make sure the data is good to create the date - if let month = month, let day = day, let year = year { - return VGSDate(day: day, month: month, year: year) - } - - case .ddmmyyyy: - /// Get day, month and year - let day = Int(input.prefix(daysCharacters)) - let month = Int(input.prefix(daysCharacters + monthCharacters).dropFirst(daysCharacters)) - let year = Int(input.suffix(yearCharacters)) - /// Make sure the data is good to create the date - if let day = day, let month = month, let year = year { - return VGSDate(day: day, month: month, year: year) - } - - case .yyyymmdd: - /// Get year, month and day - let year = Int(input.prefix(yearCharacters)) - let month = Int(input.prefix(yearCharacters + monthCharacters).dropFirst(yearCharacters)) - let day = Int(input.suffix(daysCharacters)) - /// Make sure the data is good to create the date - if let year = year, let month = month, let day = day { - return VGSDate(day: day, month: month, year: year) - } - } - // By default return nil, no valid date - return nil - } - - /// Date format used for display in UI - public var displayFormat: String { - switch self { - case .mmddyyyy: - return "mm-dd-yyyy" - case .ddmmyyyy: - return "dd-mm-yyyy" - case .yyyymmdd: - return "yyyy-mm-dd" - } - } - - /// Date format pattern used to display in the text field - internal var formatPattern: String { - switch self { - case .mmddyyyy, .ddmmyyyy: - return "##-##-####" - case .yyyymmdd: - return "####-##-##" - } - } - - // MARK: - Static properties and methods - /// Default format - static public let `default`: VGSDateFormat = .mmddyyyy - - /// Search the separator used in the input - /// - Parameter input: `String` object, input data. - /// - Returns: `String`, divider reference or empty string. - static internal func dividerInInput(_ input: String) -> String { - /// Remove all digits - let dividers = input.components(separatedBy: CharacterSet.decimalDigits).split(separator: "") - /// There must be only 2 dividers - if dividers.count == 2, - let first = dividers.first?.first, - let second = dividers.last?.first { - /// The dividers must be the same - if String(first) == String(second) { - return String(first) - } - } - /// If no divider found, return empty - return "" - } -} diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleDateRange.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleDateRange.swift deleted file mode 100644 index 5a6905b4..00000000 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleDateRange.swift +++ /dev/null @@ -1,76 +0,0 @@ -// -// VGSDateRangeValidationRule.swift -// VGSCollectSDK -// - -import Foundation - -/// Validation rule used to validate the date input in objects -/// like `VGSDateTextField`, `VGSTextField` and `VGSExpDateTextField` -public struct VGSValidationRuleDateRange: VGSValidationRuleProtocol { - - // MARK: - Properties - /// Store the start date, it can be null - internal let startDate: VGSDate? - - /// Store the end date, it can be null - internal let endDate: VGSDate? - - /// Date format used to validate the rule - public let dateFormat: VGSDateFormat - - /// Error used in case the validation is invalid - public let error: VGSValidationError - - // MARK: - Constructor - /// Initialization - /// - /// - Parameters: - /// - dateFormat: Format used to validate the rule, defaults to `VGSDateFormat.default`. - /// - error: Error used in case there is an error with the validation rule. - /// - startDate: optional `VGSDate` instance. - /// - endDate: optional `VGSDate` instance. - public init(dateFormat: VGSDateFormat = VGSDateFormat.default, - error: VGSValidationError, - start: VGSDate? = nil, - end: VGSDate? = nil) { - self.dateFormat = dateFormat - self.error = error - self.startDate = start - self.endDate = end - } -} - -// MARK: - VGSRuleValidator implementation -extension VGSValidationRuleDateRange: VGSRuleValidator { - - /// :nodoc: - internal func validate(input: String?) -> Bool { - /// Must have valid input - guard let input = input else { - return false - } - - /// Format input date match selected format - guard let inputDate = dateFormat.dateFromInput(input) else { - return false - } - - /// When startDate and endDate are set, validate that startDate `<=` inputDate `<=` endDate - if let startDate = startDate, let endDate = endDate { - return startDate <= inputDate && inputDate <= endDate - } - - /// When startDate is set, validate that startDate `<=` inputDate - if let startDate = startDate { - return startDate <= inputDate - } - - /// When endDate is set, validate that inputDate `<=` endDate - if let endDate = endDate { - return inputDate <= endDate - } - - return true - } -} diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleExpirationDate.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleExpirationDate.swift index 749d4f0e..98a7aa22 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleExpirationDate.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSValidationRuleExpirationDate.swift @@ -9,7 +9,7 @@ import Foundation /// Payment Card Expiration Date Format -public enum VGSCardExpDateFormat: InputConvertableFormat, OutputConvertableFormat { +public enum VGSCardExpDateFormat { /// Exp.Date in format mm/yy: 01/22 case shortYear @@ -88,7 +88,7 @@ public struct VGSValidationRuleCardExpirationDate: VGSValidationRuleProtocol { /// Validation Error public let error: VGSValidationError - /// Initialization + /// Initialzation /// /// - Parameters: /// - error:`VGSValidationError` - error on failed validation relust. diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/VGSValidationError.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/VGSValidationError.swift index 5305f02d..aa36c81d 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/VGSValidationError.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/VGSValidationError.swift @@ -24,9 +24,6 @@ public enum VGSValidationErrorType: String { /// Default Validation error for `VGSValidationRuleCardExpirationDate` case expDate = "EXPIRATION_DATE_VALIDATION_ERROR" - - /// Default Validation error for `VGSValidationRuleDateRange` - case date = "DATE_VALIDATION_ERROR" /// Default Validation error for `VGSValidationRulePaymentCard` case cardNumber = "CARD_NUMBER_VALIDATION_ERROR" diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/VGSValidationRule.swift b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/VGSValidationRule.swift index 7f9e92cb..1afc01bc 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/Validation/VGSValidationRule.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/Validation/VGSValidationRule.swift @@ -20,10 +20,10 @@ public struct VGSValidationRuleSet { internal var rules = [AnyValidationRule]() - /// Initialization + /// Initialzation public init() { } - /// Initialization + /// Initialzation /// /// - Parameters: /// - rules: array of validation rules diff --git a/Sources/VGSCollectSDK/Utils/Convertors/DateFormatConvertor.swift b/Sources/VGSCollectSDK/Utils/Convertors/DateFormatConvertor.swift deleted file mode 100644 index b6d85832..00000000 --- a/Sources/VGSCollectSDK/Utils/Convertors/DateFormatConvertor.swift +++ /dev/null @@ -1,75 +0,0 @@ -// -// DateFormatConvertor.swift -// VGSCollectSDK -// - -import Foundation - -/// Date format convertor -internal class DateFormatConvertor: TextFormatConvertor { - - /// Convert date string with input `VGSDateFormat` to output `VGSDateFormat` - func convert(_ input: String, - inputFormat: InputConvertableFormat, - outputFormat: OutputConvertableFormat) -> String { - /// Make sure the input and output formats are references to `VGSCardExpDateFormat` - guard let inputFormat = inputFormat as? VGSDateFormat, - let outputFormat = outputFormat as? VGSDateFormat else { - let text = "CANNOT CONVERT DATE FORMAT! NOT VALID INPUT OR OUTPUT FORMATS. WILL USE ORIGINAL(INPUT) DATE FORMAT!" - let event = VGSLogEvent(level: .warning, text: text, severityLevel: .warning) - VGSCollectLogger.shared.forwardLogEvent(event) - return input - } - - // Get digits - let result = input.digits - // Get output - if let inputDate = inputFormat.dateFromInput(result) { - /// Store the dividers - let divider = VGSDateFormat.dividerInInput(input) - // Return output date including the divider - return outputFormat.formatDate(inputDate, divider: divider) - } - - // Error, no valid input - let text = "CANNOT CONVERT DATE FORMAT! NOT VALID INPUT OR OUTPUT FORMATS. WILL USE ORIGINAL(INPUT) DATE FORMAT!" - let event = VGSLogEvent(level: .warning, text: text, severityLevel: .warning) - VGSCollectLogger.shared.forwardLogEvent(event) - return input - } - - /// Serializes date - /// - Parameters: - /// - content: `String` object, content to serialize - /// - serializers: `[VGSFormatSerializerProtocol]` object, an array of serializers. - /// - outputFormat: `VGSDateFormat` object, output date format, - /// - Returns: `[String: Any]` object, json with serialized data. - static internal func serialize(_ content: String, - serializers: [VGSFormatSerializerProtocol], - outputFormat: VGSDateFormat?) -> [String: Any] { - var result = [String: Any]() - for serializer in serializers { - if let serializer = serializer as? VGSDateSeparateSerializer { - /// Remove dividers - let dateDigitsString = content.digits - - /// Get output date format, or default if not set - let outputDateFormat = outputFormat ?? .default - - /// Check output date components length - if let outputDate = outputDateFormat.dateFromInput(dateDigitsString) { - /// Set result for specific field names - result[serializer.dayFieldName] = outputDate.dayFormatted - result[serializer.monthFieldName] = outputDate.monthFormatted - result[serializer.yearFieldName] = String(outputDate.year) - } else { - // Error, no valid output - let text = "CANNOT SERIALIZE DATE! NOT VALID OUTPUT FORMATS OR INPUT. WILL USE ORIGINAL(INPUT) DATE FORMAT!" - let event = VGSLogEvent(level: .warning, text: text, severityLevel: .warning) - VGSCollectLogger.shared.forwardLogEvent(event) - } - } - } - return result - } -} diff --git a/Sources/VGSCollectSDK/Utils/Convertors/ExpDateFormatConvertor.swift b/Sources/VGSCollectSDK/Utils/Convertors/ExpDateFormatConvertor.swift index b6174a1c..da1b01b2 100644 --- a/Sources/VGSCollectSDK/Utils/Convertors/ExpDateFormatConvertor.swift +++ b/Sources/VGSCollectSDK/Utils/Convertors/ExpDateFormatConvertor.swift @@ -11,85 +11,89 @@ import Foundation import UIKit #endif +internal protocol FormatConvertable { + /// Input text format + var inputFormat: VGSCardExpDateFormat? { get } + /// Output text format + var outputFormat: VGSCardExpDateFormat? { get } + /// Text convertor object + var convertor: TextFormatConvertor { get } +} + +internal protocol TextFormatConvertor { + func convert(_ input: String, inputFormat: VGSCardExpDateFormat, outputFormat: VGSCardExpDateFormat) -> String +} + /// Card Expiration date format convertor internal class ExpDateFormatConvertor: TextFormatConvertor { + + /// Convert Exp Date String with input `CardExpDateFormat` to Output `CardExpDateFormat` + func convert(_ input: String, inputFormat: VGSCardExpDateFormat, outputFormat: VGSCardExpDateFormat) -> String { + let inputYear = inputFormat.isYearFirst ? String(input.prefix(inputFormat.yearCharacters)) : String(input.suffix(inputFormat.yearCharacters)) + let inputMonth = inputFormat.isYearFirst ? input.suffix(inputFormat.monthCharacters) : input.prefix(inputFormat.monthCharacters) + let divider = inputFormat.isYearFirst ? String(input.dropLast(inputFormat.monthCharacters)).dropFirst(inputFormat.yearCharacters) : String(input.dropLast(inputFormat.yearCharacters)).dropFirst(inputFormat.monthCharacters) - /// Convert Exp Date String with input `CardExpDateFormat` to Output `CardExpDateFormat` - func convert(_ input: String, inputFormat: InputConvertableFormat, outputFormat: OutputConvertableFormat) -> String { - /// Make sure the input and output formats are references to `VGSCardExpDateFormat` - guard let inputFormat = inputFormat as? VGSCardExpDateFormat, - let outputFormat = outputFormat as? VGSCardExpDateFormat else { - let text = "CANNOT CONVERT DATE FORMAT! NOT VALID INPUT OR OUTPUT FORMATS. WILL USE ORIGINAL(INPUT) DATE FORMAT!" - let event = VGSLogEvent(level: .warning, text: text, severityLevel: .warning) - VGSCollectLogger.shared.forwardLogEvent(event) - return input - } - /// Get input data - let inputYear = inputFormat.isYearFirst ? String(input.prefix(inputFormat.yearCharacters)) : String(input.suffix(inputFormat.yearCharacters)) - let inputMonth = inputFormat.isYearFirst ? input.suffix(inputFormat.monthCharacters) : input.prefix(inputFormat.monthCharacters) - let divider = inputFormat.isYearFirst ? String(input.dropLast(inputFormat.monthCharacters)).dropFirst(inputFormat.yearCharacters) : String(input.dropLast(inputFormat.yearCharacters)).dropFirst(inputFormat.monthCharacters) - - let dateFormatter = DateFormatter() - dateFormatter.calendar = Calendar(identifier: .gregorian) - dateFormatter.dateFormat = inputFormat.dateYearFormat - dateFormatter.locale = Locale(identifier: "en_US") - - if let date = dateFormatter.date(from: inputYear) { - dateFormatter.dateFormat = outputFormat.dateYearFormat - let outputYear = dateFormatter.string(from: date) - let output = outputFormat.isYearFirst ? String(outputYear + divider + inputMonth) : - String(inputMonth + divider + outputYear) - return output - } - let text = "CANNOT CONVERT DATE FORMAT! NOT VALID INPUT YEAR - \(inputYear). WILL USE ORIGINAL(INPUT) DATE FORMAT!" - let event = VGSLogEvent(level: .warning, text: text, severityLevel: .warning) - VGSCollectLogger.shared.forwardLogEvent(event) - - return input + let dateFormatter = DateFormatter() + dateFormatter.calendar = Calendar(identifier: .gregorian) + dateFormatter.dateFormat = inputFormat.dateYearFormat + dateFormatter.locale = Locale(identifier: "en_US") + + if let date = dateFormatter.date(from: inputYear) { + dateFormatter.dateFormat = outputFormat.dateYearFormat + let outputYear = dateFormatter.string(from: date) + let output = outputFormat.isYearFirst ? String(outputYear + divider + inputMonth) : + String(inputMonth + divider + outputYear) + return output } + let text = "CANNOT CONVERT DATE FORMAT! NOT VALID INPUT YEAR - \(inputYear). WILL USE ORIGINAL(INPUT) DATE FORMAT!" + let event = VGSLogEvent(level: .warning, text: text, severityLevel: .warning) + VGSCollectLogger.shared.forwardLogEvent(event) - /// Serializes expiration date. - /// - Parameters: - /// - content: `String` object, content to serialize - /// - serializers: `[VGSFormatSerializerProtocol]` object, an array of serializers. - /// - outputFormat: `VGSCardExpDateFormat` object, output date format, - /// - Returns: `[String: Any]` object, json with serialized data. - static internal func serialize(_ content: String, serializers: [VGSFormatSerializerProtocol], outputFormat: VGSCardExpDateFormat?) -> [String: Any] { - var result = [String: Any]() - for serializer in serializers { - if let serializer = serializer as? VGSExpDateSeparateSerializer { - /// remove dividers - var dateDigitsString = content.digits - - /// get output date format, if not set - use default - let outputDateFormat = outputFormat ?? .shortYear - /// check output date components length - let outputMonthDigits = outputDateFormat.monthCharacters - let outputYearDigits = outputDateFormat.yearCharacters - - let mth: String - let year: String - if outputDateFormat.isYearFirst { - /// take month digitis - year = String(dateDigitsString.prefix(outputYearDigits)) - /// remove month digits - dateDigitsString = String(dateDigitsString.dropFirst(outputYearDigits)) - /// take year digitis - mth = String(dateDigitsString.prefix(outputMonthDigits)) - } else { - /// take month digitis - mth = String(dateDigitsString.prefix(outputMonthDigits)) - /// remove month digits - dateDigitsString = String(dateDigitsString.dropFirst(outputMonthDigits)) - /// take year digitis - year = String(dateDigitsString.prefix(outputYearDigits)) - } - - /// set result for specific fieldnames - result[serializer.monthFieldName] = mth - result[serializer.yearFieldName] = year - } + return input + } + + /// Serializes expiration date. + /// - Parameters: + /// - content: `String` object, content to serialize + /// - serializers: `[VGSFormatSerializerProtocol]` object, an array of serializers. + /// - outputFormat: `VGSCardExpDateFormat` object, output date format, + /// - Returns: `[String: Any]` object, json with serialized data. + static internal func serialize(_ content: String, serializers: [VGSFormatSerializerProtocol], outputFormat: VGSCardExpDateFormat?) -> [String: Any] { + var result = [String: Any]() + for serializer in serializers { + if let serializer = serializer as? VGSExpDateSeparateSerializer { + /// remove dividers + var dateDigitsString = content.digits + + /// get output date format, if not set - use default + let outputDateFormat = outputFormat ?? .shortYear + /// check output date components length + let outputMonthDigits = outputDateFormat.monthCharacters + let outputYearDigits = outputDateFormat.yearCharacters + + let mth: String + let year: String + if outputDateFormat.isYearFirst { + /// take month digitis + year = String(dateDigitsString.prefix(outputYearDigits)) + /// remove month digits + dateDigitsString = String(dateDigitsString.dropFirst(outputYearDigits)) + /// take year digitis + mth = String(dateDigitsString.prefix(outputMonthDigits)) + } else { + /// take month digitis + mth = String(dateDigitsString.prefix(outputMonthDigits)) + /// remove month digits + dateDigitsString = String(dateDigitsString.dropFirst(outputMonthDigits)) + /// take year digitis + year = String(dateDigitsString.prefix(outputYearDigits)) } - return result + + /// set result for specific fieldnames + result[serializer.monthFieldName] = mth + result[serializer.yearFieldName] = year + } } + return result + } } diff --git a/Sources/VGSCollectSDK/Utils/Convertors/VGSTextFormatConvertable.swift b/Sources/VGSCollectSDK/Utils/Convertors/VGSTextFormatConvertable.swift deleted file mode 100644 index 2a8242e5..00000000 --- a/Sources/VGSCollectSDK/Utils/Convertors/VGSTextFormatConvertable.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// VGSTextFormatConvertable.swift -// VGSCollectSDK -// - -import Foundation - -/// Base protocol describing the input format to conver a string value -protocol InputConvertableFormat { } - -/// Base protocol describing the output format to conver a string value -protocol OutputConvertableFormat { } - -/// Base protocol to implements the method to convert an `input` string -/// with input `InputConvertableFormat` to output `OutputConvertableFormat` -protocol TextFormatConvertor { - func convert(_ input: String, - inputFormat: InputConvertableFormat, - outputFormat: OutputConvertableFormat) -> String -} - -/// Base protocol to implement the input and output formats and -/// the convertor for input strings -protocol VGSTextFormatConvertable { - /// Input text format - var inputFormat: InputConvertableFormat? { get } - /// Output text format - var outputFormat: OutputConvertableFormat? { get } - /// Text convertor object - var convertor: TextFormatConvertor { get } -} diff --git a/Sources/VGSCollectSDK/Utils/Helpers/Serializers/VGSDateSeparateSerializer.swift b/Sources/VGSCollectSDK/Utils/Helpers/Serializers/VGSDateSeparateSerializer.swift deleted file mode 100644 index 737aeaa9..00000000 --- a/Sources/VGSCollectSDK/Utils/Helpers/Serializers/VGSDateSeparateSerializer.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// VGSDateSeparateSerializer.swift -// VGSCollectSDK -// - -import Foundation - -public struct VGSDateSeparateSerializer: VGSFormatSerializerProtocol { - - // MARK: - Properties - /// Field Name that will be used as a JSON key with day value from date string on send request. - public let dayFieldName: String - - /// Field Name that will be used as a JSON key with month value from date string on send request. - public let monthFieldName: String - - /// Field Name that will be used as a JSON key with year value from date string on send request. - public let yearFieldName: String - - // MARK: - Initialization - /// Initialization - /// - /// - Parameters: - /// - dayFielddName: key, that should be associated with day value in request JSON. - /// - monthFieldName: key, that should be associated with month value in request JSON. - /// - yearFieldName: key, that should be associated with year value in request JSON. - public init(dayFieldName: String, monthFieldName: String, yearFieldName: String) { - self.dayFieldName = dayFieldName - self.monthFieldName = monthFieldName - self.yearFieldName = yearFieldName - } -} diff --git a/Tests/FrameworkTests/ConvertorsTests/DateConvertorTests.swift b/Tests/FrameworkTests/ConvertorsTests/DateConvertorTests.swift deleted file mode 100644 index 289bdf02..00000000 --- a/Tests/FrameworkTests/ConvertorsTests/DateConvertorTests.swift +++ /dev/null @@ -1,309 +0,0 @@ -// -// DateConvertorTests.swift -// FrameworkTests -// - -import XCTest -@testable import VGSCollectSDK - -class DateConvertorTests: VGSCollectBaseTestCase { - - // MARK: - Properties - private var collector: VGSCollect! - private var textField: VGSDateTextField! - - // MARK: - Inner objects - struct TestDataType { - let input: String - let output: String - } - - // MARK: - Overrides - override func setUp() { - super.setUp() - - collector = VGSCollect(id: "any") - textField = VGSDateTextField() - } - - override func tearDown() { - collector = nil - textField = nil - } - - // MARK: - Tests - /// Test to convert a date from default format - func testConvertDate() { - /// Setup configuration - let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") - textField.configuration = config - - /// Test dates - let testDates: [TestDataType] = [ - TestDataType(input: "12/10/2021", output: "12/10/2021"), - TestDataType(input: "01/04/2050", output: "01/04/2050"), - TestDataType(input: "05/07/2100", output: "05/07/2100") - ] - - /// Assert: Test dates output - for date in testDates { - textField.setText(date.input) - XCTAssertEqual(textField.getOutputText(), date.output) - } - } - - /// Test to convert a date from ddmmyyy to ddmmyyy - func testConvertDate_ddmmyyyy_to_ddmmyyyy() { - /// Setup configuration - let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") - config.formatPattern = VGSDateFormat.ddmmyyyy.formatPattern - config.inputDateFormat = .ddmmyyyy - config.outputDateFormat = .ddmmyyyy - textField.configuration = config - - /// Test dates - let testDates: [TestDataType] = [ - TestDataType(input: "12/10/2021", output: "12/10/2021"), - TestDataType(input: "01/04/2050", output: "01/04/2050"), - TestDataType(input: "05/07/2100", output: "05/07/2100") - ] - - /// Assert: Test dates - for date in testDates { - textField.setText(date.input) - XCTAssertEqual(textField.getOutputText(), date.output) - } - } - - /// Test to convert a date from ddmmyyy to mmddyyyy - func testConvertDate_ddmmyyyy_to_mmddyyyy() { - /// Setup configuration - let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") - config.formatPattern = VGSDateFormat.ddmmyyyy.formatPattern - config.inputDateFormat = .ddmmyyyy - config.outputDateFormat = .mmddyyyy - textField.configuration = config - - /// Test dates - let testDates: [TestDataType] = [ - TestDataType(input: "12/10/2021", output: "10/12/2021"), - TestDataType(input: "01/04/2050", output: "04/01/2050"), - TestDataType(input: "05/07/2100", output: "07/05/2100") - ] - - /// Assert: Test dates - for date in testDates { - textField.setText(date.input) - XCTAssertEqual(textField.getOutputText(), date.output) - } - } - - /// Test to convert a date from ddmmyyy to yyyymmdd - func testConvertDate_ddmmyyyy_to_yyyymmdd() { - /// Setup configuration - let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") - config.formatPattern = VGSDateFormat.ddmmyyyy.formatPattern - config.inputDateFormat = .ddmmyyyy - config.outputDateFormat = .yyyymmdd - textField.configuration = config - - /// Test dates - let testDates: [TestDataType] = [ - TestDataType(input: "12/10/2021", output: "2021/10/12"), - TestDataType(input: "01/04/2050", output: "2050/04/01"), - TestDataType(input: "05/07/2100", output: "2100/07/05") - ] - - /// Assert: Test dates - for date in testDates { - textField.setText(date.input) - XCTAssertEqual(textField.getOutputText(), date.output) - } - } - - /// Test to convert a date from mmddyyyy to mmddyyyy - func testConvertDate_mmddyyyy_to_mmddyyyy() { - /// Setup configuration - let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") - config.formatPattern = VGSDateFormat.mmddyyyy.formatPattern - config.inputDateFormat = .mmddyyyy - config.outputDateFormat = .mmddyyyy - textField.configuration = config - - /// Test dates - let testDates: [TestDataType] = [ - TestDataType(input: "10/12/2021", output: "10/12/2021"), - TestDataType(input: "04/01/2050", output: "04/01/2050"), - TestDataType(input: "07/05/2100", output: "07/05/2100") - ] - - /// Assert: Test dates - for date in testDates { - textField.setText(date.input) - XCTAssertEqual(textField.getOutputText(), date.output) - } - } - - /// Test to convert a date from mmddyyyy to ddmmyyy - func testConvertDate_mmddyyyy_to_ddmmyyy() { - /// Setup configuration - let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") - config.formatPattern = VGSDateFormat.mmddyyyy.formatPattern - config.inputDateFormat = .mmddyyyy - config.outputDateFormat = .ddmmyyyy - textField.configuration = config - - /// Test dates - let testDates: [TestDataType] = [ - TestDataType(input: "10/12/2021", output: "12/10/2021"), - TestDataType(input: "04/01/2050", output: "01/04/2050"), - TestDataType(input: "07/05/2100", output: "05/07/2100") - ] - - /// Assert: Test dates - for date in testDates { - textField.setText(date.input) - XCTAssertEqual(textField.getOutputText(), date.output) - } - } - - /// Test to convert a date from mmddyyyy to yyyymmdd - func testConvertDate_mmddyyyy_to_yyyymmdd() { - /// Setup configuration - let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") - config.formatPattern = VGSDateFormat.mmddyyyy.formatPattern - config.inputDateFormat = .mmddyyyy - config.outputDateFormat = .yyyymmdd - textField.configuration = config - - /// Test dates - let testDates: [TestDataType] = [ - TestDataType(input: "10/12/2021", output: "2021/10/12"), - TestDataType(input: "04/01/2050", output: "2050/04/01"), - TestDataType(input: "07/05/2100", output: "2100/07/05") - ] - - /// Assert: Test dates - for date in testDates { - textField.setText(date.input) - XCTAssertEqual(textField.getOutputText(), date.output) - } - } - - /// Test to convert a date from yyyymmdd to yyyymmdd - func testConvertDate_yyyymmdd_to_yyyymmdd() { - /// Setup configuration - let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") - config.formatPattern = VGSDateFormat.yyyymmdd.formatPattern - config.inputDateFormat = .yyyymmdd - config.outputDateFormat = .yyyymmdd - textField.configuration = config - - /// Test dates - let testDates: [TestDataType] = [ - TestDataType(input: "2021/10/12", output: "2021/10/12"), - TestDataType(input: "2050/04/01", output: "2050/04/01"), - TestDataType(input: "2100/07/05", output: "2100/07/05") - ] - - /// Assert: Test dates - for date in testDates { - textField.setText(date.input) - XCTAssertEqual(textField.getOutputText(), date.output) - } - } - - /// Test to convert a date from yyyymmdd to mmddyyyy - func testConvertDate_yyyymmdd_to_mmddyyyy() { - /// Setup configuration - let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") - config.formatPattern = VGSDateFormat.yyyymmdd.formatPattern - config.inputDateFormat = .yyyymmdd - config.outputDateFormat = .mmddyyyy - textField.configuration = config - - /// Test dates - let testDates: [TestDataType] = [ - TestDataType(input: "2021/10/12", output: "10/12/2021"), - TestDataType(input: "2050/04/01", output: "04/01/2050"), - TestDataType(input: "2100/07/05", output: "07/05/2100") - ] - - /// Assert: Test dates - for date in testDates { - textField.setText(date.input) - XCTAssertEqual(textField.getOutputText(), date.output) - } - } - - /// Test to convert a date from yyyymmdd to ddmmyyy - func testConvertDate_yyyymmdd_to_ddmmyyy() { - /// Setup configuration - let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") - config.formatPattern = VGSDateFormat.yyyymmdd.formatPattern - config.inputDateFormat = .yyyymmdd - config.outputDateFormat = .ddmmyyyy - textField.configuration = config - - /// Test dates - let testDates: [TestDataType] = [ - TestDataType(input: "2021/10/12", output: "12/10/2021"), - TestDataType(input: "2050/04/01", output: "01/04/2050"), - TestDataType(input: "2100/07/05", output: "05/07/2100") - ] - - /// Assert: Test dates - for date in testDates { - textField.setText(date.input) - XCTAssertEqual(textField.getOutputText(), date.output) - } - } - - /// Test to convert a date with an empty divider - func testConvertDateEmptyDivider() { - /// Setup configuration - let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") - config.formatPattern = VGSDateFormat.ddmmyyyy.formatPattern - config.divider = "" - config.inputDateFormat = .ddmmyyyy - config.outputDateFormat = .ddmmyyyy - textField.configuration = config - - /// Test dates - let testDates: [TestDataType] = [ - TestDataType(input: "12/10/2021", output: "12102021"), - TestDataType(input: "01/04/2050", output: "01042050"), - TestDataType(input: "05/07/2100", output: "05072100") - ] - - /// Assert: Test dates - for date in testDates { - textField.setText(date.input) - XCTAssertEqual(textField.getOutputText(), date.output) - } - } - - /// Test to convert a date with a custom divider - func testConvertDateCustomDivider() { - /// Setup configuration - let config = VGSDateConfiguration(collector: collector, fieldName: "test_field") - config.formatPattern = VGSDateFormat.ddmmyyyy.formatPattern - config.divider = "-/-" - config.inputDateFormat = .ddmmyyyy - config.outputDateFormat = .ddmmyyyy - textField.configuration = config - - /// Test dates - let testDates: [TestDataType] = [ - TestDataType(input: "12/10/2021", output: "12-/-10-/-2021"), - TestDataType(input: "01/04/2050", output: "01-/-04-/-2050"), - TestDataType(input: "05/07/2100", output: "05-/-07-/-2100") - ] - - /// Assert: Test dates - for date in testDates { - textField.setText(date.input) - XCTAssertEqual(textField.getOutputText(), date.output) - } - } -} diff --git a/Tests/FrameworkTests/Core/DateTests.swift b/Tests/FrameworkTests/Core/DateTests.swift deleted file mode 100644 index 3f2bba9d..00000000 --- a/Tests/FrameworkTests/Core/DateTests.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// DateTests.swift -// FrameworkTests -// - -import XCTest -@testable import VGSCollectSDK - -class DateTests: VGSCollectBaseTestCase { - - // MARK: - Tests - /// Test date initialization - func testDateInitialization() { - /// Valid date - let validDate = VGSDate(day: 1, month: 1, year: 2010) - XCTAssertNotNil(validDate) - - /// Invalid date - let invalidDate = VGSDate(day: 50, month: 50, year: 2) - XCTAssertNil(invalidDate) - } - - /// Test date formatted - func testFormatters() { - /// Date - let date = VGSDate(day: 2, month: 6, year: 2010) - XCTAssertNotNil(date) - - /// Validate formatted month and day - XCTAssertEqual(date?.dayFormatted, "02") - XCTAssertEqual(date?.monthFormatted, "06") - } - - /// Test date comparable - func testDateComparable() { - /// Dates - let dateA = VGSDate(day: 12, month: 5, year: 2010)! - var dateB = VGSDate(day: 12, month: 5, year: 2010)! - - /// Validate equals - XCTAssertEqual(dateA, dateB) - - /// Validate not equals - dateB.year = 2011 - XCTAssertNotEqual(dateA, dateB) - - /// Validate less than - XCTAssertLessThan(dateA, dateB) - - /// Validate greater than - XCTAssertGreaterThan(dateB, dateA) - } -} diff --git a/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_CustomConfig.json b/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_CustomConfig.json deleted file mode 100644 index 71caacf9..00000000 --- a/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_CustomConfig.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "test_data":[ - { - "monthFieldName":"month", - "dayFieldName":"day", - "yearFieldName":"year", - "fieldValue":"2030-/-01-/-15", - "expectedResult":{ - "month":"01", - "day":"15", - "year":"2030" - }, - "comment":"Single key fieldNames." - }, - { - "monthFieldName":"date.month", - "dayFieldName":"date.day", - "yearFieldName":"date.year", - "fieldValue":"2026-/-10-/-18", - "expectedResult":{ - "date":{ - "month":"10", - "day":"18", - "year":"2026" - } - }, - "comment":"Map to dot JSON" - }, - { - "monthFieldName":"date.month", - "dayFieldName":"day", - "yearFieldName":"year", - "fieldValue":"2015-/-05-/-25", - "expectedResult":{ - "date":{ - "month":"05" - }, - "day":"25", - "year":"2015" - }, - "comment":"Map to dot JSON with single key" - } - ] -} \ No newline at end of file diff --git a/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_CustomExpDateOutputConfig.json b/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_CustomExpDateOutputConfig.json deleted file mode 100644 index 7e07148a..00000000 --- a/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_CustomExpDateOutputConfig.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "test_data":[ - { - "monthFieldName":"month", - "dayFieldName":"day", - "yearFieldName":"year", - "fieldValue":"2030-/-01-/-15", - "expectedResult":{ - "month":"01", - "day":"15", - "year":"2030" - }, - "comment":"Single key fieldNames." - }, - { - "monthFieldName":"date.month", - "dayFieldName":"date.day", - "yearFieldName":"date.year", - "fieldValue":"2033-/-10-/-18", - "expectedResult":{ - "date":{ - "month":"10", - "day":"18", - "year":"2033" - } - }, - "comment":"Map to dot JSON" - }, - { - "monthFieldName":"date.month", - "dayFieldName":"day", - "yearFieldName":"year", - "fieldValue":"2025-/-05-/-25", - "expectedResult":{ - "date":{ - "month":"05" - }, - "day":"25", - "year":"2025" - }, - "comment":"Map to dot JSON with single key" - } - ] -} \ No newline at end of file diff --git a/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_DefaultConfig.json b/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_DefaultConfig.json deleted file mode 100644 index 2e0e4613..00000000 --- a/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_DefaultConfig.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "test_data":[ - { - "monthFieldName":"month", - "dayFieldName":"day", - "yearFieldName":"year", - "fieldValue":"01/02/2030", - "expectedResult":{ - "month":"01", - "day":"02", - "year":"2030" - }, - "comment":"Single key fieldNames." - }, - { - "monthFieldName":"date.month", - "dayFieldName":"date.day", - "yearFieldName":"date.year", - "fieldValue":"10/02/2033", - "expectedResult":{ - "date":{ - "month":"10", - "day":"02", - "year":"2033" - } - }, - "comment":"Map to dot JSON" - }, - { - "monthFieldName":"date.month", - "dayFieldName":"day", - "yearFieldName":"year", - "fieldValue":"05/15/2025", - "expectedResult":{ - "date":{ - "month":"05" - }, - "day":"15", - "year":"2025" - }, - "comment":"Map to dot JSON with single key" - } - ] -} \ No newline at end of file diff --git a/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_MapWithArrayMerge.json b/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_MapWithArrayMerge.json deleted file mode 100644 index 6ea8d9b7..00000000 --- a/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_MapWithArrayMerge.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "test_data":[ - { - "monthFieldName":"card_data[0].month", - "dayFieldName":"card_data[0].day", - "yearFieldName":"card_data[0].year", - "fieldValue":"01/30/2020", - "expectedResult":{ - "card_data":[ - { - "user_id":"123", - "month":"01", - "day":"30", - "year":"2020" - } - ] - }, - "comment":"Map to array with JSON." - }, - { - "monthFieldName":"card_data[1].month", - "dayFieldName":"card_data[1].day", - "yearFieldName":"card_data[1].year", - "fieldValue":"01/30/2020", - "expectedResult":{ - "card_data":[ - { - "user_id":"123" - }, - { - "month":"01", - "day":"30", - "year":"2020" - } - ] - }, - "comment":"Map to array with JSON adjusting array capacity." - }, - { - "monthFieldName":"card_data[2]", - "dayFieldName":"card_data[3]", - "yearFieldName":"card_data[4]", - "fieldValue":"01/30/2020", - "expectedResult":{ - "card_data":[ - { - "user_id":"123" - }, - null, - "01", - "30", - "2020" - ] - }, - "comment":"Map to array with primitive values and adjusting array capacity." - }, - { - "monthFieldName":"card_data.month", - "dayFieldName":"card_data.day", - "yearFieldName":"card_data.year", - "fieldValue":"10/30/2020", - "expectedResult":{ - "card_data":{ - "month":"10", - "day":"30", - "year":"2020" - } - }, - "comment":"Map to nested JSON. Merge fieldData as JSON with more priority as extra data array." - } - ] -} \ No newline at end of file diff --git a/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_MapWithArrayOverwrite.json b/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_MapWithArrayOverwrite.json deleted file mode 100644 index 50532ab9..00000000 --- a/Tests/FrameworkTests/Resources/DateSplitSerializerTestJSONs/VGSDateSerialization_MapWithArrayOverwrite.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "test_data":[ - { - "monthFieldName":"card_data[0].month", - "dayFieldName":"card_data[0].day", - "yearFieldName":"card_data[0].year", - "fieldValue":"01/30/2020", - "expectedResult":{ - "card_data":[ - { - "month":"01", - "day":"30", - "year":"2020" - } - ] - }, - "comment":"Map to array with JSON." - }, - { - "monthFieldName":"card_data[1].month", - "dayFieldName":"card_data[1].day", - "yearFieldName":"card_data[1].year", - "fieldValue":"01/30/2020", - "expectedResult":{ - "card_data":[ - null, - { - "month":"01", - "day":"30", - "year":"2020" - } - ] - }, - "comment":"Map to array with JSON adjusting array capacity." - }, - { - "monthFieldName":"card_data[0].month", - "dayFieldName":"card_data[0].day", - "yearFieldName":"card_data[0].year", - "fieldValue":"01/12/2035", - "expectedResult":{ - "card_data":[ - { - "month":"01", - "day":"12", - "year":"2035" - } - ] - }, - "comment":"Map to nested JSON." - } - ] -} \ No newline at end of file diff --git a/Tests/FrameworkTests/Resources/DateTokenizationJSON/VGSDateTokenizationSerialization_DefaultConfig.json b/Tests/FrameworkTests/Resources/DateTokenizationJSON/VGSDateTokenizationSerialization_DefaultConfig.json deleted file mode 100644 index 2e95ea84..00000000 --- a/Tests/FrameworkTests/Resources/DateTokenizationJSON/VGSDateTokenizationSerialization_DefaultConfig.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "test_data":[ - { - "monthFieldName":"month", - "dayFieldName":"day", - "yearFieldName":"year", - "fieldValue":"04/26/2016", - "outputFormat":"mmddyyyy", - "expectedResult":{ - "data":[ - { - "format":"UUID", - "value":"04", - "storage":"PERSISTENT" - }, - { - "format":"UUID", - "value":"26", - "storage":"PERSISTENT" - }, - { - "value":"2016", - "storage":"PERSISTENT", - "format":"UUID" - } - ] - }, - "comment":"Serialized date mmddyyyy." - }, - { - "monthFieldName":"month", - "dayFieldName":"day", - "yearFieldName":"year", - "fieldValue":"04/26/2016", - "outputFormat":"ddmmyyyy", - "expectedResult":{ - "data":[ - { - "format":"UUID", - "value":"04", - "storage":"PERSISTENT" - }, - { - "format":"UUID", - "value":"26", - "storage":"PERSISTENT" - }, - { - "value":"2016", - "storage":"PERSISTENT", - "format":"UUID" - } - ] - }, - "comment":"Serialized date ddmmyyyy." - }, - { - "monthFieldName":"month", - "dayFieldName":"day", - "yearFieldName":"year", - "fieldValue":"04/26/2016", - "outputFormat":"yyyymmdd", - "expectedResult":{ - "data":[ - { - "format":"UUID", - "value":"04", - "storage":"PERSISTENT" - }, - { - "format":"UUID", - "value":"26", - "storage":"PERSISTENT" - }, - { - "value":"2016", - "storage":"PERSISTENT", - "format":"UUID" - } - ] - }, - "comment":"Serialized date yyyymmdd." - } - ] -} diff --git a/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/DateTextFieldTest.swift b/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/DateTextFieldTest.swift deleted file mode 100644 index 8b48fb37..00000000 --- a/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/DateTextFieldTest.swift +++ /dev/null @@ -1,225 +0,0 @@ -// -// DateTextField.swift -// VGSCollectSDK -// - -import XCTest -@testable import VGSCollectSDK - -class DateTextFieldTest: VGSCollectBaseTestCase { - - // MARK: - Properties - private var collector: VGSCollect! - private var textField: VGSDateTextField! - - // MARK: - Overrides - override func setUp() { - super.setUp() - - collector = VGSCollect(id: "any") - textField = VGSDateTextField() - - let config = VGSConfiguration(collector: collector, fieldName: "textField") - config.formatPattern = VGSDateFormat.default.formatPattern - textField.configuration = config - } - - override func tearDown() { - collector = nil - textField = nil - } - - // MARK: - Tests - /// Test when different month formats are selected - func testMonthFormat() { - /// Define the first month `January` for each month format - let firstLongAr = "يناير" - var validLongMonth = "January" - var validShortMonth = "Jan" - - /// For Arabic long and short month is the same. - if Locale.current.languageCode == "ar" { - validLongMonth = firstLongAr - validShortMonth = firstLongAr - } - - /// Asserts - textField.monthPickerFormat = .longSymbols - XCTAssertEqual(textField.monthsDataSource.first, validLongMonth) - textField.monthPickerFormat = .shortSymbols - XCTAssertEqual(textField.monthsDataSource.first, validShortMonth) - textField.monthPickerFormat = .numbers - XCTAssertEqual(textField.monthsDataSource.last, "12") - } - - /// Test when a valid date is selected using the default start and end date range - func testSelectDateWithDefaultDateRange() { - /// Select month - let monthSelected = 0 - textField.picker.selectRow(monthSelected, inComponent: 0, animated: false) - textField.pickerView(textField.picker, didSelectRow: monthSelected, inComponent: 0) - - /// Select day - let daySelected = 8 - textField.picker.selectRow(daySelected, inComponent: 1, animated: false) - textField.pickerView(textField.picker, didSelectRow: daySelected, inComponent: 1) - - /// Select year - let yearSelected = 61 - textField.picker.selectRow(yearSelected, inComponent: 2, animated: false) - textField.pickerView(textField.picker, didSelectRow: yearSelected, inComponent: 2) - - /// Get selected date - let currentValue = textField.textField.secureText - let monthComponent = currentValue?.components(separatedBy: "-").first ?? "0" - let dayComponent = currentValue?.components(separatedBy: "-")[1] ?? "0" - let yearComponent = currentValue?.components(separatedBy: "-").last ?? "0" - - /// Asserts: Validate the selected date is correct - XCTAssertEqual(Int(monthComponent), monthSelected + 1) - XCTAssertEqual(Int(dayComponent), daySelected + 1) - XCTAssertEqual(Int(yearComponent), (Calendar.currentYear - VGSDateConfiguration.validYearsCount) + yearSelected) - } - - /// Test when an invalid date is selected using the default start and end date range - func testSelectWrongDateWithDefaultDateRange() { - /// Select month - let monthSelected = 0 - textField.picker.selectRow(monthSelected, inComponent: 0, animated: false) - textField.pickerView(textField.picker, didSelectRow: monthSelected, inComponent: 0) - - /// Select day - let daySelected = 8 - textField.picker.selectRow(daySelected, inComponent: 1, animated: false) - textField.pickerView(textField.picker, didSelectRow: daySelected, inComponent: 1) - - /// Select invalid year, outside valid default range - let yearSelected = VGSDateConfiguration.validYearsCount * 3 - textField.picker.selectRow(yearSelected, inComponent: 2, animated: false) - textField.pickerView(textField.picker, didSelectRow: yearSelected, inComponent: 2) - - /// Get selected date - let currentValue = textField.textField.secureText - let monthComponent = currentValue?.components(separatedBy: "-").first ?? "0" - let dayComponent = currentValue?.components(separatedBy: "-")[1] ?? "0" - let yearComponent = currentValue?.components(separatedBy: "-").last ?? "0" - - /// Asserts: Selecting invalid day, month or year should be ignored - XCTAssertEqual(Int(monthComponent), monthSelected + 1) - XCTAssertEqual(Int(dayComponent), daySelected + 1) - XCTAssertEqual(Int(yearComponent), Calendar.currentYear - VGSDateConfiguration.validYearsCount) - } - - /// Test when a valid date is selected with a configuration that has custom start and end dates - func testSelectDateWithCustomDateRange() { - /// Define custom dates - let startDate = VGSDate(day: 1, month: 1, year: 2000)! - let endDate = VGSDate(day: 1, month: 1, year: 2030)! - - /// Setup custom configuration - let customConfig = VGSDateConfiguration( - collector: collector, - fieldName: "textField", - datePickerStartDate: startDate, - datePickerEndDate: endDate - ) - textField.configuration = customConfig - - /// Select month - let monthSelected = 6 - textField.picker.selectRow(monthSelected, inComponent: 0, animated: false) - textField.pickerView(textField.picker, didSelectRow: monthSelected, inComponent: 0) - - /// Select day - let daySelected = 15 - textField.picker.selectRow(daySelected, inComponent: 1, animated: false) - textField.pickerView(textField.picker, didSelectRow: daySelected, inComponent: 1) - - /// Select year, exactly the middle between start and end dates - let yearSelected = (endDate.year - startDate.year) / 2 - textField.picker.selectRow(yearSelected, inComponent: 2, animated: false) - textField.pickerView(textField.picker, didSelectRow: yearSelected, inComponent: 2) - - /// Get current date - let currentValue = textField.textField.secureText - let monthComponent = currentValue?.components(separatedBy: "-").first ?? "0" - let dayComponent = currentValue?.components(separatedBy: "-")[1] ?? "0" - let yearComponent = currentValue?.components(separatedBy: "-").last ?? "0" - - /// Asserts: The selected year should be the same selected in the textField - XCTAssertEqual(Int(monthComponent), monthSelected + 1) - XCTAssertEqual(Int(dayComponent), daySelected + 1) - XCTAssertEqual(Int(yearComponent), startDate.year + yearSelected) - XCTAssertEqual(Int(yearComponent), endDate.year - yearSelected) - } - - /// Test when an invalid date is selected with a configuration that has custom start and end dates - func testSelectWrongDateWithCustomDateRange() { - /// Define custom dates - let startDate = VGSDate(day: 1, month: 1, year: 2000)! - let endDate = VGSDate(day: 1, month: 1, year: 2030)! - - /// Setup custom configuration - let customConfig = VGSDateConfiguration( - collector: collector, - fieldName: "textField", - datePickerStartDate: startDate, - datePickerEndDate: endDate - ) - textField.configuration = customConfig - - /// Select month - let monthSelected = 6 - textField.picker.selectRow(monthSelected, inComponent: 0, animated: false) - textField.pickerView(textField.picker, didSelectRow: monthSelected, inComponent: 0) - - /// Select invalid day, outside the custom range - let daySelected = 50 - textField.picker.selectRow(daySelected, inComponent: 1, animated: false) - textField.pickerView(textField.picker, didSelectRow: daySelected, inComponent: 1) - - /// Select year - let yearSelected = 5 - textField.picker.selectRow(yearSelected, inComponent: 2, animated: false) - textField.pickerView(textField.picker, didSelectRow: yearSelected, inComponent: 2) - - /// Get current date - let currentValue = textField.textField.secureText - let monthComponent = currentValue?.components(separatedBy: "-").first ?? "0" - let dayComponent = currentValue?.components(separatedBy: "-")[1] ?? "0" - let yearComponent = currentValue?.components(separatedBy: "-").last ?? "0" - - /// Asserts: Selecting invalid day, month or year should be ignored - XCTAssertEqual(Int(monthComponent), monthSelected + 1) - XCTAssertEqual(Int(dayComponent), 1) - XCTAssertEqual(Int(yearComponent), startDate.year + yearSelected) - } - - /// Test when the keyboard configuration is selected in the configuration - func testDateKeyboardConfiguration() { - /// Setup custom configuration with keyboard - let customConfig = VGSDateConfiguration(collector: collector, fieldName: "textField") - customConfig.inputSource = .keyboard - customConfig.keyboardType = .namePhonePad - customConfig.returnKeyType = .go - customConfig.keyboardAppearance = .dark - textField.configuration = customConfig - - /// Asserts - XCTAssertTrue(textField.textField.keyboardType == customConfig.keyboardType, "Wrong keyboardType!") - XCTAssertTrue(textField.textField.returnKeyType == customConfig.returnKeyType, "Wrong returnKeyType!") - XCTAssertTrue(textField.textField.keyboardAppearance == customConfig.keyboardAppearance, "Wrong keyboardAppearance!") - } - - /// Test when the picker configuration is selected in the configuration - func testDateDatePickerConfiguration() { - /// Setup custom configuration with date picker - let customConfig = VGSDateConfiguration(collector: collector, fieldName: "textField") - customConfig.inputSource = .datePicker - textField.configuration = customConfig - - /// Asserts - XCTAssertTrue(textField.textField.inputView != nil, "Date picker not set!") - XCTAssertTrue(textField.textField.inputView is UIPickerView, "Wrong date picker view!") - } -} diff --git a/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/VGSDateFormatTests.swift b/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/VGSDateFormatTests.swift deleted file mode 100644 index 6d7faec8..00000000 --- a/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/VGSDateFormatTests.swift +++ /dev/null @@ -1,178 +0,0 @@ -// -// VGSDateFormatTests.swift -// FrameworkTests -// - -import XCTest -@testable import VGSCollectSDK - -class VGSDateFormatTests: VGSCollectBaseTestCase { - - // MARK: - Tests - /// Test date format initialization - func testDateFormatInitialization() { - /// Date format mmddyyyy - let mmddyyyyFormat = VGSDateFormat(name: "mmddyyyy") - XCTAssertEqual(mmddyyyyFormat, .mmddyyyy) - - /// Date format ddmmyyyy - let ddmmyyyyFormat = VGSDateFormat(name: "ddmmyyyy") - XCTAssertEqual(ddmmyyyyFormat, .ddmmyyyy) - - /// Date format yyyymmdd - let yyyymmddFormat = VGSDateFormat(name: "yyyymmdd") - XCTAssertEqual(yyyymmddFormat, .yyyymmdd) - - /// Invalid format - let invalidFormat = VGSDateFormat(name: "any") - XCTAssertNil(invalidFormat) - } - - /// Test the amount of expected characters for each part of the date - func testAmountOfCharacters() { - /// Expected values - let expectedDays = 2 - let expectedMonths = 2 - let expectedYears = 4 - let expectedDivider = 2 - - /// Days - XCTAssertEqual(VGSDateFormat.mmddyyyy.daysCharacters, expectedDays) - XCTAssertEqual(VGSDateFormat.ddmmyyyy.daysCharacters, expectedDays) - XCTAssertEqual(VGSDateFormat.yyyymmdd.daysCharacters, expectedDays) - - /// Months - XCTAssertEqual(VGSDateFormat.mmddyyyy.monthCharacters, expectedMonths) - XCTAssertEqual(VGSDateFormat.ddmmyyyy.monthCharacters, expectedMonths) - XCTAssertEqual(VGSDateFormat.yyyymmdd.monthCharacters, expectedMonths) - - /// Years - XCTAssertEqual(VGSDateFormat.mmddyyyy.yearCharacters, expectedYears) - XCTAssertEqual(VGSDateFormat.ddmmyyyy.yearCharacters, expectedYears) - XCTAssertEqual(VGSDateFormat.yyyymmdd.yearCharacters, expectedYears) - - /// Divider - XCTAssertEqual(VGSDateFormat.mmddyyyy.dividerCharacters, expectedDivider) - XCTAssertEqual(VGSDateFormat.ddmmyyyy.dividerCharacters, expectedDivider) - XCTAssertEqual(VGSDateFormat.yyyymmdd.dividerCharacters, expectedDivider) - } - - /// Test when the map picker data is formatted - func testMapDatePickerDataForFieldFormat() { - /// Expected date - let date = VGSDate(day: 2, month: 5, year: 2016)! - - /// mmddyyyy - XCTAssertEqual(VGSDateFormat.mmddyyyy.mapDatePickerDataForFieldFormat(date), "05022016") - - /// ddmmyyyy - XCTAssertEqual(VGSDateFormat.ddmmyyyy.mapDatePickerDataForFieldFormat(date), "02052016") - - /// yyyymmdd - XCTAssertEqual(VGSDateFormat.yyyymmdd.mapDatePickerDataForFieldFormat(date), "20160502") - } - - /// Test when the format date is called - func testFormatDate() { - /// Expected date - let date = VGSDate(day: 2, month: 5, year: 2016)! - - /// Divider A - var divider = "_" - XCTAssertEqual(VGSDateFormat.mmddyyyy.formatDate(date, divider: divider), "05\(divider)02\(divider)2016") - XCTAssertEqual(VGSDateFormat.ddmmyyyy.formatDate(date, divider: divider), "02\(divider)05\(divider)2016") - XCTAssertEqual(VGSDateFormat.yyyymmdd.formatDate(date, divider: divider), "2016\(divider)05\(divider)02") - - /// Divider B - divider = "+_+" - XCTAssertEqual(VGSDateFormat.mmddyyyy.formatDate(date, divider: divider), "05\(divider)02\(divider)2016") - XCTAssertEqual(VGSDateFormat.ddmmyyyy.formatDate(date, divider: divider), "02\(divider)05\(divider)2016") - XCTAssertEqual(VGSDateFormat.yyyymmdd.formatDate(date, divider: divider), "2016\(divider)05\(divider)02") - - /// Divider C - divider = "/" - XCTAssertEqual(VGSDateFormat.mmddyyyy.formatDate(date, divider: divider), "05\(divider)02\(divider)2016") - XCTAssertEqual(VGSDateFormat.ddmmyyyy.formatDate(date, divider: divider), "02\(divider)05\(divider)2016") - XCTAssertEqual(VGSDateFormat.yyyymmdd.formatDate(date, divider: divider), "2016\(divider)05\(divider)02") - - /// Divider C - divider = "..." - XCTAssertEqual(VGSDateFormat.mmddyyyy.formatDate(date, divider: divider), "05\(divider)02\(divider)2016") - XCTAssertEqual(VGSDateFormat.ddmmyyyy.formatDate(date, divider: divider), "02\(divider)05\(divider)2016") - XCTAssertEqual(VGSDateFormat.yyyymmdd.formatDate(date, divider: divider), "2016\(divider)05\(divider)02") - } - - /// Test when a date is created from an input string - func testDateFromInput() { - /// Expected date - let date = VGSDate(day: 2, month: 5, year: 2016)! - - /// mmddyyyy - XCTAssertEqual(VGSDateFormat.mmddyyyy.dateFromInput("05022016"), date) - - /// ddmmyyyy - XCTAssertEqual(VGSDateFormat.ddmmyyyy.dateFromInput("02052016"), date) - - /// yyyymmdd - XCTAssertEqual(VGSDateFormat.yyyymmdd.dateFromInput("20160502"), date) - - /// Invalid input - XCTAssertNil(VGSDateFormat.mmddyyyy.dateFromInput("any")) - } - - /// Test the display format - func testDisplayFormat() { - /// mmddyyyy - XCTAssertEqual(VGSDateFormat.mmddyyyy.displayFormat, "mm-dd-yyyy") - - /// ddmmyyyy - XCTAssertEqual(VGSDateFormat.ddmmyyyy.displayFormat, "dd-mm-yyyy") - - /// yyyymmdd - XCTAssertEqual(VGSDateFormat.yyyymmdd.displayFormat, "yyyy-mm-dd") - } - - /// Test format pattern - func testFormatPattern() { - /// mmddyyyy - XCTAssertEqual(VGSDateFormat.mmddyyyy.formatPattern, "##-##-####") - - /// ddmmyyyy - XCTAssertEqual(VGSDateFormat.ddmmyyyy.formatPattern, "##-##-####") - - /// yyyymmdd - XCTAssertEqual(VGSDateFormat.yyyymmdd.formatPattern, "####-##-##") - } - - /// Test to get the divider in an input date string - func testDividerInInput() { - /// Divider A - var divider = "_" - XCTAssertEqual(VGSDateFormat.dividerInInput("05\(divider)02\(divider)2016"), divider) - XCTAssertEqual(VGSDateFormat.dividerInInput("02\(divider)05\(divider)2016"), divider) - XCTAssertEqual(VGSDateFormat.dividerInInput("2016\(divider)05\(divider)02"), divider) - - /// Divider B - divider = "+_+" - XCTAssertEqual(VGSDateFormat.dividerInInput("05\(divider)02\(divider)2016"), divider) - XCTAssertEqual(VGSDateFormat.dividerInInput("02\(divider)05\(divider)2016"), divider) - XCTAssertEqual(VGSDateFormat.dividerInInput("2016\(divider)05\(divider)02"), divider) - - /// Divider C - divider = "/" - XCTAssertEqual(VGSDateFormat.dividerInInput("05\(divider)02\(divider)2016"), divider) - XCTAssertEqual(VGSDateFormat.dividerInInput("02\(divider)05\(divider)2016"), divider) - XCTAssertEqual(VGSDateFormat.dividerInInput("2016\(divider)05\(divider)02"), divider) - - /// Divider C - divider = "..." - XCTAssertEqual(VGSDateFormat.dividerInInput("05\(divider)02\(divider)2016"), divider) - XCTAssertEqual(VGSDateFormat.dividerInInput("02\(divider)05\(divider)2016"), divider) - XCTAssertEqual(VGSDateFormat.dividerInInput("2016\(divider)05\(divider)02"), divider) - - /// Invalid input - XCTAssertEqual(VGSDateFormat.dividerInInput("05|02-2016"), "") - XCTAssertEqual(VGSDateFormat.dividerInInput("05-02*2016"), "") - XCTAssertEqual(VGSDateFormat.dividerInInput("05-..-022016"), "") - } -} diff --git a/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/ValidationRuleDateTests.swift b/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/ValidationRuleDateTests.swift deleted file mode 100644 index 736adccd..00000000 --- a/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/ValidationRuleDateTests.swift +++ /dev/null @@ -1,204 +0,0 @@ -// -// ValidationRuleDateTests.swift -// FrameworkTests -// - -import XCTest -@testable import VGSCollectSDK - -class ValidationRuleDateTests: VGSCollectBaseTestCase { - - // MARK: - Constants - /// Default error - private let error = "date_error" - - // MARK: - Properties - private var collector: VGSCollect! - private var textField: VGSTextField! - private var config: VGSConfiguration! - - // MARK: - Overrides - override func setUp() { - super.setUp() - - collector = VGSCollect(id: "any") - textField = VGSTextField() - config = VGSConfiguration(collector: collector, fieldName: "test_field") - config.type = .date - } - - override func tearDown() { - collector = nil - textField = nil - config = nil - } - - // MARK: - Tests - /// Test date validation rule with default configuration - func testDateRule() { - /// Test validation success - textField.configuration = config - textField.textField.secureText = "10102004" - XCTAssertTrue(textField.state.isValid) - XCTAssertEqual(textField.state.validationErrors.count, 0) - - /// Test invalid format - textField.textField.secureText = "102024" - XCTAssertFalse(textField.state.isValid) - XCTAssertEqual(textField.state.validationErrors.count, 1) - - /// Test invalid date, in this case month is `50` - textField.textField.secureText = "50012024" - XCTAssertFalse(textField.state.isValid) - XCTAssertEqual(textField.state.validationErrors.count, 1) - } - - /// Test each of the date formats - func testRuleDateFormats() { - /// Use `ddmmyyy` format - config.validationRules = VGSValidationRuleSet(rules: [ - VGSValidationRuleDateRange( - dateFormat: .ddmmyyyy, - error: error - ) - ]) - - /// Test validation success - textField.configuration = config - textField.textField.secureText = "20111984" - XCTAssertTrue(textField.state.isValid) - XCTAssertEqual(textField.state.validationErrors.count, 0) - - /// Test validation fails - textField.configuration = config - textField.textField.secureText = "19841120" - XCTAssertFalse(textField.state.isValid) - XCTAssertEqual(textField.state.validationErrors.count, 1) - - /// Use `mmddyyyy` format - config.validationRules = VGSValidationRuleSet(rules: [ - VGSValidationRuleDateRange( - dateFormat: .mmddyyyy, - error: error - ) - ]) - - // Test validation success - textField.configuration = config - textField.textField.secureText = "11201984" - XCTAssertTrue(textField.state.isValid) - XCTAssertEqual(textField.state.validationErrors.count, 0) - - /// Test validation fails - textField.configuration = config - textField.textField.secureText = "19842011" - XCTAssertFalse(textField.state.isValid) - XCTAssertEqual(textField.state.validationErrors.count, 1) - - /// Use `yyyymmdd` format - config.validationRules = VGSValidationRuleSet(rules: [ - VGSValidationRuleDateRange( - dateFormat: .yyyymmdd, - error: error - ) - ]) - - // Test validation success - textField.configuration = config - textField.textField.secureText = "19841120" - XCTAssertTrue(textField.state.isValid) - XCTAssertEqual(textField.state.validationErrors.count, 0) - - /// Test validation fails - textField.configuration = config - textField.textField.secureText = "20111984" - XCTAssertFalse(textField.state.isValid) - XCTAssertEqual(textField.state.validationErrors.count, 1) - } - - /// Test when start date and end date are set - func testRuleWithStartAndEndDate() { - /// Setup start and end dates - let startDate = VGSDate(day: 10, month: 11, year: 2015) - let endDate = VGSDate(day: 08, month: 12, year: 2030) - - /// Use default format - config.validationRules = VGSValidationRuleSet(rules: [ - VGSValidationRuleDateRange( - error: error, - start: startDate, - end: endDate - ) - ]) - - /// Test validation success - textField.configuration = config - textField.textField.secureText = "10122020" - XCTAssertTrue(textField.state.isValid) - XCTAssertEqual(textField.state.validationErrors.count, 0) - - /// Test validation fails, date before start date - textField.configuration = config - textField.textField.secureText = "1012215" - XCTAssertFalse(textField.state.isValid) - XCTAssertEqual(textField.state.validationErrors.count, 1) - - /// Test validation fails, date after end date - textField.configuration = config - textField.textField.secureText = "12102030" - XCTAssertFalse(textField.state.isValid) - XCTAssertEqual(textField.state.validationErrors.count, 1) - } - - /// Test when only start date is set - func testRuleWithStartDate() { - /// Setup start date - let startDate = VGSDate(day: 10, month: 11, year: 2015) - - /// Use default format - config.validationRules = VGSValidationRuleSet(rules: [ - VGSValidationRuleDateRange( - error: error, - start: startDate - ) - ]) - - /// Test validation success - textField.configuration = config - textField.textField.secureText = "10122020" - XCTAssertTrue(textField.state.isValid) - XCTAssertEqual(textField.state.validationErrors.count, 0) - - /// Test validation fails, date before start date - textField.configuration = config - textField.textField.secureText = "1012215" - XCTAssertFalse(textField.state.isValid) - XCTAssertEqual(textField.state.validationErrors.count, 1) - } - - /// Test when only end date is set - func testRuleWithEndDate() { - /// Setup end date - let endDate = VGSDate(day: 08, month: 12, year: 2030) - - /// Use default format - config.validationRules = VGSValidationRuleSet(rules: [ - VGSValidationRuleDateRange( - error: error, - end: endDate - ) - ]) - - /// Test validation success - textField.configuration = config - textField.textField.secureText = "10122020" - XCTAssertTrue(textField.state.isValid) - XCTAssertEqual(textField.state.validationErrors.count, 0) - - /// Test validation fails, date after end date - textField.configuration = config - textField.textField.secureText = "12102030" - XCTAssertFalse(textField.state.isValid) - XCTAssertEqual(textField.state.validationErrors.count, 1) - } -} diff --git a/Tests/FrameworkTests/SerializersTest/SerializersDataProvider.swift b/Tests/FrameworkTests/SerializersTest/SerializersDataProvider.swift deleted file mode 100644 index 1baa750b..00000000 --- a/Tests/FrameworkTests/SerializersTest/SerializersDataProvider.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// SerializersDataProvider.swift -// FrameworkTests -// - -import XCTest -@testable import VGSCollectSDK - -/// Define the methods required to parse test JSON data -protocol TestJSONDataProtocol { - init?(json: JsonData) -} - -/// Class with the methods required to read and parse JSON files for testing -final class SerializersDataProvider { - - /// Method that reads and parse `JSON` file with data for testing. It define an abstract - /// parameter that must implement the `TestJSONDataProtocol` - /// - /// - Parameters: - /// - fileName: `String` with the name of the `JSON` file to read the data from. - /// - rootName: `String` with the name of the root node of the `JSON` file, by defaul it is defined as `test_data` - static func provideTestData(for fileName: String, rootNodeName: String = "test_data") -> [T] { - /// Read json data from file - guard let rootTestJSON = JsonData(jsonFileName: fileName) else { - XCTFail("Cannot build data for file \(fileName)") - return [] - } - - /// Get root node - guard let testDataJSONArray = rootTestJSON[rootNodeName] as? [JsonData] else { - XCTFail("\(rootNodeName) JSON array not found in \(fileName)") - return [] - } - - /// Parse test data - var testData = [T]() - for json in testDataJSONArray { - if let testItem = T(json: json) { - testData.append(testItem) - } else { - XCTFail("Cannot build test data for JSON: \(json)") - } - } - return testData - } -} diff --git a/Tests/FrameworkTests/SerializersTest/VGSDateSeparateSerializerTests.swift b/Tests/FrameworkTests/SerializersTest/VGSDateSeparateSerializerTests.swift deleted file mode 100644 index 663a0e4b..00000000 --- a/Tests/FrameworkTests/SerializersTest/VGSDateSeparateSerializerTests.swift +++ /dev/null @@ -1,256 +0,0 @@ -// -// VGSDateSeparateSerializerTests.swift -// FrameworkTests -// - -import XCTest -@testable import VGSCollectSDK - -class VGSDateSeparateSerializerTests: VGSCollectBaseTestCase { - - // MARK: - Properties - private var collector: VGSCollect! - private var textField: VGSDateTextField! - - // MARK: - Inner objects - /// Define the file names with JSON data for testing - private enum TestFlow { - case defaultConfig - case customConfig - case customExpDateOutputConfig - case mapWithArrayOverwrite - case mapWithArrayMerge - - /// Name of the JSON file - var jsonFileName: String { - return "VGSDateSerialization_" + jsonFileNameSuffix - } - - /// JSON file name - private var jsonFileNameSuffix: String { - switch self { - case .defaultConfig: - return "DefaultConfig" - case .customConfig: - return "CustomConfig" - case .customExpDateOutputConfig: - return "CustomExpDateOutputConfig" - case .mapWithArrayOverwrite: - return "MapWithArrayOverwrite" - case .mapWithArrayMerge: - return "MapWithArrayMerge" - } - } - } - - /// Store the JSON data for testing - private struct TestJSONData: TestJSONDataProtocol { - - // MARK: - Properties - let fieldValue: String - let monthFieldName: String - let dayFieldName: String - let yearFieldName: String - let submitJSON: JsonData - - /// Initializer - init?(json: JsonData) { - guard let submitJSON = json["expectedResult"] as? JsonData else { - XCTFail("Cannot parse test data.") - return nil - } - self.fieldValue = json["fieldValue"] as? String ?? "" - self.monthFieldName = json["monthFieldName"] as? String ?? "" - self.dayFieldName = json["dayFieldName"] as? String ?? "" - self.yearFieldName = json["yearFieldName"] as? String ?? "" - self.submitJSON = submitJSON - } - } - - // MARK: - Overrides - override func setUp() { - super.setUp() - - collector = VGSCollect(id: "any") - textField = VGSDateTextField() - } - - override func tearDown() { - collector = nil - textField = nil - } - - // MARK: - Tests - /// Test default configuration - func testSplitDateSerializerWithDefaultConfig() { - /// Get JSON test data - let fileName = TestFlow.defaultConfig.jsonFileName - let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) - - /// Prepare configuration - let config = VGSDateConfiguration(collector: collector, fieldName: "date") - config.formatPattern = VGSDateFormat.default.formatPattern - - /// Run test for each case from JSON - for test in testData { - /// Prepare serializer - config.serializers = [ - VGSDateSeparateSerializer( - dayFieldName: test.dayFieldName, - monthFieldName: test.monthFieldName, - yearFieldName: test.yearFieldName - ) - ] - /// Update configuration - textField.configuration = config - /// Setup test value - textField.setText(test.fieldValue) - /// Get JSON from collector using serializer - let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSON, extraData: nil) - /// Assert: Test JSON content should be equals to the JSON from the collector - XCTAssertTrue(NSDictionary(dictionary: submitJSON).isEqual(to: test.submitJSON)) - } - } - - /// Test custom configuration - func testSplitDateSerializerWithCustomConfig() { - /// Get JSON test data - let fileName = TestFlow.customConfig.jsonFileName - let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) - - /// Prepare configuration - let config = VGSDateConfiguration(collector: collector, fieldName: "card.date") - config.formatPattern = VGSDateFormat.default.formatPattern - config.inputDateFormat = .yyyymmdd - config.outputDateFormat = .ddmmyyyy - config.divider = "-/-" - - /// Run test for each case from JSON - for test in testData { - /// Prepare serializer - config.serializers = [ - VGSDateSeparateSerializer( - dayFieldName: test.dayFieldName, - monthFieldName: test.monthFieldName, - yearFieldName: test.yearFieldName - ) - ] - /// Update configuration - textField.configuration = config - /// Setup test value - textField.setText(test.fieldValue) - /// Get JSON from collector using serializer - let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSON, extraData: nil) - /// Assert: Test JSON content should be equals to the JSON from the collector - XCTAssertTrue(NSDictionary(dictionary: submitJSON).isEqual(to: test.submitJSON)) - } - } - - /// Test custom output format. - func testSplitCustomDateOutputSerializerWithCustomConfig() { - /// Get JSON test data - let fileName = TestFlow.customExpDateOutputConfig.jsonFileName - let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) - - /// Prepare configuration - let config = VGSDateConfiguration(collector: collector, fieldName: "card.date") - config.formatPattern = VGSDateFormat.default.formatPattern - config.inputDateFormat = .yyyymmdd - config.outputDateFormat = .ddmmyyyy - config.divider = "-/-" - - /// Run test for each case from JSON - for test in testData { - /// Prepare serializer - config.serializers = [ - VGSDateSeparateSerializer( - dayFieldName: test.dayFieldName, - monthFieldName: test.monthFieldName, - yearFieldName: test.yearFieldName - ) - ] - /// Update configuration - textField.configuration = config - /// Setup test value - textField.setText(test.fieldValue) - /// Get JSON from collector using serializer - let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSON, extraData: nil) - /// Assert: Test JSON content should be equals to the JSON from the collector - XCTAssertTrue(NSDictionary(dictionary: submitJSON).isEqual(to: test.submitJSON)) - } - } - - /// Test map with array merge. - func testSplitExpDateSerializersMapWithArray() { - /// Get JSON test data - let fileName = TestFlow.mapWithArrayMerge.jsonFileName - let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) - - /// Prepare configuration - let config = VGSDateConfiguration(collector: collector, fieldName: "date") - config.formatPattern = VGSDateFormat.default.formatPattern - config.inputDateFormat = .mmddyyyy - config.outputDateFormat = .mmddyyyy - config.divider = "/" - - /// Setup extra data - let extraData = ["card_data": [["user_id": "123"]]] - - /// Run test for each case from JSON - for test in testData { - /// Prepare serializer - config.serializers = [ - VGSDateSeparateSerializer( - dayFieldName: test.dayFieldName, - monthFieldName: test.monthFieldName, - yearFieldName: test.yearFieldName - ) - ] - /// Update configuration - textField.configuration = config - /// Setup test value - textField.setText(test.fieldValue) - /// Get JSON from collector using serializer - let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSONWithArrayMerge, extraData: extraData) - /// Assert: Test JSON content should be equals to the JSON from the collector - XCTAssertTrue(NSDictionary(dictionary: submitJSON).isEqual(to: test.submitJSON)) - } - } - - /// Test map with array overwrite. - func testSplitExpDateSerializersMapWithArrayOverwrite() { - /// Get JSON test data - let fileName = TestFlow.mapWithArrayOverwrite.jsonFileName - let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) - - /// Prepare configuration - let config = VGSDateConfiguration(collector: collector, fieldName: "date") - config.formatPattern = VGSDateFormat.default.formatPattern - config.inputDateFormat = .mmddyyyy - config.outputDateFormat = .mmddyyyy - config.divider = "/" - - /// Setup extra data - let extraData = ["card_data": [["month": "3", "year": "2033"]]] - - /// Run test for each case from JSON - for test in testData { - /// Prepare serializer - config.serializers = [ - VGSDateSeparateSerializer( - dayFieldName: test.dayFieldName, - monthFieldName: test.monthFieldName, - yearFieldName: test.yearFieldName - ) - ] - /// Update configuration - textField.configuration = config - /// Setup test value - textField.setText(test.fieldValue) - /// Get JSON from collector using serializer - let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSONWithArrayOverwrite, extraData: extraData) - /// Assert: Test JSON content should be equals to the JSON from the collector - XCTAssertTrue(NSDictionary(dictionary: submitJSON).isEqual(to: test.submitJSON)) - } - } -} diff --git a/Tests/FrameworkTests/SerializersTest/VGSDateTokenizationSerializerTests.swift b/Tests/FrameworkTests/SerializersTest/VGSDateTokenizationSerializerTests.swift deleted file mode 100644 index 75ffb216..00000000 --- a/Tests/FrameworkTests/SerializersTest/VGSDateTokenizationSerializerTests.swift +++ /dev/null @@ -1,135 +0,0 @@ -// -// VGSDateTokenizationSerializerTests.swift -// FrameworkTests -// - -import XCTest -@testable import VGSCollectSDK - -class VGSDateTokenizationSerializerTests: VGSCollectBaseTestCase { - - // MARK: - Properties - private var collector: VGSCollect! - private var textField: VGSDateTextField! - - // MARK: - Inner objects - /// Define the file names with JSON data for testing - private enum TestFlow { - case defaultConfig - - /// Name of the JSON file - var jsonFileName: String { - return "VGSDateTokenizationSerialization_" + jsonFileNameSuffix - } - - /// JSON file name - private var jsonFileNameSuffix: String { - switch self { - case .defaultConfig: - return "DefaultConfig" - } - } - } - - /// Store the JSON data for testing - private struct TestJSONData: TestJSONDataProtocol { - - // MARK: - Properties - let fieldValue: String - let monthFieldName: String - let dayFieldName: String - let yearFieldName: String - let submitJSON: JsonData - let outputFormat: VGSDateFormat - let comment: String - let tokenizedPayloads: [JsonData] - - /// Initializer - init?(json: JsonData) { - guard let submitJSON = json["expectedResult"] as? JsonData else { - XCTFail("Cannot parse test data.") - return nil - } - guard let formatName = json["outputFormat"] as? String, - let format = VGSDateFormat(name: formatName) else { - XCTFail("Cannot parse output format from test json") - return nil - } - self.fieldValue = json["fieldValue"] as? String ?? "" - self.monthFieldName = json["monthFieldName"] as? String ?? "" - self.dayFieldName = json["dayFieldName"] as? String ?? "" - self.yearFieldName = json["yearFieldName"] as? String ?? "" - self.submitJSON = submitJSON - self.outputFormat = format - self.comment = json["comment"] as? String ?? "" - guard let tokenizedPayloads = submitJSON["data"] as? [JsonData] else { - XCTFail("Invalid payload") - return nil - } - self.tokenizedPayloads = tokenizedPayloads - } - } - - // MARK: - Overrides - override func setUp() { - super.setUp() - - collector = VGSCollect(id: "any") - textField = VGSDateTextField() - } - - override func tearDown() { - collector = nil - textField = nil - } - - // MARK: - Tests - /// Test default configuration - func testSplitDateSerializerWithDefaultConfig() { - /// Get JSON test data - let fileName = TestFlow.defaultConfig.jsonFileName - let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) - - /// Prepare configuration - let config = VGSDateTokenizationConfiguration(collector: collector, fieldName: "date") - config.inputDateFormat = VGSDateFormat.default - config.formatPattern = VGSDateFormat.default.formatPattern - - /// Run test for each case from JSON - for test in testData { - /// Prepare serializer - config.serializers = [ - VGSDateSeparateSerializer( - dayFieldName: test.dayFieldName, - monthFieldName: test.monthFieldName, - yearFieldName: test.yearFieldName - ) - ] - config.outputDateFormat = test.outputFormat - /// Update configuration - textField.configuration = config - /// Setup test value - textField.setText(test.fieldValue) - /// Get JSON from collector using serializer - let submitJSON = collector.mapFieldsToTokenizationRequestBodyJSON(collector.textFields) - - /// Get payloads - guard let tokenizedPayloads = submitJSON["data"] as? [JsonData] else { - XCTFail("Cannot find tokenized data array.") - return - } - var matchedPayloads = 0 - /// mapFieldsToTokenizationRequestBodyJSON can produce array of tokenized data in different - /// order. So we need to iterate through payloads and check them one by one to get 3 matches - /// (one is for month, one for day and another one for year). - for payload in tokenizedPayloads { - for expectedPayload in test.tokenizedPayloads where payload == expectedPayload { - matchedPayloads += 1 - } - } - - /// Assert: Should be at least 3 matches of payloads - XCTAssertEqual(matchedPayloads, 3) - } - } -} diff --git a/Tests/FrameworkTests/SerializersTest/VGSExpDateSeparateSerializerTests.swift b/Tests/FrameworkTests/SerializersTest/VGSExpDateSeparateSerializerTests.swift index 554ce30e..0fb484be 100644 --- a/Tests/FrameworkTests/SerializersTest/VGSExpDateSeparateSerializerTests.swift +++ b/Tests/FrameworkTests/SerializersTest/VGSExpDateSeparateSerializerTests.swift @@ -11,242 +11,175 @@ import XCTest @testable import VGSCollectSDK class VGSExpDateSeparateSerializerTests: VGSCollectBaseTestCase { + var collector: VGSCollect! + var textField: VGSExpDateTextField! + + enum TestFlow { + case defaultConfiguration + case customConfiguration + case customExpDateOutputConfiguration + case mapWithArrayOverwrite + case mapWithArrayMerge + + var jsonFileName: String { + return "VGSExpDateSerialization_" + jsonFileNameSuffix + } + + var jsonFileNameSuffix: String { + switch self { + case .defaultConfiguration: + return "DefaultConfig" + case .customConfiguration: + return "CustomConfig" + case .customExpDateOutputConfiguration: + return "CustomExpDateOutputConfig" + case .mapWithArrayOverwrite: + return "MapWithArrayOverwrite" + case .mapWithArrayMerge: + return "MapWithArrayMerge" + } + } + } + + struct TestJSONData { + let fieldValue: String + let monthFieldName: String + let yearFieldName: String + let submitJSON: JsonData - // MARK: - Properties - private var collector: VGSCollect! - private var textField: VGSExpDateTextField! - - // MARK: - Inner objects - /// Define the file names with JSON data for testing - private enum TestFlow { - case defaultConfig - case customConfig - case customExpDateOutputConfig - case mapWithArrayOverwrite - case mapWithArrayMerge - - /// Name of the JSON file - var jsonFileName: String { - return "VGSExpDateSerialization_" + jsonFileNameSuffix - } - - /// JSON file name - var jsonFileNameSuffix: String { - switch self { - case .defaultConfig: - return "DefaultConfig" - case .customConfig: - return "CustomConfig" - case .customExpDateOutputConfig: - return "CustomExpDateOutputConfig" - case .mapWithArrayOverwrite: - return "MapWithArrayOverwrite" - case .mapWithArrayMerge: - return "MapWithArrayMerge" - } - } - } - - /// Store the JSON data for testing - private struct TestJSONData: TestJSONDataProtocol { - - // MARK: - Properties - let fieldValue: String - let monthFieldName: String - let yearFieldName: String - let submitJSON: JsonData - - /// Initializer - init?(json: JsonData) { - guard let submitJSON = json["expectedResult"] as? JsonData else { - XCTFail("Cannot parse test data.") - return nil - } - self.fieldValue = json["fieldValue"] as? String ?? "" - self.monthFieldName = json["monthFieldName"] as? String ?? "" - self.yearFieldName = json["yearFieldName"] as? String ?? "" - self.submitJSON = submitJSON - } - } - - // MARK: - Override - override func setUp() { - super.setUp() - - collector = VGSCollect(id: "any") - textField = VGSExpDateTextField() + init?(json: JsonData) { + guard let submitJSON = json["expectedResult"] as? JsonData else { + XCTFail("Cannot parse test data.") + return nil + } + self.fieldValue = json["fieldValue"] as? String ?? "" + self.monthFieldName = json["monthFieldName"] as? String ?? "" + self.yearFieldName = json["yearFieldName"] as? String ?? "" + self.submitJSON = submitJSON } + } + + // MARK: - Override + + override func setUp() { + super.setUp() + collector = VGSCollect(id: "any") + textField = VGSExpDateTextField() + } + + override func tearDown() { + collector = nil + textField = nil + } + + // MARK: - Tests + + /// Test default configuration. + func testSplitExpDateSerializerWithDefaultConfig() { + let fileName = TestFlow.defaultConfiguration.jsonFileName + let testData = VGSExpDateSerializersDataProvider.provideTestData(for: fileName) - override func tearDown() { - collector = nil - textField = nil - } + let config = VGSExpDateConfiguration(collector: collector, fieldName: "expDate") + config.formatPattern = "##/##" - // MARK: - Tests - /// Test default configuration. - func testSplitExpDateSerializerWithDefaultConfig() { - /// Get JSON test data - let fileName = TestFlow.defaultConfig.jsonFileName - let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) - - /// Prepare configuration - let config = VGSExpDateConfiguration(collector: collector, fieldName: "expDate") - config.formatPattern = "##/##" - - /// Run test for each case from JSON - for test in testData { - /// Prepare serializer - config.serializers = [ - VGSExpDateSeparateSerializer( - monthFieldName: test.monthFieldName, - yearFieldName: test.yearFieldName - ) - ] - /// Update configuration - textField.configuration = config - /// Setup test value - textField.setText(test.fieldValue) - /// Get JSON from collector using serializer - let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSON, extraData: nil) - /// Assert: Test JSON content should be equals to the JSON from the collector - XCTAssertTrue(submitJSON == test.submitJSON, - "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") - } + for test in testData { + config.serializers = [VGSExpDateSeparateSerializer(monthFieldName: test.monthFieldName, yearFieldName: test.yearFieldName)] + textField.configuration = config + textField.setText(test.fieldValue) + + let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSON, extraData: nil) + XCTAssertTrue(submitJSON == test.submitJSON, "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") } + } + + /// Test custom exp date configuration. + func testSplitExpDateSerializerWithCustomConfig() { + let fileName = TestFlow.customConfiguration.jsonFileName + let testData = VGSExpDateSerializersDataProvider.provideTestData(for: fileName) - /// Test custom exp date configuration. - func testSplitExpDateSerializerWithCustomConfig() { - /// Get JSON test data - let fileName = TestFlow.customConfig.jsonFileName - let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) - - /// Prepare configuration - let config = VGSExpDateConfiguration(collector: collector, fieldName: "card.expDate") - config.formatPattern = "##/##" - config.inputDateFormat = .shortYear - config.outputDateFormat = .longYear - config.divider = "-/-" - - /// Run test for each case from JSON - for test in testData { - /// Prepare serializer - config.serializers = [ - VGSExpDateSeparateSerializer( - monthFieldName: test.monthFieldName, - yearFieldName: test.yearFieldName - ) - ] - /// Update configuration - textField.configuration = config - /// Setup test value - textField.setText(test.fieldValue) - /// Get JSON from collector using serializer - let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSON, extraData: nil) - /// Assert: Test JSON content should be equals to the JSON from the collector - XCTAssertTrue(submitJSON == test.submitJSON, - "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") - } - } + let config = VGSExpDateConfiguration(collector: collector, fieldName: "card.expDate") + config.formatPattern = "##/##" + config.inputDateFormat = .shortYear + config.outputDateFormat = .longYear + config.divider = "-/-" - /// Test custom exp date output format. - func testSplitCustomExpDateOutputSerializerWithCustomConfig() { - /// Get JSON test data - let fileName = TestFlow.customExpDateOutputConfig.jsonFileName - let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) - - /// Prepare configuration - let config = VGSExpDateConfiguration(collector: collector, fieldName: "card.expDate") - config.formatPattern = "####/##" - config.inputDateFormat = .longYearThenMonth - config.outputDateFormat = .shortYearThenMonth - config.divider = "-/-" - - /// Run test for each case from JSON - for test in testData { - /// Prepare serializer - config.serializers = [ - VGSExpDateSeparateSerializer( - monthFieldName: test.monthFieldName, - yearFieldName: test.yearFieldName - ) - ] - /// Update configuration - textField.configuration = config - /// Setup test value - textField.setText(test.fieldValue) - /// Get JSON from collector using serializer - let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSON, extraData: nil) - /// Assert: Test JSON content should be equals to the JSON from the collector - XCTAssertTrue(submitJSON == test.submitJSON, - "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") - } + for test in testData { + config.serializers = [VGSExpDateSeparateSerializer(monthFieldName: test.monthFieldName, yearFieldName: test.yearFieldName)] + textField.configuration = config + textField.setText(test.fieldValue) + + let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSON, extraData: nil) + XCTAssertTrue(submitJSON == test.submitJSON, "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") + } + } + + /// Test custom exp date output format. + func testSplitCustomExpDateOutputSerializerWithCustomConfig() { + let fileName = TestFlow.customExpDateOutputConfiguration.jsonFileName + let testData = VGSExpDateSerializersDataProvider.provideTestData(for: fileName) - /// Test map with array merge. - func testSplitExpDateSerializersMapWithArray() { - /// Get JSON test data - let fileName = TestFlow.mapWithArrayMerge.jsonFileName - let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) - - /// Prepare configuration - let config = VGSExpDateConfiguration(collector: collector, fieldName: "expDate") - config.formatPattern = "##/##" - - /// Setup extra data - let extraData = ["card_data": [["user_id": "123"]]] - - /// Run test for each case from JSON - for test in testData { - /// Prepare serializer - config.serializers = [ - VGSExpDateSeparateSerializer( - monthFieldName: test.monthFieldName, - yearFieldName: test.yearFieldName - ) - ] - /// Update configuration - textField.configuration = config - /// Setup test value - textField.setText(test.fieldValue) - /// Get JSON from collector using serializer - let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSONWithArrayMerge, extraData: extraData) - /// Assert: Test JSON content should be equals to the JSON from the collector - XCTAssertTrue(submitJSON == test.submitJSON, - "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") - } - } + let config = VGSExpDateConfiguration(collector: collector, fieldName: "card.expDate") + config.formatPattern = "####/##" + config.inputDateFormat = .longYearThenMonth + config.outputDateFormat = .shortYearThenMonth + config.divider = "-/-" - /// Test map with array overwrite. - func testSplitExpDateSerializersMapWithArrayOverwrite() { - /// Get JSON test data - let fileName = TestFlow.mapWithArrayOverwrite.jsonFileName - let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) - - /// Prepare configuration - let config = VGSExpDateConfiguration(collector: collector, fieldName: "expDate") - config.formatPattern = "##/##" - - /// Setup extra data - let extraData = ["card_data": [["month": "3", "year": "2033"]]] - - /// Run test for each case from JSON - for test in testData { - /// Prepare serializer - config.serializers = [ - VGSExpDateSeparateSerializer( - monthFieldName: test.monthFieldName, - yearFieldName: test.yearFieldName - ) - ] - /// Update configuration - textField.configuration = config - /// Setup test value - textField.setText(test.fieldValue) - /// Get JSON from collector using serializer - let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSONWithArrayOverwrite, extraData: extraData) - /// Assert: Test JSON content should be equals to the JSON from the collector - XCTAssertTrue(submitJSON == test.submitJSON, - "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") - } + for test in testData { + config.serializers = [VGSExpDateSeparateSerializer(monthFieldName: test.monthFieldName, yearFieldName: test.yearFieldName)] + textField.configuration = config + textField.setText(test.fieldValue) + + let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSON, extraData: nil) + XCTAssertTrue(submitJSON == test.submitJSON, "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") + } + } + + /// Test map with array merge. + func testSplitExpDateSerializersMapWithArray() { + let fileName = TestFlow.mapWithArrayMerge.jsonFileName + let testData = VGSExpDateSerializersDataProvider.provideTestData(for: fileName) + + let config = VGSExpDateConfiguration(collector: collector, fieldName: "expDate") + config.formatPattern = "##/##" + + let extraData = ["card_data": + [ + ["user_id": "123"] + ]] + + for test in testData { + config.serializers = [VGSExpDateSeparateSerializer(monthFieldName: test.monthFieldName, yearFieldName: test.yearFieldName)] + textField.configuration = config + textField.setText(test.fieldValue) + + let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSONWithArrayMerge, extraData: extraData) + XCTAssertTrue(submitJSON == test.submitJSON, "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") + } + } + + /// Test map with array overwrite. + func testSplitExpDateSerializersMapWithArrayOverwrite() { + let fileName = TestFlow.mapWithArrayOverwrite.jsonFileName + let testData = VGSExpDateSerializersDataProvider.provideTestData(for: fileName) + + let config = VGSExpDateConfiguration(collector: collector, fieldName: "expDate") + config.formatPattern = "##/##" + + let extraData = ["card_data": + [ + ["month": "3", + "year": "2033"] + ]] + + for test in testData { + config.serializers = [VGSExpDateSeparateSerializer(monthFieldName: test.monthFieldName, yearFieldName: test.yearFieldName)] + textField.configuration = config + textField.setText(test.fieldValue) + + let submitJSON = collector.mapFieldsToBodyJSON(with: .nestedJSONWithArrayOverwrite, extraData: extraData) + XCTAssertTrue(submitJSON == test.submitJSON, "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON)") + } + } } diff --git a/Tests/FrameworkTests/SerializersTest/VGSExpDateSerializersDataProvider.swift b/Tests/FrameworkTests/SerializersTest/VGSExpDateSerializersDataProvider.swift new file mode 100644 index 00000000..effde585 --- /dev/null +++ b/Tests/FrameworkTests/SerializersTest/VGSExpDateSerializersDataProvider.swift @@ -0,0 +1,59 @@ +// +// VGSExpDateSerializersDataProvider.swift +// FrameworkTests +// +// Copyright © 2021 VGS. All rights reserved. +// + +import Foundation +import XCTest +@testable import VGSCollectSDK + +final class VGSExpDateSerializersDataProvider { + + static func provideTestData(for fileName: String) -> [VGSExpDateSeparateSerializerTests.TestJSONData] { + guard let rootTestJSON = JsonData(jsonFileName: fileName) else { + XCTFail("cannot build data for file \(fileName)") + return [] + } + + guard let testDataJSONArray = rootTestJSON["test_data"] as? [JsonData] else { + XCTFail("test_data JSON array not found in \(fileName)") + return [] + } + + var testData = [VGSExpDateSeparateSerializerTests.TestJSONData]() + + for json in testDataJSONArray { + if let testItem = VGSExpDateSeparateSerializerTests.TestJSONData(json: json) { + testData.append(testItem) + } else { + XCTFail("Cannot build test data for json: \(json)") + } + } + return testData + } + + static func provideTokenizationTestData(for fileName: String) -> [VGSExpDateTokenizationSerializerTests.TestJSONData] { + guard let rootTestJSON = JsonData(jsonFileName: fileName) else { + XCTFail("cannot build data for file \(fileName)") + return [] + } + + guard let testDataJSONArray = rootTestJSON["test_data"] as? [JsonData] else { + XCTFail("test_data JSON array not found in \(fileName)") + return [] + } + + var testData = [VGSExpDateTokenizationSerializerTests.TestJSONData]() + + for json in testDataJSONArray { + if let testItem = VGSExpDateTokenizationSerializerTests.TestJSONData(json: json) { + testData.append(testItem) + } else { + XCTFail("Cannot build test data for json: \(json)") + } + } + return testData + } +} diff --git a/Tests/FrameworkTests/SerializersTest/VGSExpDateTokenizationSerializerTests.swift b/Tests/FrameworkTests/SerializersTest/VGSExpDateTokenizationSerializerTests.swift index 8339d219..f1f2c494 100644 --- a/Tests/FrameworkTests/SerializersTest/VGSExpDateTokenizationSerializerTests.swift +++ b/Tests/FrameworkTests/SerializersTest/VGSExpDateTokenizationSerializerTests.swift @@ -7,105 +7,105 @@ import XCTest @testable import VGSCollectSDK class VGSExpDateTokenizationSerializerTests: VGSCollectBaseTestCase { - var collector: VGSCollect! - var textField: VGSExpDateTextField! - - enum TestFlow { - case defaultConfiguration - - var jsonFileName: String { - return "VGSExpDateTokenizationSerialization_" + jsonFileNameSuffix - } - - var jsonFileNameSuffix: String { - switch self { - case .defaultConfiguration: - return "DefaultConfig" - } - } - } - - struct TestJSONData: TestJSONDataProtocol { - let fieldValue: String - let monthFieldName: String - let yearFieldName: String - let submitJSON: JsonData - let outputFormat: VGSCardExpDateFormat - let comment: String - let tokenizedPayloads: [JsonData] - - init?(json: JsonData) { - guard let submitJSON = json["expectedResult"] as? JsonData else { - XCTFail("Cannot parse test data.") - return nil - } - guard let formatName = json["outputFormat"] as? String, - let format = VGSCardExpDateFormat(name: formatName) else { - XCTFail("Cannot parse output format from test json") - return nil - } - self.fieldValue = json["fieldValue"] as? String ?? "" - self.monthFieldName = json["monthFieldName"] as? String ?? "" - self.yearFieldName = json["yearFieldName"] as? String ?? "" - self.submitJSON = submitJSON - self.outputFormat = format - self.comment = json["comment"] as? String ?? "" - guard let tokenizedPayloads = submitJSON["data"] as? [JsonData] else { - XCTFail("Invalid payload") - return nil - } - self.tokenizedPayloads = tokenizedPayloads - } + var collector: VGSCollect! + var textField: VGSExpDateTextField! + + enum TestFlow { + case defaultConfiguration + + var jsonFileName: String { + return "VGSExpDateTokenizationSerialization_" + jsonFileNameSuffix } - - // MARK: - Override - - override func setUp() { - super.setUp() - collector = VGSCollect(id: "any") - textField = VGSExpDateTextField() + + var jsonFileNameSuffix: String { + switch self { + case .defaultConfiguration: + return "DefaultConfig" + } } - - override func tearDown() { - collector = nil - textField = nil + } + + struct TestJSONData { + let fieldValue: String + let monthFieldName: String + let yearFieldName: String + let submitJSON: JsonData + let outputFormat: VGSCardExpDateFormat + let comment: String + let tokenizedPayloads: [JsonData] + + init?(json: JsonData) { + guard let submitJSON = json["expectedResult"] as? JsonData else { + XCTFail("Cannot parse test data.") + return nil + } + guard let formatName = json["outputFormat"] as? String, + let format = VGSCardExpDateFormat(name: formatName) else { + XCTFail("Cannot parse output format from test json") + return nil + } + self.fieldValue = json["fieldValue"] as? String ?? "" + self.monthFieldName = json["monthFieldName"] as? String ?? "" + self.yearFieldName = json["yearFieldName"] as? String ?? "" + self.submitJSON = submitJSON + self.outputFormat = format + self.comment = json["comment"] as? String ?? "" + guard let tokenizedPayloads = submitJSON["data"] as? [JsonData] else { + XCTFail("Invalid payload") + return nil + } + self.tokenizedPayloads = tokenizedPayloads } - - // MARK: - Tests - - /// Test default configuration. - func testSplitExpDateSerializerWithDefaultConfig() { - let fileName = TestFlow.defaultConfiguration.jsonFileName - let testData: [TestJSONData] = SerializersDataProvider.provideTestData(for: fileName) - - let config = VGSExpDateTokenizationConfiguration(collector: collector, fieldName: "expDate") - config.formatPattern = "##/##" - config.inputDateFormat = .shortYear - - for test in testData { - config.serializers = [VGSExpDateSeparateSerializer(monthFieldName: test.monthFieldName, yearFieldName: test.yearFieldName)] - config.outputDateFormat = test.outputFormat - textField.configuration = config - - textField.setText(test.fieldValue) - - let submitJSON = collector.mapFieldsToTokenizationRequestBodyJSON(collector.textFields) - - guard let tokenizedPayloads = submitJSON["data"] as? [JsonData] else { - XCTFail("Cannot find tokenized data array.") - return - } - - var matchedPayloads = 0 - // mapFieldsToTokenizationRequestBodyJSON can produce array of tokenized data in different order. So we need to iterate through payloads and check them one by one to get 2 matches (one is for month, another one is for year). - for payload in tokenizedPayloads { - for expectedPayload in test.tokenizedPayloads where payload == expectedPayload { - matchedPayloads += 1 - } - } - - // Should be at least 2 matches of payloads. - XCTAssertTrue(matchedPayloads == 2, "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON) \nComment: \(test.comment)") + } + + // MARK: - Override + + override func setUp() { + super.setUp() + collector = VGSCollect(id: "any") + textField = VGSExpDateTextField() + } + + override func tearDown() { + collector = nil + textField = nil + } + + // MARK: - Tests + + /// Test default configuration. + func testSplitExpDateSerializerWithDefaultConfig() { + let fileName = TestFlow.defaultConfiguration.jsonFileName + let testData = VGSExpDateSerializersDataProvider.provideTokenizationTestData(for: fileName) + + let config = VGSExpDateTokenizationConfiguration(collector: collector, fieldName: "expDate") + config.formatPattern = "##/##" + config.inputDateFormat = .shortYear + + for test in testData { + config.serializers = [VGSExpDateSeparateSerializer(monthFieldName: test.monthFieldName, yearFieldName: test.yearFieldName)] + config.outputDateFormat = test.outputFormat + textField.configuration = config + + textField.setText(test.fieldValue) + + let submitJSON = collector.mapFieldsToTokenizationRequestBodyJSON(collector.textFields) + + guard let tokenizedPayloads = submitJSON["data"] as? [JsonData] else { + XCTFail("Cannot find tokenized data array.") + return + } + + var matchedPayloads = 0 + // mapFieldsToTokenizationRequestBodyJSON can produce array of tokenized data in different order. So we need to iterate through payloads and check them one by one to get 2 matches (one is for month, another one is for year). + for payload in tokenizedPayloads { + for expectedPayload in test.tokenizedPayloads where payload == expectedPayload { + matchedPayloads += 1 } + } + + // Should be at least 2 matches of payloads. + XCTAssertTrue(matchedPayloads == 2, "Expiration date convert error:\n - Input: \(test.fieldValue)\n - Output: \(test.submitJSON)\n - Result: \(submitJSON) \nComment: \(test.comment)") } + } } diff --git a/VGSCollectSDK.xcodeproj/project.pbxproj b/VGSCollectSDK.xcodeproj/project.pbxproj index d75d9df9..3fc33ff6 100644 --- a/VGSCollectSDK.xcodeproj/project.pbxproj +++ b/VGSCollectSDK.xcodeproj/project.pbxproj @@ -109,6 +109,7 @@ 443FDDC225DD4B2B006932C4 /* VGSCollectBaseTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 443FDDC125DD4B2B006932C4 /* VGSCollectBaseTestCase.swift */; }; 44447F7725F74CCC00D4CE68 /* VGSFieldNameMapUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44447F7625F74CCC00D4CE68 /* VGSFieldNameMapUtilsTests.swift */; }; 44447F8025F7651100D4CE68 /* JSONData+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44447F7F25F7651100D4CE68 /* JSONData+Extensions.swift */; }; + 4459728A26135BE600139EAA /* VGSExpDateSerializersDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4459728926135BE600139EAA /* VGSExpDateSerializersDataProvider.swift */; }; 4479453E25F8C032006CB371 /* VGSCollect+fieldNameMapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4479453D25F8C032006CB371 /* VGSCollect+fieldNameMapping.swift */; }; 4479456525F8EB93006CB371 /* VGSCollectFieldNameMappingPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4479456425F8EB93006CB371 /* VGSCollectFieldNameMappingPolicy.swift */; }; 449C89D525F0AB9F00BE009F /* VGSDeepMergeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 449C89D425F0AB9F00BE009F /* VGSDeepMergeUtils.swift */; }; @@ -146,29 +147,6 @@ 44ECD60627D9E87000460FDF /* CardIcon.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 44ECD60527D9E87000460FDF /* CardIcon.xcassets */; }; 44F8F51C25DBD1950052647A /* VGSCollectSatelliteUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44F8F51B25DBD1950052647A /* VGSCollectSatelliteUtils.swift */; }; 44F8F52F25DBE8770052647A /* VGSCollectSatelliteUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44F8F52325DBE7E40052647A /* VGSCollectSatelliteUtilsTests.swift */; }; - A01CE3F729E5D67E0059700F /* VGSDateTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = A01CE3F629E5D67E0059700F /* VGSDateTextField.swift */; }; - A0752C7329EF373400337C99 /* VGSTextFormatConvertable.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0752C7229EF373400337C99 /* VGSTextFormatConvertable.swift */; }; - A0752C7529EF376100337C99 /* VGSDateSeparateSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0752C7429EF376100337C99 /* VGSDateSeparateSerializer.swift */; }; - A0752C7829EF3C9200337C99 /* DateTextFieldTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0752C7629EF3AC300337C99 /* DateTextFieldTest.swift */; }; - A08DA9F329F1B03A00DA62A5 /* VGSDateTokenizationConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = A08DA9F229F1B03A00DA62A5 /* VGSDateTokenizationConfiguration.swift */; }; - A08DA9FC29F1CE0B00DA62A5 /* VGSDateTokenizationSerializerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A08DA9FB29F1CE0B00DA62A5 /* VGSDateTokenizationSerializerTests.swift */; }; - A08DA9FD29F1D1E000DA62A5 /* VGSDateTokenizationSerialization_DefaultConfig.json in Resources */ = {isa = PBXBuildFile; fileRef = A08DA9F929F1CC2A00DA62A5 /* VGSDateTokenizationSerialization_DefaultConfig.json */; }; - A08DA9FF29F1D4D500DA62A5 /* VGSDateFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = A08DA9FE29F1D4D500DA62A5 /* VGSDateFormat.swift */; }; - A08DAA0129F1D52A00DA62A5 /* VGSDateFormatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A08DAA0029F1D52A00DA62A5 /* VGSDateFormatTests.swift */; }; - A08E91B529F04600007EDA49 /* ValidationRuleDateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A08E91B429F04600007EDA49 /* ValidationRuleDateTests.swift */; }; - A093FE1729F0AA76002C6ABC /* VGSDateSeparateSerializerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A093FE1629F0AA76002C6ABC /* VGSDateSeparateSerializerTests.swift */; }; - A093FE1E29F0BD38002C6ABC /* VGSDateSerialization_CustomExpDateOutputConfig.json in Resources */ = {isa = PBXBuildFile; fileRef = A093FE1929F0BD38002C6ABC /* VGSDateSerialization_CustomExpDateOutputConfig.json */; }; - A093FE1F29F0BD38002C6ABC /* VGSDateSerialization_CustomConfig.json in Resources */ = {isa = PBXBuildFile; fileRef = A093FE1A29F0BD38002C6ABC /* VGSDateSerialization_CustomConfig.json */; }; - A093FE2029F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayMerge.json in Resources */ = {isa = PBXBuildFile; fileRef = A093FE1B29F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayMerge.json */; }; - A093FE2129F0BD38002C6ABC /* VGSDateSerialization_DefaultConfig.json in Resources */ = {isa = PBXBuildFile; fileRef = A093FE1C29F0BD38002C6ABC /* VGSDateSerialization_DefaultConfig.json */; }; - A093FE2229F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayOverwrite.json in Resources */ = {isa = PBXBuildFile; fileRef = A093FE1D29F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayOverwrite.json */; }; - A093FE2429F0BDC7002C6ABC /* SerializersDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A093FE2329F0BDC7002C6ABC /* SerializersDataProvider.swift */; }; - A0988FA129F9739600FAFA67 /* VGSValidationRuleDateRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0988FA029F9739600FAFA67 /* VGSValidationRuleDateRange.swift */; }; - A0BCC67229F064D4009F1118 /* DateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0BCC67129F064D4009F1118 /* DateTests.swift */; }; - A0BCC67429F06CF6009F1118 /* DateConvertorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0BCC67329F06CF6009F1118 /* DateConvertorTests.swift */; }; - A0C1F09A29EE30AB00EE8447 /* VGSDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0C1F09829EE30AB00EE8447 /* VGSDate.swift */; }; - A0C1F09C29EE30AB00EE8447 /* VGSDateConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0C1F09929EE30AB00EE8447 /* VGSDateConfiguration.swift */; }; - A0C1F0A329EE319D00EE8447 /* DateFormatConvertor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0C1F0A129EE319D00EE8447 /* DateFormatConvertor.swift */; }; FD05F9472316CE5A000EAF52 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD05F9392316CE5A000EAF52 /* Storage.swift */; }; FD05F94A2316CE5A000EAF52 /* VGSConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD05F93C2316CE5A000EAF52 /* VGSConfiguration.swift */; }; FD05F94C2316CE5A000EAF52 /* VGSCollectSDK.h in Headers */ = {isa = PBXBuildFile; fileRef = FD05F93F2316CE5A000EAF52 /* VGSCollectSDK.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -320,6 +298,7 @@ 443FDDC125DD4B2B006932C4 /* VGSCollectBaseTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSCollectBaseTestCase.swift; sourceTree = ""; }; 44447F7625F74CCC00D4CE68 /* VGSFieldNameMapUtilsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSFieldNameMapUtilsTests.swift; sourceTree = ""; }; 44447F7F25F7651100D4CE68 /* JSONData+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSONData+Extensions.swift"; sourceTree = ""; }; + 4459728926135BE600139EAA /* VGSExpDateSerializersDataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSExpDateSerializersDataProvider.swift; sourceTree = ""; }; 4479453D25F8C032006CB371 /* VGSCollect+fieldNameMapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VGSCollect+fieldNameMapping.swift"; sourceTree = ""; }; 4479456425F8EB93006CB371 /* VGSCollectFieldNameMappingPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSCollectFieldNameMappingPolicy.swift; sourceTree = ""; }; 449C89D425F0AB9F00BE009F /* VGSDeepMergeUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSDeepMergeUtils.swift; sourceTree = ""; }; @@ -358,29 +337,6 @@ 44ECD60527D9E87000460FDF /* CardIcon.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = CardIcon.xcassets; sourceTree = ""; }; 44F8F51B25DBD1950052647A /* VGSCollectSatelliteUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSCollectSatelliteUtils.swift; sourceTree = ""; }; 44F8F52325DBE7E40052647A /* VGSCollectSatelliteUtilsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSCollectSatelliteUtilsTests.swift; sourceTree = ""; }; - A01CE3F629E5D67E0059700F /* VGSDateTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSDateTextField.swift; sourceTree = ""; }; - A0752C7229EF373400337C99 /* VGSTextFormatConvertable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VGSTextFormatConvertable.swift; sourceTree = ""; }; - A0752C7429EF376100337C99 /* VGSDateSeparateSerializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VGSDateSeparateSerializer.swift; sourceTree = ""; }; - A0752C7629EF3AC300337C99 /* DateTextFieldTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTextFieldTest.swift; sourceTree = ""; }; - A08DA9F229F1B03A00DA62A5 /* VGSDateTokenizationConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSDateTokenizationConfiguration.swift; sourceTree = ""; }; - A08DA9F929F1CC2A00DA62A5 /* VGSDateTokenizationSerialization_DefaultConfig.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = VGSDateTokenizationSerialization_DefaultConfig.json; sourceTree = ""; }; - A08DA9FB29F1CE0B00DA62A5 /* VGSDateTokenizationSerializerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSDateTokenizationSerializerTests.swift; sourceTree = ""; }; - A08DA9FE29F1D4D500DA62A5 /* VGSDateFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSDateFormat.swift; sourceTree = ""; }; - A08DAA0029F1D52A00DA62A5 /* VGSDateFormatTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSDateFormatTests.swift; sourceTree = ""; }; - A08E91B429F04600007EDA49 /* ValidationRuleDateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidationRuleDateTests.swift; sourceTree = ""; }; - A093FE1629F0AA76002C6ABC /* VGSDateSeparateSerializerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VGSDateSeparateSerializerTests.swift; sourceTree = ""; }; - A093FE1929F0BD38002C6ABC /* VGSDateSerialization_CustomExpDateOutputConfig.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = VGSDateSerialization_CustomExpDateOutputConfig.json; sourceTree = ""; }; - A093FE1A29F0BD38002C6ABC /* VGSDateSerialization_CustomConfig.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = VGSDateSerialization_CustomConfig.json; sourceTree = ""; }; - A093FE1B29F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayMerge.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = VGSDateSerialization_MapWithArrayMerge.json; sourceTree = ""; }; - A093FE1C29F0BD38002C6ABC /* VGSDateSerialization_DefaultConfig.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = VGSDateSerialization_DefaultConfig.json; sourceTree = ""; }; - A093FE1D29F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayOverwrite.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = VGSDateSerialization_MapWithArrayOverwrite.json; sourceTree = ""; }; - A093FE2329F0BDC7002C6ABC /* SerializersDataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SerializersDataProvider.swift; sourceTree = ""; }; - A0988FA029F9739600FAFA67 /* VGSValidationRuleDateRange.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VGSValidationRuleDateRange.swift; sourceTree = ""; }; - A0BCC67129F064D4009F1118 /* DateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTests.swift; sourceTree = ""; }; - A0BCC67329F06CF6009F1118 /* DateConvertorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateConvertorTests.swift; sourceTree = ""; }; - A0C1F09829EE30AB00EE8447 /* VGSDate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VGSDate.swift; sourceTree = ""; }; - A0C1F09929EE30AB00EE8447 /* VGSDateConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VGSDateConfiguration.swift; sourceTree = ""; }; - A0C1F0A129EE319D00EE8447 /* DateFormatConvertor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateFormatConvertor.swift; sourceTree = ""; }; FD05F9392316CE5A000EAF52 /* Storage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = ""; }; FD05F93A2316CE5A000EAF52 /* Enums.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Enums.swift; sourceTree = ""; }; FD05F93B2316CE5A000EAF52 /* VGSCollect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VGSCollect.swift; sourceTree = ""; }; @@ -478,7 +434,6 @@ 035179A0285920F100394BFC /* VGSCardTokenizationConfiguration.swift */, 035179A22859BABC00394BFC /* VGSSSNTokenizationConfiguration.swift */, 035179A42859BB7D00394BFC /* VGSExpDateTokenizationConfiguration.swift */, - A08DA9F229F1B03A00DA62A5 /* VGSDateTokenizationConfiguration.swift */, 035179A62859BCC400394BFC /* VGSCardHolderNameTokenizationConfiguration.swift */, 035179A82859BD5500394BFC /* VGSTokenizationConfiguration.swift */, ); @@ -523,13 +478,6 @@ path = CardDataMappers; sourceTree = ""; }; - 24A3321F33CCBCFBF0C01580 /* Pods */ = { - isa = PBXGroup; - children = ( - ); - path = Pods; - sourceTree = ""; - }; 32093D7225CD9F88006CD242 /* Loggers */ = { isa = PBXGroup; children = ( @@ -558,7 +506,6 @@ children = ( 3215C4BB260DAF3D00F21259 /* VGSFormatSerializerProtocol.swift */, 3215C4C7260DAF9400F21259 /* VGSExpDateSeparateSerializer.swift */, - A0752C7429EF376100337C99 /* VGSDateSeparateSerializer.swift */, ); path = Serializers; sourceTree = ""; @@ -566,12 +513,10 @@ 3215C4E72611B4B900F21259 /* SerializersTest */ = { isa = PBXGroup; children = ( - A093FE2329F0BDC7002C6ABC /* SerializersDataProvider.swift */, - A093FE1629F0AA76002C6ABC /* VGSDateSeparateSerializerTests.swift */, - A08DA9FB29F1CE0B00DA62A5 /* VGSDateTokenizationSerializerTests.swift */, 3215C4E82611B50A00F21259 /* VGSExpDateSeparateSerializerTests.swift */, - 44EAE09D28FE8B2700FC6BBB /* VGSExpDateTokenizationSerializerTests.swift */, + 4459728926135BE600139EAA /* VGSExpDateSerializersDataProvider.swift */, 44168FBE2632945D0088E515 /* VGSExpirationDateTextFieldUtilsTests.swift */, + 44EAE09D28FE8B2700FC6BBB /* VGSExpDateTokenizationSerializerTests.swift */, ); path = SerializersTest; sourceTree = ""; @@ -579,8 +524,6 @@ 322F94B925BABE82001CDF12 /* Convertors */ = { isa = PBXGroup; children = ( - A0752C7229EF373400337C99 /* VGSTextFormatConvertable.swift */, - A0C1F0A129EE319D00EE8447 /* DateFormatConvertor.swift */, 322F94BA25BABE97001CDF12 /* ExpDateFormatConvertor.swift */, ); path = Convertors; @@ -590,7 +533,6 @@ isa = PBXGroup; children = ( 322F94D625BAC3E0001CDF12 /* ExpDateConvertorTests.swift */, - A0BCC67329F06CF6009F1118 /* DateConvertorTests.swift */, ); path = ConvertorsTests; sourceTree = ""; @@ -598,8 +540,6 @@ 324B5E6224A235BC0036867E /* Date */ = { isa = PBXGroup; children = ( - A0988FA029F9739600FAFA67 /* VGSValidationRuleDateRange.swift */, - A08DA9FE29F1D4D500DA62A5 /* VGSDateFormat.swift */, 324B5E7424A23FA60036867E /* VGSValidationRuleExpirationDate.swift */, ); path = Date; @@ -837,12 +777,10 @@ 44D5210B2681B803005AB588 /* Resources */ = { isa = PBXGroup; children = ( - A093FE1829F0ACA2002C6ABC /* DateSplitSerializerTestJSONs */, - A08DA9F829F1CC2A00DA62A5 /* DateTokenizationJSON */, - 44D521152681B803005AB588 /* ExpDateSplitSerializerTestJSONs */, + 442A391129097167007CCC58 /* VGSTokenizationJSONs */, 44EAE09A28FE65B900FC6BBB /* ExpDateTokenizationJSON */, 44D5210C2681B803005AB588 /* TestJSONs */, - 442A391129097167007CCC58 /* VGSTokenizationJSONs */, + 44D521152681B803005AB588 /* ExpDateSplitSerializerTestJSONs */, 442BB2C5287314DC001FD26B /* MockedData.plist */, ); path = Resources; @@ -894,11 +832,11 @@ 44D521152681B803005AB588 /* ExpDateSplitSerializerTestJSONs */ = { isa = PBXGroup; children = ( - 44D5211A2681B803005AB588 /* VGSExpDateSerialization_CustomConfig.json */, - 44D521172681B803005AB588 /* VGSExpDateSerialization_CustomExpDateOutputConfig.json */, 44D521162681B803005AB588 /* VGSExpDateSerialization_DefaultConfig.json */, - 44D521192681B803005AB588 /* VGSExpDateSerialization_MapWithArrayMerge.json */, + 44D521172681B803005AB588 /* VGSExpDateSerialization_CustomExpDateOutputConfig.json */, 44D521182681B803005AB588 /* VGSExpDateSerialization_MapWithArrayOverwrite.json */, + 44D521192681B803005AB588 /* VGSExpDateSerialization_MapWithArrayMerge.json */, + 44D5211A2681B803005AB588 /* VGSExpDateSerialization_CustomConfig.json */, ); path = ExpDateSplitSerializerTestJSONs; sourceTree = ""; @@ -961,34 +899,6 @@ path = "Satellite Tests"; sourceTree = ""; }; - A08DA9F829F1CC2A00DA62A5 /* DateTokenizationJSON */ = { - isa = PBXGroup; - children = ( - A08DA9F929F1CC2A00DA62A5 /* VGSDateTokenizationSerialization_DefaultConfig.json */, - ); - path = DateTokenizationJSON; - sourceTree = ""; - }; - A093FE1829F0ACA2002C6ABC /* DateSplitSerializerTestJSONs */ = { - isa = PBXGroup; - children = ( - A093FE1A29F0BD38002C6ABC /* VGSDateSerialization_CustomConfig.json */, - A093FE1929F0BD38002C6ABC /* VGSDateSerialization_CustomExpDateOutputConfig.json */, - A093FE1C29F0BD38002C6ABC /* VGSDateSerialization_DefaultConfig.json */, - A093FE1B29F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayMerge.json */, - A093FE1D29F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayOverwrite.json */, - ); - path = DateSplitSerializerTestJSONs; - sourceTree = ""; - }; - A0BCC67029F064C0009F1118 /* Core */ = { - isa = PBXGroup; - children = ( - A0BCC67129F064D4009F1118 /* DateTests.swift */, - ); - path = Core; - sourceTree = ""; - }; FD05F9372316CE5A000EAF52 /* VGSCollectSDK */ = { isa = PBXGroup; children = ( @@ -1012,11 +922,9 @@ 44ECD5F427D9C18C00460FDF /* VGSPaymentCards */, 035179992858B39100394BFC /* TokenizationConfiguration */, FD05F93A2316CE5A000EAF52 /* Enums.swift */, - A0C1F09829EE30AB00EE8447 /* VGSDate.swift */, FD05F9392316CE5A000EAF52 /* Storage.swift */, FD05F93C2316CE5A000EAF52 /* VGSConfiguration.swift */, 322F94B025BABD9D001CDF12 /* VGSExpDateConfiguration.swift */, - A0C1F09929EE30AB00EE8447 /* VGSDateConfiguration.swift */, 3219D73C2404279700F4A7E5 /* VGSError.swift */, 327C9E132407EF92004C641C /* VGSErrorInfo.swift */, 327C9E152407F43A004C641C /* VGSErrorInfoKey.swift */, @@ -1044,7 +952,6 @@ 03B10BB028E20A3A009B409B /* VGSBlinkCardCollector */, FD12B9B02304619100B670DD /* Products */, 32CFC72324EBF3B500457B17 /* Frameworks */, - 24A3321F33CCBCFBF0C01580 /* Pods */, ); sourceTree = ""; }; @@ -1080,7 +987,6 @@ FD2495522330CB49009024E6 /* FrameworkTests */ = { isa = PBXGroup; children = ( - A0BCC67029F064C0009F1118 /* Core */, 442A391529097408007CCC58 /* TokenizationTests */, 44447F7D25F7648700D4CE68 /* Test Helpers */, 449C89E225F0AFAE00BE009F /* DeepMergeUtils Tests */, @@ -1172,7 +1078,6 @@ children = ( FD24956F2330E834009024E6 /* CardNumerTextFieldTests.swift */, FDAAB6AA249A8844001F5C1A /* ExpDateTextField.swift */, - A0752C7629EF3AC300337C99 /* DateTextFieldTest.swift */, FDE8907C2333A1D400FA170D /* CVVTextFieldTests.swift */, 3270D3F0248155B200004E3B /* SSNTextFieldTests.swift */, FDE8907A2333A16A00FA170D /* ExpDateTextFieldTests.swift */, @@ -1183,8 +1088,6 @@ FDF696E023463ACA00063507 /* TextFielsStyleUI.swift */, FDA680DE239844FC00372817 /* CardTextFieldTests.swift */, 324B5E7924A3A34F0036867E /* ValidationRulesTest.swift */, - A08DAA0029F1D52A00DA62A5 /* VGSDateFormatTests.swift */, - A08E91B429F04600007EDA49 /* ValidationRuleDateTests.swift */, 32AFB93624FFD218007FFCAE /* VGSTextFieldTests.swift */, 441A727C272AAEEA0036BECB /* TextFieldMaxInputLengthTests.swift */, ); @@ -1199,7 +1102,6 @@ FD2495622330E313009024E6 /* Validation */, FDD398ED247D776600B55057 /* VGSCardTextField.swift */, FD8B62462497CD580097C9AB /* VGSExpDateTextField.swift */, - A01CE3F629E5D67E0059700F /* VGSDateTextField.swift */, FD05F9442316CE5A000EAF52 /* VGSTextField.swift */, 321FE73925DE45FC00B138E9 /* VGSCVCTextField.swift */, FD3C01C223AFC0980096B4A4 /* VGSTextField+CVC.swift */, @@ -1419,19 +1321,13 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - A093FE1F29F0BD38002C6ABC /* VGSDateSerialization_CustomConfig.json in Resources */, 44D521212681B803005AB588 /* VGSExpDateSerialization_MapWithArrayOverwrite.json in Resources */, 44D5211C2681B803005AB588 /* FlatPolicyTestJSONs.json in Resources */, 44D521202681B803005AB588 /* VGSExpDateSerialization_CustomExpDateOutputConfig.json in Resources */, 442BB2C6287314DC001FD26B /* MockedData.plist in Resources */, 44D5210A2681B7F6005AB588 /* FrameworkTests.xctestplan in Resources */, - A093FE2229F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayOverwrite.json in Resources */, - A093FE1E29F0BD38002C6ABC /* VGSDateSerialization_CustomExpDateOutputConfig.json in Resources */, - A093FE2029F0BD38002C6ABC /* VGSDateSerialization_MapWithArrayMerge.json in Resources */, 44D521232681B803005AB588 /* VGSExpDateSerialization_CustomConfig.json in Resources */, - A08DA9FD29F1D1E000DA62A5 /* VGSDateTokenizationSerialization_DefaultConfig.json in Resources */, 44D5211F2681B803005AB588 /* VGSExpDateSerialization_DefaultConfig.json in Resources */, - A093FE2129F0BD38002C6ABC /* VGSDateSerialization_DefaultConfig.json in Resources */, 44D5211D2681B803005AB588 /* OverwriteArraysTestJSONs.json in Resources */, 442A39132909718F007CCC58 /* VGSTokenizationTestJSON_DefaultConfig.json in Resources */, 44EAE09C28FE666200FC6BBB /* VGSExpDateTokenizationSerialization_DefaultConfig.json in Resources */, @@ -1558,7 +1454,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - A0752C7329EF373400337C99 /* VGSTextFormatConvertable.swift in Sources */, 324B5E7124A23E670036867E /* VGSValidationRuleLength.swift in Sources */, FDD42A3D233F67BA0005D631 /* VGSTextField+UIBuilder.swift in Sources */, 3219D73D2404279700F4A7E5 /* VGSError.swift in Sources */, @@ -1567,7 +1462,6 @@ 033C979729D5BDC60088E045 /* VGSTextField+statePublisher.swift in Sources */, 32093D7E25CD9F88006CD242 /* VGSCollectRequestLogger.swift in Sources */, FD3C01C423AFCEEE0096B4A4 /* Enums.swift in Sources */, - A08DA9F329F1B03A00DA62A5 /* VGSDateTokenizationConfiguration.swift in Sources */, 441B26D425DB88C50099AA3A /* APIHostURLPolicy.swift in Sources */, 44ECD60227D9C18C00460FDF /* CardType+icon.swift in Sources */, 449C8A3825F2513300BE009F /* VGSFieldNameToSubscriptMapper.swift in Sources */, @@ -1578,24 +1472,20 @@ 32093D7A25CD9F88006CD242 /* VGSCollectLoggingConfiguration.swift in Sources */, 44ECD5FF27D9C18C00460FDF /* VGSPaymentCards.swift in Sources */, FD05F94A2316CE5A000EAF52 /* VGSConfiguration.swift in Sources */, - A0C1F0A329EE319D00EE8447 /* DateFormatConvertor.swift in Sources */, 324B5E6F24A23D530036867E /* VGSValidationRule.swift in Sources */, 324B5E7524A23FA60036867E /* VGSValidationRuleExpirationDate.swift in Sources */, 441B26F025DB956B0099AA3A /* URL+Extensions.swift in Sources */, 0351799B2858B3B700394BFC /* VGSTextFieldTokenizationProtocol.swift in Sources */, - A0988FA129F9739600FAFA67 /* VGSValidationRuleDateRange.swift in Sources */, 441B26DD25DB88DB0099AA3A /* VGSResponse.swift in Sources */, 325AB9CB2420C5410024134B /* VGSFilePickerControllerDelegate.swift in Sources */, 328B5C7023C8DA2600A39515 /* String+extension.swift in Sources */, 32093D7D25CD9F88006CD242 /* VGSCollectLogEvent.swift in Sources */, 44ECD60427D9C18C00460FDF /* CheckSumAlgoritmType.swift in Sources */, 3215C4BC260DAF3D00F21259 /* VGSFormatSerializerProtocol.swift in Sources */, - A0752C7529EF376100337C99 /* VGSDateSeparateSerializer.swift in Sources */, 441B4E9B293EFD050011EFAC /* VGSCollectHTTPMethod.swift in Sources */, 32093D8625CDA3E6006CD242 /* VGSReadWriteSafeContainer.swift in Sources */, FD3C01C323AFC0980096B4A4 /* VGSTextField+CVC.swift in Sources */, 44F8F51C25DBD1950052647A /* VGSCollectSatelliteUtils.swift in Sources */, - A0C1F09C29EE30AB00EE8447 /* VGSDateConfiguration.swift in Sources */, 326FFB0424F90B940024A4F9 /* CrardScannerInteractionProtocol.swift in Sources */, 44ECD5FE27D9C18C00460FDF /* VGSPaymentCardModel.swift in Sources */, FD8B62472497CD580097C9AB /* VGSExpDateTextField.swift in Sources */, @@ -1613,7 +1503,6 @@ FD05F9472316CE5A000EAF52 /* Storage.swift in Sources */, 449C8A4025F2521900BE009F /* VGSFieldNameSubscriptType.swift in Sources */, 3259B39D263079AD008EECE0 /* VGSExpirationDateTextFieldUtils.swift in Sources */, - A01CE3F729E5D67E0059700F /* VGSDateTextField.swift in Sources */, 4479453E25F8C032006CB371 /* VGSCollect+fieldNameMapping.swift in Sources */, 441B26D625DB88C50099AA3A /* APICustomHostStatus.swift in Sources */, 441B26D225DB88C50099AA3A /* APIClient.swift in Sources */, @@ -1629,12 +1518,10 @@ 324B5E9D24A64A600036867E /* VGSValidationRulePaymentCard.swift in Sources */, 327C9E142407EF92004C641C /* VGSErrorInfo.swift in Sources */, 32F4B7F424C881FA006086F3 /* Calendar+extension.swift in Sources */, - A08DA9FF29F1D4D500DA62A5 /* VGSDateFormat.swift in Sources */, 32F23A6D24B60E1100E389F7 /* VGSValidationRuleLengthMatch.swift in Sources */, 321300172417F2B70062FEF0 /* VGSTextField.swift in Sources */, 328A574023FADC3500714675 /* VGSFilePickerConfiguration.swift in Sources */, 449C89DC25F0ABB000BE009F /* Collection+Extensions.swift in Sources */, - A0C1F09A29EE30AB00EE8447 /* VGSDate.swift in Sources */, 328A574223FADD3D00714675 /* VGSFilePickerController+internal.swift in Sources */, 32093D7B25CD9F88006CD242 /* VGSCollectLogger.swift in Sources */, FD1489FF232D4F8000FD7781 /* MaskedTextField.swift in Sources */, @@ -1672,9 +1559,7 @@ FDF696E3234643F300063507 /* LuhnTests.swift in Sources */, 44C23A7925F7B7EF000EA556 /* VGSFieldNameToJSONTests.swift in Sources */, 3270D3F1248155B200004E3B /* SSNTextFieldTests.swift in Sources */, - A08DAA0129F1D52A00DA62A5 /* VGSDateFormatTests.swift in Sources */, 44D520AE2672218A005AB588 /* VGSFlatJSONStructMappingTests.swift in Sources */, - A0752C7829EF3C9200337C99 /* DateTextFieldTest.swift in Sources */, FDF696E123463ACB00063507 /* TextFielsStyleUI.swift in Sources */, 442A391729097425007CCC58 /* VGSTokenizationResponseMappingTests.swift in Sources */, 3213005B241FA0BE0062FEF0 /* VGSCollectTest+Validation.swift in Sources */, @@ -1688,13 +1573,10 @@ FDA680DF239844FC00372817 /* CardTextFieldTests.swift in Sources */, 44447F8025F7651100D4CE68 /* JSONData+Extensions.swift in Sources */, 32F23A7924B752E200E389F7 /* PaymentCardsTest.swift in Sources */, - A0BCC67229F064D4009F1118 /* DateTests.swift in Sources */, FDAAB6AD249A9257001F5C1A /* FileInfoTest.swift in Sources */, 44168FBF2632945D0088E515 /* VGSExpirationDateTextFieldUtilsTests.swift in Sources */, 327C9E172407FC58004C641C /* VGSErrorInfo.swift in Sources */, FDAAB6AB249A8844001F5C1A /* ExpDateTextField.swift in Sources */, - A093FE1729F0AA76002C6ABC /* VGSDateSeparateSerializerTests.swift in Sources */, - A093FE2429F0BDC7002C6ABC /* SerializersDataProvider.swift in Sources */, FDF696E52346461D00063507 /* StorageTests.swift in Sources */, FD1BE48823462F1E006D8658 /* ExpDateTextFieldTests.swift in Sources */, FD790B97243BB403006A30CB /* CardBrandTest.swift in Sources */, @@ -1702,19 +1584,17 @@ 32AFB93724FFD218007FFCAE /* VGSTextFieldTests.swift in Sources */, 0313A1202975A22700DB2F2C /* VGSTokenizationConfigurationTests.swift in Sources */, 449C89E925F0AFF400BE009F /* VGSDeepMergeUtilsTests.swift in Sources */, - A0BCC67429F06CF6009F1118 /* DateConvertorTests.swift in Sources */, 322F94D725BAC3E0001CDF12 /* ExpDateConvertorTests.swift in Sources */, FD4ED0E52373666500AEAD24 /* TextFieldSecurity.swift in Sources */, - A08DA9FC29F1CE0B00DA62A5 /* VGSDateTokenizationSerializerTests.swift in Sources */, FD24955E2330CC62009024E6 /* VGSCollectTests.swift in Sources */, 324B5E7B24A3A5880036867E /* ValidationRulesTest.swift in Sources */, 44447F7725F74CCC00D4CE68 /* VGSFieldNameMapUtilsTests.swift in Sources */, 442BB2C82873158A001FD26B /* MockedDataProvider.swift in Sources */, 4404600F256801890064BEA0 /* APIHostnameValidatorTests.swift in Sources */, - A08E91B529F04600007EDA49 /* ValidationRuleDateTests.swift in Sources */, 3299585D23DF043D0018FA50 /* MaskedTextFieldTest.swift in Sources */, 324CDEE323FB12E200653890 /* FilePickerTests.swift in Sources */, 443FDDC225DD4B2B006932C4 /* VGSCollectBaseTestCase.swift in Sources */, + 4459728A26135BE600139EAA /* VGSExpDateSerializersDataProvider.swift in Sources */, 327C9E182407FC62004C641C /* VGSErrorInfoKey.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/demoapp/demoapp.xcodeproj/project.pbxproj b/demoapp/demoapp.xcodeproj/project.pbxproj index 3a5c6e16..1af5cd1d 100644 --- a/demoapp/demoapp.xcodeproj/project.pbxproj +++ b/demoapp/demoapp.xcodeproj/project.pbxproj @@ -52,7 +52,6 @@ 44D8691C26205F670014645F /* SSNCollectingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44D8691426205F670014645F /* SSNCollectingViewController.swift */; }; 44D8691D26205F670014645F /* CustomDataCollectingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44D8691526205F670014645F /* CustomDataCollectingViewController.swift */; }; 44D8692026205F670014645F /* FilePickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44D8691926205F670014645F /* FilePickerViewController.swift */; }; - A01CE3F529E5C50D0059700F /* DateValidationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A01CE3F429E5C50D0059700F /* DateValidationViewController.swift */; }; C8CBAAC0A0A75BF9CF5A7FA4 /* Pods_demoapp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DAC2D9D525DA573788F57B /* Pods_demoapp.framework */; }; FD12B9782304616C00B670DD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD12B9772304616C00B670DD /* AppDelegate.swift */; }; FD12B97F2304616E00B670DD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FD12B97E2304616E00B670DD /* Assets.xcassets */; }; @@ -131,7 +130,6 @@ 7D9EC63EB636126947A436E7 /* libPods-demoappUITests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-demoappUITests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 971F95F0CD23156BC2F071A3 /* Pods-demoappUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-demoappUITests.release.xcconfig"; path = "Target Support Files/Pods-demoappUITests/Pods-demoappUITests.release.xcconfig"; sourceTree = ""; }; 9E14BE9AC3107988B3A45EBF /* Pods-demoapp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-demoapp.release.xcconfig"; path = "Target Support Files/Pods-demoapp/Pods-demoapp.release.xcconfig"; sourceTree = ""; }; - A01CE3F429E5C50D0059700F /* DateValidationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateValidationViewController.swift; sourceTree = ""; }; B96EAC87AAF5BF889451003A /* Pods-demoapp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-demoapp.debug.xcconfig"; path = "Target Support Files/Pods-demoapp/Pods-demoapp.debug.xcconfig"; sourceTree = ""; }; C0DAC2D9D525DA573788F57B /* Pods_demoapp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_demoapp.framework; sourceTree = BUILT_PRODUCTS_DIR; }; FD12B9742304616C00B670DD /* demoapp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = demoapp.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -349,7 +347,6 @@ 44D8691926205F670014645F /* FilePickerViewController.swift */, 03DBB7B3292FBFDA00F4DCA2 /* CollectApplePayDataViewController.swift */, 03B992D729C8A5BF00B10A70 /* CombineExamplesViewController.swift */, - A01CE3F429E5C50D0059700F /* DateValidationViewController.swift */, ); path = UseCases; sourceTree = ""; @@ -722,7 +719,6 @@ 44D8692026205F670014645F /* FilePickerViewController.swift in Sources */, 446FE1D625D557080021C7C0 /* UIDevice+Extensions.swift in Sources */, 44D8691C26205F670014645F /* SSNCollectingViewController.swift in Sources */, - A01CE3F529E5C50D0059700F /* DateValidationViewController.swift in Sources */, 44D8691D26205F670014645F /* CustomDataCollectingViewController.swift in Sources */, 449FFCBE28A517E200FE4A1F /* UITableView+Extensions.swift in Sources */, 0351799F2858D53C00394BFC /* CardsDataTokenizationViewController.swift in Sources */, @@ -915,7 +911,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 35; - DEVELOPMENT_TEAM = 7S7622HN85; + DEVELOPMENT_TEAM = 4445Y664U5; INFOPLIST_FILE = demoapp/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.1; LD_RUNPATH_SEARCH_PATHS = ( @@ -941,7 +937,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 35; - DEVELOPMENT_TEAM = 7S7622HN85; + DEVELOPMENT_TEAM = 4445Y664U5; INFOPLIST_FILE = demoapp/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.1; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/demoapp/demoapp/Main.storyboard b/demoapp/demoapp/Main.storyboard index d971ec2d..4b2159ea 100644 --- a/demoapp/demoapp/Main.storyboard +++ b/demoapp/demoapp/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -100,14 +100,14 @@ - + - + - - + - + - + - - + - + - + - - + - + - + - - - - - - - - - - - - - - - - + - + @@ -443,7 +423,7 @@ - + @@ -938,7 +918,7 @@ - + @@ -1333,151 +1313,25 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + - + - + - + - - - + - + - + - + - - - - - - - - - - - + + + + + + + + + + - + - - - - - - - - - - + + + + + + + + + + - - + + - - - - + + + + - + - + diff --git a/demoapp/demoapp/UseCases/DateValidationViewController.swift b/demoapp/demoapp/UseCases/DateValidationViewController.swift deleted file mode 100644 index 11f20738..00000000 --- a/demoapp/demoapp/UseCases/DateValidationViewController.swift +++ /dev/null @@ -1,186 +0,0 @@ -// -// DateValidationViewController.swift -// demoapp -// - -import UIKit -import VGSCollectSDK - -class DateValidationViewController: UIViewController { - - // MARK: - Outlets - @IBOutlet weak var containerStackView: UIStackView! - @IBOutlet weak var consoleStatusLabel: UILabel! - @IBOutlet weak var consoleLabel: UILabel! - - // MARK: - Properties - /// Init VGS Collector - var vgsCollect = VGSCollect( - id: AppCollectorConfiguration.shared.vaultId, - environment: AppCollectorConfiguration.shared.environment - ) - /// VGS UI Elements - var dateField = VGSDateTextField() - var consoleMessage: String = "" { - didSet { - consoleLabel.text = consoleMessage - } - } - - // MARK: - View life cycle - override func viewDidLoad() { - super.viewDidLoad() - - /// Configuration - setupUI() - setupElementsConfiguration() - - /// Set custom headers - vgsCollect.customHeaders = [ - "my custome header": "some custom data" - ] - - /// Observe VGSTextFields changes - vgsCollect.observeStates = { [weak self] form in - - self?.consoleMessage = "" - self?.consoleStatusLabel.text = "STATE" - - form.forEach({ textField in - self?.consoleMessage.append(textField.state.description) - self?.consoleMessage.append("\n") - }) - } - } -} - -// MARK: - Private methods -private extension DateValidationViewController { - - func setupUI() { - containerStackView.addArrangedSubview(dateField) - let tapGesture = UITapGestureRecognizer( - target: self, - action: #selector(hideKeyboard) - ) - consoleLabel.addGestureRecognizer(tapGesture) - consoleLabel.isUserInteractionEnabled = true - view.addGestureRecognizer(tapGesture) - } - - @objc - func hideKeyboard() { - view.endEditing(true) - consoleLabel.endEditing(true) - } - - func setupElementsConfiguration() { - - /// Start and end dates - let startDate = VGSDate(day: 1, month: 1, year: 2010) - let endDate = VGSDate(day: 20, month: 12, year: 2025) - - // Date format - let inputDateFormat = VGSDateFormat.mmddyyyy - - /// Create configuration - let dateFieldConfiguration = VGSDateConfiguration( - collector: vgsCollect, - fieldName: "date_field", - datePickerStartDate: startDate, - datePickerEndDate: endDate - ) - dateFieldConfiguration.inputDateFormat = inputDateFormat - dateFieldConfiguration.outputDateFormat = .yyyymmdd - dateFieldConfiguration.inputSource = .datePicker - dateFieldConfiguration.divider = "-" - dateFieldConfiguration.formatPattern = "##/##/####" - - /// Setup validation rules, it is important to set the same start and - /// end date used in the configuration - dateFieldConfiguration.validationRules = VGSValidationRuleSet( - rules: [ - VGSValidationRuleDateRange( - dateFormat: inputDateFormat, - error: VGSValidationErrorType.date.rawValue, - start: startDate, - end: endDate - ) - ] - ) - - /// Update configuration in the text field - dateField.configuration = dateFieldConfiguration - dateField.placeholder = "MM-DD-YYYY" - dateField.monthPickerFormat = .longSymbols - - /// Add logging - vgsCollect.textFields.forEach { textField in - textField.textColor = UIColor.inputBlackTextColor - textField.font = .systemFont(ofSize: 22) - textField.padding = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) - textField.tintColor = .lightGray - /// Implement VGSTextFieldDelegate methods - textField.delegate = self - } - } - - // Upload data from TextFields to VGS - @IBAction func uploadAction(_ sender: Any) { - // Hide kayboard - hideKeyboard() - - // Check if textfields are valid - vgsCollect.textFields.forEach { textField in - textField.borderColor = textField.state.isValid ? .lightGray : .red - } - - // Send extra data - var extraData = [String: Any]() - extraData["customKey"] = "Custom Value" - - /// New sendRequest func - vgsCollect.sendData(path: "/post", extraData: extraData) { [weak self] (response) in - self?.consoleStatusLabel.text = "RESPONSE" - switch response { - case .success(_, let data, _): - if let data = data, let jsonData = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] { - // swiftlint:disable force_try - let response = ( - String(data: try! JSONSerialization.data(withJSONObject: jsonData["json"]!, - options: .prettyPrinted), encoding: .utf8)! - ) - self?.consoleLabel.text = "Success: \n\(response)" - print(response) - // swiftlint:enable force_try - } - return - - case .failure(let code, _, _, let error): - switch code { - case 400..<499: - // Wrong request. This also can happend when your Routs not setup yet or your is wrong - self?.consoleLabel.text = "Error: Wrong Request, code: \(code)" - - case VGSErrorType.inputDataIsNotValid.rawValue: - if let error = error as? VGSError { - self?.consoleLabel.text = "Error: Input data is not valid. Details:\n \(error)" - } - - default: - self?.consoleLabel.text = "Error: Something went wrong. Code: \(code)" - } - print("Submit request error: \(code), \(String(describing: error))") - return - } - } - } -} - -// MARK: - VGSTextFieldDelegate implementation -extension DateValidationViewController: VGSTextFieldDelegate { - - func vgsTextFieldDidChange(_ textField: VGSTextField) { - textField.borderColor = textField.state.isValid ? .gray : .red - } -} From 0e3bd45e8cf85a28bffad81bd6c5fd740ca5e618 Mon Sep 17 00:00:00 2001 From: Dmytro Khludkov Date: Mon, 12 Jun 2023 17:18:52 +0300 Subject: [PATCH 5/9] 8-digits bin support for Visa Electron. --- Sources/VGSCollectSDK/UIElements/Text Field/State/State.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/State/State.swift b/Sources/VGSCollectSDK/UIElements/Text Field/State/State.swift index 2fc4c331..4c803cf0 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/State/State.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/State/State.swift @@ -119,7 +119,7 @@ public class CardState: State { */ private func getBin(_ cardNumber: String, cardBrand: VGSPaymentCards.CardBrand) -> String { switch cardBrand { - case .visa, .mastercard, .maestro: + case .visa, .visaElectron, .mastercard, .maestro: /// check min card length allowed guard cardNumber.count >= 16 else { return "" From 8064a7764bf911c77bc3b06e8d4fc507353a2ce6 Mon Sep 17 00:00:00 2001 From: Dmytro Khludkov Date: Mon, 12 Jun 2023 17:19:29 +0300 Subject: [PATCH 6/9] Update reference docs. --- .jazzy.yaml | 31 +- docs/Classes/CardState.html | 291 ++-- docs/Classes/SSNState.html | 257 +-- docs/Classes/State.html | 366 +++-- docs/Classes/VGSCVCTextField.html | 283 ++-- .../VGSCVCTextField/CVCIconLocation.html | 253 +-- .../VGSCVCTokenizationConfiguration.html | 255 +-- ...rdHolderNameTokenizationConfiguration.html | 255 +-- ...GSCardNumberTokenizationConfiguration.html | 255 +-- docs/Classes/VGSCardTextField.html | 283 ++-- .../VGSCardTextField/CardIconLocation.html | 253 +-- docs/Classes/VGSCollect.html | 1373 +++++++++++++++-- docs/Classes/VGSCollectLogger.html | 268 ++-- docs/Classes/VGSConfiguration.html | 459 ++++-- docs/Classes/VGSDateConfiguration.html | 757 +++++++++ docs/Classes/VGSDateTextField.html | 536 +++++++ .../Classes/VGSDateTextField/MonthFormat.html | 500 ++++++ .../VGSDateTokenizationConfiguration.html | 655 ++++++++ docs/Classes/VGSError.html | 268 ++-- docs/Classes/VGSExpDateConfiguration.html | 302 ++-- docs/Classes/VGSExpDateTextField.html | 280 ++-- .../VGSExpDateTextField/MonthFormat.html | 268 ++-- .../VGSExpDateTextField/YearFormat.html | 253 +-- .../VGSExpDateTokenizationConfiguration.html | 317 ++-- docs/Classes/VGSFileInfo.html | 268 ++-- docs/Classes/VGSFilePickerConfiguration.html | 296 ++-- docs/Classes/VGSFilePickerController.html | 376 +++-- docs/Classes/VGSPaymentCards.html | 514 ++++-- docs/Classes/VGSPaymentCards/CardBrand.html | 523 +++++-- .../VGSSSNTokenizationConfiguration.html | 255 +-- docs/Classes/VGSTextField.html | 648 ++++++-- .../Classes/VGSTokenizationConfiguration.html | 238 +-- docs/Debugging.html | 258 ++-- docs/Enumerations.html | 243 +-- docs/Enums/CheckSumAlgorithmType.html | 253 +-- docs/Enums/Environment.html | 253 +-- docs/Enums/FieldType.html | 343 ++-- docs/Enums/VGSCardExpDateFormat.html | 283 ++-- .../VGSCollectFieldNameMappingPolicy.html | 283 ++-- docs/Enums/VGSCollectHTTPMethod.html | 298 ++-- docs/Enums/VGSDateFormat.html | 483 ++++++ docs/Enums/VGSErrorType.html | 343 ++-- docs/Enums/VGSFileSource.html | 268 ++-- docs/Enums/VGSLogLevel.html | 268 ++-- docs/Enums/VGSResponse.html | 352 +++-- docs/Enums/VGSTextFieldInputSource.html | 253 +-- docs/Enums/VGSTokenizationResponse.html | 352 +++-- docs/Enums/VGSValidationErrorType.html | 343 ++-- docs/Enums/VGSVaultAliasFormat.html | 358 +++-- docs/Enums/VGSVaultStorageType.html | 253 +-- docs/Error Keys.html | 335 ++-- docs/Errors.html | 288 ++-- docs/File Picker.html | 289 ++-- docs/Observe State and Send Data.html | 448 ++++-- docs/Other Classes.html | 519 ------- docs/Other Enums.html | 499 ------ docs/Other Extensions.html | 466 ------ docs/Other Protocols.html | 439 ------ docs/Payment Cards.html | 275 ++-- .../VGSDateConfigurationProtocol.html | 500 ++++++ .../VGSExpDateConfigurationProtocol.html | 268 ++-- .../VGSFilePickerControllerDelegate.html | 269 ++-- docs/Protocols/VGSTextFieldDelegate.html | 288 ++-- .../VGSTokenizationParametersProtocol.html | 253 +-- .../Structs/VGSCVCTokenizationParameters.html | 253 +-- ...SCardHolderNameTokenizationParameters.html | 253 +-- .../VGSCardNumberTokenizationParameters.html | 253 +-- .../VGSCollectLoggingConfiguration.html | 268 ++-- docs/Structs/VGSCollectRequestOptions.html | 253 +-- docs/Structs/VGSCustomPaymentCardModel.html | 474 ++++-- docs/Structs/VGSDate.html | 570 +++++++ .../VGSDateTokenizationParameters.html | 470 ++++++ .../Structs/VGSExpDateSeparateSerializer.html | 299 ++-- .../VGSExpDateTokenizationParameters.html | 253 +-- docs/Structs/VGSPaymentCardModel.html | 360 +++-- .../Structs/VGSSSNTokenizationParameters.html | 253 +-- docs/Structs/VGSTextFieldStatePublisher.html | 518 +++++++ docs/Structs/VGSTokenizationParameters.html | 253 +-- docs/Structs/VGSUnknownPaymentCardModel.html | 332 ++-- .../VGSValidationRuleCardExpirationDate.html | 301 ++-- docs/Structs/VGSValidationRuleDateRange.html | 581 +++++++ docs/Structs/VGSValidationRuleLength.html | 328 ++-- .../Structs/VGSValidationRuleLengthMatch.html | 301 ++-- docs/Structs/VGSValidationRuleLuhnCheck.html | 274 ++-- docs/Structs/VGSValidationRulePattern.html | 301 ++-- .../Structs/VGSValidationRulePaymentCard.html | 339 ++-- docs/Structs/VGSValidationRuleSet.html | 291 ++-- ...ucts.html => Tokenization Parameters.html} | 440 ++++-- docs/UI Elements.html | 769 +++++++-- docs/VGSTextField Serializers.html | 243 +-- docs/Validation Rules.html | 367 +++-- .../Documents/Classes/CardState.html | 291 ++-- .../Resources/Documents/Classes/SSNState.html | 257 +-- .../Resources/Documents/Classes/State.html | 366 +++-- .../Documents/Classes/VGSCVCTextField.html | 283 ++-- .../VGSCVCTextField/CVCIconLocation.html | 253 +-- .../VGSCVCTokenizationConfiguration.html | 255 +-- ...rdHolderNameTokenizationConfiguration.html | 255 +-- ...GSCardNumberTokenizationConfiguration.html | 255 +-- .../Documents/Classes/VGSCardTextField.html | 283 ++-- .../VGSCardTextField/CardIconLocation.html | 253 +-- .../Documents/Classes/VGSCollect.html | 1373 +++++++++++++++-- .../Documents/Classes/VGSCollectLogger.html | 268 ++-- .../Documents/Classes/VGSConfiguration.html | 459 ++++-- .../Classes/VGSDateConfiguration.html | 757 +++++++++ .../Documents/Classes/VGSDateTextField.html | 536 +++++++ .../Classes/VGSDateTextField/MonthFormat.html | 500 ++++++ .../VGSDateTokenizationConfiguration.html | 655 ++++++++ .../Resources/Documents/Classes/VGSError.html | 268 ++-- .../Classes/VGSExpDateConfiguration.html | 302 ++-- .../Classes/VGSExpDateTextField.html | 280 ++-- .../VGSExpDateTextField/MonthFormat.html | 268 ++-- .../VGSExpDateTextField/YearFormat.html | 253 +-- .../VGSExpDateTokenizationConfiguration.html | 317 ++-- .../Documents/Classes/VGSFileInfo.html | 268 ++-- .../Classes/VGSFilePickerConfiguration.html | 296 ++-- .../Classes/VGSFilePickerController.html | 376 +++-- .../Documents/Classes/VGSPaymentCards.html | 514 ++++-- .../Classes/VGSPaymentCards/CardBrand.html | 523 +++++-- .../VGSSSNTokenizationConfiguration.html | 255 +-- .../Documents/Classes/VGSTextField.html | 648 ++++++-- .../Classes/VGSTokenizationConfiguration.html | 238 +-- .../Resources/Documents/Debugging.html | 258 ++-- .../Resources/Documents/Enumerations.html | 243 +-- .../Enums/CheckSumAlgorithmType.html | 253 +-- .../Documents/Enums/Environment.html | 253 +-- .../Resources/Documents/Enums/FieldType.html | 343 ++-- .../Documents/Enums/VGSCardExpDateFormat.html | 283 ++-- .../VGSCollectFieldNameMappingPolicy.html | 283 ++-- .../Documents/Enums/VGSCollectHTTPMethod.html | 298 ++-- .../Documents/Enums/VGSDateFormat.html | 483 ++++++ .../Documents/Enums/VGSErrorType.html | 343 ++-- .../Documents/Enums/VGSFileSource.html | 268 ++-- .../Documents/Enums/VGSLogLevel.html | 268 ++-- .../Documents/Enums/VGSResponse.html | 352 +++-- .../Enums/VGSTextFieldInputSource.html | 253 +-- .../Enums/VGSTokenizationResponse.html | 352 +++-- .../Enums/VGSValidationErrorType.html | 343 ++-- .../Documents/Enums/VGSVaultAliasFormat.html | 358 +++-- .../Documents/Enums/VGSVaultStorageType.html | 253 +-- .../Resources/Documents/Error Keys.html | 335 ++-- .../Contents/Resources/Documents/Errors.html | 288 ++-- .../Resources/Documents/File Picker.html | 289 ++-- .../Observe State and Send Data.html | 448 ++++-- .../Resources/Documents/Other Classes.html | 519 ------- .../Resources/Documents/Other Enums.html | 499 ------ .../Resources/Documents/Other Extensions.html | 466 ------ .../Resources/Documents/Other Protocols.html | 439 ------ .../Resources/Documents/Payment Cards.html | 275 ++-- .../VGSDateConfigurationProtocol.html | 500 ++++++ .../VGSExpDateConfigurationProtocol.html | 268 ++-- .../VGSFilePickerControllerDelegate.html | 269 ++-- .../Protocols/VGSTextFieldDelegate.html | 288 ++-- .../VGSTokenizationParametersProtocol.html | 253 +-- .../Structs/VGSCVCTokenizationParameters.html | 253 +-- ...SCardHolderNameTokenizationParameters.html | 253 +-- .../VGSCardNumberTokenizationParameters.html | 253 +-- .../VGSCollectLoggingConfiguration.html | 268 ++-- .../Structs/VGSCollectRequestOptions.html | 253 +-- .../Structs/VGSCustomPaymentCardModel.html | 474 ++++-- .../Resources/Documents/Structs/VGSDate.html | 570 +++++++ .../VGSDateTokenizationParameters.html | 470 ++++++ .../Structs/VGSExpDateSeparateSerializer.html | 299 ++-- .../VGSExpDateTokenizationParameters.html | 253 +-- .../Structs/VGSPaymentCardModel.html | 360 +++-- .../Structs/VGSSSNTokenizationParameters.html | 253 +-- .../Structs/VGSTextFieldStatePublisher.html | 518 +++++++ .../Structs/VGSTokenizationParameters.html | 253 +-- .../Structs/VGSUnknownPaymentCardModel.html | 332 ++-- .../VGSValidationRuleCardExpirationDate.html | 301 ++-- .../Structs/VGSValidationRuleDateRange.html | 581 +++++++ .../Structs/VGSValidationRuleLength.html | 328 ++-- .../Structs/VGSValidationRuleLengthMatch.html | 301 ++-- .../Structs/VGSValidationRuleLuhnCheck.html | 274 ++-- .../Structs/VGSValidationRulePattern.html | 301 ++-- .../Structs/VGSValidationRulePaymentCard.html | 339 ++-- .../Structs/VGSValidationRuleSet.html | 291 ++-- .../Documents/Tokenization Parameters.html} | 440 ++++-- .../Resources/Documents/UI Elements.html | 769 +++++++-- .../Documents/VGSTextField Serializers.html | 243 +-- .../Resources/Documents/Validation Rules.html | 367 +++-- .../Contents/Resources/Documents/index.html | 236 +-- .../Resources/Documents/js/jquery.min.js | 4 +- .../Contents/Resources/Documents/search.json | 2 +- .../Contents/Resources/docSet.dsidx | Bin 77824 -> 131072 bytes docs/docsets/VGSCollectSDK.tgz | Bin 160125 -> 242816 bytes docs/index.html | 236 +-- docs/js/jquery.min.js | 4 +- docs/search.json | 2 +- docs/undocumented.json | 73 +- 190 files changed, 43435 insertions(+), 21803 deletions(-) create mode 100644 docs/Classes/VGSDateConfiguration.html create mode 100644 docs/Classes/VGSDateTextField.html create mode 100644 docs/Classes/VGSDateTextField/MonthFormat.html create mode 100644 docs/Classes/VGSDateTokenizationConfiguration.html create mode 100644 docs/Enums/VGSDateFormat.html delete mode 100644 docs/Other Classes.html delete mode 100644 docs/Other Enums.html delete mode 100644 docs/Other Extensions.html delete mode 100644 docs/Other Protocols.html create mode 100644 docs/Protocols/VGSDateConfigurationProtocol.html create mode 100644 docs/Structs/VGSDate.html create mode 100644 docs/Structs/VGSDateTokenizationParameters.html create mode 100644 docs/Structs/VGSTextFieldStatePublisher.html create mode 100644 docs/Structs/VGSValidationRuleDateRange.html rename docs/{docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Structs.html => Tokenization Parameters.html} (56%) create mode 100644 docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSDateConfiguration.html create mode 100644 docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSDateTextField.html create mode 100644 docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSDateTextField/MonthFormat.html create mode 100644 docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSDateTokenizationConfiguration.html create mode 100644 docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSDateFormat.html delete mode 100644 docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Classes.html delete mode 100644 docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Enums.html delete mode 100644 docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Extensions.html delete mode 100644 docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Protocols.html create mode 100644 docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSDateConfigurationProtocol.html create mode 100644 docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSDate.html create mode 100644 docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSDateTokenizationParameters.html create mode 100644 docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSTextFieldStatePublisher.html create mode 100644 docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleDateRange.html rename docs/{Other Structs.html => docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Tokenization Parameters.html} (56%) diff --git a/.jazzy.yaml b/.jazzy.yaml index ae15e459..c57c444c 100644 --- a/.jazzy.yaml +++ b/.jazzy.yaml @@ -30,11 +30,37 @@ custom_categories: - VGSTextField - VGSCardTextField - VGSExpDateTextField + - VGSDateTextField - VGSCVCTextField - VGSTextFieldDelegate - VGSConfiguration - VGSExpDateConfiguration + - VGSDateConfiguration + - VGSCardHolderNameTokenizationConfiguration + - VGSCardNumberTokenizationConfiguration + - VGSCVCTokenizationConfiguration + - VGSDateTokenizationConfiguration + - VGSExpDateTokenizationConfiguration + - VGSSSNTokenizationConfiguration + - VGSTokenizationConfiguration + - VGSDateConfigurationProtocol + - VGSExpDateConfigurationProtocol - FieldType + - VGSDateFormat + - VGSDate + - VGSTextFieldInputSource +- name: Tokenization Parameters + children: + - VGSTokenizationParametersProtocol + - VGSCVCTokenizationParameters + - VGSCardHolderNameTokenizationParameters + - VGSCardNumberTokenizationParameters + - VGSDateTokenizationParameters + - VGSExpDateTokenizationParameters + - VGSSSNTokenizationParameters + - VGSTokenizationParameters + - VGSVaultAliasFormat + - VGSVaultStorageType - name: Card Scan children: - VGSCardIOScanController @@ -54,10 +80,12 @@ custom_categories: - State - SSNState - CardState + - VGSTextFieldStatePublisher - VGSResponse + - VGSTokenizationResponse - VGSCollectRequestOptions - JsonData - - HTTPMethod + - VGSCollectHTTPMethod - HTTPHeaders - name: Payment Cards children: @@ -78,6 +106,7 @@ custom_categories: - VGSValidationRulePaymentCard - VGSValidationRuleLuhnCheck - VGSValidationRuleCardExpirationDate + - VGSValidationRuleDateRange - CheckSumAlgorithmType - CardExpDateFormat - name: Errors diff --git a/docs/Classes/CardState.html b/docs/Classes/CardState.html index 5fc52267..7f3f558c 100644 --- a/docs/Classes/CardState.html +++ b/docs/Classes/CardState.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
@@ -375,8 +376,18 @@

CardState

-

An object that describes VGSTextField state with configuration FieldType.cardNumber . State attributes are read-only.

+
+
+ +
public class CardState : State
+
+
+

An object that describes VGSTextField state with configuration FieldType.cardNumber . State attributes are read-only.

+ +
@@ -387,9 +398,9 @@

CardState

  • - + - last4 + last4
    @@ -397,8 +408,19 @@

    CardState

    -

    Last 4 digits of the valid card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    +

    Last 4 digits of the valid card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var last4: String { get }
    +
    +
    +
    @@ -406,9 +428,9 @@

    CardState

  • - + - bin + bin
    @@ -416,8 +438,19 @@

    CardState

    -

    Bin digits of the valid card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    +

    Bin digits of the valid card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var bin: String { get }
    +
    +
    +
    @@ -425,9 +458,9 @@

    CardState

  • @@ -435,18 +468,29 @@

    CardState

    -

    Credit Card Brand of the card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    +

    Credit Card Brand of the card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var cardBrand: VGSPaymentCards.CardBrand { get }
    + +
    +
    +
  • @@ -457,6 +501,17 @@

    CardState

    Message that contains CardState attributes and their values.

    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var description: String { get }
    + +
    +
    +
  • @@ -468,8 +523,8 @@

    CardState

    diff --git a/docs/Classes/SSNState.html b/docs/Classes/SSNState.html index eca160e6..8f695bee 100644 --- a/docs/Classes/SSNState.html +++ b/docs/Classes/SSNState.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    SSNState

    -

    An object that describes VGSTextField state with configuration FieldType.ssn . State attributes are read-only.

    +
    +
    + +
    public class SSNState : State
    +
    +
    +

    An object that describes VGSTextField state with configuration FieldType.ssn . State attributes are read-only.

    + +
    @@ -387,9 +398,9 @@

    SSNState

  • - + - last4 + last4
    @@ -397,8 +408,19 @@

    SSNState

    -

    Last 4 digits of the valid ssn from associated VGSTextField with field configuration type FieldType.ssn.

    +

    Last 4 digits of the valid ssn from associated VGSTextField with field configuration type FieldType.ssn.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var last4: String { get }
    +
    +
    +
    @@ -406,9 +428,9 @@

    SSNState

  • @@ -419,6 +441,17 @@

    SSNState

    Message that contains SSNState attributes and their values.

    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var description: String { get }
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    SSNState

    diff --git a/docs/Classes/State.html b/docs/Classes/State.html index 4aab1a7d..b4761360 100644 --- a/docs/Classes/State.html +++ b/docs/Classes/State.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    State

    +
    +
    + +
    public class State
    + +
    +

    An object that describes VGSTextField state. State attributes are read-only.

    +
    @@ -387,9 +398,9 @@

    State

  • @@ -397,18 +408,29 @@

    State

    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var fieldName: String! { get }
    + +
    +
    +
  • @@ -416,18 +438,29 @@

    State

    -

    VGSConfiguration.isRequired attribute defined for VGSTextField

    +

    VGSConfiguration.isRequired attribute defined for VGSTextField

    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var isRequired: Bool { get }
    + +
    +
    +
  • @@ -435,18 +468,29 @@

    State

    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var isRequiredValidOnly: Bool { get }
    + +
    +
    +
  • - + - isValid + isValid
    @@ -457,15 +501,26 @@

    State

    Contains current validation state for VGSTextField

    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var isValid: Bool { get }
    + +
    +
    +
  • - + - isEmpty + isEmpty
    @@ -476,15 +531,26 @@

    State

    Show if VGSTextField input is empty

    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var isEmpty: Bool { get }
    + +
    +
    +
  • - + - isDirty + isDirty
    @@ -495,15 +561,26 @@

    State

    Show if VGSTextField was edited

    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var isDirty: Bool { get }
    + +
    +
    +
  • @@ -514,15 +591,26 @@

    State

    Input data length in VGSTextField

    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var inputLength: Int { get }
    + +
    +
    +
  • @@ -530,18 +618,29 @@

    State

    -

    Array of VGSValidationError. Should be empty when textfield input is valid.

    +

    Array of VGSValidationError. Should be empty when textfield input is valid.

    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var validationErrors: [VGSValidationError] { get }
    + +
    +
    +
  • @@ -552,6 +651,17 @@

    State

    Message that contains State attributes and their values

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var description: String { get }
    + +
    +
    +
  • @@ -563,8 +673,8 @@

    State

    diff --git a/docs/Classes/VGSCVCTextField.html b/docs/Classes/VGSCVCTextField.html index e71240ce..be69d3bf 100644 --- a/docs/Classes/VGSCVCTextField.html +++ b/docs/Classes/VGSCVCTextField.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCVCTextField

    +
    +
    + +
    public final class VGSCVCTextField : VGSTextField
    + +
    +

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to show CVC/CVV images for credit card brands.

    +
    @@ -396,9 +407,9 @@

    Enum cases
  • @@ -410,6 +421,17 @@

    Enum cases See more

    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum CVCIconLocation
    + +
    +
    +
  • @@ -429,9 +451,9 @@

    Attributes
  • @@ -442,15 +464,26 @@

    Attributes

    CVC icon position inside VGSCardTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcIconLocation: VGSCVCTextField.CVCIconLocation { get set }
    + +
    +
    +
  • @@ -461,6 +494,17 @@

    Attributes

    CVC icon size.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcIconSize: CGSize { get set }
    + +
    +
    +
  • @@ -480,9 +524,9 @@

    Custom CVC images for specific card brands
  • @@ -493,6 +537,17 @@

    Custom CVC images for specific card brands

    Asks custom image for specific VGSPaymentCards.CardBrand

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcIconSource: ((VGSPaymentCards.CardBrand) -> UIImage?)?
    + +
    +
    +
  • @@ -504,8 +559,8 @@

    Custom CVC images for specific card brands

    diff --git a/docs/Classes/VGSCVCTextField/CVCIconLocation.html b/docs/Classes/VGSCVCTextField/CVCIconLocation.html index f5526019..f7357ce7 100644 --- a/docs/Classes/VGSCVCTextField/CVCIconLocation.html +++ b/docs/Classes/VGSCVCTextField/CVCIconLocation.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    CVCIconLocation

    +
    +
    + +
    public enum CVCIconLocation
    + +
    +

    Available CVC icon positions enum.

    +
    @@ -387,9 +398,9 @@

    CVCIconLocation

  • - + - left + left
    @@ -400,15 +411,26 @@

    CVCIconLocation

    CVC icon at left side of VGSCardTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case left
    + +
    +
    +
  • - + - right + right
    @@ -419,6 +441,17 @@

    CVCIconLocation

    CVC icon at right side of VGSCardTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case right
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    CVCIconLocation

    diff --git a/docs/Classes/VGSCVCTokenizationConfiguration.html b/docs/Classes/VGSCVCTokenizationConfiguration.html index 7987fc27..448faf60 100644 --- a/docs/Classes/VGSCVCTokenizationConfiguration.html +++ b/docs/Classes/VGSCVCTokenizationConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCVCTokenizationConfiguration

    +
    +
    + +
    public class VGSCVCTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +

    VGSCVCTokenizationConfiguration - textfield configuration for textfield with type .cvc, required for work with tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSCVCTokenizationConfiguration

  • @@ -400,15 +411,26 @@

    VGSCVCTokenizationConfiguration

    VGSCVCTokenizationParameters - tokenization configuration parameters.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var tokenizationParameters: VGSCVCTokenizationParameters
    + +
    +
    +
  • - + - type + type
    @@ -416,9 +438,20 @@

    VGSCVCTokenizationConfiguration

    -

    FieldType.cvc type of VGSTextFieldtokenization configuration.

    +

    FieldType.cvc type of VGSTextFieldtokenization configuration.

    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var type: FieldType { get set }
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSCVCTokenizationConfiguration

    diff --git a/docs/Classes/VGSCardHolderNameTokenizationConfiguration.html b/docs/Classes/VGSCardHolderNameTokenizationConfiguration.html index fdc946af..a6eac2ba 100644 --- a/docs/Classes/VGSCardHolderNameTokenizationConfiguration.html +++ b/docs/Classes/VGSCardHolderNameTokenizationConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCardHolderNameTokenizationConfiguration

    +
    +
    + +
    public class VGSCardHolderNameTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +

    VGSCardHolderNameTokenizationConfiguration - textfield configuration for textfield with type .cardHolderName, required for work with tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSCardHolderNameTokenizationConfiguration

  • @@ -400,15 +411,26 @@

    VGSCardHolderNameTokenizationConfiguration

    VGSCardHolderNameTokenizationParameters - tokenization configuration parameters.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var tokenizationParameters: VGSCardHolderNameTokenizationParameters
    + +
    +
    +
  • - + - type + type
    @@ -416,9 +438,20 @@

    VGSCardHolderNameTokenizationConfiguration

    -

    FieldType.cardHolderName type of VGSTextFieldtokenization configuration.

    +

    FieldType.cardHolderName type of VGSTextFieldtokenization configuration.

    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var type: FieldType { get set }
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSCardHolderNameTokenizationConfiguration

    diff --git a/docs/Classes/VGSCardNumberTokenizationConfiguration.html b/docs/Classes/VGSCardNumberTokenizationConfiguration.html index 28bca781..f35f52d1 100644 --- a/docs/Classes/VGSCardNumberTokenizationConfiguration.html +++ b/docs/Classes/VGSCardNumberTokenizationConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCardNumberTokenizationConfiguration

    +
    +
    + +
    public class VGSCardNumberTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +

    VGSCardTokenizationConfiguration - textfield configuration for textfield with type .cardNumber, required for work with tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSCardNumberTokenizationConfiguration

  • @@ -400,15 +411,26 @@

    VGSCardNumberTokenizationConfiguration

    VGSCardTokenizationParameters - tokenization configuration parameters.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var tokenizationParameters: VGSCardNumberTokenizationParameters
    + +
    +
    +
  • - + - type + type
    @@ -416,9 +438,20 @@

    VGSCardNumberTokenizationConfiguration

    -

    FieldType.cardNumber type of VGSTextFieldtokenization configuration.

    +

    FieldType.cardNumber type of VGSTextFieldtokenization configuration.

    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var type: FieldType { get set }
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSCardNumberTokenizationConfiguration

    diff --git a/docs/Classes/VGSCardTextField.html b/docs/Classes/VGSCardTextField.html index cd28a1ad..ac1e17ce 100644 --- a/docs/Classes/VGSCardTextField.html +++ b/docs/Classes/VGSCardTextField.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCardTextField

    +
    +
    + +
    public final class VGSCardTextField : VGSTextField
    + +
    +

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to detect and show credit card brand images.

    +
    @@ -396,9 +407,9 @@

    Enum cases
  • @@ -410,6 +421,17 @@

    Enum cases See more

    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum CardIconLocation
    + +
    +
    +
  • @@ -429,9 +451,9 @@

    Attributes
  • @@ -442,15 +464,26 @@

    Attributes

    Card brand icon position inside VGSCardTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cardIconLocation: VGSCardTextField.CardIconLocation { get set }
    + +
    +
    +
  • @@ -461,6 +494,17 @@

    Attributes

    Card brand icon size.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cardIconSize: CGSize { get set }
    + +
    +
    +
  • @@ -480,9 +524,9 @@

    Custom card brand images
  • @@ -493,6 +537,17 @@

    Custom card brand images

    Asks custom image for specific VGSPaymentCards.CardBrand

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cardsIconSource: ((VGSPaymentCards.CardBrand) -> UIImage?)?
    + +
    +
    +
  • @@ -504,8 +559,8 @@

    Custom card brand images

    diff --git a/docs/Classes/VGSCardTextField/CardIconLocation.html b/docs/Classes/VGSCardTextField/CardIconLocation.html index 49cd901c..3a7ca7be 100644 --- a/docs/Classes/VGSCardTextField/CardIconLocation.html +++ b/docs/Classes/VGSCardTextField/CardIconLocation.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    CardIconLocation

    +
    +
    + +
    public enum CardIconLocation
    + +
    +

    Available Card brand icon positions enum.

    +
    @@ -387,9 +398,9 @@

    CardIconLocation

  • - + - left + left
    @@ -400,15 +411,26 @@

    CardIconLocation

    Card brand icon at left side of VGSCardTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case left
    + +
    +
    +
  • - + - right + right
    @@ -419,6 +441,17 @@

    CardIconLocation

    Card brand icon at right side of VGSCardTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case right
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    CardIconLocation

    diff --git a/docs/Classes/VGSCollect.html b/docs/Classes/VGSCollect.html index de2a9f13..81178585 100644 --- a/docs/Classes/VGSCollect.html +++ b/docs/Classes/VGSCollect.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCollect

    +
    +
    + +
    public class VGSCollect
    + +
    +

    An object you use for observing VGSTextField State and send data to your organization vault.

    +
    @@ -396,9 +407,9 @@

    Custom HTTP Headers
  • @@ -409,6 +420,17 @@

    Custom HTTP Headers

    Set your custom HTTP headers.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var customHeaders: [String : String]? { get set }
    + +
    +
    +
  • @@ -428,9 +450,9 @@

    Observe VGSTextField states
  • @@ -441,15 +463,26 @@

    Observe VGSTextField states

    Observe only focused VGSTextField on editing events.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var observeFieldState: ((_ textField: VGSTextField) -> Void)?
    + +
    +
    +
  • @@ -460,6 +493,17 @@

    Observe VGSTextField states

    Observe all VGSTextField on editing events.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var observeStates: ((_ form: [VGSTextField]) -> Void)?
    + +
    +
    +
  • @@ -479,9 +523,9 @@

    Get Registered VGSTextFields
  • @@ -492,6 +536,17 @@

    Get Registered VGSTextFields

    Returns array of VGSTextFields associated with VGSCollect instance.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var textFields: [VGSTextField] { get }
    + +
    +
    +
  • @@ -499,11 +554,11 @@

    Get Registered VGSTextFields
    - - + +
    - -

    Initialzation + +

    Initialization

    @@ -511,9 +566,9 @@

    Initialzation
  • @@ -521,8 +576,74 @@

    Initialzation
    -

    Initialzation.

    +

    Initialization.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(id: String, environment: String, hostname: String? = nil, satellitePort: Int? = nil)
    +
    +
    +
    +

    Parameters

    + + + + + + + + + + + + + + + + + + + +
    + + id + + +
    +

    String object, your organization vault id.

    +
    +
    + + environment + + +
    +

    String object, your organization vault environment with data region.(e.g. “live”, “live-eu1”, “sandbox”).

    +
    +
    + + hostname + + +
    +

    String? object, custom Hostname, if not set, data will be sent to Vault Url. Default is nil.

    +
    +
    + + satellitePort + + +
    +

    Int? object, custom port for satellite configuration. Default is nil. IMPORTANT! Use only with .sandbox environment! Hostname should be specified for valid http://localhost or in local IP format http://192.168.X.X.

    +
    +
    +
    +

    @@ -530,9 +651,9 @@

    Initialzation
  • @@ -540,9 +661,87 @@

    Initialzation
    -

    Initialzation.

    +

    Initialization.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public convenience init(id: String, environment: Environment = .sandbox, dataRegion: String? = nil, hostname: String? = nil, satellitePort: Int? = nil)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + + + + + + + + + + + + + +
    + + id + + +
    +

    String object, your organization vault id.

    +
    +
    + + environment + + +
    +

    Environment object, your organization vault environment. By default Environment.sandbox.

    +
    +
    + + dataRegion + + +
    +

    String object, id of data storage region (e.g. “eu-123”).

    +
    +
    + + hostname + + +
    +

    String object, custom Hostname, if not set, data will be sent to Vault Url. Default is nil.

    +
    +
    + + satellitePort + + +
    +

    Int? object, custom port for satellite configuration. Default is nil. IMPORTANT! Use only with .sandbox environment! Hostname should be specified for valid http://localhost or in local IP format http://192.168.X.X.

    +
    +
    +
    +

  • @@ -562,9 +761,9 @@

    Manage VGSTextFields
  • @@ -572,18 +771,29 @@

    Manage VGSTextFields
    -

    Returns VGSTextField with VGSConfiguration.fieldName associated with VGCollect instance.

    +

    Returns VGSTextField with VGSConfiguration.fieldName associated with VGCollect instance.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func getTextField(fieldName: String) -> VGSTextField?
    + +
    +
    +

  • @@ -594,15 +804,45 @@

    Manage VGSTextFields

    Unasubscribe VGSTextField from VGSCollect instance.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func unsubscribeTextField(_ textField: VGSTextField)
    + +
    +
    +
    +

    Parameters

    + + + + + + + +
    + + textField + + +
    +

    VGSTextField that should be unsubscribed.

    +
    +
    +
    +
  • @@ -613,15 +853,45 @@

    Manage VGSTextFields

    Unasubscribe VGSTextFields from VGSCollect instance.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func unsubscribeTextFields(_ textFields: [VGSTextField])
    + +
    +
    +
    +

    Parameters

    + + + + + + + +
    + + textFields + + +
    +

    an array of VGSTextFields that should be unsubscribed.

    +
    +
    +
    +
  • @@ -632,6 +902,17 @@

    Manage VGSTextFields

    Unasubscribe all VGSTextFields from VGSCollect instance.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func unsubscribeAllTextFields()
    + +
    +
    +
  • @@ -651,9 +932,9 @@

    Manage Files
  • @@ -664,6 +945,17 @@

    Manage Files

    Detach files for associated VGSCollect instance.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func cleanFiles()
    + +
    +
    +
  • @@ -683,9 +975,9 @@

    Send data
  • @@ -696,20 +988,110 @@

    Send data

    Send data from VGSTextFields to your organization vault.

    Note

    -

    Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain.

    +

    Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func sendData(path: String, method: VGSCollectHTTPMethod = .post, routeId: String? = nil, extraData: [String : Any]? = nil, requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions(), completion block: @escaping (VGSResponse) -> Void)
    + +
    +
    +
    +

    Parameters

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

    Inbound rout path for your organization vault.

    +
    +
    + + method + + +
    +

    VGSCollectHTTPMethod, default is .post.

    +
    +
    + + routeId + + +
    +

    id of VGS Proxy Route, default is nil.

    +
    +
    + + extraData + + +
    +

    Any data you want to send together with data from VGSTextFields , default is nil.

    +
    +
    + + requestOptions + + +
    +

    VGSCollectRequestOptions object, holds additional request options. Default options are .nestedJSON.

    +
    +
    + + completion + + +
    +

    response completion block, returns VGSResponse.

    +
    +
    +
    +
  • @@ -720,20 +1102,579 @@

    Send data

    Send file to your organization vault. Only send one file at a time.

    Note

    -

    Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain.

    +

    Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func sendFile(path: String, method: VGSCollectHTTPMethod = .post, routeId: String? = nil, extraData: [String : Any]? = nil, requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions(), completion block: @escaping (VGSResponse) -> Void)
    + +
    +
    +
    +

    Parameters

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

    Inbound rout path for your organization vault.

    +
    +
    + + method + + +
    +

    HTTPMethod, default is .post.

    +
    +
    + + routeId + + +
    +

    id of VGS Proxy Route, default is nil.

    +
    +
    + + extraData + + +
    +

    Any data you want to send together with data from VGSTextFields , default is nil.

    +
    +
    + + completion + + +
    +

    response completion block, returns VGSResponse.

    +
    +
    +
    +
  • +
    +
    +
    +
    +
    +

    Send tokenization request with data from VGSTextFields.

    +
    +

    Note

    + Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain. + +
    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public func tokenizeData(routeId: String? = nil, completion block: @escaping (VGSTokenizationResponse) -> Void)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + +
    + + routeId + + +
    +

    id of VGS Proxy Route, default is nil.

    +
    +
    + + completion + + +
    +

    response completion block, returns VGSTokenizationResponse.

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

    VGSCollect + async +

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

      Asynchronously send data from VGSTextFields to your organization vault.

      +
      +

      Note

      +

      Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain.

      + +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public func sendData(path: String, method: VGSCollectHTTPMethod = .post, routeId: String? = nil, extraData: [String : Any]? = nil, requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions()) async -> VGSResponse
      + +
      +
      +
      +

      Parameters

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

      Inbound rout path for your organization vault.

      +
      +
      + + method + + +
      +

      VGSCollectHTTPMethod, default is .post.

      +
      +
      + + routeId + + +
      +

      id of VGS Proxy Route, default is nil.

      +
      +
      + + extraData + + +
      +

      Any data you want to send together with data from VGSTextFields , default is nil.

      +
      +
      + + requestOptions + + +
      +

      VGSCollectRequestOptions object, holds additional request options. Default options are .nestedJSON.

      +
      +
      +
      +
      +

      Return Value

      +

      +
      + +
      +
      +
    • +
    • +
      + + + + sendFile(path:method:routeId:extraData:) + + + Asynchronous + +
      +
      +
      +
      +
      +
      +

      Asynchronously send file to your organization vault. Only send one file at a time.

      +
      +

      Note

      +

      Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain.

      + +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public func sendFile(path: String, method: VGSCollectHTTPMethod = .post, routeId: String? = nil, extraData: [String : Any]? = nil) async -> VGSResponse
      + +
      +
      +
      +

      Parameters

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

      Inbound rout path for your organization vault.

      +
      +
      + + method + + +
      +

      HTTPMethod, default is .post.

      +
      +
      + + routeId + + +
      +

      id of VGS Proxy Route, default is nil.

      +
      +
      + + extraData + + +
      +

      Any data you want to send together with data from VGSTextFields , default is nil.

      +
      +
      + + completion + + +
      +

      response completion block, returns VGSResponse.

      +
      +
      +
      + +
      +
      +
    • +
    • +
      + + + + tokenizeData(routeId:) + + + Asynchronous + +
      +
      +
      +
      +
      +
      +

      Asynchronously send tokenization request with data from VGSTextFields.

      +
      +

      Note

      + Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain. + +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public func tokenizeData(routeId: String? = nil) async -> VGSTokenizationResponse
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + +
      + + routeId + + +
      +

      id of VGS Proxy Route, default is nil.

      +
      +
      + + completion + + +
      +

      response completion block, returns VGSTokenizationResponse.

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

    VGSCollect + Combine +

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

      Send data from VGSTextFields to your organization vault using the Combine framework.

      +
      +

      Note

      +

      Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain.

      + +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public func sendDataPublisher(path: String, method: VGSCollectHTTPMethod = .post, routeId: String? = nil, extraData: [String : Any]? = nil, requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions()) -> Future<VGSResponse, Never>
      + +
      +
      +
      +

      Parameters

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

      Inbound rout path for your organization vault.

      +
      +
      + + method + + +
      +

      VGSCollectHTTPMethod, default is .post.

      +
      +
      + + routeId + + +
      +

      id of VGS Proxy Route, default is nil.

      +
      +
      + + extraData + + +
      +

      Any data you want to send together with data from VGSTextFields , default is nil.

      +
      +
      + + requestOptions + + +
      +

      VGSCollectRequestOptions object, holds additional request options. Default options are .nestedJSON.

      +
      +
      +
      +
      +

      Return Value

      +

      A Future publisher that emits a single VGSResponse.

      +
      + +
      +
      +
    • +
    • +
      @@ -741,14 +1682,154 @@

      Send data
      -

      Makes tokenization response with data from VGSTextFields.

      +

      Send file to your organization vault using the Combine framework.

      Note

      - Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain. +

      Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain.

      +
      +

      Declaration

      +
      +

      Swift

      +
      public func sendFilePublisher(path: String, method: VGSCollectHTTPMethod = .post, routeId: String? = nil, extraData: [String : Any]? = nil, requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions()) -> Future<VGSResponse, Never>
      + +
      +
      +
      +

      Parameters

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

      Inbound rout path for your organization vault.

      +
      +
      + + method + + +
      +

      VGSCollectHTTPMethod, default is .post.

      +
      +
      + + routeId + + +
      +

      id of VGS Proxy Route, default is nil.

      +
      +
      + + extraData + + +
      +

      Any data you want to send together with data from VGSTextFields , default is nil.

      +
      +
      + + requestOptions + + +
      +

      VGSCollectRequestOptions object, holds additional request options. Default options are .nestedJSON.

      +
      +
      +
      +
      +

      Return Value

      +

      A Future publisher that emits a single VGSResponse.

      +
      + +
      +

      +
    • +
    • + +
      +
      +
      +
      +
      +

      Send tokenization request with data from VGSTextFields to your organization vault using the Combine framework.

      +
      +

      Note

      +

      Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain.

      + +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public func tokenizeDataPublisher(routeId: String? = nil) -> Future<VGSTokenizationResponse, Never>
      + +
      +
      +
      +

      Parameters

      + + + + + + + +
      + + routeId + + +
      +

      id of VGS Proxy Route, default is nil.

      +
      +
      +
      +
      +

      Return Value

      +

      A Future publisher that emits a single VGSTokenizationResponse.

      +
      +
    • @@ -760,8 +1841,8 @@

      Send data

    diff --git a/docs/Classes/VGSCollectLogger.html b/docs/Classes/VGSCollectLogger.html index 71ff2cc0..ee15b418 100644 --- a/docs/Classes/VGSCollectLogger.html +++ b/docs/Classes/VGSCollectLogger.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,9 +376,19 @@

    VGSCollectLogger

    +
    +
    + +
    public final class VGSCollectLogger
    + +
    +

    VGSCollectLogger encapsulates logging logic and debugging options for VGSCollectSDK. Use .configuration property to setup these options. VGSCollectLogger logging implies only printing logs to Xcode console. It doesn’t save logs to persistent store/local file, also it doesn’t send debugging logs to backend services. IMPORTANT You should NOT use logging in your production configuration for live apps.

    +
    @@ -397,9 +408,9 @@

    vars
  • - + - shared + shared
    @@ -410,15 +421,26 @@

    vars

    Shared instance.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var shared: VGSCollectLogger
    + +
    +
    +
  • @@ -429,6 +451,17 @@

    vars

    Logging configuration. Check VGSCollectLoggingConfiguration for logging options.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var configuration: VGSCollectLoggingConfiguration
    + +
    +
    +
  • @@ -448,9 +481,9 @@

    Public
  • @@ -461,6 +494,17 @@

    Public

    Stop logging all activities.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func disableAllLoggers()
    + +
    +
    +
  • @@ -472,8 +516,8 @@

    Public

    diff --git a/docs/Classes/VGSConfiguration.html b/docs/Classes/VGSConfiguration.html index 5938d661..583dd239 100644 --- a/docs/Classes/VGSConfiguration.html +++ b/docs/Classes/VGSConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSConfiguration

    +
    +
    + +
    public class VGSConfiguration : VGSTextFieldConfigurationProtocol
    + +
    +

    A class responsible for configuration VGSTextField.

    +
    @@ -396,9 +407,9 @@

    Attributes
  • @@ -409,15 +420,26 @@

    Attributes

    Collect form that will be assiciated with VGSTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public private(set) weak var vgsCollector: VGSCollect? { get }
    + +
    +
    +
  • - + - type + type
    @@ -425,8 +447,19 @@

    Attributes
    -

    Type of field congfiguration. Default is FieldType.none.

    +

    Type of field congfiguration. Default is FieldType.none.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public var type: FieldType
    +
    +
    +

    @@ -434,9 +467,9 @@

    Attributes
  • @@ -447,15 +480,26 @@

    Attributes

    Name that will be associated with VGSTextField and used as a JSON key on send request with textfield data to your organozation vault.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let fieldName: String
    + +
    +
    +
  • @@ -466,15 +510,26 @@

    Attributes

    Set if VGSTextField is required to be non-empty and non-nil on send request. Default is false.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var isRequired: Bool
    + +
    +
    +
  • @@ -485,15 +540,26 @@

    Attributes

    Set if VGSTextField is required to be valid only on send request. Default is false.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var isRequiredValidOnly: Bool
    + +
    +
    +
  • @@ -501,8 +567,19 @@

    Attributes
    -

    Input data visual format pattern. If not applied, will be set by default depending on field type.

    +

    Input data visual format pattern. If not applied, will be set by default depending on field type.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public var formatPattern: String? { get set }
    +
    +
    +

    @@ -510,9 +587,9 @@

    Attributes
  • - + - divider + divider
    @@ -520,18 +597,29 @@

    Attributes
    -

    String, used to replace not default VGSConfiguration.formatPattern characters in input text on send request.

    +

    String, used to replace not default VGSConfiguration.formatPattern characters in input text on send request.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var divider: String?
    + +
    +
    +

  • @@ -539,18 +627,29 @@

    Attributes
    -

    Preferred UIKeyboardType for VGSTextField. If not applied, will be set by default depending on field type parameter.

    +

    Preferred UIKeyboardType for VGSTextField. If not applied, will be set by default depending on field type parameter.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var keyboardType: UIKeyboardType?
    + +
    +
    +

  • @@ -561,15 +660,26 @@

    Attributes

    Preferred UIReturnKeyType for VGSTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var returnKeyType: UIReturnKeyType?
    + +
    +
    +
  • @@ -580,15 +690,26 @@

    Attributes

    Preferred UIKeyboardAppearance for textfield. By default is UIKeyboardAppearance.default.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var keyboardAppearance: UIKeyboardAppearance?
    + +
    +
    +
  • @@ -599,15 +720,26 @@

    Attributes

    Validation rules for field input. Defines State.isValide result.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var validationRules: VGSValidationRuleSet?
    + +
    +
    +
  • @@ -615,9 +747,20 @@

    Attributes
    -

    Max input length. IMPORTANT! Can conflict with .formatPattern attribute.

    +

    Max input length. IMPORTANT! Can conflict with .formatPattern attribute.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var maxInputLength: Int? { get set }
    + +
    +
    +

  • @@ -637,9 +780,9 @@

    Initialization
  • @@ -650,6 +793,48 @@

    Initialization

    Initialization

    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(collector vgs: VGSCollect, fieldName: String)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + +
    + + vgs + + +
    +

    VGSCollect instance.

    +
    +
    + + fieldName + + +
    +

    associated fieldName.

    +
    +
    +
    +
  • @@ -661,8 +846,8 @@

    Initialization

  • diff --git a/docs/Classes/VGSDateConfiguration.html b/docs/Classes/VGSDateConfiguration.html new file mode 100644 index 00000000..4c11627b --- /dev/null +++ b/docs/Classes/VGSDateConfiguration.html @@ -0,0 +1,757 @@ + + + + VGSDateConfiguration Class Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    VGSDateConfiguration

    +
    +
    + +
    public final class VGSDateConfiguration : VGSConfiguration, VGSDateConfigurationProtocol, VGSFormatSerializableProtocol
    + +
    +
    +

    Class responsible for configuration VGSDateTextField or VGSTextField with fieldType = .date. Extends VGSConfiguration

    + + +
    +
    + +
    +
    +
    +
    + + +
    + +

    Constructor +

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

      Initialization +Date configuration initializer, if no datePickerStartDate is provided, +a default date will be used adding 100 years to the current date. +Similar approach will be used if datePickerEndDate is not provided, +it will be calculated removing 100 years from current date.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(collector vgs: VGSCollect,
      +            fieldName: String,
      +            datePickerStartDate: VGSDate? = nil,
      +            datePickerEndDate: VGSDate? = nil)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + + + + + + + + + +
      + + vgs + + +
      +

      VGSCollect instance.

      +
      +
      + + fieldName + + +
      +

      associated fieldName.

      +
      +
      + + datePickerStartDate + + +
      +

      optional VGSDate instance.

      +
      +
      + + datePickerEndDate + + +
      +

      optional VGSDate instance.

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

    Overridden methods and properties +

    +
    +
    +
      +
    • +
      + + + + type + +
      +
      +
      +
      +
      +
      +

      Super initializer

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public override var type: FieldType { get set }
      + +
      +
      + +
      +
      +
    • +
    +
    +
    +
    + + +
    + +

    VGSDateConfigurationProtocol implementation +

    +
    +
    + +
    +
    +
    + + +
    + +

    Static properties and methods +

    +
    +
    + +
    +
    +
    + +
    +
    + + + diff --git a/docs/Classes/VGSDateTextField.html b/docs/Classes/VGSDateTextField.html new file mode 100644 index 00000000..b5c0f2c5 --- /dev/null +++ b/docs/Classes/VGSDateTextField.html @@ -0,0 +1,536 @@ + + + + VGSDateTextField Class Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    VGSDateTextField

    +
    +
    + +
    public final class VGSDateTextField : VGSTextField
    +
    extension VGSDateTextField: UIPickerViewDelegate, UIPickerViewDataSource
    + +
    +
    +

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to show picker view with a Date. It support to define a range of valid dates to select from.

    + + +
    +
    + +
    +
    +
    +
    + + +
    + +

    Inner objects +

    +
    +
    +
      +
    • +
      + + + + MonthFormat + +
      +
      +
      +
      +
      +
      +

      Available month Label formats in UIPickerView

      + + See more +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public enum MonthFormat
      + +
      +
      + +
      +
      +
    • +
    +
    +
    +
    + + +
    + +

    Properties +

    +
    +
    + +
    +
    +
    + + +
    + +

    Overridden methods and properties +

    +
    +
    + +
    +
    +
    + +
    +
    + + + diff --git a/docs/Classes/VGSDateTextField/MonthFormat.html b/docs/Classes/VGSDateTextField/MonthFormat.html new file mode 100644 index 00000000..3709f8c8 --- /dev/null +++ b/docs/Classes/VGSDateTextField/MonthFormat.html @@ -0,0 +1,500 @@ + + + + MonthFormat Enumeration Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    MonthFormat

    +
    +
    + +
    public enum MonthFormat
    + +
    +
    +

    Available month Label formats in UIPickerView

    + + +
    +
    + +
    +
    +
    +
      +
    • +
      + + + + shortSymbols + +
      +
      +
      +
      +
      +
      +

      Short month name, e.g.: Jan

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case shortSymbols
      + +
      +
      + +
      +
      +
    • +
    • +
      + + + + longSymbols + +
      +
      +
      +
      +
      +
      +

      Long month name, e.g.: January

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case longSymbols
      + +
      +
      + +
      +
      +
    • +
    • +
      + + + + numbers + +
      +
      +
      +
      +
      +
      +

      Month number: e.g.: 01

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case numbers
      + +
      +
      + +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/docs/Classes/VGSDateTokenizationConfiguration.html b/docs/Classes/VGSDateTokenizationConfiguration.html new file mode 100644 index 00000000..50e491e7 --- /dev/null +++ b/docs/Classes/VGSDateTokenizationConfiguration.html @@ -0,0 +1,655 @@ + + + + VGSDateTokenizationConfiguration Class Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    VGSDateTokenizationConfiguration

    +
    +
    + +
    public final class VGSDateTokenizationConfiguration : VGSConfiguration, VGSDateConfigurationProtocol, VGSTextFieldTokenizationConfigurationProtocol, VGSFormatSerializableProtocol
    + +
    +
    +

    Class responsible for configuration VGSDateTextField or VGSTextField with fieldType = .date. +Extends VGSConfiguration. Required to work with tokenization API.

    + + +
    +
    + +
    +
    +
    +
    + + +
    + +

    Constructor +

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

      Initialization +Date configuration initializer, if no datePickerStartDate is provided, +a default date will be used adding 100 years to the current date. +Similar approach will be used if datePickerEndDate is not provided, +it will be calculated removing 100 years from current date.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(collector vgs: VGSCollect,
      +            fieldName: String,
      +            datePickerStartDate: VGSDate? = nil,
      +            datePickerEndDate: VGSDate? = nil)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + + + + + + + + + +
      + + vgs + + +
      +

      VGSCollect instance.

      +
      +
      + + fieldName + + +
      +

      associated fieldName.

      +
      +
      + + datePickerStartDate + + +
      +

      optional VGSDate instance.

      +
      +
      + + datePickerEndDate + + +
      +

      optional VGSDate instance.

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

    Overridden methods and properties +

    +
    +
    +
      +
    • +
      + + + + type + +
      +
      +
      +
      +
      +
      +

      Super initializer

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public override var type: FieldType { get set }
      + +
      +
      + +
      +
      +
    • +
    +
    +
    +
    + + +
    + +

    VGSDateConfigurationProtocol implementation +

    +
    +
    + +
    +
    +
    + +
    +
    + + + diff --git a/docs/Classes/VGSError.html b/docs/Classes/VGSError.html index 55acdea2..a49b05dc 100644 --- a/docs/Classes/VGSError.html +++ b/docs/Classes/VGSError.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSError

    +
    +
    + +
    public class VGSError : NSError
    + +
    +

    An error produced by VGSCollectSDK. Works similar to default NSError in iOS.

    +
    @@ -387,9 +398,9 @@

    VGSError

  • - + - type + type
    @@ -400,15 +411,26 @@

    VGSError

    VGSErrorType- required for each VGSError instance

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let type: VGSErrorType!
    + +
    +
    +
  • - + - code + code
    @@ -419,15 +441,26 @@

    VGSError

    Code assiciated with VGSErrorType

    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var code: Int { get }
    + +
    +
    +
  • @@ -438,6 +471,17 @@

    VGSError

    : nodoc. Public required init.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public required init?(coder: NSCoder)
    + +
    +
    +
  • @@ -449,8 +493,8 @@

    VGSError

    diff --git a/docs/Classes/VGSExpDateConfiguration.html b/docs/Classes/VGSExpDateConfiguration.html index 3750bc31..8939dcfd 100644 --- a/docs/Classes/VGSExpDateConfiguration.html +++ b/docs/Classes/VGSExpDateConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSExpDateConfiguration

    +
    +
    + +
    public final class VGSExpDateConfiguration : VGSConfiguration, VGSExpDateConfigurationProtocol, VGSFormatSerializableProtocol
    + +
    +

    A class responsible for configuration VGSTextField with fieldType = .expDate. Extends VGSConfiguration class.

    +
    @@ -396,9 +407,9 @@

    Attributes
  • - + - type + type
    @@ -406,8 +417,19 @@

    Attributes
    -

    FieldType.expDate type of VGSTextField configuration.

    +

    FieldType.expDate type of VGSTextField configuration.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var type: FieldType { get set }
    +
    +
    +

    @@ -428,9 +450,9 @@

    VGSExpDateConfigurationProtocol
  • @@ -438,8 +460,19 @@

    VGSExpDateConfigurationProtocol
    -

    Input Source type. Default is VGSTextFieldInputSource.datePicker.

    +

    Input Source type. Default is VGSTextFieldInputSource.datePicker.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public var inputSource: VGSTextFieldInputSource
    +
    +
    +

    @@ -447,9 +480,9 @@

    VGSExpDateConfigurationProtocol
  • @@ -460,15 +493,26 @@

    VGSExpDateConfigurationProtocol

    Input date format to convert.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var inputDateFormat: VGSCardExpDateFormat?
    + +
    +
    +
  • @@ -479,6 +523,17 @@

    VGSExpDateConfigurationProtocol

    Output date format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var outputDateFormat: VGSCardExpDateFormat?
    + +
    +
    +
  • @@ -498,9 +553,9 @@

    VGSFormatSerializableProtocol
  • @@ -511,6 +566,17 @@

    VGSFormatSerializableProtocol

    Output date format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var serializers: [VGSFormatSerializerProtocol]
    + +
    +
    +
  • @@ -522,8 +588,8 @@

    VGSFormatSerializableProtocol

  • diff --git a/docs/Classes/VGSExpDateTextField.html b/docs/Classes/VGSExpDateTextField.html index 77148b81..c61d6c83 100644 --- a/docs/Classes/VGSExpDateTextField.html +++ b/docs/Classes/VGSExpDateTextField.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -378,11 +379,16 @@

    VGSExpDateTextField

    - +
    public final class VGSExpDateTextField : VGSTextField
    +
    extension VGSExpDateTextField: UIPickerViewDelegate, UIPickerViewDataSource
    +

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to show picker view with Card Number Expiration Month and Year.

    + @@ -402,9 +408,9 @@

    Enums
  • @@ -416,15 +422,26 @@

    Enums See more

    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum MonthFormat
    + +
    +
    +
  • @@ -436,6 +453,17 @@

    Enums See more

    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum YearFormat
    + +
    +
    +
  • @@ -455,9 +483,9 @@

    Attributes
  • @@ -468,15 +496,26 @@

    Attributes

    UIPickerView Month Label format

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var monthPickerFormat: MonthFormat { get set }
    + +
    +
    +
  • @@ -487,6 +526,17 @@

    Attributes

    UIPickerView Year Label format

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var yearPickeFormat: YearFormat { get set }
    + +
    +
    +
  • @@ -498,8 +548,8 @@

    Attributes

    diff --git a/docs/Classes/VGSExpDateTextField/MonthFormat.html b/docs/Classes/VGSExpDateTextField/MonthFormat.html index e4808690..99480171 100644 --- a/docs/Classes/VGSExpDateTextField/MonthFormat.html +++ b/docs/Classes/VGSExpDateTextField/MonthFormat.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    MonthFormat

    +
    +
    + +
    public enum MonthFormat
    + +
    +

    Available Month Label formats in UIPickerView

    +
    @@ -387,9 +398,9 @@

    MonthFormat

  • @@ -400,15 +411,26 @@

    MonthFormat

    Short month name, e.g.: Jan

    +
    +

    Declaration

    +
    +

    Swift

    +
    case shortSymbols
    + +
    +
    +
  • @@ -419,15 +441,26 @@

    MonthFormat

    Long month name, e.g.: January

    +
    +

    Declaration

    +
    +

    Swift

    +
    case longSymbols
    + +
    +
    +
  • - + - numbers + numbers
    @@ -438,6 +471,17 @@

    MonthFormat

    Month number: e.g.: 01

    +
    +

    Declaration

    +
    +

    Swift

    +
    case numbers
    + +
    +
    +
  • @@ -449,8 +493,8 @@

    MonthFormat

    diff --git a/docs/Classes/VGSExpDateTextField/YearFormat.html b/docs/Classes/VGSExpDateTextField/YearFormat.html index 65725d58..796dd565 100644 --- a/docs/Classes/VGSExpDateTextField/YearFormat.html +++ b/docs/Classes/VGSExpDateTextField/YearFormat.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    YearFormat

    +
    +
    + +
    public enum YearFormat
    + +
    +

    Available Year Label formats in UIPickerView

    +
    @@ -387,9 +398,9 @@

    YearFormat

  • - + - short + short
    @@ -400,15 +411,26 @@

    YearFormat

    Two digits year format, e.g.: 21

    +
    +

    Declaration

    +
    +

    Swift

    +
    case short
    + +
    +
    +
  • - + - long + long
    @@ -419,6 +441,17 @@

    YearFormat

    Four digits year format:, e.g.:2021

    +
    +

    Declaration

    +
    +

    Swift

    +
    case long
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    YearFormat

    diff --git a/docs/Classes/VGSExpDateTokenizationConfiguration.html b/docs/Classes/VGSExpDateTokenizationConfiguration.html index 0e59386f..d4690f3d 100644 --- a/docs/Classes/VGSExpDateTokenizationConfiguration.html +++ b/docs/Classes/VGSExpDateTokenizationConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSExpDateTokenizationConfiguration

    +
    +
    + +
    public final class VGSExpDateTokenizationConfiguration : VGSConfiguration, VGSExpDateConfigurationProtocol, VGSTextFieldTokenizationConfigurationProtocol, VGSFormatSerializableProtocol
    + +
    +

    VGSExpDateTokenizationConfiguration - textfield configuration for textfield with type .expDate, required for work with tokenization api.

    +
    @@ -396,9 +407,9 @@

    Attributes
  • - + - type + type
    @@ -406,8 +417,19 @@

    Attributes
    -

    FieldType.expDate type of VGSTextFieldtokenization configuration.

    +

    FieldType.expDate type of VGSTextFieldtokenization configuration.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var type: FieldType { get set }
    +
    +
    +

    @@ -428,9 +450,9 @@

    VGSExpDateConfigurationProtocol
  • @@ -438,8 +460,19 @@

    VGSExpDateConfigurationProtocol
    -

    Input Source type. Default is VGSTextFieldInputSource.datePicker.

    +

    Input Source type. Default is VGSTextFieldInputSource.datePicker.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public var inputSource: VGSTextFieldInputSource
    +
    +
    +

    @@ -447,9 +480,9 @@

    VGSExpDateConfigurationProtocol
  • @@ -460,15 +493,26 @@

    VGSExpDateConfigurationProtocol

    Input date format to convert.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var inputDateFormat: VGSCardExpDateFormat?
    + +
    +
    +
  • @@ -479,6 +523,17 @@

    VGSExpDateConfigurationProtocol

    Output date format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var outputDateFormat: VGSCardExpDateFormat?
    + +
    +
    +
  • @@ -498,9 +553,9 @@

    VGSTokenizationParametersProtocol
  • @@ -511,6 +566,17 @@

    VGSTokenizationParametersProtocol

    VGSExpDateTokenizationParameters - tokenization configuration parameters.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var tokenizationParameters: VGSExpDateTokenizationParameters
    + +
    +
    +
  • @@ -530,9 +596,9 @@

    VGSFormatSerializableProtocol
  • @@ -543,6 +609,17 @@

    VGSFormatSerializableProtocol

    Output date format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var serializers: [VGSFormatSerializerProtocol]
    + +
    +
    +
  • @@ -554,8 +631,8 @@

    VGSFormatSerializableProtocol

  • diff --git a/docs/Classes/VGSFileInfo.html b/docs/Classes/VGSFileInfo.html index be38d84f..a8563c52 100644 --- a/docs/Classes/VGSFileInfo.html +++ b/docs/Classes/VGSFileInfo.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSFileInfo

    +
    +
    + +
    public class VGSFileInfo : NSObject, VGSFileInfoProtocol
    + +
    +

    An object that holds optional files’ metadata on selecting file through VGSFilePickerController.

    +
    @@ -387,9 +398,9 @@

    VGSFileInfo

  • @@ -405,15 +416,26 @@

    VGSFileInfo

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let fileExtension: String?
    + +
    +
    +
  • - + - size + size
    @@ -424,15 +446,26 @@

    VGSFileInfo

    File size.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let size: Int
    + +
    +
    +
  • @@ -443,6 +476,17 @@

    VGSFileInfo

    File size units.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let sizeUnits: String?
    + +
    +
    +
  • @@ -454,8 +498,8 @@

    VGSFileInfo

    diff --git a/docs/Classes/VGSFilePickerConfiguration.html b/docs/Classes/VGSFilePickerConfiguration.html index e1db878a..fc82cfb7 100644 --- a/docs/Classes/VGSFilePickerConfiguration.html +++ b/docs/Classes/VGSFilePickerConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSFilePickerConfiguration

    +
    +
    + +
    public class VGSFilePickerConfiguration : VGSFilePickerConfigurationProtocol
    + +
    +

    A class responsible for configuration VGSFilePickerController.

    +
    @@ -396,9 +407,9 @@

    Attributes
  • @@ -409,6 +420,17 @@

    Attributes

    Name that will be associated with selected file by user. Used as a JSON key on send request with file data to your organozation vault.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let fieldName: String
    + +
    +
    +
  • @@ -428,9 +450,9 @@

    Initialization
  • @@ -441,6 +463,60 @@

    Initialization

    Initialization

    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(collector vgs: VGSCollect, fieldName: String, fileSource: VGSFileSource)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + + + + + +
    + + vgs + + +
    +

    VGSCollect instance.

    +
    +
    + + fieldName + + +
    +

    name that should be associated with selected file.

    +
    +
    + + fileSource + + +
    +

    type of VGSFileSource that should be provided to user.

    +
    +
    +
    +
  • @@ -452,8 +528,8 @@

    Initialization

    diff --git a/docs/Classes/VGSFilePickerController.html b/docs/Classes/VGSFilePickerController.html index 5701e75a..778c1ce4 100644 --- a/docs/Classes/VGSFilePickerController.html +++ b/docs/Classes/VGSFilePickerController.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSFilePickerController

    +
    +
    + +
    public class VGSFilePickerController
    + +
    +

    Controller responsible for importing files from device sources.

    +
    @@ -396,9 +407,9 @@

    Attributes
  • - + - delegate + delegate
    @@ -409,6 +420,17 @@

    Attributes

    VGSFilePickerControllerDelegate - handle user interaction on file picking.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public weak var delegate: VGSFilePickerControllerDelegate? { get set }
    + +
    +
    +
  • @@ -428,9 +450,9 @@

    Initialization
  • @@ -441,6 +463,36 @@

    Initialization

    Initialization

    +
    +

    Declaration

    +
    +

    Swift

    +
    public required init(configuration: VGSFilePickerConfiguration)
    + +
    +
    +
    +

    Parameters

    + + + + + + + +
    + + configuration + + + +
    +
    +
  • @@ -460,9 +512,9 @@

    Methods
  • @@ -473,15 +525,69 @@

    Methods

    Present file picker view

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func presentFilePicker(on viewController: UIViewController, animated: Bool, completion: (() -> Void)? = nil)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + + + + + +
    + + viewController + + +
    +

    UIViewController that will present card scanner

    +
    +
    + + animated + + +
    +

    pass true to animate the presentation; otherwise, pass false

    +
    +
    + + completion + + +
    +

    the block to execute after the presentation finishes

    +
    +
    +
    +
  • @@ -492,6 +598,48 @@

    Methods

    Dismiss file picker view

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func dismissFilePicker(animated: Bool, completion: (() -> Void)? = nil)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + +
    + + animated + + +
    +

    pass true to animate the dismiss of presented viewcontroller; otherwise, pass false

    +
    +
    + + completion + + +
    +

    the block to execute after the dismiss finishes

    +
    +
    +
    +
  • @@ -503,8 +651,8 @@

    Methods

    diff --git a/docs/Classes/VGSPaymentCards.html b/docs/Classes/VGSPaymentCards.html index 283c2697..2eb7c665 100644 --- a/docs/Classes/VGSPaymentCards.html +++ b/docs/Classes/VGSPaymentCards.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,6 +376,13 @@

    VGSPaymentCards

    +
    +
    + +
    public class VGSPaymentCards
    + +
    +

    Class responsible for storing and managing Payment Cards in SDK.

      @@ -383,6 +391,9 @@

      VGSPaymentCards

    • Allows to edit Unknown Payment Cards Models(brands not defined by SDK and Developer)
    +
    @@ -402,9 +413,9 @@

    CardBrand Enum Cases
  • @@ -416,6 +427,17 @@

    CardBrand Enum Cases See more

    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum CardBrand : Equatable
    + +
    +
    +
  • @@ -435,9 +457,9 @@

    Payment Card Models
  • - + - elo + elo
    @@ -448,15 +470,26 @@

    Payment Card Models

    Elo Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var elo: VGSPaymentCardModel
    + +
    +
    +
  • @@ -467,15 +500,26 @@

    Payment Card Models

    Visa Electron Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var visaElectron: VGSPaymentCardModel
    + +
    +
    +
  • - + - maestro + maestro
    @@ -486,15 +530,26 @@

    Payment Card Models

    Maestro Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var maestro: VGSPaymentCardModel
    + +
    +
    +
  • @@ -505,15 +560,26 @@

    Payment Card Models

    Forbrugsforeningen Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var forbrugsforeningen: VGSPaymentCardModel
    + +
    +
    +
  • - + - dankort + dankort
    @@ -524,15 +590,26 @@

    Payment Card Models

    Dankort Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var dankort: VGSPaymentCardModel
    + +
    +
    +
  • - + - visa + visa
    @@ -543,15 +620,26 @@

    Payment Card Models

    Elo Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var visa: VGSPaymentCardModel
    + +
    +
    +
  • @@ -562,15 +650,26 @@

    Payment Card Models

    Master Card Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var masterCard: VGSPaymentCardModel
    + +
    +
    +
  • - + - amex + amex
    @@ -581,15 +680,26 @@

    Payment Card Models

    Amex Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var amex: VGSPaymentCardModel
    + +
    +
    +
  • @@ -600,15 +710,26 @@

    Payment Card Models

    Hipercard Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var hipercard: VGSPaymentCardModel
    + +
    +
    +
  • @@ -619,15 +740,26 @@

    Payment Card Models

    DinersClub Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var dinersClub: VGSPaymentCardModel
    + +
    +
    +
  • - + - discover + discover
    @@ -638,15 +770,26 @@

    Payment Card Models

    Discover Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var discover: VGSPaymentCardModel
    + +
    +
    +
  • - + - unionpay + unionpay
    @@ -657,15 +800,26 @@

    Payment Card Models

    UnionPay Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var unionpay: VGSPaymentCardModel
    + +
    +
    +
  • - + - jcb + jcb
    @@ -676,6 +830,17 @@

    Payment Card Models

    JCB Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var jcb: VGSPaymentCardModel
    + +
    +
    +
  • @@ -695,9 +860,9 @@

    Unknown Payment Card Model
  • - + - unknown + unknown
    @@ -705,8 +870,19 @@

    Unknown Payment Card Model
    -

    Unknown Brand Payment Card Model. Can be used for specifing cards details when VGSValidationRulePaymentCard requires validating CardBrand.unknown cards.

    +

    Unknown Brand Payment Card Model. Can be used for specifing cards details when VGSValidationRulePaymentCard requires validating CardBrand.unknown cards.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var unknown: VGSUnknownPaymentCardModel
    +
    +
    +

    @@ -727,9 +903,9 @@

    Custom Payment Card Models
  • @@ -740,20 +916,31 @@

    Custom Payment Card Models

    Array of Custom Payment Card Models.

    Note

    - the order has impact on which card brand should be detected first by VGSPaymentCardModel.regex. + the order has impact on which card brand should be detected first by VGSPaymentCardModel.regex.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var cutomPaymentCardModels: [VGSCustomPaymentCardModel]
    + +
    +
    +
  • @@ -764,11 +951,22 @@

    Custom Payment Card Models

    An array of valid Card Brands, could include custom and default brands. If not set, will use availableCardBrands array instead.

    Note

    - the order has impact on which card brand should be detected first by VGSPaymentCardModel.regex. + the order has impact on which card brand should be detected first by VGSPaymentCardModel.regex.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var validCardBrands: [VGSPaymentCardModelProtocol]?
    + +
    +
    +
  • @@ -788,9 +986,9 @@

    Attributes
  • @@ -801,15 +999,26 @@

    Attributes

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    static func getCardModelFromAvailableModels(brand: VGSPaymentCards.CardBrand) -> VGSPaymentCardModelProtocol?
    + +
    +
    +
  • @@ -820,6 +1029,17 @@

    Attributes

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    static func detectCardBrandFromAvailableCards(input: String) -> VGSPaymentCards.CardBrand
    + +
    +
    +
  • @@ -831,8 +1051,8 @@

    Attributes

  • diff --git a/docs/Classes/VGSPaymentCards/CardBrand.html b/docs/Classes/VGSPaymentCards/CardBrand.html index 70137750..8314c190 100644 --- a/docs/Classes/VGSPaymentCards/CardBrand.html +++ b/docs/Classes/VGSPaymentCards/CardBrand.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    CardBrand

    +
    +
    + +
    public enum CardBrand : Equatable
    + +
    +

    Supported card brands

    +
    @@ -387,9 +398,9 @@

    CardBrand

  • - + - elo + elo
    @@ -400,15 +411,26 @@

    CardBrand

    ELO

    +
    +

    Declaration

    +
    +

    Swift

    +
    case elo
    + +
    +
    +
  • @@ -419,15 +441,26 @@

    CardBrand

    Visa Electron

    +
    +

    Declaration

    +
    +

    Swift

    +
    case visaElectron
    + +
    +
    +
  • - + - maestro + maestro
    @@ -438,15 +471,26 @@

    CardBrand

    Maestro

    +
    +

    Declaration

    +
    +

    Swift

    +
    case maestro
    + +
    +
    +
  • @@ -457,15 +501,26 @@

    CardBrand

    Forbrugsforeningen

    +
    +

    Declaration

    +
    +

    Swift

    +
    case forbrugsforeningen
    + +
    +
    +
  • - + - dankort + dankort
    @@ -476,15 +531,26 @@

    CardBrand

    Dankort

    +
    +

    Declaration

    +
    +

    Swift

    +
    case dankort
    + +
    +
    +
  • - + - visa + visa
    @@ -495,15 +561,26 @@

    CardBrand

    Visa

    +
    +

    Declaration

    +
    +

    Swift

    +
    case visa
    + +
    +
    +
  • @@ -514,15 +591,26 @@

    CardBrand

    Mastercard

    +
    +

    Declaration

    +
    +

    Swift

    +
    case mastercard
    + +
    +
    +
  • - + - amex + amex
    @@ -533,15 +621,26 @@

    CardBrand

    American Express

    +
    +

    Declaration

    +
    +

    Swift

    +
    case amex
    + +
    +
    +
  • @@ -552,15 +651,26 @@

    CardBrand

    Hipercard

    +
    +

    Declaration

    +
    +

    Swift

    +
    case hipercard
    + +
    +
    +
  • @@ -571,15 +681,26 @@

    CardBrand

    Diners Club

    +
    +

    Declaration

    +
    +

    Swift

    +
    case dinersClub
    + +
    +
    +
  • - + - discover + discover
    @@ -590,15 +711,26 @@

    CardBrand

    Discover

    +
    +

    Declaration

    +
    +

    Swift

    +
    case discover
    + +
    +
    +
  • - + - unionpay + unionpay
    @@ -609,15 +741,26 @@

    CardBrand

    UnionPay

    +
    +

    Declaration

    +
    +

    Swift

    +
    case unionpay
    + +
    +
    +
  • - + - jcb + jcb
    @@ -628,15 +771,26 @@

    CardBrand

    JCB

    +
    +

    Declaration

    +
    +

    Swift

    +
    case jcb
    + +
    +
    +
  • - + - unknown + unknown
    @@ -647,15 +801,26 @@

    CardBrand

    Not supported card brand - “unknown”

    +
    +

    Declaration

    +
    +

    Swift

    +
    case unknown
    + +
    +
    +
  • @@ -666,15 +831,26 @@

    CardBrand

    Custom Payment Card Brand. Should have unique brandName.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case custom(brandName: String)
    + +
    +
    +
  • @@ -685,15 +861,26 @@

    CardBrand

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcFormatPattern: String { get }
    + +
    +
    +
  • @@ -704,15 +891,26 @@

    CardBrand

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var brandIcon: UIImage? { get }
    + +
    +
    +
  • - + - cvcIcon + cvcIcon
    @@ -723,6 +921,17 @@

    CardBrand

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcIcon: UIImage? { get }
    + +
    +
    +
  • @@ -742,9 +951,9 @@

    Attributes
  • @@ -755,15 +964,26 @@

    Attributes

    String representation of VGSPaymentCards.CardBrand enum values.

    +
    +

    Declaration

    +
    +

    Swift

    +
    var stringValue: String { get }
    + +
    +
    +
  • @@ -774,6 +994,17 @@

    Attributes

    Returns array with valid card number lengths for specific VGSPaymentCards.CardBrand

    +
    +

    Declaration

    +
    +

    Swift

    +
    var cardLengths: [Int] { get }
    + +
    +
    +
  • @@ -785,8 +1016,8 @@

    Attributes

    diff --git a/docs/Classes/VGSSSNTokenizationConfiguration.html b/docs/Classes/VGSSSNTokenizationConfiguration.html index a48253b0..e3009be0 100644 --- a/docs/Classes/VGSSSNTokenizationConfiguration.html +++ b/docs/Classes/VGSSSNTokenizationConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSSSNTokenizationConfiguration

    +
    +
    + +
    public class VGSSSNTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +

    VGSSSNTokenizationConfiguration - textfield configuration for textfield with type .ssn, required for work with tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSSSNTokenizationConfiguration

  • @@ -400,15 +411,26 @@

    VGSSSNTokenizationConfiguration

    VGSSSNTokenizationParameters - tokenization configuration parameters.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var tokenizationParameters: VGSSSNTokenizationParameters
    + +
    +
    +
  • - + - type + type
    @@ -416,9 +438,20 @@

    VGSSSNTokenizationConfiguration

    -

    FieldType.ssn type of VGSTextFieldtokenization configuration.

    +

    FieldType.ssn type of VGSTextFieldtokenization configuration.

    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var type: FieldType { get set }
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSSSNTokenizationConfiguration

    diff --git a/docs/Classes/VGSTextField.html b/docs/Classes/VGSTextField.html index 19232ac3..bb07559e 100644 --- a/docs/Classes/VGSTextField.html +++ b/docs/Classes/VGSTextField.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -378,11 +379,16 @@

    VGSTextField

    - +
    public class VGSTextField : UIView
    +
    extension VGSTextField: UITextFieldDelegate
    +

    An object that displays an editable text area in user interface.

    + @@ -402,9 +408,9 @@

    UI Attributes
  • @@ -415,15 +421,26 @@

    UI Attributes

    Textfield placeholder string.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var placeholder: String? { get set }
    + +
    +
    +
  • @@ -434,15 +451,26 @@

    UI Attributes

    Textfield autocapitalization type. Default is .sentences.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var autocapitalizationType: UITextAutocapitalizationType { get set }
    + +
    +
    +
  • @@ -453,15 +481,26 @@

    UI Attributes

    Textfield spell checking type. Default is UITextSpellCheckingType.default.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var spellCheckingType: UITextSpellCheckingType { get set }
    + +
    +
    +
  • @@ -472,15 +511,26 @@

    UI Attributes

    Textfield attributedPlaceholder string.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var attributedPlaceholder: NSAttributedString? { get set }
    + +
    +
    +
  • - + - padding + padding
    @@ -491,15 +541,26 @@

    UI Attributes

    UIEdgeInsets for text and placeholder inside VGSTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var padding: UIEdgeInsets { get set }
    + +
    +
    +
  • @@ -510,15 +571,26 @@

    UI Attributes

    The technique to use for aligning the text.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var textAlignment: NSTextAlignment { get set }
    + +
    +
    +
  • @@ -529,15 +601,26 @@

    UI Attributes

    Sets when the clear button shows up. Default is UITextField.ViewMode.never

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var clearButtonMode: UITextField.ViewMode { get set }
    + +
    +
    +
  • @@ -548,15 +631,26 @@

    UI Attributes

    Identifies whether the text object should disable text copying and in some cases hide the text being entered. Default is false.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var isSecureTextEntry: Bool { get set }
    + +
    +
    +
  • @@ -567,15 +661,26 @@

    UI Attributes

    Indicates whether VGSTextField should automatically update its font when the device’s UIContentSizeCategory is changed.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var adjustsFontForContentSizeCategory: Bool { get set }
    + +
    +
    +
  • @@ -586,15 +691,26 @@

    UI Attributes

    Input Accessory View

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var keyboardAccessoryView: UIView? { get set }
    + +
    +
    +
  • @@ -605,15 +721,26 @@

    UI Attributes

    Determines whether autocorrection is enabled or disabled during typing.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var autocorrectionType: UITextAutocorrectionType { get set }
    + +
    +
    +
  • @@ -624,15 +751,26 @@

    UI Attributes

    A succinct label in a localized string that identifies the accessibility text field.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var textFieldAccessibilityLabel: String? { get set }
    + +
    +
    +
  • @@ -643,6 +781,17 @@

    UI Attributes

    A localized string that contains a brief description of the result of performing an action on the accessibility text field.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var textFieldAccessibilityHint: String? { get set }
    + +
    +
    +
  • @@ -662,9 +811,9 @@

    Functional Attributes
  • @@ -675,15 +824,26 @@

    Functional Attributes

    Specifies VGSTextField configuration parameters to work with VGSCollect.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var configuration: VGSConfiguration? { get set }
    + +
    +
    +
  • - + - delegate + delegate
    @@ -694,6 +854,17 @@

    Functional Attributes

    Delegates VGSTextField editing events. Default is nil.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public weak var delegate: VGSTextFieldDelegate?
    + +
    +
    +
  • @@ -713,9 +884,9 @@

    Manage input
  • @@ -726,22 +897,33 @@

    Manage input

    Set textfield default text.

    Note

    - This will not change State.isDirty attribute. + This will not change State.isDirty attribute.
    • Discussion: probably you should want to set field configuration before setting default value, so the input format will be update as required.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func setDefaultText(_ text: String?)
    + +
    +
    +
  • @@ -752,6 +934,17 @@

    Manage input

    Removes input from field.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func cleanText()
    + +
    +
    +
  • @@ -771,9 +964,9 @@

    Compare Input
  • @@ -789,6 +982,17 @@

    Compare Input

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func isContentEqual(_ textField: VGSTextField) -> Bool
    + +
    +
    +
  • @@ -808,9 +1012,9 @@

    Text Attribute
  • - + - font + font
    @@ -821,15 +1025,26 @@

    Text Attribute

    VGSTextField text font

    +
    +

    Declaration

    +
    +

    Swift

    +
    var font: UIFont? { get set }
    + +
    +
    +
  • @@ -840,6 +1055,18 @@

    Text Attribute

    VGSTextField text color

    +
    +

    Declaration

    +
    +

    Swift

    +
    @IBInspectable
    +var textColor: UIColor? { get set }
    + +
    +
    +
  • @@ -859,9 +1086,9 @@

    UI Layer Attribute
  • @@ -872,15 +1099,27 @@

    UI Layer Attribute

    VGSTextField layer corner radius

    +
    +

    Declaration

    +
    +

    Swift

    +
    @IBInspectable
    +var cornerRadius: CGFloat { get set }
    + +
    +
    +
  • @@ -891,15 +1130,27 @@

    UI Layer Attribute

    VGSTextField layer borderWidth

    +
    +

    Declaration

    +
    +

    Swift

    +
    @IBInspectable
    +var borderWidth: CGFloat { get set }
    + +
    +
    +
  • @@ -910,6 +1161,48 @@

    UI Layer Attribute

    VGSTextField layer borderColor

    +
    +

    Declaration

    +
    +

    Swift

    +
    @IBInspectable
    +var borderColor: UIColor? { get set }
    + +
    +
    + + + +
  • +
  • +
    + + + + statePublisher + +
    +
    +
    +
    +
    +
    +

    VGSTextFieldStatePublisher publisher that emits the State of a given VGSTextField.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    var statePublisher: VGSTextFieldStatePublisher { get }
    + +
    +
    +
  • @@ -929,9 +1222,9 @@

    UIResponder methods
  • @@ -942,15 +1235,27 @@

    UIResponder methods

    Make VGSTextField focused.

    +
    +

    Declaration

    +
    +

    Swift

    +
    @discardableResult
    +override public func becomeFirstResponder() -> Bool
    + +
    +
    +
  • @@ -961,15 +1266,27 @@

    UIResponder methods

    Remove focus from VGSTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    @discardableResult
    +override public func resignFirstResponder() -> Bool
    + +
    +
    +
  • @@ -980,6 +1297,17 @@

    UIResponder methods

    Check if VGSTextField is focused.

    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var isFirstResponder: Bool { get }
    + +
    +
    +
  • @@ -991,8 +1319,8 @@

    UIResponder methods

    diff --git a/docs/Classes/VGSTokenizationConfiguration.html b/docs/Classes/VGSTokenizationConfiguration.html index 073256f6..18a2a57d 100644 --- a/docs/Classes/VGSTokenizationConfiguration.html +++ b/docs/Classes/VGSTokenizationConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSTokenizationConfiguration

    +
    +
    + +
    public class VGSTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +

    VGSTokenizationConfiguration - textfield configuration for textfield with any type of data, required for work with tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSTokenizationConfiguration

  • @@ -400,6 +411,17 @@

    VGSTokenizationConfiguration

    VGSTokenizationParameters - tokenization configuration parameters.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var tokenizationParameters: VGSTokenizationParameters
    + +
    +
    +
  • @@ -411,8 +433,8 @@

    VGSTokenizationConfiguration

    diff --git a/docs/Debugging.html b/docs/Debugging.html index 66d65a74..df867e6e 100644 --- a/docs/Debugging.html +++ b/docs/Debugging.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -386,9 +387,9 @@

    Debugging

  • @@ -401,15 +402,26 @@

    Debugging

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public final class VGSCollectLogger
    + +
    +
    +
  • @@ -421,15 +433,26 @@

    Debugging

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSLogLevel : String
    + +
    +
    +
  • @@ -441,6 +464,17 @@

    Debugging

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSCollectLoggingConfiguration
    + +
    +
    +
  • @@ -452,8 +486,8 @@

    Debugging

    diff --git a/docs/Enumerations.html b/docs/Enumerations.html index f4739984..80f007a4 100644 --- a/docs/Enumerations.html +++ b/docs/Enumerations.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -386,9 +387,9 @@

    Enumerations

  • @@ -400,15 +401,26 @@

    Enumerations

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSCardExpDateFormat : InputConvertableFormat, OutputConvertableFormat
    + +
    +
    +
  • @@ -420,6 +432,17 @@

    Enumerations

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSCollectFieldNameMappingPolicy
    + +
    +
    +
  • @@ -431,8 +454,8 @@

    Enumerations

    diff --git a/docs/Enums/CheckSumAlgorithmType.html b/docs/Enums/CheckSumAlgorithmType.html index a8cda2bb..6cfd7bb5 100644 --- a/docs/Enums/CheckSumAlgorithmType.html +++ b/docs/Enums/CheckSumAlgorithmType.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    CheckSumAlgorithmType

    +
    +
    + +
    public enum CheckSumAlgorithmType
    + +
    +

    Check Sum Algorithm Types

    +
    @@ -387,9 +398,9 @@

    CheckSumAlgorithmType

  • - + - luhn + luhn
    @@ -400,15 +411,26 @@

    CheckSumAlgorithmType

    Luhn Algorithm

    +
    +

    Declaration

    +
    +

    Swift

    +
    case luhn
    + +
    +
    +
  • @@ -419,6 +441,17 @@

    CheckSumAlgorithmType

    Validate input String with specified algorithm.

    +
    +

    Declaration

    +
    +

    Swift

    +
    func validate(_ input: String) -> Bool
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    CheckSumAlgorithmType

    diff --git a/docs/Enums/Environment.html b/docs/Enums/Environment.html index e7eed69c..d290ae67 100644 --- a/docs/Enums/Environment.html +++ b/docs/Enums/Environment.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    Environment

    +
    +
    + +
    public enum Environment : String
    + +
    +

    Organization vault environment.

    +
    @@ -387,9 +398,9 @@

    Environment

  • - + - sandbox + sandbox
    @@ -400,15 +411,26 @@

    Environment

    Should be used for development and testing purpose.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case sandbox
    + +
    +
    +
  • - + - live + live
    @@ -419,6 +441,17 @@

    Environment

    Should be used for production.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case live
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    Environment

    diff --git a/docs/Enums/FieldType.html b/docs/Enums/FieldType.html index 2cb26f95..d9b4f112 100644 --- a/docs/Enums/FieldType.html +++ b/docs/Enums/FieldType.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    FieldType

    +
    +
    + +
    public enum FieldType : Int, CaseIterable
    + +
    +

    Type of VGSTextField configuration.

    +
    @@ -387,9 +398,9 @@

    FieldType

  • - + - none + none
    @@ -400,15 +411,26 @@

    FieldType

    Field type that doesn’t require any input formatting and validation.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case none
    + +
    +
    +
  • @@ -419,15 +441,26 @@

    FieldType

    Field type that requires Credit Card Number input formatting and validation.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case cardNumber
    + +
    +
    +
  • - + - expDate + expDate
    @@ -438,15 +471,56 @@

    FieldType

    Field type that requires Expiration Date input formatting and validation.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case expDate
    + +
    +
    + + + +
  • +
  • +
    + + + + date + +
    +
    +
    +
    +
    +
    +

    Field type that requires Date input formatting and validation.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    case date
    + +
    +
    +
  • - + - cvc + cvc
    @@ -457,15 +531,26 @@

    FieldType

    Field type that requires Credit Card CVC input formatting and validation.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case cvc
    + +
    +
    +
  • @@ -476,15 +561,26 @@

    FieldType

    Field type that requires Cardholder Name input formatting and validation.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case cardHolderName
    + +
    +
    +
  • - + - ssn + ssn
    @@ -495,6 +591,17 @@

    FieldType

    Field type that requires US Social Security Number input formatting and validation.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case ssn
    + +
    +
    +
  • @@ -506,8 +613,8 @@

    FieldType

    diff --git a/docs/Enums/VGSCardExpDateFormat.html b/docs/Enums/VGSCardExpDateFormat.html index a31d68d0..76f4ff1b 100644 --- a/docs/Enums/VGSCardExpDateFormat.html +++ b/docs/Enums/VGSCardExpDateFormat.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCardExpDateFormat

    +
    +
    + +
    public enum VGSCardExpDateFormat : InputConvertableFormat, OutputConvertableFormat
    + +
    +

    Payment Card Expiration Date Format

    +
    @@ -387,9 +398,9 @@

    VGSCardExpDateFormat

  • @@ -400,15 +411,26 @@

    VGSCardExpDateFormat

    Exp.Date in format mm/yy: 01/22

    +
    +

    Declaration

    +
    +

    Swift

    +
    case shortYear
    + +
    +
    +
  • - + - longYear + longYear
    @@ -419,15 +441,26 @@

    VGSCardExpDateFormat

    Exp.Date in format mm/yyyy: 01/2022

    +
    +

    Declaration

    +
    +

    Swift

    +
    case longYear
    + +
    +
    +
  • @@ -438,15 +471,26 @@

    VGSCardExpDateFormat

    Exp.Date in format yy/mm: 22/01

    +
    +

    Declaration

    +
    +

    Swift

    +
    case shortYearThenMonth
    + +
    +
    +
  • @@ -457,6 +501,17 @@

    VGSCardExpDateFormat

    Exp.Date in format yy/mm: 2022/01

    +
    +

    Declaration

    +
    +

    Swift

    +
    case longYearThenMonth
    + +
    +
    +
  • @@ -468,8 +523,8 @@

    VGSCardExpDateFormat

    diff --git a/docs/Enums/VGSCollectFieldNameMappingPolicy.html b/docs/Enums/VGSCollectFieldNameMappingPolicy.html index 023b91ca..7684b5e1 100644 --- a/docs/Enums/VGSCollectFieldNameMappingPolicy.html +++ b/docs/Enums/VGSCollectFieldNameMappingPolicy.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCollectFieldNameMappingPolicy

    +
    +
    + +
    public enum VGSCollectFieldNameMappingPolicy
    + +
    +

    Defines fieldName mapping to JSON.

    +
    @@ -387,9 +398,9 @@

    VGSCollectFieldNameMappingPolicy

  • - + - flatJSON + flatJSON
    @@ -407,15 +418,26 @@

    VGSCollectFieldNameMappingPolicy

    +
    +

    Declaration

    +
    +

    Swift

    +
    case flatJSON
    + +
    +
    +
  • @@ -435,15 +457,26 @@

    VGSCollectFieldNameMappingPolicy

    +
    +

    Declaration

    +
    +

    Swift

    +
    case nestedJSON
    + +
    +
    +
  • @@ -485,15 +518,26 @@

    VGSCollectFieldNameMappingPolicy

    +
    +

    Declaration

    +
    +

    Swift

    +
    case nestedJSONWithArrayMerge
    + +
    +
    +
  • @@ -535,6 +579,17 @@

    VGSCollectFieldNameMappingPolicy

    +
    +

    Declaration

    +
    +

    Swift

    +
    case nestedJSONWithArrayOverwrite
    + +
    +
    +
  • @@ -546,8 +601,8 @@

    VGSCollectFieldNameMappingPolicy

    diff --git a/docs/Enums/VGSCollectHTTPMethod.html b/docs/Enums/VGSCollectHTTPMethod.html index ca2f66ee..e2a37d05 100644 --- a/docs/Enums/VGSCollectHTTPMethod.html +++ b/docs/Enums/VGSCollectHTTPMethod.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCollectHTTPMethod

    +
    +
    + +
    public enum VGSCollectHTTPMethod : String
    + +
    +

    HTTP request methods

    +
    @@ -387,9 +398,9 @@

    VGSCollectHTTPMethod

  • - + - get + get
    @@ -400,15 +411,26 @@

    VGSCollectHTTPMethod

    GET method.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case get = "GET"
    + +
    +
    +
  • - + - post + post
    @@ -419,15 +441,26 @@

    VGSCollectHTTPMethod

    POST method.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case post = "POST"
    + +
    +
    +
  • - + - put + put
    @@ -438,15 +471,26 @@

    VGSCollectHTTPMethod

    PUT method.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case put = "PUT"
    + +
    +
    +
  • - + - patch + patch
    @@ -457,15 +501,26 @@

    VGSCollectHTTPMethod

    PATCH method.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case patch = "PATCH"
    + +
    +
    +
  • - + - delete + delete
    @@ -476,6 +531,17 @@

    VGSCollectHTTPMethod

    DELETE method.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case delete = "DELETE"
    + +
    +
    +
  • @@ -487,8 +553,8 @@

    VGSCollectHTTPMethod

    diff --git a/docs/Enums/VGSDateFormat.html b/docs/Enums/VGSDateFormat.html new file mode 100644 index 00000000..51c97f75 --- /dev/null +++ b/docs/Enums/VGSDateFormat.html @@ -0,0 +1,483 @@ + + + + VGSDateFormat Enumeration Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    VGSDateFormat

    +
    +
    + +
    public enum VGSDateFormat : InputConvertableFormat, OutputConvertableFormat
    + +
    +
    +

    Format used to validate a VGS date text input

    + + +
    +
    + +
    +
    +
    +
      +
    • +
      + + + + displayFormat + +
      +
      +
      +
      +
      +
      +

      Date format used for display in UI

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public var displayFormat: String { get }
      + +
      +
      + +
      +
      +
    • +
    +
    +
    +
    + + +
    + +

    Static properties and methods +

    +
    +
    +
      +
    • +
      + + + + default + +
      +
      +
      +
      +
      +
      +

      Default format

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public static let `default`: VGSDateFormat
      + +
      +
      + +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/docs/Enums/VGSErrorType.html b/docs/Enums/VGSErrorType.html index 92812f55..abbde3d0 100644 --- a/docs/Enums/VGSErrorType.html +++ b/docs/Enums/VGSErrorType.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSErrorType

    +
    +
    + +
    public enum VGSErrorType : Int
    + +
    +

    Type of VGSError and it status code.

    +
    @@ -396,9 +407,9 @@

    Text input data errors
  • @@ -409,6 +420,17 @@

    Text input data errors

    When input data is not valid, but required to be valid

    +
    +

    Declaration

    +
    +

    Swift

    +
    case inputDataIsNotValid = 1001
    + +
    +
    +
  • @@ -428,9 +450,9 @@

    Files data errors
  • @@ -441,15 +463,26 @@

    Files data errors

    When can’t find file on device

    +
    +

    Declaration

    +
    +

    Swift

    +
    case inputFileNotFound = 1101
    + +
    +
    +
  • @@ -460,15 +493,26 @@

    Files data errors

    When can’t find file on device

    +
    +

    Declaration

    +
    +

    Swift

    +
    case inputFileTypeIsNotSupported = 1102
    + +
    +
    +
  • @@ -479,15 +523,26 @@

    Files data errors

    When file size is larger then allowed limit

    +
    +

    Declaration

    +
    +

    Swift

    +
    case inputFileSizeExceedsTheLimit = 1103
    + +
    +
    +
  • @@ -498,6 +553,17 @@

    Files data errors

    When can’t get access to file source

    +
    +

    Declaration

    +
    +

    Swift

    +
    case sourceNotAvailable = 1150
    + +
    +
    +
  • @@ -517,9 +583,9 @@

    Other errors
  • @@ -530,15 +596,26 @@

    Other errors

    When response type is not supported

    +
    +

    Declaration

    +
    +

    Swift

    +
    case unexpectedResponseType = 1400
    + +
    +
    +
  • @@ -549,15 +626,26 @@

    Other errors

    When reponse data format is not supported

    +
    +

    Declaration

    +
    +

    Swift

    +
    case unexpectedResponseDataFormat = 1401
    + +
    +
    +
  • @@ -568,6 +656,17 @@

    Other errors

    When VGS config URL is not valid.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case invalidConfigurationURL = 1480
    + +
    +
    +
  • @@ -579,8 +678,8 @@

    Other errors

    diff --git a/docs/Enums/VGSFileSource.html b/docs/Enums/VGSFileSource.html index f84748ff..42ac711e 100644 --- a/docs/Enums/VGSFileSource.html +++ b/docs/Enums/VGSFileSource.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSFileSource

    +
    +
    + +
    public enum VGSFileSource : Int, CaseIterable
    + +
    +

    Available file source destinations that VGSFilePickerController can work with.

    +
    @@ -387,9 +398,9 @@

    VGSFileSource

  • @@ -400,15 +411,26 @@

    VGSFileSource

    Device photo library.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case photoLibrary
    + +
    +
    +
  • - + - camera + camera
    @@ -419,15 +441,26 @@

    VGSFileSource

    Device camera.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case camera
    + +
    +
    +
  • @@ -438,6 +471,17 @@

    VGSFileSource

    Device documents directory.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case documentsDirectory
    + +
    +
    +
  • @@ -449,8 +493,8 @@

    VGSFileSource

    diff --git a/docs/Enums/VGSLogLevel.html b/docs/Enums/VGSLogLevel.html index 79ab4bf9..72fb8657 100644 --- a/docs/Enums/VGSLogLevel.html +++ b/docs/Enums/VGSLogLevel.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSLogLevel

    +
    +
    + +
    public enum VGSLogLevel : String
    + +
    +

    Defines levels of logging.

    +
    @@ -387,9 +398,9 @@

    VGSLogLevel

  • - + - info + info
    @@ -400,15 +411,26 @@

    VGSLogLevel

    Log all events including errors and warnings.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case info
    + +
    +
    +
  • - + - warning + warning
    @@ -419,15 +441,26 @@

    VGSLogLevel

    Log only events indicating warnings and errors.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case warning
    + +
    +
    +
  • - + - none + none
    @@ -438,6 +471,17 @@

    VGSLogLevel

    Log no events.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case none
    + +
    +
    +
  • @@ -449,8 +493,8 @@

    VGSLogLevel

    diff --git a/docs/Enums/VGSResponse.html b/docs/Enums/VGSResponse.html index 528e5f85..62b5171a 100644 --- a/docs/Enums/VGSResponse.html +++ b/docs/Enums/VGSResponse.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,19 @@

    VGSResponse

    +
    +
    + +
    @frozen
    +public enum VGSResponse
    + +
    +

    Response enum cases for SDK requests.

    +
    @@ -387,9 +399,9 @@

    VGSResponse

  • @@ -400,15 +412,69 @@

    VGSResponse

    Success response case

    +
    +

    Declaration

    +
    +

    Swift

    +
    case success(_: Int, _: Data?, _: URLResponse?)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + + + + + +
    + + code + + +
    +

    response status code.

    +
    +
    + + data + + +
    +

    response data object.

    +
    +
    + + response + + +
    +

    URLResponse object represents a URL load response.

    +
    +
    +
    +
  • @@ -419,6 +485,72 @@

    VGSResponse

    Failed response case

    +
    +

    Declaration

    +
    +

    Swift

    +
    case failure(_: Int, _: Data?, _: URLResponse?, _: Error?)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + + + + + + + + + +
    + + code + + +
    +

    response status code.

    +
    +
    + + data + + +
    +

    response Data object.

    +
    +
    + + response + + +
    +

    URLResponse object represents a URL load response.

    +
    +
    + + error + + +
    +

    Error object.

    +
    +
    +
    +
  • @@ -430,8 +562,8 @@

    VGSResponse

    diff --git a/docs/Enums/VGSTextFieldInputSource.html b/docs/Enums/VGSTextFieldInputSource.html index 609f6400..875f0444 100644 --- a/docs/Enums/VGSTextFieldInputSource.html +++ b/docs/Enums/VGSTextFieldInputSource.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSTextFieldInputSource

    +
    +
    + +
    public enum VGSTextFieldInputSource
    + +
    +

    Type of VGSTextField input source.

    +
    @@ -387,9 +398,9 @@

    VGSTextFieldInputSource

  • - + - keyboard + keyboard
    @@ -400,15 +411,26 @@

    VGSTextFieldInputSource

    UIKeyboard input type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case keyboard
    + +
    +
    +
  • @@ -419,6 +441,17 @@

    VGSTextFieldInputSource

    UIDatePicker input type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case datePicker
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSTextFieldInputSource

    diff --git a/docs/Enums/VGSTokenizationResponse.html b/docs/Enums/VGSTokenizationResponse.html index 6498d32f..1bea722d 100644 --- a/docs/Enums/VGSTokenizationResponse.html +++ b/docs/Enums/VGSTokenizationResponse.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,19 @@

    VGSTokenizationResponse

    +
    +
    + +
    @frozen
    +public enum VGSTokenizationResponse
    + +
    +

    Tokenization response enum cases for SDK requests.

    +
    @@ -387,9 +399,9 @@

    VGSTokenizationResponse

  • @@ -400,15 +412,69 @@

    VGSTokenizationResponse

    Success response case

    +
    +

    Declaration

    +
    +

    Swift

    +
    case success(_: Int, _: JsonData?, _: URLResponse?)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + + + + + +
    + + code + + +
    +

    response status code.

    +
    +
    + + body + + +
    +

    response JsonData object.

    +
    +
    + + response + + +
    +

    URLResponse object represents a URL load response.

    +
    +
    +
    +
  • @@ -419,6 +485,72 @@

    VGSTokenizationResponse

    Failed response case

    +
    +

    Declaration

    +
    +

    Swift

    +
    case failure(_: Int, _: Data?, _: URLResponse?, _: Error?)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + + + + + + + + + +
    + + code + + +
    +

    response status code.

    +
    +
    + + data + + +
    +

    response Data object.

    +
    +
    + + response + + +
    +

    URLResponse object represents a URL load response.

    +
    +
    + + error + + +
    +

    Error object.

    +
    +
    +
    +
  • @@ -430,8 +562,8 @@

    VGSTokenizationResponse

    diff --git a/docs/Enums/VGSValidationErrorType.html b/docs/Enums/VGSValidationErrorType.html index 4abb42b4..5b8d6143 100644 --- a/docs/Enums/VGSValidationErrorType.html +++ b/docs/Enums/VGSValidationErrorType.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSValidationErrorType

    +
    +
    + +
    public enum VGSValidationErrorType : String
    + +
    +

    Default validation error types

    +
    @@ -387,9 +398,9 @@

    VGSValidationErrorType

  • - + - pattern + pattern
    @@ -400,15 +411,26 @@

    VGSValidationErrorType

    Default Validation error for VGSValidationRulePattern

    +
    +

    Declaration

    +
    +

    Swift

    +
    case pattern = "PATTERN_VALIDATION_ERROR"
    + +
    +
    +
  • - + - length + length
    @@ -419,15 +441,26 @@

    VGSValidationErrorType

    Default Validation error for VGSValidationRuleLength

    +
    +

    Declaration

    +
    +

    Swift

    +
    case length = "LENGTH_VALIDATION_ERROR"
    + +
    +
    +
  • @@ -438,15 +471,26 @@

    VGSValidationErrorType

    Default Validation error for VGSValidationRuleLength

    +
    +

    Declaration

    +
    +

    Swift

    +
    case lengthMathes = "LENGTH_RANGE_MATCH_VALIDATION_ERROR"
    + +
    +
    +
  • - + - expDate + expDate
    @@ -457,15 +501,56 @@

    VGSValidationErrorType

    Default Validation error for VGSValidationRuleCardExpirationDate

    +
    +

    Declaration

    +
    +

    Swift

    +
    case expDate = "EXPIRATION_DATE_VALIDATION_ERROR"
    + +
    +
    +
  • - + + + date + +
    +
    +
    +
    +
    +
    +

    Default Validation error for VGSValidationRuleDateRange

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    case date = "DATE_VALIDATION_ERROR"
    + +
    +
    + +
    +
    +
  • +
  • +
    @@ -476,15 +561,26 @@

    VGSValidationErrorType

    Default Validation error for VGSValidationRulePaymentCard

    +
    +

    Declaration

    +
    +

    Swift

    +
    case cardNumber = "CARD_NUMBER_VALIDATION_ERROR"
    + +
    +
    +
  • @@ -495,6 +591,17 @@

    VGSValidationErrorType

    Default Validation error for VGSValidationRuleLuhnCheck

    +
    +

    Declaration

    +
    +

    Swift

    +
    case luhnCheck = "LUHN_ALGORITHM_CHECK_VALIDATION_ERROR"
    + +
    +
    +
  • @@ -506,8 +613,8 @@

    VGSValidationErrorType

    diff --git a/docs/Enums/VGSVaultAliasFormat.html b/docs/Enums/VGSVaultAliasFormat.html index 01cd8f84..32beb7b5 100644 --- a/docs/Enums/VGSVaultAliasFormat.html +++ b/docs/Enums/VGSVaultAliasFormat.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSVaultAliasFormat

    +
    +
    + +
    public enum VGSVaultAliasFormat : String
    + +
    +

    Type of Alias format. Read more about avaliable formats: https://www.verygoodsecurity.com/docs/terminology/nomenclature#alias-formats .

    +
    @@ -387,9 +398,9 @@

    VGSVaultAliasFormat

  • @@ -400,15 +411,26 @@

    VGSVaultAliasFormat

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    case FPE_ACC_NUM_T_FOUR = "FPE_ACC_NUM_T_FOUR"
    + +
    +
    +
  • @@ -419,15 +441,26 @@

    VGSVaultAliasFormat

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    case FPE_ALPHANUMERIC_ACC_NUM_T_FOUR = "FPE_ALPHANUMERIC_ACC_NUM_T_FOUR"
    + +
    +
    +
  • @@ -438,15 +471,26 @@

    VGSVaultAliasFormat

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    case FPE_SIX_T_FOUR = "FPE_SIX_T_FOUR"
    + +
    +
    +
  • @@ -457,15 +501,26 @@

    VGSVaultAliasFormat

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    case FPE_SSN_T_FOUR = "FPE_SSN_T_FOUR"
    + +
    +
    +
  • @@ -476,15 +531,26 @@

    VGSVaultAliasFormat

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    case FPE_T_FOUR = "FPE_T_FOUR"
    + +
    +
    +
  • @@ -495,15 +561,26 @@

    VGSVaultAliasFormat

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    case NUM_LENGTH_PRESERVING = "NUM_LENGTH_PRESERVING"
    + +
    +
    +
  • - + - PFPT + PFPT
    @@ -514,15 +591,26 @@

    VGSVaultAliasFormat

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    case PFPT = "PFPT"
    + +
    +
    +
  • - + - RAW_UUID + RAW_UUID
    @@ -533,15 +621,26 @@

    VGSVaultAliasFormat

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    case RAW_UUID = "RAW_UUID"
    + +
    +
    +
  • - + - UUID + UUID
    @@ -552,6 +651,17 @@

    VGSVaultAliasFormat

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    case UUID = "UUID"
    + +
    +
    +
  • @@ -563,8 +673,8 @@

    VGSVaultAliasFormat

    diff --git a/docs/Enums/VGSVaultStorageType.html b/docs/Enums/VGSVaultStorageType.html index f47d96a7..be51033c 100644 --- a/docs/Enums/VGSVaultStorageType.html +++ b/docs/Enums/VGSVaultStorageType.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSVaultStorageType

    +
    +
    + +
    public enum VGSVaultStorageType : String
    + +
    +

    Type of VGS Vault storage.

    +
    @@ -387,9 +398,9 @@

    VGSVaultStorageType

  • @@ -400,15 +411,26 @@

    VGSVaultStorageType

    PERSISTENT data storage.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case PERSISTENT = "PERSISTENT"
    + +
    +
    +
  • - + - VOLATILE + VOLATILE
    @@ -419,6 +441,17 @@

    VGSVaultStorageType

    VOLATILE data storage.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case VOLATILE = "VOLATILE"
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSVaultStorageType

    diff --git a/docs/Error Keys.html b/docs/Error Keys.html index 06118376..4ff7dd1f 100644 --- a/docs/Error Keys.html +++ b/docs/Error Keys.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -395,9 +396,9 @@

    Input data errors
  • @@ -408,20 +409,31 @@

    Input data errors

    Error key, used for errors when input data is required to be not empty or to be valid only, but is not valid.

    Note

    - VGSError with this error key can include VGSSDKErrorInputDataRequired and VGSSDKErrorInputDataRequiredValid error keys in userInfo dictionary. + VGSError with this error key can include VGSSDKErrorInputDataRequired and VGSSDKErrorInputDataRequiredValid error keys in userInfo dictionary.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let VGSSDKErrorInputDataIsNotValid: VGSErrorInfoKey
    + +
    +
    +
  • @@ -432,15 +444,26 @@

    Input data errors

    Error key, used for errors when input data is required to be not empty but is empty or nil.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let VGSSDKErrorInputDataRequired: VGSErrorInfoKey
    + +
    +
    +
  • @@ -451,6 +474,17 @@

    Input data errors

    Error key, used for errors when input data is required to be valid is not valid.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let VGSSDKErrorInputDataRequiredValid: VGSErrorInfoKey
    + +
    +
    +
  • @@ -470,9 +504,9 @@

    File data errors
  • @@ -483,15 +517,26 @@

    File data errors

    Error key, used for errors when SDK can’t find the file at file path. Can happened when file changes the path or doesn’t exist.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let VGSSDKErrorFileNotFound: VGSErrorInfoKey
    + +
    +
    +
  • @@ -502,15 +547,26 @@

    File data errors

    Error key, used for errors when file type is not supported by SDK.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let VGSSDKErrorFileTypeNotSupported: VGSErrorInfoKey
    + +
    +
    +
  • @@ -521,6 +577,17 @@

    File data errors

    Error key, used for errors when file size exceeds maximum limit.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let VGSSDKErrorFileSizeExceedsTheLimit: VGSErrorInfoKey
    + +
    +
    +
  • @@ -540,9 +607,9 @@

    Source errors
  • @@ -553,6 +620,17 @@

    Source errors

    Error key, used for errors when SDK can’t get access to specific source.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let VGSSDKErrorSourceNotAvailable: VGSErrorInfoKey
    + +
    +
    +
  • @@ -572,9 +650,9 @@

    Response errors
  • @@ -585,6 +663,17 @@

    Response errors

    Error key, used for errors when response for SDK API request is in format that not supported by SDK.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let VGSSDKErrorUnexpectedResponseDataFormat: VGSErrorInfoKey
    + +
    +
    +
  • @@ -596,8 +685,8 @@

    Response errors

    diff --git a/docs/Errors.html b/docs/Errors.html index fad443a8..e49e3a5c 100644 --- a/docs/Errors.html +++ b/docs/Errors.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -386,9 +387,9 @@

    Errors

  • - + - VGSError + VGSError
    @@ -400,15 +401,26 @@

    Errors

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSError : NSError
    + +
    +
    +
  • @@ -420,15 +432,26 @@

    Errors

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSErrorType : Int
    + +
    +
    +
  • @@ -439,15 +462,26 @@

    Errors

    An error domain string used to produce VGSError from VGSCollectSDK - “vgscollect.sdk”

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let VGSCollectSDKErrorDomain: String
    + +
    +
    +
  • @@ -458,15 +492,26 @@

    Errors

    VGS Validation Error object type

    +
    +

    Declaration

    +
    +

    Swift

    +
    public typealias VGSValidationError = String
    + +
    +
    +
  • @@ -478,6 +523,17 @@

    Errors

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSValidationErrorType : String
    + +
    +
    +
  • @@ -489,8 +545,8 @@

    Errors

    diff --git a/docs/File Picker.html b/docs/File Picker.html index 925c0e9c..60e9539c 100644 --- a/docs/File Picker.html +++ b/docs/File Picker.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -386,9 +387,9 @@

    File Picker

  • @@ -400,15 +401,26 @@

    File Picker

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSFilePickerController
    + +
    +
    +
  • @@ -420,15 +432,26 @@

    File Picker

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSFilePickerConfiguration : VGSFilePickerConfigurationProtocol
    + +
    +
    +
  • @@ -440,15 +463,27 @@

    File Picker

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    @objc
    +public protocol VGSFilePickerControllerDelegate
    + +
    +
    +
  • @@ -460,15 +495,26 @@

    File Picker

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSFileSource : Int, CaseIterable
    + +
    +
    +
  • @@ -480,6 +526,17 @@

    File Picker

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSFileInfo : NSObject, VGSFileInfoProtocol
    + +
    +
    +
  • @@ -491,8 +548,8 @@

    File Picker

    diff --git a/docs/Observe State and Send Data.html b/docs/Observe State and Send Data.html index 6220acac..fb390174 100644 --- a/docs/Observe State and Send Data.html +++ b/docs/Observe State and Send Data.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -386,9 +387,9 @@

    Observe State and Send Data

  • @@ -400,15 +401,26 @@

    Observe State and Send Data

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSCollect
    + +
    +
    +
  • @@ -420,15 +432,26 @@

    Observe State and Send Data

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum Environment : String
    + +
    +
    +
  • - + - State + State
    @@ -440,15 +463,26 @@

    Observe State and Send Data

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class State
    + +
    +
    +
  • - + - SSNState + SSNState
    @@ -456,19 +490,30 @@

    Observe State and Send Data

    -

    An object that describes VGSTextField state with configuration FieldType.ssn . State attributes are read-only.

    +

    An object that describes VGSTextField state with configuration FieldType.ssn . State attributes are read-only.

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class SSNState : State
    + +
    +
    +
  • @@ -476,19 +521,62 @@

    Observe State and Send Data

    -

    An object that describes VGSTextField state with configuration FieldType.cardNumber . State attributes are read-only.

    +

    An object that describes VGSTextField state with configuration FieldType.cardNumber . State attributes are read-only.

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class CardState : State
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    A custom publisher that emits State of a given VGSTextField.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    @available(iOS 13, *)
    +public struct VGSTextFieldStatePublisher : Publisher
    + +
    +
    +
  • @@ -500,15 +588,59 @@

    Observe State and Send Data

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    @frozen
    +public enum VGSResponse
    + +
    +
    +
  • +
    +
    +
    +
    +
    +

    Tokenization response enum cases for SDK requests.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    @frozen
    +public enum VGSTokenizationResponse
    + +
    +
    + +
    +
    +
  • +
  • +
    @@ -520,15 +652,26 @@

    Observe State and Send Data

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSCollectRequestOptions
    + +
    +
    +
  • - + - JsonData + JsonData
    @@ -539,15 +682,57 @@

    Observe State and Send Data

    Key-value data type, usually used for response format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public typealias JsonData = [String : Any]
    + +
    +
    + + + +
  • +
  • +
    + + + + VGSCollectHTTPMethod + +
    +
    +
    +
    +
    +
    +

    HTTP request methods

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSCollectHTTPMethod : String
    + +
    +
    +
  • @@ -558,6 +743,17 @@

    Observe State and Send Data

    Key-value data type, used in http request headers.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public typealias HTTPHeaders = [String : String]
    + +
    +
    +
  • @@ -569,8 +765,8 @@

    Observe State and Send Data

    diff --git a/docs/Other Classes.html b/docs/Other Classes.html deleted file mode 100644 index 630a8cd7..00000000 --- a/docs/Other Classes.html +++ /dev/null @@ -1,519 +0,0 @@ - - - - Other Classes Reference - - - - - - - - - - - - - - - - -
    -

    - - VGSCollectSDK - - -

    - -
    -
    - -
    -
    - -

    - - GitHub - View on GitHub - -

    - -
    - - - -
    - -
    - -
    -
    -

    Other Classes

    -

    The following classes are available globally.

    - -
    -
    - -
    -
    -
    -
      -
    • - -
      -
      -
      -
      -
      -

      VGSCVCTokenizationConfiguration - textfield configuration for textfield with type .cvc, required for work with tokenization api.

      - - See more -
      -
      -
      -
    • -
    • - -
      -
      -
      -
      -
      -

      VGSCardHolderNameTokenizationConfiguration - textfield configuration for textfield with type .cardHolderName, required for work with tokenization api.

      - - See more -
      -
      -
      -
    • -
    • - -
      -
      -
      -
      -
      -

      VGSCardTokenizationConfiguration - textfield configuration for textfield with type .cardNumber, required for work with tokenization api.

      - - See more -
      -
      -
      -
    • -
    • - -
      -
      -
      -
      -
      -

      VGSExpDateTokenizationConfiguration - textfield configuration for textfield with type .expDate, required for work with tokenization api.

      - - See more -
      -
      -
      -
    • -
    • - -
      -
      -
      -
      -
      -

      VGSSSNTokenizationConfiguration - textfield configuration for textfield with type .ssn, required for work with tokenization api.

      - - See more -
      -
      -
      -
    • -
    • - -
      -
      -
      -
      -
      -

      VGSTokenizationConfiguration - textfield configuration for textfield with any type of data, required for work with tokenization api.

      - - See more -
      -
      -
      -
    • -
    -
    -
    -
    - -
    -
    - - - diff --git a/docs/Other Enums.html b/docs/Other Enums.html deleted file mode 100644 index 74c364fe..00000000 --- a/docs/Other Enums.html +++ /dev/null @@ -1,499 +0,0 @@ - - - - Other Enumerations Reference - - - - - - - - - - - - - - - - -
    -

    - - VGSCollectSDK - - -

    - -
    -
    - -
    -
    - -

    - - GitHub - View on GitHub - -

    - -
    - - - -
    - -
    - -
    -
    -

    Other Enumerations

    -

    The following enumerations are available globally.

    - -
    -
    - -
    -
    -
    - -
    -
    -
    - -
    -
    - - - diff --git a/docs/Other Extensions.html b/docs/Other Extensions.html deleted file mode 100644 index cba223eb..00000000 --- a/docs/Other Extensions.html +++ /dev/null @@ -1,466 +0,0 @@ - - - - Other Extensions Reference - - - - - - - - - - - - - - - - -
    -

    - - VGSCollectSDK - - -

    - -
    -
    - -
    -
    - -

    - - GitHub - View on GitHub - -

    - -
    - - - -
    - -
    - -
    -
    -

    Other Extensions

    -

    The following extensions are available globally.

    - -
    -
    - -
    -
    -
    - -
    -
    -
    - - -
    - -

    UITextFieldDelegate -

    -
    -
    - -
    -
    -
    - -
    -
    - - - diff --git a/docs/Other Protocols.html b/docs/Other Protocols.html deleted file mode 100644 index 142194bc..00000000 --- a/docs/Other Protocols.html +++ /dev/null @@ -1,439 +0,0 @@ - - - - Other Protocols Reference - - - - - - - - - - - - - - - - -
    -

    - - VGSCollectSDK - - -

    - -
    -
    - -
    -
    - -

    - - GitHub - View on GitHub - -

    - -
    - - - -
    - -
    - -
    -
    -

    Other Protocols

    -

    The following protocols are available globally.

    - -
    -
    - -
    -
    -
    - -
    -
    -
    - -
    -
    - - - diff --git a/docs/Payment Cards.html b/docs/Payment Cards.html index 313d9a50..5a70d9cc 100644 --- a/docs/Payment Cards.html +++ b/docs/Payment Cards.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -386,9 +387,9 @@

    Payment Cards

  • @@ -406,15 +407,26 @@

    Payment Cards

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSPaymentCards
    + +
    +
    +
  • @@ -426,15 +438,26 @@

    Payment Cards

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSPaymentCardModel : VGSPaymentCardModelProtocol
    + +
    +
    +
  • @@ -446,15 +469,26 @@

    Payment Cards

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSCustomPaymentCardModel : VGSPaymentCardModelProtocol
    + +
    +
    +
  • @@ -462,10 +496,21 @@

    Payment Cards

    -

    An object representing Unknown Payment Cards - cards not defined in the SDK. Object is used when validation forCardBrand.unknown is set as true. Check VGSValidationRulePaymentCard for more details. Validation attributes can be edited through `VGSPaymentCards.unknown model.

    +

    An object representing Unknown Payment Cards - cards not defined in the SDK. Object is used when validation forCardBrand.unknown is set as true. Check VGSValidationRulePaymentCard for more details. Validation attributes can be edited through `VGSPaymentCards.unknown model.

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSUnknownPaymentCardModel
    + +
    +
    +
  • @@ -477,8 +522,8 @@

    Payment Cards

    diff --git a/docs/Protocols/VGSDateConfigurationProtocol.html b/docs/Protocols/VGSDateConfigurationProtocol.html new file mode 100644 index 00000000..60e86959 --- /dev/null +++ b/docs/Protocols/VGSDateConfigurationProtocol.html @@ -0,0 +1,500 @@ + + + + VGSDateConfigurationProtocol Protocol Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    VGSDateConfigurationProtocol

    +
    +
    + +
    public protocol VGSDateConfigurationProtocol
    + +
    +
    +

    Define the methods and properties the date configuration must have

    + + +
    +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    + + + diff --git a/docs/Protocols/VGSExpDateConfigurationProtocol.html b/docs/Protocols/VGSExpDateConfigurationProtocol.html index 2236f29f..72e4aeae 100644 --- a/docs/Protocols/VGSExpDateConfigurationProtocol.html +++ b/docs/Protocols/VGSExpDateConfigurationProtocol.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSExpDateConfigurationProtocol

    +
    +
    + +
    public protocol VGSExpDateConfigurationProtocol
    + +
    +

    Attributes required to configure date format and input source for field with type .expDate.

    +
    @@ -387,9 +398,9 @@

    VGSExpDateConfigurationProtocol

  • @@ -400,15 +411,26 @@

    VGSExpDateConfigurationProtocol

    Input Source type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    var inputSource: VGSTextFieldInputSource { get set }
    + +
    +
    +
  • @@ -419,15 +441,26 @@

    VGSExpDateConfigurationProtocol

    Input date format to convert.

    +
    +

    Declaration

    +
    +

    Swift

    +
    var inputDateFormat: VGSCardExpDateFormat? { get set }
    + +
    +
    +
  • @@ -438,6 +471,17 @@

    VGSExpDateConfigurationProtocol

    Output date format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    var outputDateFormat: VGSCardExpDateFormat? { get set }
    + +
    +
    +
  • @@ -449,8 +493,8 @@

    VGSExpDateConfigurationProtocol

    diff --git a/docs/Protocols/VGSFilePickerControllerDelegate.html b/docs/Protocols/VGSFilePickerControllerDelegate.html index 7df7f8ed..4ea61309 100644 --- a/docs/Protocols/VGSFilePickerControllerDelegate.html +++ b/docs/Protocols/VGSFilePickerControllerDelegate.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,19 @@

    VGSFilePickerControllerDelegate

    +
    +
    + +
    @objc
    +public protocol VGSFilePickerControllerDelegate
    + +
    +

    Delegates produced by VGSFilePickerController.

    +
    @@ -396,9 +408,9 @@

    Handle user ineraction.
  • @@ -409,15 +421,26 @@

    Handle user ineraction.

    On user select a file

    +
    +

    Declaration

    +
    +

    Swift

    +
    func userDidPickFileWithInfo(_ info: VGSFileInfo)
    + +
    +
    +
  • @@ -428,15 +451,26 @@

    Handle user ineraction.

    On user canceling file picking

    +
    +

    Declaration

    +
    +

    Swift

    +
    func userDidSCancelFilePicking()
    + +
    +
    +
  • @@ -447,6 +481,17 @@

    Handle user ineraction.

    On error occured when user pick a file.

    +
    +

    Declaration

    +
    +

    Swift

    +
    func filePickingFailedWithError(_ error: VGSError)
    + +
    +
    +
  • @@ -458,8 +503,8 @@

    Handle user ineraction.

    diff --git a/docs/Protocols/VGSTextFieldDelegate.html b/docs/Protocols/VGSTextFieldDelegate.html index 13f26628..51f2a1c2 100644 --- a/docs/Protocols/VGSTextFieldDelegate.html +++ b/docs/Protocols/VGSTextFieldDelegate.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,19 @@

    VGSTextFieldDelegate

    +
    +
    + +
    @objc
    +public protocol VGSTextFieldDelegate
    + +
    +

    Delegates produced by VGSTextField instance.

    +
    @@ -396,9 +408,9 @@

    Handle user ineraction with VGSTextField
  • @@ -409,15 +421,27 @@

    Handle user ineraction with VGSTextField

    VGSTextField did become first responder.

    +
    +

    Declaration

    +
    +

    Swift

    +
    @objc
    +optional func vgsTextFieldDidBeginEditing(_ textField: VGSTextField)
    + +
    +
    +
  • @@ -428,15 +452,27 @@

    Handle user ineraction with VGSTextField

    VGSTextField did resign first responder.

    +
    +

    Declaration

    +
    +

    Swift

    +
    @objc
    +optional func vgsTextFieldDidEndEditing(_ textField: VGSTextField)
    + +
    +
    +
  • @@ -447,15 +483,27 @@

    Handle user ineraction with VGSTextField

    VGSTextField did resign first responder on Return button pressed.

    +
    +

    Declaration

    +
    +

    Swift

    +
    @objc
    +optional func vgsTextFieldDidEndEditingOnReturn(_ textField: VGSTextField)
    + +
    +
    +
  • @@ -466,6 +514,18 @@

    Handle user ineraction with VGSTextField

    VGSTextField input changed.

    +
    +

    Declaration

    +
    +

    Swift

    +
    @objc
    +optional func vgsTextFieldDidChange(_ textField: VGSTextField)
    + +
    +
    +
  • @@ -477,8 +537,8 @@

    Handle user ineraction with VGSTextField

    diff --git a/docs/Protocols/VGSTokenizationParametersProtocol.html b/docs/Protocols/VGSTokenizationParametersProtocol.html index d6bc5746..a1c04ed7 100644 --- a/docs/Protocols/VGSTokenizationParametersProtocol.html +++ b/docs/Protocols/VGSTokenizationParametersProtocol.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSTokenizationParametersProtocol

    +
    +
    + +
    public protocol VGSTokenizationParametersProtocol
    + +
    +

    Parameters describing textfield input tokenization.

    +
    @@ -387,9 +398,9 @@

    VGSTokenizationParametersProtocol

  • - + - format + format
    @@ -400,15 +411,26 @@

    VGSTokenizationParametersProtocol

    Tokenization format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    var format: String { get }
    + +
    +
    +
  • - + - storage + storage
    @@ -419,6 +441,17 @@

    VGSTokenizationParametersProtocol

    Storage type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    var storage: String { get }
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSTokenizationParametersProtocol

    diff --git a/docs/Structs/VGSCVCTokenizationParameters.html b/docs/Structs/VGSCVCTokenizationParameters.html index d527dd7f..1e6f2e5b 100644 --- a/docs/Structs/VGSCVCTokenizationParameters.html +++ b/docs/Structs/VGSCVCTokenizationParameters.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCVCTokenizationParameters

    +
    +
    + +
    public struct VGSCVCTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +

    VGSCVCTokenizationParameters - parameters required for tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSCVCTokenizationParameters

  • - + - storage + storage
    @@ -400,15 +411,26 @@

    VGSCVCTokenizationParameters

    Vault storage type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let storage: String
    + +
    +
    +
  • - + - format + format
    @@ -419,6 +441,17 @@

    VGSCVCTokenizationParameters

    Data alies format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var format: String
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSCVCTokenizationParameters

    diff --git a/docs/Structs/VGSCardHolderNameTokenizationParameters.html b/docs/Structs/VGSCardHolderNameTokenizationParameters.html index 403b021f..8db7af15 100644 --- a/docs/Structs/VGSCardHolderNameTokenizationParameters.html +++ b/docs/Structs/VGSCardHolderNameTokenizationParameters.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCardHolderNameTokenizationParameters

    +
    +
    + +
    public struct VGSCardHolderNameTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +

    VGSCardHolderNameTokenizationParameters - parameters required for tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSCardHolderNameTokenizationParameters

  • - + - storage + storage
    @@ -400,15 +411,26 @@

    VGSCardHolderNameTokenizationParameters

    Vault storage type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var storage: String
    + +
    +
    +
  • - + - format + format
    @@ -419,6 +441,17 @@

    VGSCardHolderNameTokenizationParameters

    Data alies format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var format: String
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSCardHolderNameTokenizationParameters

    diff --git a/docs/Structs/VGSCardNumberTokenizationParameters.html b/docs/Structs/VGSCardNumberTokenizationParameters.html index cff52f20..c34a8669 100644 --- a/docs/Structs/VGSCardNumberTokenizationParameters.html +++ b/docs/Structs/VGSCardNumberTokenizationParameters.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCardNumberTokenizationParameters

    +
    +
    + +
    public struct VGSCardNumberTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +

    VGSCardTokenizationParameters - parameters required for tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSCardNumberTokenizationParameters

  • - + - storage + storage
    @@ -400,15 +411,26 @@

    VGSCardNumberTokenizationParameters

    Vault storage type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let storage: String
    + +
    +
    +
  • - + - format + format
    @@ -419,6 +441,17 @@

    VGSCardNumberTokenizationParameters

    Data alies format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var format: String
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSCardNumberTokenizationParameters

    diff --git a/docs/Structs/VGSCollectLoggingConfiguration.html b/docs/Structs/VGSCollectLoggingConfiguration.html index 050ddaba..04ad1045 100644 --- a/docs/Structs/VGSCollectLoggingConfiguration.html +++ b/docs/Structs/VGSCollectLoggingConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCollectLoggingConfiguration

    +
    +
    + +
    public struct VGSCollectLoggingConfiguration
    + +
    +

    Holds configuration for VGSCollectSDK logging.

    +
    @@ -387,9 +398,9 @@

    VGSCollectLoggingConfiguration

  • - + - level + level
    @@ -400,15 +411,26 @@

    VGSCollectLoggingConfiguration

    Log level. Default is .none.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var level: VGSLogLevel
    + +
    +
    +
  • @@ -419,15 +441,26 @@

    VGSCollectLoggingConfiguration

    Bool flag. Specify true to record VGSCollectSDK network session with success/failed requests. Default is false.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var isNetworkDebugEnabled: Bool
    + +
    +
    +
  • @@ -438,6 +471,17 @@

    VGSCollectLoggingConfiguration

    Bool flag. Specify true to enable extensive debugging. Default is false.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var isExtensiveDebugEnabled: Bool
    + +
    +
    +
  • @@ -449,8 +493,8 @@

    VGSCollectLoggingConfiguration

    diff --git a/docs/Structs/VGSCollectRequestOptions.html b/docs/Structs/VGSCollectRequestOptions.html index 0ed8a197..a08bb8e7 100644 --- a/docs/Structs/VGSCollectRequestOptions.html +++ b/docs/Structs/VGSCollectRequestOptions.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCollectRequestOptions

    +
    +
    + +
    public struct VGSCollectRequestOptions
    + +
    +

    Request options.

    +
    @@ -387,9 +398,9 @@

    VGSCollectRequestOptions

  • @@ -400,15 +411,26 @@

    VGSCollectRequestOptions

    Defines how to map fieldNames to JSON. Default is .nestedJSON.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var fieldNameMappingPolicy: VGSCollectFieldNameMappingPolicy
    + +
    +
    +
  • - + - init() + init()
    @@ -419,6 +441,17 @@

    VGSCollectRequestOptions

    Initializer.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public init()
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSCollectRequestOptions

    diff --git a/docs/Structs/VGSCustomPaymentCardModel.html b/docs/Structs/VGSCustomPaymentCardModel.html index 80934ec8..e4549362 100644 --- a/docs/Structs/VGSCustomPaymentCardModel.html +++ b/docs/Structs/VGSCustomPaymentCardModel.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCustomPaymentCardModel

    +
    +
    + +
    public struct VGSCustomPaymentCardModel : VGSPaymentCardModelProtocol
    + +
    +

    Holds information for custom payment model.

    +
    @@ -387,9 +398,9 @@

    VGSCustomPaymentCardModel

  • - + - brand + brand
    @@ -400,15 +411,26 @@

    VGSCustomPaymentCardModel

    Payment Card Brand

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let brand: VGSPaymentCards.CardBrand
    + +
    +
    +
  • - + - name + name
    @@ -419,15 +441,26 @@

    VGSCustomPaymentCardModel

    Payment Card Name

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var name: String
    + +
    +
    +
  • - + - regex + regex
    @@ -438,15 +471,26 @@

    VGSCustomPaymentCardModel

    Regex Pattern required to detect Payment Card Brand

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var regex: String
    + +
    +
    +
  • @@ -457,15 +501,26 @@

    VGSCustomPaymentCardModel

    Valid Card Number Lengths

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cardNumberLengths: [Int]
    + +
    +
    +
  • @@ -476,15 +531,26 @@

    VGSCustomPaymentCardModel

    Valid Card CVC/CVV Lengths. For most brands valid cvc lengths is [3], while for Amex is [4]. For unknown brands can be set as [3, 4]

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcLengths: [Int]
    + +
    +
    +
  • @@ -492,8 +558,19 @@

    VGSCustomPaymentCardModel

    -

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    +

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public var checkSumAlgorithm: CheckSumAlgorithmType?
    +
    +
    +
    @@ -501,9 +578,9 @@

    VGSCustomPaymentCardModel

  • @@ -519,15 +596,26 @@

    VGSCustomPaymentCardModel

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var formatPattern: String
    + +
    +
    +
  • @@ -538,15 +626,26 @@

    VGSCustomPaymentCardModel

    Image, associated with Payment Card Brand.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var brandIcon: UIImage?
    + +
    +
    +
  • - + - cvcIcon + cvcIcon
    @@ -557,6 +656,17 @@

    VGSCustomPaymentCardModel

    Image, associated with CVC for Payment Card Brand.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcIcon: UIImage?
    + +
    +
    +
  • @@ -564,11 +674,11 @@

    VGSCustomPaymentCardModel

    - - + +
    - -

    Initialzation + +

    Initialization

    @@ -576,9 +686,9 @@

    Initialzation
  • @@ -589,6 +699,108 @@

    Initialzation

    Initializer.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(name: String, regex: String, formatPattern: String, cardNumberLengths: [Int], cvcLengths: [Int] = [3], checkSumAlgorithm: CheckSumAlgorithmType? = .luhn, brandIcon: UIImage?)
    + +
    +
    +
    +

    Parameters

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

    String object, payment card model name.

    +
    +
    + + regex + + +
    +

    String object, should be valid regex expression.

    +
    +
    + + formatPattern + + +
    +

    String object, should be valid format pattern.

    +
    +
    + + cardNumberLengths + + +
    +

    [Int] object, array of valid card number lengths.

    +
    +
    + + cvcLengths + + +
    +

    [Int] object, array of valid card number CVC. Default is [3].

    +
    +
    + + checkSumAlgorithm + + +
    +

    CheckSumAlgorithmType? object, should be valid checkSumAlgorithm object, default is .luhn.

    +
    +
    + + brandIcon + + +
    +

    UIImage?, card image icon.

    +
    +
    +
    +
  • @@ -600,8 +812,8 @@

    Initialzation

    diff --git a/docs/Structs/VGSDate.html b/docs/Structs/VGSDate.html new file mode 100644 index 00000000..df8c2856 --- /dev/null +++ b/docs/Structs/VGSDate.html @@ -0,0 +1,570 @@ + + + + VGSDate Structure Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    VGSDate

    +
    +
    + +
    public struct VGSDate
    +
    extension VGSDate: Comparable
    + +
    +
    +

    Struct that represents a date including year, month and day. It doesn’t include hours, minutes or seconds.

    + + +
    +
    + +
    +
    +
    +
    + + +
    + +

    Properties +

    +
    +
    +
      +
    • +
      + + + + dayFormatted + +
      +
      +
      +
      +
      +
      +

      Get the day formatted value, for example if the day is 1 it is returned as 01

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public var dayFormatted: String { get }
      + +
      +
      + +
      +
      +
    • +
    • +
      + + + + monthFormatted + +
      +
      +
      +
      +
      +
      +

      Get the month formatted value, for example if the month is 3 it is returned as 03

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public var monthFormatted: String { get }
      + +
      +
      + +
      +
      +
    • +
    +
    +
    +
    + + +
    + +

    Initialization +

    +
    +
    +
      +
    • +
      + + + + init(day:month:year:) + +
      +
      +
      +
      +
      +
      +

      Create a new instance of a VGSDate object, if the date is not valid, it returns nil

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init?(day: Int, month: Int, year: Int)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + + + + + +
      + + day + + +
      +

      Int. Represents the day in the date.

      +
      +
      + + month + + +
      +

      Int. Represents the month in the date.

      +
      +
      + + year + + +
      +

      Int. Represents the year in the date.

      +
      +
      +
      +
      +

      Return Value

      +

      VGSDate, date reference or nil if the date is invalid.

      +
      + +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/docs/Structs/VGSDateTokenizationParameters.html b/docs/Structs/VGSDateTokenizationParameters.html new file mode 100644 index 00000000..56d4f728 --- /dev/null +++ b/docs/Structs/VGSDateTokenizationParameters.html @@ -0,0 +1,470 @@ + + + + VGSDateTokenizationParameters Structure Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    VGSDateTokenizationParameters

    +
    +
    + +
    public struct VGSDateTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +
    +

    VGSDateTokenizationParameters - parameters required for tokenization API

    + + +
    +
    + +
    +
    +
    +
      +
    • +
      + + + + storage + +
      +
      +
      +
      +
      +
      +

      Vault storage type.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public var storage: String
      + +
      +
      + +
      +
      +
    • +
    • +
      + + + + format + +
      +
      +
      +
      +
      +
      +

      Data alies format.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public var format: String
      + +
      +
      + +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/docs/Structs/VGSExpDateSeparateSerializer.html b/docs/Structs/VGSExpDateSeparateSerializer.html index a41fad83..ee67b387 100644 --- a/docs/Structs/VGSExpDateSeparateSerializer.html +++ b/docs/Structs/VGSExpDateSeparateSerializer.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSExpDateSeparateSerializer

    +
    +
    + +
    public struct VGSExpDateSeparateSerializer : VGSFormatSerializerProtocol
    + +
    +

    Expiration Date Separate serializer, split date string to components with separate fieldNames

    +
    @@ -387,9 +398,9 @@

    VGSExpDateSeparateSerializer

  • @@ -400,15 +411,26 @@

    VGSExpDateSeparateSerializer

    Field Name that will be used as a JSON key with month value from expDate string on send request.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let monthFieldName: String
    + +
    +
    +
  • @@ -419,6 +441,17 @@

    VGSExpDateSeparateSerializer

    Field Name that will be used as a JSON key with year value from expDate string on send request.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let yearFieldName: String
    + +
    +
    +
  • @@ -438,9 +471,9 @@

    Initialization
  • @@ -451,6 +484,48 @@

    Initialization

    Initialization

    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(monthFieldName: String, yearFieldName: String)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + +
    + + monthFieldName + + +
    +

    key, that should be associated with month value in request JSON.

    +
    +
    + + yearFieldName + + +
    +

    key, that should be associated with year value in request JSON.

    +
    +
    +
    +
  • @@ -462,8 +537,8 @@

    Initialization

    diff --git a/docs/Structs/VGSExpDateTokenizationParameters.html b/docs/Structs/VGSExpDateTokenizationParameters.html index f96b3cb7..672659cb 100644 --- a/docs/Structs/VGSExpDateTokenizationParameters.html +++ b/docs/Structs/VGSExpDateTokenizationParameters.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSExpDateTokenizationParameters

    +
    +
    + +
    public struct VGSExpDateTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +

    VGSExpDateTokenizationParameters - parameters required for tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSExpDateTokenizationParameters

  • - + - storage + storage
    @@ -400,15 +411,26 @@

    VGSExpDateTokenizationParameters

    Vault storage type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let storage: String
    + +
    +
    +
  • - + - format + format
    @@ -419,6 +441,17 @@

    VGSExpDateTokenizationParameters

    Data alies format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var format: String
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSExpDateTokenizationParameters

    diff --git a/docs/Structs/VGSPaymentCardModel.html b/docs/Structs/VGSPaymentCardModel.html index 268dec58..9d1a7551 100644 --- a/docs/Structs/VGSPaymentCardModel.html +++ b/docs/Structs/VGSPaymentCardModel.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSPaymentCardModel

    +
    +
    + +
    public struct VGSPaymentCardModel : VGSPaymentCardModelProtocol
    + +
    +

    An object representing Payment Card

    +
    @@ -387,9 +398,9 @@

    VGSPaymentCardModel

  • - + - brand + brand
    @@ -400,15 +411,26 @@

    VGSPaymentCardModel

    Payment Card Brand

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let brand: VGSPaymentCards.CardBrand
    + +
    +
    +
  • - + - name + name
    @@ -419,15 +441,26 @@

    VGSPaymentCardModel

    Payment Card Name

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var name: String
    + +
    +
    +
  • - + - regex + regex
    @@ -438,15 +471,26 @@

    VGSPaymentCardModel

    Regex Pattern required to detect Payment Card Brand

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var regex: String
    + +
    +
    +
  • @@ -457,15 +501,26 @@

    VGSPaymentCardModel

    Valid Card Number Lengths

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cardNumberLengths: [Int]
    + +
    +
    +
  • @@ -476,15 +531,26 @@

    VGSPaymentCardModel

    Valid Card CVC/CVV Lengths. For most brands valid cvc lengths is [3], while for Amex is [4]. For unknown brands can be set as [3, 4]

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcLengths: [Int]
    + +
    +
    +
  • @@ -492,18 +558,29 @@

    VGSPaymentCardModel

    -

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    +

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var checkSumAlgorithm: CheckSumAlgorithmType?
    + +
    +
    +
  • @@ -519,15 +596,26 @@

    VGSPaymentCardModel

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var formatPattern: String
    + +
    +
    +
  • @@ -538,15 +626,26 @@

    VGSPaymentCardModel

    Image, associated with Payment Card Brand.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var brandIcon: UIImage?
    + +
    +
    +
  • - + - cvcIcon + cvcIcon
    @@ -557,6 +656,17 @@

    VGSPaymentCardModel

    Image, associated with CVC for Payment Card Brand.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcIcon: UIImage?
    + +
    +
    +
  • @@ -568,8 +678,8 @@

    VGSPaymentCardModel

    diff --git a/docs/Structs/VGSSSNTokenizationParameters.html b/docs/Structs/VGSSSNTokenizationParameters.html index cc70b31a..9a6a6b28 100644 --- a/docs/Structs/VGSSSNTokenizationParameters.html +++ b/docs/Structs/VGSSSNTokenizationParameters.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSSSNTokenizationParameters

    +
    +
    + +
    public struct VGSSSNTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +

    VGSSSNTokenizationParameters - parameters required for tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSSSNTokenizationParameters

  • - + - storage + storage
    @@ -400,15 +411,26 @@

    VGSSSNTokenizationParameters

    Vault storage type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let storage: String
    + +
    +
    +
  • - + - format + format
    @@ -419,6 +441,17 @@

    VGSSSNTokenizationParameters

    Data alies format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var format: String
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSSSNTokenizationParameters

    diff --git a/docs/Structs/VGSTextFieldStatePublisher.html b/docs/Structs/VGSTextFieldStatePublisher.html new file mode 100644 index 00000000..3a1fd72d --- /dev/null +++ b/docs/Structs/VGSTextFieldStatePublisher.html @@ -0,0 +1,518 @@ + + + + VGSTextFieldStatePublisher Structure Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    VGSTextFieldStatePublisher

    +
    +
    + +
    @available(iOS 13, *)
    +public struct VGSTextFieldStatePublisher : Publisher
    + +
    +
    +

    A custom publisher that emits State of a given VGSTextField.

    + + +
    +
    + +
    +
    +
    +
      +
    • +
      + + + + Output + +
      +
      +
      +
      +
      +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public typealias Output = State
      + +
      +
      + +
      +
      +
    • +
    • +
      + + + + Failure + +
      +
      +
      +
      +
      +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public typealias Failure = Never
      + +
      +
      + +
      +
      +
    • +
    • +
      + + + + receive(subscriber:) + +
      +
      +
      +
      +
      +
      +

      Attaches a subscriber to the publisher to receive updates on the VGSTextField State.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public func receive<S>(subscriber: S) where S : Subscriber, S.Failure == Never, S.Input == State
      + +
      +
      +
      +

      Parameters

      + + + + + + + +
      + + subscriber + + +
      +

      The subscriber that will receive state updates.

      +
      +
      +
      + +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/docs/Structs/VGSTokenizationParameters.html b/docs/Structs/VGSTokenizationParameters.html index 04f1bdb0..dc3eeb5e 100644 --- a/docs/Structs/VGSTokenizationParameters.html +++ b/docs/Structs/VGSTokenizationParameters.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSTokenizationParameters

    +
    +
    + +
    public struct VGSTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +

    VGSTokenizationParameters - parameters required for tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSTokenizationParameters

  • - + - storage + storage
    @@ -400,15 +411,26 @@

    VGSTokenizationParameters

    Vault storage type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var storage: String
    + +
    +
    +
  • - + - format + format
    @@ -419,6 +441,17 @@

    VGSTokenizationParameters

    Data alies format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var format: String
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSTokenizationParameters

    diff --git a/docs/Structs/VGSUnknownPaymentCardModel.html b/docs/Structs/VGSUnknownPaymentCardModel.html index be2ae0b0..24f1804b 100644 --- a/docs/Structs/VGSUnknownPaymentCardModel.html +++ b/docs/Structs/VGSUnknownPaymentCardModel.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSUnknownPaymentCardModel

    -

    An object representing Unknown Payment Cards - cards not defined in the SDK. Object is used when validation forCardBrand.unknown is set as true. Check VGSValidationRulePaymentCard for more details. Validation attributes can be edited through `VGSPaymentCards.unknown model.

    +
    +
    + +
    public struct VGSUnknownPaymentCardModel
    + +
    +
    +

    An object representing Unknown Payment Cards - cards not defined in the SDK. Object is used when validation forCardBrand.unknown is set as true. Check VGSValidationRulePaymentCard for more details. Validation attributes can be edited through `VGSPaymentCards.unknown model.

    +
    @@ -387,9 +398,9 @@

    VGSUnknownPaymentCardModel

  • - + - regex + regex
    @@ -400,15 +411,26 @@

    VGSUnknownPaymentCardModel

    Regex validating that input contains digits only.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let regex: String
    + +
    +
    +
  • @@ -419,15 +441,26 @@

    VGSUnknownPaymentCardModel

    Valid Unknown Card Numbers Lengths

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cardNumberLengths: [Int]
    + +
    +
    +
  • @@ -438,15 +471,26 @@

    VGSUnknownPaymentCardModel

    Valid Unknown Card CVC/CVV Lengths. For most brands valid cvc lengths is [3], while for Amex is [4]. For unknown brands can be set as [3, 4]

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcLengths: [Int]
    + +
    +
    +
  • @@ -454,18 +498,29 @@

    VGSUnknownPaymentCardModel

    -

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    +

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var checkSumAlgorithm: CheckSumAlgorithmType?
    + +
    +
    +
  • @@ -476,15 +531,26 @@

    VGSUnknownPaymentCardModel

    Unknown Payment Card Numbers visual format pattern. NOTE: format pattern length limits input length.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var formatPattern: String
    + +
    +
    +
  • @@ -495,15 +561,26 @@

    VGSUnknownPaymentCardModel

    Image, associated with Unknown Payment Card Brands.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var brandIcon: UIImage?
    + +
    +
    +
  • - + - cvcIcon + cvcIcon
    @@ -514,6 +591,17 @@

    VGSUnknownPaymentCardModel

    Image, associated with CVC for Unknown Payment Card Brands.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcIcon: UIImage?
    + +
    +
    +
  • @@ -525,8 +613,8 @@

    VGSUnknownPaymentCardModel

    diff --git a/docs/Structs/VGSValidationRuleCardExpirationDate.html b/docs/Structs/VGSValidationRuleCardExpirationDate.html index 2711419a..0fa6b5ed 100644 --- a/docs/Structs/VGSValidationRuleCardExpirationDate.html +++ b/docs/Structs/VGSValidationRuleCardExpirationDate.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSValidationRuleCardExpirationDate

    +
    +
    + +
    public struct VGSValidationRuleCardExpirationDate : VGSValidationRuleProtocol
    + +
    +

    Validate input in scope of matching card expiration date format and time range.

    +
    @@ -387,9 +398,9 @@

    VGSValidationRuleCardExpirationDate

  • @@ -400,15 +411,26 @@

    VGSValidationRuleCardExpirationDate

    Payment Card Expiration Date Format

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let dateFormat: VGSCardExpDateFormat
    + +
    +
    +
  • - + - error + error
    @@ -419,15 +441,26 @@

    VGSValidationRuleCardExpirationDate

    Validation Error

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let error: VGSValidationError
    + +
    +
    +
  • @@ -435,8 +468,50 @@

    VGSValidationRuleCardExpirationDate

    -

    Initialzation

    +

    Initialization

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(dateFormat: VGSCardExpDateFormat = .shortYear, error: VGSValidationError)
    +
    +
    +
    +

    Parameters

    + + + + + + + + + + + +
    + + error + + +
    +

    VGSValidationError - error on failed validation relust.

    +
    +
    + + dateFormat + + +
    +

    CardExpDateFormat date format

    +
    +
    +
    +
    @@ -449,8 +524,8 @@

    VGSValidationRuleCardExpirationDate

  • diff --git a/docs/Structs/VGSValidationRuleDateRange.html b/docs/Structs/VGSValidationRuleDateRange.html new file mode 100644 index 00000000..cb4498c4 --- /dev/null +++ b/docs/Structs/VGSValidationRuleDateRange.html @@ -0,0 +1,581 @@ + + + + VGSValidationRuleDateRange Structure Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    VGSValidationRuleDateRange

    +
    +
    + +
    public struct VGSValidationRuleDateRange : VGSValidationRuleProtocol
    + +
    +
    +

    Validation rule used to validate the date input in objects +like VGSDateTextField, VGSTextField and VGSExpDateTextField

    + + +
    +
    + +
    +
    +
    +
    + + +
    + +

    Properties +

    +
    +
    + +
    +
    +
    + + +
    + +

    Constructor +

    +
    +
    + +
    +
    +
    + +
    +
    + + + diff --git a/docs/Structs/VGSValidationRuleLength.html b/docs/Structs/VGSValidationRuleLength.html index 2543a655..ecf7ccb0 100644 --- a/docs/Structs/VGSValidationRuleLength.html +++ b/docs/Structs/VGSValidationRuleLength.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSValidationRuleLength

    +
    +
    + +
    public struct VGSValidationRuleLength : VGSValidationRuleProtocol
    + +
    +

    Validate input in scope of length.

    +
    @@ -387,9 +398,9 @@

    VGSValidationRuleLength

  • - + - min + min
    @@ -400,15 +411,26 @@

    VGSValidationRuleLength

    Min input length required

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let min: Int
    + +
    +
    +
  • - + - max + max
    @@ -419,15 +441,26 @@

    VGSValidationRuleLength

    Max input length required

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let max: Int
    + +
    +
    +
  • - + - error + error
    @@ -438,15 +471,26 @@

    VGSValidationRuleLength

    Validation Error

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let error: VGSValidationError
    + +
    +
    +
  • @@ -454,8 +498,62 @@

    VGSValidationRuleLength

    -

    Initialzation

    +

    Initialization

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(min: Int = 0, max: Int = Int.max, error: VGSValidationError)
    +
    +
    +
    +

    Parameters

    + + + + + + + + + + + + + + + +
    + + error + + +
    +

    VGSValidationError - error on failed validation relust.

    +
    +
    + + min + + +
    +

    min input length required

    +
    +
    + + max + + +
    +

    max input length required

    +
    +
    +
    +
    @@ -468,8 +566,8 @@

    VGSValidationRuleLength

  • diff --git a/docs/Structs/VGSValidationRuleLengthMatch.html b/docs/Structs/VGSValidationRuleLengthMatch.html index 448a4d75..23dae294 100644 --- a/docs/Structs/VGSValidationRuleLengthMatch.html +++ b/docs/Structs/VGSValidationRuleLengthMatch.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSValidationRuleLengthMatch

    +
    +
    + +
    public struct VGSValidationRuleLengthMatch : VGSValidationRuleProtocol
    + +
    +

    Validate input in scope of multiple lengths, e.x.: [16, 19].

    +
    @@ -387,9 +398,9 @@

    VGSValidationRuleLengthMatch

  • - + - lengths + lengths
    @@ -400,15 +411,26 @@

    VGSValidationRuleLengthMatch

    Array of valid length ranges

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let lengths: [Int]
    + +
    +
    +
  • - + - error + error
    @@ -419,15 +441,26 @@

    VGSValidationRuleLengthMatch

    Validation Error

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let error: VGSValidationError
    + +
    +
    +
  • @@ -435,8 +468,50 @@

    VGSValidationRuleLengthMatch

    -

    Initialzation

    +

    Initialization

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(lengths: [Int], error: VGSValidationError)
    +
    +
    +
    +

    Parameters

    + + + + + + + + + + + +
    + + error + + +
    +

    VGSValidationError - error on failed validation relust.

    +
    +
    + + lengths + + +
    +

    array of valid lengths

    +
    +
    +
    +
    @@ -449,8 +524,8 @@

    VGSValidationRuleLengthMatch

  • diff --git a/docs/Structs/VGSValidationRuleLuhnCheck.html b/docs/Structs/VGSValidationRuleLuhnCheck.html index 52a5a0f7..8b17ac3b 100644 --- a/docs/Structs/VGSValidationRuleLuhnCheck.html +++ b/docs/Structs/VGSValidationRuleLuhnCheck.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSValidationRuleLuhnCheck

    +
    +
    + +
    public struct VGSValidationRuleLuhnCheck : VGSValidationRuleProtocol
    + +
    +

    Validate input in scope of matching Luhn algorithm.

    +
    @@ -387,9 +398,9 @@

    VGSValidationRuleLuhnCheck

  • - + - error + error
    @@ -400,15 +411,26 @@

    VGSValidationRuleLuhnCheck

    Validation Error

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var error: VGSValidationError
    + +
    +
    +
  • @@ -416,8 +438,38 @@

    VGSValidationRuleLuhnCheck

    -

    Initialzation

    +

    Initialization

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(error: VGSValidationError)
    +
    +
    +
    +

    Parameters

    + + + + + + + +
    + + error + + +
    +

    VGSValidationError - error on failed validation relust.

    +
    +
    +
    +
    @@ -430,8 +482,8 @@

    VGSValidationRuleLuhnCheck

  • diff --git a/docs/Structs/VGSValidationRulePattern.html b/docs/Structs/VGSValidationRulePattern.html index 33ce9586..b5375946 100644 --- a/docs/Structs/VGSValidationRulePattern.html +++ b/docs/Structs/VGSValidationRulePattern.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSValidationRulePattern

    +
    +
    + +
    public struct VGSValidationRulePattern : VGSValidationRuleProtocol
    + +
    +

    Validate input in scope of matching the pattern(regex).

    +
    @@ -387,9 +398,9 @@

    VGSValidationRulePattern

  • - + - pattern + pattern
    @@ -400,15 +411,26 @@

    VGSValidationRulePattern

    Regex pattern

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let pattern: String
    + +
    +
    +
  • - + - error + error
    @@ -419,15 +441,26 @@

    VGSValidationRulePattern

    Validation Error

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let error: VGSValidationError
    + +
    +
    +
  • @@ -435,8 +468,50 @@

    VGSValidationRulePattern

    -

    Initialzation

    +

    Initialization

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(pattern: String, error: VGSValidationError)
    +
    +
    +
    +

    Parameters

    + + + + + + + + + + + +
    + + error + + +
    +

    VGSValidationError - error on failed validation relust.

    +
    +
    + + pattern + + +
    +

    regex pattern

    +
    +
    +
    +
    @@ -449,8 +524,8 @@

    VGSValidationRulePattern

  • diff --git a/docs/Structs/VGSValidationRulePaymentCard.html b/docs/Structs/VGSValidationRulePaymentCard.html index 4a6fe0d7..76caa9d0 100644 --- a/docs/Structs/VGSValidationRulePaymentCard.html +++ b/docs/Structs/VGSValidationRulePaymentCard.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,10 +376,20 @@

    VGSValidationRulePaymentCard

    +
    +
    + +
    public struct VGSValidationRulePaymentCard : VGSValidationRuleProtocol
    + +
    +

    Validate input in scope of matching supported card brands, available lengths and checkSum algorithms. Supports optional validation of cards that are not defined in SDK - CardBrand.unknown. -To edit validation requirments for CardBrand.unknown cards in SDK, setup VGSPaymentCards.unknown model attributes.

    +To edit validation requirments for CardBrand.unknown cards in SDK, setup VGSPaymentCards.unknown model attributes.

    +
    @@ -389,9 +400,9 @@

    VGSValidationRulePaymentCard

  • - + - error + error
    @@ -402,15 +413,26 @@

    VGSValidationRulePaymentCard

    Validation Error

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var error: VGSValidationError
    + +
    +
    +
  • @@ -421,15 +443,26 @@

    VGSValidationRulePaymentCard

    Turn on/off validation of cards that are not defined in SDK - CardBrand.unknown

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var validateUnknownCardBrand: Bool
    + +
    +
    +
  • @@ -437,18 +470,48 @@

    VGSValidationRulePaymentCard

    -

    Initialzation

    +

    Initialization

    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(error: VGSValidationError)
    + +
    +
    +
    +

    Parameters

    + + + + + + + +
    + + error + + +
    +

    VGSValidationError - error on failed validation relust.

    +
    +
    +
    +
  • @@ -456,8 +519,50 @@

    VGSValidationRulePaymentCard

    -

    Initialzation

    +

    Initialization

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(error: VGSValidationError, validateUnknownCardBrand: Bool)
    +
    +
    +
    +

    Parameters

    + + + + + + + + + + + +
    + + error + + +
    +

    VGSValidationError - error on failed validation relust.

    +
    +
    + + validateUnknownCardBrand + + +
    +

    flag that turn on/off validation CardBrand.unknowncards.

    +
    +
    +
    +
    @@ -470,8 +575,8 @@

    VGSValidationRulePaymentCard

  • diff --git a/docs/Structs/VGSValidationRuleSet.html b/docs/Structs/VGSValidationRuleSet.html index 0b69059c..ca4adc58 100644 --- a/docs/Structs/VGSValidationRuleSet.html +++ b/docs/Structs/VGSValidationRuleSet.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSValidationRuleSet

    +
    +
    + +
    public struct VGSValidationRuleSet
    + +
    +

    Set of validation rules

    +
    @@ -387,9 +398,9 @@

    VGSValidationRuleSet

  • - + - init() + init()
    @@ -397,18 +408,29 @@

    VGSValidationRuleSet

    -

    Initialzation

    +

    Initialization

    +
    +

    Declaration

    +
    +

    Swift

    +
    public init()
    + +
    +
    +
  • @@ -416,8 +438,38 @@

    VGSValidationRuleSet

    -

    Initialzation

    +

    Initialization

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(rules: [VGSValidationRuleProtocol])
    +
    +
    +
    +

    Parameters

    + + + + + + + +
    + + rules + + +
    +

    array of validation rules

    +
    +
    +
    +
    @@ -425,9 +477,9 @@

    VGSValidationRuleSet

  • @@ -438,6 +490,17 @@

    VGSValidationRuleSet

    Add validation rule

    +
    +

    Declaration

    +
    +

    Swift

    +
    public mutating func add(rule: VGSValidationRuleProtocol)
    + +
    +
    +
  • @@ -449,8 +512,8 @@

    VGSValidationRuleSet

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Structs.html b/docs/Tokenization Parameters.html similarity index 56% rename from docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Structs.html rename to docs/Tokenization Parameters.html index 040a677b..686a5149 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Structs.html +++ b/docs/Tokenization Parameters.html @@ -1,7 +1,7 @@ - Other Structures Reference + Tokenization Parameters Reference @@ -14,9 +14,9 @@ - + - +

    @@ -44,7 +44,7 @@

    @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    -

    Other Structures

    -

    The following structures are available globally.

    - +

    Tokenization Parameters

    +
    @@ -387,9 +387,40 @@

    Other Structures

  • +
    +
    +
    +
    +
    +

    Parameters describing textfield input tokenization.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public protocol VGSTokenizationParametersProtocol
    + +
    +
    + +
    +
    +
  • +
  • +
    @@ -401,15 +432,26 @@

    Other Structures

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSCVCTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +
    +
  • @@ -421,15 +463,26 @@

    Other Structures

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSCardHolderNameTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +
    +
  • @@ -441,15 +494,57 @@

    Other Structures

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSCardNumberTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +
    +
  • +
    +
    +
    +
    +
    +

    VGSDateTokenizationParameters - parameters required for tokenization API

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSDateTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +
    + +
    +
    +
  • +
  • +
    @@ -461,15 +556,26 @@

    Other Structures

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSExpDateTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +
    +
  • @@ -481,15 +587,26 @@

    Other Structures

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSSSNTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +
    +
  • @@ -501,6 +618,79 @@

    Other Structures

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +
    + + + +
  • +
  • +
    + + + + VGSVaultAliasFormat + +
    +
    +
    +
    +
    +
    +

    Type of Alias format. Read more about avaliable formats: https://www.verygoodsecurity.com/docs/terminology/nomenclature#alias-formats .

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSVaultAliasFormat : String
    + +
    +
    + +
    +
    +
  • +
  • +
    + + + + VGSVaultStorageType + +
    +
    +
    +
    +
    +
    +

    Type of VGS Vault storage.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSVaultStorageType : String
    + +
    +
    +
  • @@ -512,8 +702,8 @@

    Other Structures

    diff --git a/docs/UI Elements.html b/docs/UI Elements.html index fc834e34..5c57cebe 100644 --- a/docs/UI Elements.html +++ b/docs/UI Elements.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -386,9 +387,9 @@

    UI Elements

  • @@ -404,18 +405,23 @@

    UI Elements

    Declaration

    Swift

    - +
    public class VGSTextField : UIView
    +
    extension VGSTextField: UITextFieldDelegate
    +
    +
  • @@ -427,15 +433,26 @@

    Declaration

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public final class VGSCardTextField : VGSTextField
    + +
    +
    +
  • @@ -451,18 +468,55 @@

    Declaration

    Declaration

    Swift

    - +
    public final class VGSExpDateTextField : VGSTextField
    +
    extension VGSExpDateTextField: UIPickerViewDelegate, UIPickerViewDataSource
    + +
    +
    + + + +
  • +
  • +
    + + + + VGSDateTextField + +
    +
    +
    +
    +
    +
    +

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to show picker view with a Date. It support to define a range of valid dates to select from.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public final class VGSDateTextField : VGSTextField
    +
    extension VGSDateTextField: UIPickerViewDelegate, UIPickerViewDataSource
    +
    +
  • @@ -474,15 +528,26 @@

    Declaration

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public final class VGSCVCTextField : VGSTextField
    + +
    +
    +
  • @@ -494,15 +559,27 @@

    Declaration

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    @objc
    +public protocol VGSTextFieldDelegate
    + +
    +
    +
  • @@ -514,15 +591,26 @@

    Declaration

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSConfiguration : VGSTextFieldConfigurationProtocol
    + +
    +
    +
  • @@ -534,15 +622,26 @@

    Declaration

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public final class VGSExpDateConfiguration : VGSConfiguration, VGSExpDateConfigurationProtocol, VGSFormatSerializableProtocol
    + +
    +
    +
  • @@ -550,9 +649,425 @@

    Declaration

    -

    Type of VGSTextField configuration.

    +

    Class responsible for configuration VGSDateTextField or VGSTextField with fieldType = .date. Extends VGSConfiguration

    - See more + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public final class VGSDateConfiguration : VGSConfiguration, VGSDateConfigurationProtocol, VGSFormatSerializableProtocol
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    VGSCardHolderNameTokenizationConfiguration - textfield configuration for textfield with type .cardHolderName, required for work with tokenization api.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSCardHolderNameTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    VGSCardTokenizationConfiguration - textfield configuration for textfield with type .cardNumber, required for work with tokenization api.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSCardNumberTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    VGSCVCTokenizationConfiguration - textfield configuration for textfield with type .cvc, required for work with tokenization api.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSCVCTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    Class responsible for configuration VGSDateTextField or VGSTextField with fieldType = .date. +Extends VGSConfiguration. Required to work with tokenization API.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public final class VGSDateTokenizationConfiguration : VGSConfiguration, VGSDateConfigurationProtocol, VGSTextFieldTokenizationConfigurationProtocol, VGSFormatSerializableProtocol
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    VGSExpDateTokenizationConfiguration - textfield configuration for textfield with type .expDate, required for work with tokenization api.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public final class VGSExpDateTokenizationConfiguration : VGSConfiguration, VGSExpDateConfigurationProtocol, VGSTextFieldTokenizationConfigurationProtocol, VGSFormatSerializableProtocol
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    VGSSSNTokenizationConfiguration - textfield configuration for textfield with type .ssn, required for work with tokenization api.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSSSNTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    VGSTokenizationConfiguration - textfield configuration for textfield with any type of data, required for work with tokenization api.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    Define the methods and properties the date configuration must have

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public protocol VGSDateConfigurationProtocol
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    Attributes required to configure date format and input source for field with type .expDate.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public protocol VGSExpDateConfigurationProtocol
    + +
    +
    + +
    +
    +
  • +
  • +
    + + + + FieldType + +
    +
    +
    +
    +
    +
    +

    Type of VGSTextField configuration.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum FieldType : Int, CaseIterable
    + +
    +
    + +
    +
    +
  • +
  • +
    + + + + VGSDateFormat + +
    +
    +
    +
    +
    +
    +

    Format used to validate a VGS date text input

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSDateFormat : InputConvertableFormat, OutputConvertableFormat
    + +
    +
    + +
    +
    +
  • +
  • +
    + + + + VGSDate + +
    +
    +
    +
    +
    +
    +

    Struct that represents a date including year, month and day. It doesn’t include hours, minutes or seconds.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSDate
    +
    extension VGSDate: Comparable
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    Type of VGSTextField input source.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSTextFieldInputSource
    + +
    +
    +
    @@ -565,8 +1080,8 @@

    Declaration

  • diff --git a/docs/VGSTextField Serializers.html b/docs/VGSTextField Serializers.html index 522748b2..2f191f73 100644 --- a/docs/VGSTextField Serializers.html +++ b/docs/VGSTextField Serializers.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -386,9 +387,9 @@

    VGSTextField Serializers

  • @@ -399,15 +400,26 @@

    VGSTextField Serializers

    Base protocol describing Content Serialization attributes

    +
    +

    Declaration

    +
    +

    Swift

    +
    public protocol VGSFormatSerializerProtocol
    + +
    +
    +
  • @@ -419,6 +431,17 @@

    VGSTextField Serializers

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSExpDateSeparateSerializer : VGSFormatSerializerProtocol
    + +
    +
    +
  • @@ -430,8 +453,8 @@

    VGSTextField Serializers

    diff --git a/docs/Validation Rules.html b/docs/Validation Rules.html index f10e4e69..79a6c768 100644 --- a/docs/Validation Rules.html +++ b/docs/Validation Rules.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -386,9 +387,9 @@

    Validation Rules

  • @@ -400,15 +401,26 @@

    Validation Rules

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSValidationRuleSet
    + +
    +
    +
  • @@ -420,15 +432,26 @@

    Validation Rules

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSValidationRuleLength : VGSValidationRuleProtocol
    + +
    +
    +
  • @@ -440,15 +463,26 @@

    Validation Rules

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSValidationRuleLengthMatch : VGSValidationRuleProtocol
    + +
    +
    +
  • @@ -460,15 +494,26 @@

    Validation Rules

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSValidationRulePattern : VGSValidationRuleProtocol
    + +
    +
    +
  • @@ -478,19 +523,30 @@

    Validation Rules

    Validate input in scope of matching supported card brands, available lengths and checkSum algorithms. Supports optional validation of cards that are not defined in SDK - CardBrand.unknown. -To edit validation requirments for CardBrand.unknown cards in SDK, setup VGSPaymentCards.unknown model attributes.

    +To edit validation requirments for CardBrand.unknown cards in SDK, setup VGSPaymentCards.unknown model attributes.

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSValidationRulePaymentCard : VGSValidationRuleProtocol
    + +
    +
    +
  • @@ -502,15 +558,26 @@

    Validation Rules

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSValidationRuleLuhnCheck : VGSValidationRuleProtocol
    + +
    +
    +
  • @@ -522,15 +589,58 @@

    Validation Rules

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSValidationRuleCardExpirationDate : VGSValidationRuleProtocol
    + +
    +
    +
  • +
    +
    +
    +
    +
    +

    Validation rule used to validate the date input in objects +like VGSDateTextField, VGSTextField and VGSExpDateTextField

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSValidationRuleDateRange : VGSValidationRuleProtocol
    + +
    +
    + +
    +
    +
  • +
  • +
    @@ -542,6 +652,17 @@

    Validation Rules

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum CheckSumAlgorithmType
    + +
    +
    +
  • @@ -553,8 +674,8 @@

    Validation Rules

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/CardState.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/CardState.html index 5fc52267..7f3f558c 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/CardState.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/CardState.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    CardState

    -

    An object that describes VGSTextField state with configuration FieldType.cardNumber . State attributes are read-only.

    +
    +
    + +
    public class CardState : State
    +
    +
    +

    An object that describes VGSTextField state with configuration FieldType.cardNumber . State attributes are read-only.

    + +
    @@ -387,9 +398,9 @@

    CardState

  • - + - last4 + last4
    @@ -397,8 +408,19 @@

    CardState

    -

    Last 4 digits of the valid card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    +

    Last 4 digits of the valid card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var last4: String { get }
    +
    +
    +
    @@ -406,9 +428,9 @@

    CardState

  • - + - bin + bin
    @@ -416,8 +438,19 @@

    CardState

    -

    Bin digits of the valid card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    +

    Bin digits of the valid card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var bin: String { get }
    +
    +
    +
    @@ -425,9 +458,9 @@

    CardState

  • @@ -435,18 +468,29 @@

    CardState

    -

    Credit Card Brand of the card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    +

    Credit Card Brand of the card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var cardBrand: VGSPaymentCards.CardBrand { get }
    + +
    +
    +
  • @@ -457,6 +501,17 @@

    CardState

    Message that contains CardState attributes and their values.

    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var description: String { get }
    + +
    +
    +
  • @@ -468,8 +523,8 @@

    CardState

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/SSNState.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/SSNState.html index eca160e6..8f695bee 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/SSNState.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/SSNState.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    SSNState

    -

    An object that describes VGSTextField state with configuration FieldType.ssn . State attributes are read-only.

    +
    +
    + +
    public class SSNState : State
    +
    +
    +

    An object that describes VGSTextField state with configuration FieldType.ssn . State attributes are read-only.

    + +
    @@ -387,9 +398,9 @@

    SSNState

  • - + - last4 + last4
    @@ -397,8 +408,19 @@

    SSNState

    -

    Last 4 digits of the valid ssn from associated VGSTextField with field configuration type FieldType.ssn.

    +

    Last 4 digits of the valid ssn from associated VGSTextField with field configuration type FieldType.ssn.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var last4: String { get }
    +
    +
    +
    @@ -406,9 +428,9 @@

    SSNState

  • @@ -419,6 +441,17 @@

    SSNState

    Message that contains SSNState attributes and their values.

    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var description: String { get }
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    SSNState

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/State.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/State.html index 4aab1a7d..b4761360 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/State.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/State.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    State

    +
    +
    + +
    public class State
    + +
    +

    An object that describes VGSTextField state. State attributes are read-only.

    +
    @@ -387,9 +398,9 @@

    State

  • @@ -397,18 +408,29 @@

    State

    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var fieldName: String! { get }
    + +
    +
    +
  • @@ -416,18 +438,29 @@

    State

    -

    VGSConfiguration.isRequired attribute defined for VGSTextField

    +

    VGSConfiguration.isRequired attribute defined for VGSTextField

    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var isRequired: Bool { get }
    + +
    +
    +
  • @@ -435,18 +468,29 @@

    State

    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var isRequiredValidOnly: Bool { get }
    + +
    +
    +
  • - + - isValid + isValid
    @@ -457,15 +501,26 @@

    State

    Contains current validation state for VGSTextField

    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var isValid: Bool { get }
    + +
    +
    +
  • - + - isEmpty + isEmpty
    @@ -476,15 +531,26 @@

    State

    Show if VGSTextField input is empty

    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var isEmpty: Bool { get }
    + +
    +
    +
  • - + - isDirty + isDirty
    @@ -495,15 +561,26 @@

    State

    Show if VGSTextField was edited

    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var isDirty: Bool { get }
    + +
    +
    +
  • @@ -514,15 +591,26 @@

    State

    Input data length in VGSTextField

    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var inputLength: Int { get }
    + +
    +
    +
  • @@ -530,18 +618,29 @@

    State

    -

    Array of VGSValidationError. Should be empty when textfield input is valid.

    +

    Array of VGSValidationError. Should be empty when textfield input is valid.

    +
    +

    Declaration

    +
    +

    Swift

    +
    internal(set) open var validationErrors: [VGSValidationError] { get }
    + +
    +
    +
  • @@ -552,6 +651,17 @@

    State

    Message that contains State attributes and their values

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var description: String { get }
    + +
    +
    +
  • @@ -563,8 +673,8 @@

    State

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCVCTextField.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCVCTextField.html index e71240ce..be69d3bf 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCVCTextField.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCVCTextField.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCVCTextField

    +
    +
    + +
    public final class VGSCVCTextField : VGSTextField
    + +
    +

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to show CVC/CVV images for credit card brands.

    +
    @@ -396,9 +407,9 @@

    Enum cases
  • @@ -410,6 +421,17 @@

    Enum cases See more

    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum CVCIconLocation
    + +
    +
    +
  • @@ -429,9 +451,9 @@

    Attributes
  • @@ -442,15 +464,26 @@

    Attributes

    CVC icon position inside VGSCardTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcIconLocation: VGSCVCTextField.CVCIconLocation { get set }
    + +
    +
    +
  • @@ -461,6 +494,17 @@

    Attributes

    CVC icon size.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcIconSize: CGSize { get set }
    + +
    +
    +
  • @@ -480,9 +524,9 @@

    Custom CVC images for specific card brands
  • @@ -493,6 +537,17 @@

    Custom CVC images for specific card brands

    Asks custom image for specific VGSPaymentCards.CardBrand

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcIconSource: ((VGSPaymentCards.CardBrand) -> UIImage?)?
    + +
    +
    +
  • @@ -504,8 +559,8 @@

    Custom CVC images for specific card brands

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCVCTextField/CVCIconLocation.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCVCTextField/CVCIconLocation.html index f5526019..f7357ce7 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCVCTextField/CVCIconLocation.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCVCTextField/CVCIconLocation.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    CVCIconLocation

    +
    +
    + +
    public enum CVCIconLocation
    + +
    +

    Available CVC icon positions enum.

    +
    @@ -387,9 +398,9 @@

    CVCIconLocation

  • - + - left + left
    @@ -400,15 +411,26 @@

    CVCIconLocation

    CVC icon at left side of VGSCardTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case left
    + +
    +
    +
  • - + - right + right
    @@ -419,6 +441,17 @@

    CVCIconLocation

    CVC icon at right side of VGSCardTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case right
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    CVCIconLocation

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCVCTokenizationConfiguration.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCVCTokenizationConfiguration.html index 7987fc27..448faf60 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCVCTokenizationConfiguration.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCVCTokenizationConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCVCTokenizationConfiguration

    +
    +
    + +
    public class VGSCVCTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +

    VGSCVCTokenizationConfiguration - textfield configuration for textfield with type .cvc, required for work with tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSCVCTokenizationConfiguration

  • @@ -400,15 +411,26 @@

    VGSCVCTokenizationConfiguration

    VGSCVCTokenizationParameters - tokenization configuration parameters.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var tokenizationParameters: VGSCVCTokenizationParameters
    + +
    +
    +
  • - + - type + type
    @@ -416,9 +438,20 @@

    VGSCVCTokenizationConfiguration

    -

    FieldType.cvc type of VGSTextFieldtokenization configuration.

    +

    FieldType.cvc type of VGSTextFieldtokenization configuration.

    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var type: FieldType { get set }
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSCVCTokenizationConfiguration

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCardHolderNameTokenizationConfiguration.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCardHolderNameTokenizationConfiguration.html index fdc946af..a6eac2ba 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCardHolderNameTokenizationConfiguration.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCardHolderNameTokenizationConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCardHolderNameTokenizationConfiguration

    +
    +
    + +
    public class VGSCardHolderNameTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +

    VGSCardHolderNameTokenizationConfiguration - textfield configuration for textfield with type .cardHolderName, required for work with tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSCardHolderNameTokenizationConfiguration

  • @@ -400,15 +411,26 @@

    VGSCardHolderNameTokenizationConfiguration

    VGSCardHolderNameTokenizationParameters - tokenization configuration parameters.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var tokenizationParameters: VGSCardHolderNameTokenizationParameters
    + +
    +
    +
  • - + - type + type
    @@ -416,9 +438,20 @@

    VGSCardHolderNameTokenizationConfiguration

    -

    FieldType.cardHolderName type of VGSTextFieldtokenization configuration.

    +

    FieldType.cardHolderName type of VGSTextFieldtokenization configuration.

    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var type: FieldType { get set }
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSCardHolderNameTokenizationConfiguration

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCardNumberTokenizationConfiguration.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCardNumberTokenizationConfiguration.html index 28bca781..f35f52d1 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCardNumberTokenizationConfiguration.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCardNumberTokenizationConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCardNumberTokenizationConfiguration

    +
    +
    + +
    public class VGSCardNumberTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +

    VGSCardTokenizationConfiguration - textfield configuration for textfield with type .cardNumber, required for work with tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSCardNumberTokenizationConfiguration

  • @@ -400,15 +411,26 @@

    VGSCardNumberTokenizationConfiguration

    VGSCardTokenizationParameters - tokenization configuration parameters.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var tokenizationParameters: VGSCardNumberTokenizationParameters
    + +
    +
    +
  • - + - type + type
    @@ -416,9 +438,20 @@

    VGSCardNumberTokenizationConfiguration

    -

    FieldType.cardNumber type of VGSTextFieldtokenization configuration.

    +

    FieldType.cardNumber type of VGSTextFieldtokenization configuration.

    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var type: FieldType { get set }
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSCardNumberTokenizationConfiguration

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCardTextField.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCardTextField.html index cd28a1ad..ac1e17ce 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCardTextField.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCardTextField.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCardTextField

    +
    +
    + +
    public final class VGSCardTextField : VGSTextField
    + +
    +

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to detect and show credit card brand images.

    +
    @@ -396,9 +407,9 @@

    Enum cases
  • @@ -410,6 +421,17 @@

    Enum cases See more

    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum CardIconLocation
    + +
    +
    +
  • @@ -429,9 +451,9 @@

    Attributes
  • @@ -442,15 +464,26 @@

    Attributes

    Card brand icon position inside VGSCardTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cardIconLocation: VGSCardTextField.CardIconLocation { get set }
    + +
    +
    +
  • @@ -461,6 +494,17 @@

    Attributes

    Card brand icon size.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cardIconSize: CGSize { get set }
    + +
    +
    +
  • @@ -480,9 +524,9 @@

    Custom card brand images
  • @@ -493,6 +537,17 @@

    Custom card brand images

    Asks custom image for specific VGSPaymentCards.CardBrand

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cardsIconSource: ((VGSPaymentCards.CardBrand) -> UIImage?)?
    + +
    +
    +
  • @@ -504,8 +559,8 @@

    Custom card brand images

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCardTextField/CardIconLocation.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCardTextField/CardIconLocation.html index 49cd901c..3a7ca7be 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCardTextField/CardIconLocation.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCardTextField/CardIconLocation.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    CardIconLocation

    +
    +
    + +
    public enum CardIconLocation
    + +
    +

    Available Card brand icon positions enum.

    +
    @@ -387,9 +398,9 @@

    CardIconLocation

  • - + - left + left
    @@ -400,15 +411,26 @@

    CardIconLocation

    Card brand icon at left side of VGSCardTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case left
    + +
    +
    +
  • - + - right + right
    @@ -419,6 +441,17 @@

    CardIconLocation

    Card brand icon at right side of VGSCardTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case right
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    CardIconLocation

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCollect.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCollect.html index de2a9f13..81178585 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCollect.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCollect.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCollect

    +
    +
    + +
    public class VGSCollect
    + +
    +

    An object you use for observing VGSTextField State and send data to your organization vault.

    +
    @@ -396,9 +407,9 @@

    Custom HTTP Headers
  • @@ -409,6 +420,17 @@

    Custom HTTP Headers

    Set your custom HTTP headers.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var customHeaders: [String : String]? { get set }
    + +
    +
    +
  • @@ -428,9 +450,9 @@

    Observe VGSTextField states
  • @@ -441,15 +463,26 @@

    Observe VGSTextField states

    Observe only focused VGSTextField on editing events.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var observeFieldState: ((_ textField: VGSTextField) -> Void)?
    + +
    +
    +
  • @@ -460,6 +493,17 @@

    Observe VGSTextField states

    Observe all VGSTextField on editing events.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var observeStates: ((_ form: [VGSTextField]) -> Void)?
    + +
    +
    +
  • @@ -479,9 +523,9 @@

    Get Registered VGSTextFields
  • @@ -492,6 +536,17 @@

    Get Registered VGSTextFields

    Returns array of VGSTextFields associated with VGSCollect instance.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var textFields: [VGSTextField] { get }
    + +
    +
    +
  • @@ -499,11 +554,11 @@

    Get Registered VGSTextFields
    - - + +
    - -

    Initialzation + +

    Initialization

    @@ -511,9 +566,9 @@

    Initialzation
  • @@ -521,8 +576,74 @@

    Initialzation
    -

    Initialzation.

    +

    Initialization.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(id: String, environment: String, hostname: String? = nil, satellitePort: Int? = nil)
    +
    +
    +
    +

    Parameters

    + + + + + + + + + + + + + + + + + + + +
    + + id + + +
    +

    String object, your organization vault id.

    +
    +
    + + environment + + +
    +

    String object, your organization vault environment with data region.(e.g. “live”, “live-eu1”, “sandbox”).

    +
    +
    + + hostname + + +
    +

    String? object, custom Hostname, if not set, data will be sent to Vault Url. Default is nil.

    +
    +
    + + satellitePort + + +
    +

    Int? object, custom port for satellite configuration. Default is nil. IMPORTANT! Use only with .sandbox environment! Hostname should be specified for valid http://localhost or in local IP format http://192.168.X.X.

    +
    +
    +
    +

    @@ -530,9 +651,9 @@

    Initialzation
  • @@ -540,9 +661,87 @@

    Initialzation
    -

    Initialzation.

    +

    Initialization.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public convenience init(id: String, environment: Environment = .sandbox, dataRegion: String? = nil, hostname: String? = nil, satellitePort: Int? = nil)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + + + + + + + + + + + + + +
    + + id + + +
    +

    String object, your organization vault id.

    +
    +
    + + environment + + +
    +

    Environment object, your organization vault environment. By default Environment.sandbox.

    +
    +
    + + dataRegion + + +
    +

    String object, id of data storage region (e.g. “eu-123”).

    +
    +
    + + hostname + + +
    +

    String object, custom Hostname, if not set, data will be sent to Vault Url. Default is nil.

    +
    +
    + + satellitePort + + +
    +

    Int? object, custom port for satellite configuration. Default is nil. IMPORTANT! Use only with .sandbox environment! Hostname should be specified for valid http://localhost or in local IP format http://192.168.X.X.

    +
    +
    +
    +

  • @@ -562,9 +761,9 @@

    Manage VGSTextFields
  • @@ -572,18 +771,29 @@

    Manage VGSTextFields
    -

    Returns VGSTextField with VGSConfiguration.fieldName associated with VGCollect instance.

    +

    Returns VGSTextField with VGSConfiguration.fieldName associated with VGCollect instance.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func getTextField(fieldName: String) -> VGSTextField?
    + +
    +
    +

  • @@ -594,15 +804,45 @@

    Manage VGSTextFields

    Unasubscribe VGSTextField from VGSCollect instance.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func unsubscribeTextField(_ textField: VGSTextField)
    + +
    +
    +
    +

    Parameters

    + + + + + + + +
    + + textField + + +
    +

    VGSTextField that should be unsubscribed.

    +
    +
    +
    +
  • @@ -613,15 +853,45 @@

    Manage VGSTextFields

    Unasubscribe VGSTextFields from VGSCollect instance.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func unsubscribeTextFields(_ textFields: [VGSTextField])
    + +
    +
    +
    +

    Parameters

    + + + + + + + +
    + + textFields + + +
    +

    an array of VGSTextFields that should be unsubscribed.

    +
    +
    +
    +
  • @@ -632,6 +902,17 @@

    Manage VGSTextFields

    Unasubscribe all VGSTextFields from VGSCollect instance.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func unsubscribeAllTextFields()
    + +
    +
    +
  • @@ -651,9 +932,9 @@

    Manage Files
  • @@ -664,6 +945,17 @@

    Manage Files

    Detach files for associated VGSCollect instance.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func cleanFiles()
    + +
    +
    +
  • @@ -683,9 +975,9 @@

    Send data
  • @@ -696,20 +988,110 @@

    Send data

    Send data from VGSTextFields to your organization vault.

    Note

    -

    Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain.

    +

    Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func sendData(path: String, method: VGSCollectHTTPMethod = .post, routeId: String? = nil, extraData: [String : Any]? = nil, requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions(), completion block: @escaping (VGSResponse) -> Void)
    + +
    +
    +
    +

    Parameters

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

    Inbound rout path for your organization vault.

    +
    +
    + + method + + +
    +

    VGSCollectHTTPMethod, default is .post.

    +
    +
    + + routeId + + +
    +

    id of VGS Proxy Route, default is nil.

    +
    +
    + + extraData + + +
    +

    Any data you want to send together with data from VGSTextFields , default is nil.

    +
    +
    + + requestOptions + + +
    +

    VGSCollectRequestOptions object, holds additional request options. Default options are .nestedJSON.

    +
    +
    + + completion + + +
    +

    response completion block, returns VGSResponse.

    +
    +
    +
    +
  • @@ -720,20 +1102,579 @@

    Send data

    Send file to your organization vault. Only send one file at a time.

    Note

    -

    Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain.

    +

    Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func sendFile(path: String, method: VGSCollectHTTPMethod = .post, routeId: String? = nil, extraData: [String : Any]? = nil, requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions(), completion block: @escaping (VGSResponse) -> Void)
    + +
    +
    +
    +

    Parameters

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

    Inbound rout path for your organization vault.

    +
    +
    + + method + + +
    +

    HTTPMethod, default is .post.

    +
    +
    + + routeId + + +
    +

    id of VGS Proxy Route, default is nil.

    +
    +
    + + extraData + + +
    +

    Any data you want to send together with data from VGSTextFields , default is nil.

    +
    +
    + + completion + + +
    +

    response completion block, returns VGSResponse.

    +
    +
    +
    +
  • +
    +
    +
    +
    +
    +

    Send tokenization request with data from VGSTextFields.

    +
    +

    Note

    + Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain. + +
    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public func tokenizeData(routeId: String? = nil, completion block: @escaping (VGSTokenizationResponse) -> Void)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + +
    + + routeId + + +
    +

    id of VGS Proxy Route, default is nil.

    +
    +
    + + completion + + +
    +

    response completion block, returns VGSTokenizationResponse.

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

    VGSCollect + async +

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

      Asynchronously send data from VGSTextFields to your organization vault.

      +
      +

      Note

      +

      Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain.

      + +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public func sendData(path: String, method: VGSCollectHTTPMethod = .post, routeId: String? = nil, extraData: [String : Any]? = nil, requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions()) async -> VGSResponse
      + +
      +
      +
      +

      Parameters

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

      Inbound rout path for your organization vault.

      +
      +
      + + method + + +
      +

      VGSCollectHTTPMethod, default is .post.

      +
      +
      + + routeId + + +
      +

      id of VGS Proxy Route, default is nil.

      +
      +
      + + extraData + + +
      +

      Any data you want to send together with data from VGSTextFields , default is nil.

      +
      +
      + + requestOptions + + +
      +

      VGSCollectRequestOptions object, holds additional request options. Default options are .nestedJSON.

      +
      +
      +
      +
      +

      Return Value

      +

      +
      + +
      +
      +
    • +
    • +
      + + + + sendFile(path:method:routeId:extraData:) + + + Asynchronous + +
      +
      +
      +
      +
      +
      +

      Asynchronously send file to your organization vault. Only send one file at a time.

      +
      +

      Note

      +

      Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain.

      + +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public func sendFile(path: String, method: VGSCollectHTTPMethod = .post, routeId: String? = nil, extraData: [String : Any]? = nil) async -> VGSResponse
      + +
      +
      +
      +

      Parameters

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

      Inbound rout path for your organization vault.

      +
      +
      + + method + + +
      +

      HTTPMethod, default is .post.

      +
      +
      + + routeId + + +
      +

      id of VGS Proxy Route, default is nil.

      +
      +
      + + extraData + + +
      +

      Any data you want to send together with data from VGSTextFields , default is nil.

      +
      +
      + + completion + + +
      +

      response completion block, returns VGSResponse.

      +
      +
      +
      + +
      +
      +
    • +
    • +
      + + + + tokenizeData(routeId:) + + + Asynchronous + +
      +
      +
      +
      +
      +
      +

      Asynchronously send tokenization request with data from VGSTextFields.

      +
      +

      Note

      + Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain. + +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public func tokenizeData(routeId: String? = nil) async -> VGSTokenizationResponse
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + +
      + + routeId + + +
      +

      id of VGS Proxy Route, default is nil.

      +
      +
      + + completion + + +
      +

      response completion block, returns VGSTokenizationResponse.

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

    VGSCollect + Combine +

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

      Send data from VGSTextFields to your organization vault using the Combine framework.

      +
      +

      Note

      +

      Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain.

      + +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public func sendDataPublisher(path: String, method: VGSCollectHTTPMethod = .post, routeId: String? = nil, extraData: [String : Any]? = nil, requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions()) -> Future<VGSResponse, Never>
      + +
      +
      +
      +

      Parameters

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

      Inbound rout path for your organization vault.

      +
      +
      + + method + + +
      +

      VGSCollectHTTPMethod, default is .post.

      +
      +
      + + routeId + + +
      +

      id of VGS Proxy Route, default is nil.

      +
      +
      + + extraData + + +
      +

      Any data you want to send together with data from VGSTextFields , default is nil.

      +
      +
      + + requestOptions + + +
      +

      VGSCollectRequestOptions object, holds additional request options. Default options are .nestedJSON.

      +
      +
      +
      +
      +

      Return Value

      +

      A Future publisher that emits a single VGSResponse.

      +
      + +
      +
      +
    • +
    • +
      @@ -741,14 +1682,154 @@

      Send data
      -

      Makes tokenization response with data from VGSTextFields.

      +

      Send file to your organization vault using the Combine framework.

      Note

      - Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain. +

      Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain.

      +
      +

      Declaration

      +
      +

      Swift

      +
      public func sendFilePublisher(path: String, method: VGSCollectHTTPMethod = .post, routeId: String? = nil, extraData: [String : Any]? = nil, requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions()) -> Future<VGSResponse, Never>
      + +
      +
      +
      +

      Parameters

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

      Inbound rout path for your organization vault.

      +
      +
      + + method + + +
      +

      VGSCollectHTTPMethod, default is .post.

      +
      +
      + + routeId + + +
      +

      id of VGS Proxy Route, default is nil.

      +
      +
      + + extraData + + +
      +

      Any data you want to send together with data from VGSTextFields , default is nil.

      +
      +
      + + requestOptions + + +
      +

      VGSCollectRequestOptions object, holds additional request options. Default options are .nestedJSON.

      +
      +
      +
      +
      +

      Return Value

      +

      A Future publisher that emits a single VGSResponse.

      +
      + +
      +

      +
    • +
    • + +
      +
      +
      +
      +
      +

      Send tokenization request with data from VGSTextFields to your organization vault using the Combine framework.

      +
      +

      Note

      +

      Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain.

      + +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public func tokenizeDataPublisher(routeId: String? = nil) -> Future<VGSTokenizationResponse, Never>
      + +
      +
      +
      +

      Parameters

      + + + + + + + +
      + + routeId + + +
      +

      id of VGS Proxy Route, default is nil.

      +
      +
      +
      +
      +

      Return Value

      +

      A Future publisher that emits a single VGSTokenizationResponse.

      +
      +
    • @@ -760,8 +1841,8 @@

      Send data

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCollectLogger.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCollectLogger.html index 71ff2cc0..ee15b418 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCollectLogger.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSCollectLogger.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,9 +376,19 @@

    VGSCollectLogger

    +
    +
    + +
    public final class VGSCollectLogger
    + +
    +

    VGSCollectLogger encapsulates logging logic and debugging options for VGSCollectSDK. Use .configuration property to setup these options. VGSCollectLogger logging implies only printing logs to Xcode console. It doesn’t save logs to persistent store/local file, also it doesn’t send debugging logs to backend services. IMPORTANT You should NOT use logging in your production configuration for live apps.

    +
    @@ -397,9 +408,9 @@

    vars
  • - + - shared + shared
    @@ -410,15 +421,26 @@

    vars

    Shared instance.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var shared: VGSCollectLogger
    + +
    +
    +
  • @@ -429,6 +451,17 @@

    vars

    Logging configuration. Check VGSCollectLoggingConfiguration for logging options.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var configuration: VGSCollectLoggingConfiguration
    + +
    +
    +
  • @@ -448,9 +481,9 @@

    Public
  • @@ -461,6 +494,17 @@

    Public

    Stop logging all activities.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func disableAllLoggers()
    + +
    +
    +
  • @@ -472,8 +516,8 @@

    Public

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSConfiguration.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSConfiguration.html index 5938d661..583dd239 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSConfiguration.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSConfiguration

    +
    +
    + +
    public class VGSConfiguration : VGSTextFieldConfigurationProtocol
    + +
    +

    A class responsible for configuration VGSTextField.

    +
    @@ -396,9 +407,9 @@

    Attributes
  • @@ -409,15 +420,26 @@

    Attributes

    Collect form that will be assiciated with VGSTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public private(set) weak var vgsCollector: VGSCollect? { get }
    + +
    +
    +
  • - + - type + type
    @@ -425,8 +447,19 @@

    Attributes
    -

    Type of field congfiguration. Default is FieldType.none.

    +

    Type of field congfiguration. Default is FieldType.none.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public var type: FieldType
    +
    +
    +

    @@ -434,9 +467,9 @@

    Attributes
  • @@ -447,15 +480,26 @@

    Attributes

    Name that will be associated with VGSTextField and used as a JSON key on send request with textfield data to your organozation vault.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let fieldName: String
    + +
    +
    +
  • @@ -466,15 +510,26 @@

    Attributes

    Set if VGSTextField is required to be non-empty and non-nil on send request. Default is false.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var isRequired: Bool
    + +
    +
    +
  • @@ -485,15 +540,26 @@

    Attributes

    Set if VGSTextField is required to be valid only on send request. Default is false.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var isRequiredValidOnly: Bool
    + +
    +
    +
  • @@ -501,8 +567,19 @@

    Attributes
    -

    Input data visual format pattern. If not applied, will be set by default depending on field type.

    +

    Input data visual format pattern. If not applied, will be set by default depending on field type.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public var formatPattern: String? { get set }
    +
    +
    +

    @@ -510,9 +587,9 @@

    Attributes
  • - + - divider + divider
    @@ -520,18 +597,29 @@

    Attributes
    -

    String, used to replace not default VGSConfiguration.formatPattern characters in input text on send request.

    +

    String, used to replace not default VGSConfiguration.formatPattern characters in input text on send request.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var divider: String?
    + +
    +
    +

  • @@ -539,18 +627,29 @@

    Attributes
    -

    Preferred UIKeyboardType for VGSTextField. If not applied, will be set by default depending on field type parameter.

    +

    Preferred UIKeyboardType for VGSTextField. If not applied, will be set by default depending on field type parameter.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var keyboardType: UIKeyboardType?
    + +
    +
    +

  • @@ -561,15 +660,26 @@

    Attributes

    Preferred UIReturnKeyType for VGSTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var returnKeyType: UIReturnKeyType?
    + +
    +
    +
  • @@ -580,15 +690,26 @@

    Attributes

    Preferred UIKeyboardAppearance for textfield. By default is UIKeyboardAppearance.default.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var keyboardAppearance: UIKeyboardAppearance?
    + +
    +
    +
  • @@ -599,15 +720,26 @@

    Attributes

    Validation rules for field input. Defines State.isValide result.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var validationRules: VGSValidationRuleSet?
    + +
    +
    +
  • @@ -615,9 +747,20 @@

    Attributes
    -

    Max input length. IMPORTANT! Can conflict with .formatPattern attribute.

    +

    Max input length. IMPORTANT! Can conflict with .formatPattern attribute.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var maxInputLength: Int? { get set }
    + +
    +
    +

  • @@ -637,9 +780,9 @@

    Initialization
  • @@ -650,6 +793,48 @@

    Initialization

    Initialization

    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(collector vgs: VGSCollect, fieldName: String)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + +
    + + vgs + + +
    +

    VGSCollect instance.

    +
    +
    + + fieldName + + +
    +

    associated fieldName.

    +
    +
    +
    +
  • @@ -661,8 +846,8 @@

    Initialization

  • diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSDateConfiguration.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSDateConfiguration.html new file mode 100644 index 00000000..4c11627b --- /dev/null +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSDateConfiguration.html @@ -0,0 +1,757 @@ + + + + VGSDateConfiguration Class Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    VGSDateConfiguration

    +
    +
    + +
    public final class VGSDateConfiguration : VGSConfiguration, VGSDateConfigurationProtocol, VGSFormatSerializableProtocol
    + +
    +
    +

    Class responsible for configuration VGSDateTextField or VGSTextField with fieldType = .date. Extends VGSConfiguration

    + + +
    +
    + +
    +
    +
    +
    + + +
    + +

    Constructor +

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

      Initialization +Date configuration initializer, if no datePickerStartDate is provided, +a default date will be used adding 100 years to the current date. +Similar approach will be used if datePickerEndDate is not provided, +it will be calculated removing 100 years from current date.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(collector vgs: VGSCollect,
      +            fieldName: String,
      +            datePickerStartDate: VGSDate? = nil,
      +            datePickerEndDate: VGSDate? = nil)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + + + + + + + + + +
      + + vgs + + +
      +

      VGSCollect instance.

      +
      +
      + + fieldName + + +
      +

      associated fieldName.

      +
      +
      + + datePickerStartDate + + +
      +

      optional VGSDate instance.

      +
      +
      + + datePickerEndDate + + +
      +

      optional VGSDate instance.

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

    Overridden methods and properties +

    +
    +
    +
      +
    • +
      + + + + type + +
      +
      +
      +
      +
      +
      +

      Super initializer

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public override var type: FieldType { get set }
      + +
      +
      + +
      +
      +
    • +
    +
    +
    +
    + + +
    + +

    VGSDateConfigurationProtocol implementation +

    +
    +
    + +
    +
    +
    + + +
    + +

    Static properties and methods +

    +
    +
    + +
    +
    +
    + +
    +
    + + + diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSDateTextField.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSDateTextField.html new file mode 100644 index 00000000..b5c0f2c5 --- /dev/null +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSDateTextField.html @@ -0,0 +1,536 @@ + + + + VGSDateTextField Class Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    VGSDateTextField

    +
    +
    + +
    public final class VGSDateTextField : VGSTextField
    +
    extension VGSDateTextField: UIPickerViewDelegate, UIPickerViewDataSource
    + +
    +
    +

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to show picker view with a Date. It support to define a range of valid dates to select from.

    + + +
    +
    + +
    +
    +
    +
    + + +
    + +

    Inner objects +

    +
    +
    +
      +
    • +
      + + + + MonthFormat + +
      +
      +
      +
      +
      +
      +

      Available month Label formats in UIPickerView

      + + See more +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public enum MonthFormat
      + +
      +
      + +
      +
      +
    • +
    +
    +
    +
    + + +
    + +

    Properties +

    +
    +
    + +
    +
    +
    + + +
    + +

    Overridden methods and properties +

    +
    +
    + +
    +
    +
    + +
    +
    + + + diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSDateTextField/MonthFormat.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSDateTextField/MonthFormat.html new file mode 100644 index 00000000..3709f8c8 --- /dev/null +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSDateTextField/MonthFormat.html @@ -0,0 +1,500 @@ + + + + MonthFormat Enumeration Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    MonthFormat

    +
    +
    + +
    public enum MonthFormat
    + +
    +
    +

    Available month Label formats in UIPickerView

    + + +
    +
    + +
    +
    +
    +
      +
    • +
      + + + + shortSymbols + +
      +
      +
      +
      +
      +
      +

      Short month name, e.g.: Jan

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case shortSymbols
      + +
      +
      + +
      +
      +
    • +
    • +
      + + + + longSymbols + +
      +
      +
      +
      +
      +
      +

      Long month name, e.g.: January

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case longSymbols
      + +
      +
      + +
      +
      +
    • +
    • +
      + + + + numbers + +
      +
      +
      +
      +
      +
      +

      Month number: e.g.: 01

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      case numbers
      + +
      +
      + +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSDateTokenizationConfiguration.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSDateTokenizationConfiguration.html new file mode 100644 index 00000000..50e491e7 --- /dev/null +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSDateTokenizationConfiguration.html @@ -0,0 +1,655 @@ + + + + VGSDateTokenizationConfiguration Class Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    VGSDateTokenizationConfiguration

    +
    +
    + +
    public final class VGSDateTokenizationConfiguration : VGSConfiguration, VGSDateConfigurationProtocol, VGSTextFieldTokenizationConfigurationProtocol, VGSFormatSerializableProtocol
    + +
    +
    +

    Class responsible for configuration VGSDateTextField or VGSTextField with fieldType = .date. +Extends VGSConfiguration. Required to work with tokenization API.

    + + +
    +
    + +
    +
    +
    +
    + + +
    + +

    Constructor +

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

      Initialization +Date configuration initializer, if no datePickerStartDate is provided, +a default date will be used adding 100 years to the current date. +Similar approach will be used if datePickerEndDate is not provided, +it will be calculated removing 100 years from current date.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init(collector vgs: VGSCollect,
      +            fieldName: String,
      +            datePickerStartDate: VGSDate? = nil,
      +            datePickerEndDate: VGSDate? = nil)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + + + + + + + + + +
      + + vgs + + +
      +

      VGSCollect instance.

      +
      +
      + + fieldName + + +
      +

      associated fieldName.

      +
      +
      + + datePickerStartDate + + +
      +

      optional VGSDate instance.

      +
      +
      + + datePickerEndDate + + +
      +

      optional VGSDate instance.

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

    Overridden methods and properties +

    +
    +
    +
      +
    • +
      + + + + type + +
      +
      +
      +
      +
      +
      +

      Super initializer

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public override var type: FieldType { get set }
      + +
      +
      + +
      +
      +
    • +
    +
    +
    +
    + + +
    + +

    VGSDateConfigurationProtocol implementation +

    +
    +
    + +
    +
    +
    + +
    +
    + + + diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSError.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSError.html index 55acdea2..a49b05dc 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSError.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSError.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSError

    +
    +
    + +
    public class VGSError : NSError
    + +
    +

    An error produced by VGSCollectSDK. Works similar to default NSError in iOS.

    +
    @@ -387,9 +398,9 @@

    VGSError

  • - + - type + type
    @@ -400,15 +411,26 @@

    VGSError

    VGSErrorType- required for each VGSError instance

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let type: VGSErrorType!
    + +
    +
    +
  • - + - code + code
    @@ -419,15 +441,26 @@

    VGSError

    Code assiciated with VGSErrorType

    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var code: Int { get }
    + +
    +
    +
  • @@ -438,6 +471,17 @@

    VGSError

    : nodoc. Public required init.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public required init?(coder: NSCoder)
    + +
    +
    +
  • @@ -449,8 +493,8 @@

    VGSError

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateConfiguration.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateConfiguration.html index 3750bc31..8939dcfd 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateConfiguration.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSExpDateConfiguration

    +
    +
    + +
    public final class VGSExpDateConfiguration : VGSConfiguration, VGSExpDateConfigurationProtocol, VGSFormatSerializableProtocol
    + +
    +

    A class responsible for configuration VGSTextField with fieldType = .expDate. Extends VGSConfiguration class.

    +
    @@ -396,9 +407,9 @@

    Attributes
  • - + - type + type
    @@ -406,8 +417,19 @@

    Attributes
    -

    FieldType.expDate type of VGSTextField configuration.

    +

    FieldType.expDate type of VGSTextField configuration.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var type: FieldType { get set }
    +
    +
    +

    @@ -428,9 +450,9 @@

    VGSExpDateConfigurationProtocol
  • @@ -438,8 +460,19 @@

    VGSExpDateConfigurationProtocol
    -

    Input Source type. Default is VGSTextFieldInputSource.datePicker.

    +

    Input Source type. Default is VGSTextFieldInputSource.datePicker.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public var inputSource: VGSTextFieldInputSource
    +
    +
    +

    @@ -447,9 +480,9 @@

    VGSExpDateConfigurationProtocol
  • @@ -460,15 +493,26 @@

    VGSExpDateConfigurationProtocol

    Input date format to convert.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var inputDateFormat: VGSCardExpDateFormat?
    + +
    +
    +
  • @@ -479,6 +523,17 @@

    VGSExpDateConfigurationProtocol

    Output date format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var outputDateFormat: VGSCardExpDateFormat?
    + +
    +
    +
  • @@ -498,9 +553,9 @@

    VGSFormatSerializableProtocol
  • @@ -511,6 +566,17 @@

    VGSFormatSerializableProtocol

    Output date format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var serializers: [VGSFormatSerializerProtocol]
    + +
    +
    +
  • @@ -522,8 +588,8 @@

    VGSFormatSerializableProtocol

  • diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateTextField.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateTextField.html index 77148b81..c61d6c83 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateTextField.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateTextField.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -378,11 +379,16 @@

    VGSExpDateTextField

    - +
    public final class VGSExpDateTextField : VGSTextField
    +
    extension VGSExpDateTextField: UIPickerViewDelegate, UIPickerViewDataSource
    +

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to show picker view with Card Number Expiration Month and Year.

    + @@ -402,9 +408,9 @@

    Enums
  • @@ -416,15 +422,26 @@

    Enums See more

    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum MonthFormat
    + +
    +
    +
  • @@ -436,6 +453,17 @@

    Enums See more

    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum YearFormat
    + +
    +
    +
  • @@ -455,9 +483,9 @@

    Attributes
  • @@ -468,15 +496,26 @@

    Attributes

    UIPickerView Month Label format

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var monthPickerFormat: MonthFormat { get set }
    + +
    +
    +
  • @@ -487,6 +526,17 @@

    Attributes

    UIPickerView Year Label format

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var yearPickeFormat: YearFormat { get set }
    + +
    +
    +
  • @@ -498,8 +548,8 @@

    Attributes

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateTextField/MonthFormat.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateTextField/MonthFormat.html index e4808690..99480171 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateTextField/MonthFormat.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateTextField/MonthFormat.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    MonthFormat

    +
    +
    + +
    public enum MonthFormat
    + +
    +

    Available Month Label formats in UIPickerView

    +
    @@ -387,9 +398,9 @@

    MonthFormat

  • @@ -400,15 +411,26 @@

    MonthFormat

    Short month name, e.g.: Jan

    +
    +

    Declaration

    +
    +

    Swift

    +
    case shortSymbols
    + +
    +
    +
  • @@ -419,15 +441,26 @@

    MonthFormat

    Long month name, e.g.: January

    +
    +

    Declaration

    +
    +

    Swift

    +
    case longSymbols
    + +
    +
    +
  • - + - numbers + numbers
    @@ -438,6 +471,17 @@

    MonthFormat

    Month number: e.g.: 01

    +
    +

    Declaration

    +
    +

    Swift

    +
    case numbers
    + +
    +
    +
  • @@ -449,8 +493,8 @@

    MonthFormat

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateTextField/YearFormat.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateTextField/YearFormat.html index 65725d58..796dd565 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateTextField/YearFormat.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateTextField/YearFormat.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    YearFormat

    +
    +
    + +
    public enum YearFormat
    + +
    +

    Available Year Label formats in UIPickerView

    +
    @@ -387,9 +398,9 @@

    YearFormat

  • - + - short + short
    @@ -400,15 +411,26 @@

    YearFormat

    Two digits year format, e.g.: 21

    +
    +

    Declaration

    +
    +

    Swift

    +
    case short
    + +
    +
    +
  • - + - long + long
    @@ -419,6 +441,17 @@

    YearFormat

    Four digits year format:, e.g.:2021

    +
    +

    Declaration

    +
    +

    Swift

    +
    case long
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    YearFormat

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateTokenizationConfiguration.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateTokenizationConfiguration.html index 0e59386f..d4690f3d 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateTokenizationConfiguration.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSExpDateTokenizationConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSExpDateTokenizationConfiguration

    +
    +
    + +
    public final class VGSExpDateTokenizationConfiguration : VGSConfiguration, VGSExpDateConfigurationProtocol, VGSTextFieldTokenizationConfigurationProtocol, VGSFormatSerializableProtocol
    + +
    +

    VGSExpDateTokenizationConfiguration - textfield configuration for textfield with type .expDate, required for work with tokenization api.

    +
    @@ -396,9 +407,9 @@

    Attributes
  • - + - type + type
    @@ -406,8 +417,19 @@

    Attributes
    -

    FieldType.expDate type of VGSTextFieldtokenization configuration.

    +

    FieldType.expDate type of VGSTextFieldtokenization configuration.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var type: FieldType { get set }
    +
    +
    +

    @@ -428,9 +450,9 @@

    VGSExpDateConfigurationProtocol
  • @@ -438,8 +460,19 @@

    VGSExpDateConfigurationProtocol
    -

    Input Source type. Default is VGSTextFieldInputSource.datePicker.

    +

    Input Source type. Default is VGSTextFieldInputSource.datePicker.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public var inputSource: VGSTextFieldInputSource
    +
    +
    +

    @@ -447,9 +480,9 @@

    VGSExpDateConfigurationProtocol
  • @@ -460,15 +493,26 @@

    VGSExpDateConfigurationProtocol

    Input date format to convert.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var inputDateFormat: VGSCardExpDateFormat?
    + +
    +
    +
  • @@ -479,6 +523,17 @@

    VGSExpDateConfigurationProtocol

    Output date format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var outputDateFormat: VGSCardExpDateFormat?
    + +
    +
    +
  • @@ -498,9 +553,9 @@

    VGSTokenizationParametersProtocol
  • @@ -511,6 +566,17 @@

    VGSTokenizationParametersProtocol

    VGSExpDateTokenizationParameters - tokenization configuration parameters.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var tokenizationParameters: VGSExpDateTokenizationParameters
    + +
    +
    +
  • @@ -530,9 +596,9 @@

    VGSFormatSerializableProtocol
  • @@ -543,6 +609,17 @@

    VGSFormatSerializableProtocol

    Output date format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var serializers: [VGSFormatSerializerProtocol]
    + +
    +
    +
  • @@ -554,8 +631,8 @@

    VGSFormatSerializableProtocol

  • diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSFileInfo.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSFileInfo.html index be38d84f..a8563c52 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSFileInfo.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSFileInfo.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSFileInfo

    +
    +
    + +
    public class VGSFileInfo : NSObject, VGSFileInfoProtocol
    + +
    +

    An object that holds optional files’ metadata on selecting file through VGSFilePickerController.

    +
    @@ -387,9 +398,9 @@

    VGSFileInfo

  • @@ -405,15 +416,26 @@

    VGSFileInfo

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let fileExtension: String?
    + +
    +
    +
  • - + - size + size
    @@ -424,15 +446,26 @@

    VGSFileInfo

    File size.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let size: Int
    + +
    +
    +
  • @@ -443,6 +476,17 @@

    VGSFileInfo

    File size units.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let sizeUnits: String?
    + +
    +
    +
  • @@ -454,8 +498,8 @@

    VGSFileInfo

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSFilePickerConfiguration.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSFilePickerConfiguration.html index e1db878a..fc82cfb7 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSFilePickerConfiguration.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSFilePickerConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSFilePickerConfiguration

    +
    +
    + +
    public class VGSFilePickerConfiguration : VGSFilePickerConfigurationProtocol
    + +
    +

    A class responsible for configuration VGSFilePickerController.

    +
    @@ -396,9 +407,9 @@

    Attributes
  • @@ -409,6 +420,17 @@

    Attributes

    Name that will be associated with selected file by user. Used as a JSON key on send request with file data to your organozation vault.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let fieldName: String
    + +
    +
    +
  • @@ -428,9 +450,9 @@

    Initialization
  • @@ -441,6 +463,60 @@

    Initialization

    Initialization

    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(collector vgs: VGSCollect, fieldName: String, fileSource: VGSFileSource)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + + + + + +
    + + vgs + + +
    +

    VGSCollect instance.

    +
    +
    + + fieldName + + +
    +

    name that should be associated with selected file.

    +
    +
    + + fileSource + + +
    +

    type of VGSFileSource that should be provided to user.

    +
    +
    +
    +
  • @@ -452,8 +528,8 @@

    Initialization

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSFilePickerController.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSFilePickerController.html index 5701e75a..778c1ce4 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSFilePickerController.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSFilePickerController.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSFilePickerController

    +
    +
    + +
    public class VGSFilePickerController
    + +
    +

    Controller responsible for importing files from device sources.

    +
    @@ -396,9 +407,9 @@

    Attributes
  • - + - delegate + delegate
    @@ -409,6 +420,17 @@

    Attributes

    VGSFilePickerControllerDelegate - handle user interaction on file picking.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public weak var delegate: VGSFilePickerControllerDelegate? { get set }
    + +
    +
    +
  • @@ -428,9 +450,9 @@

    Initialization
  • @@ -441,6 +463,36 @@

    Initialization

    Initialization

    +
    +

    Declaration

    +
    +

    Swift

    +
    public required init(configuration: VGSFilePickerConfiguration)
    + +
    +
    +
    +

    Parameters

    + + + + + + + +
    + + configuration + + + +
    +
    +
  • @@ -460,9 +512,9 @@

    Methods
  • @@ -473,15 +525,69 @@

    Methods

    Present file picker view

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func presentFilePicker(on viewController: UIViewController, animated: Bool, completion: (() -> Void)? = nil)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + + + + + +
    + + viewController + + +
    +

    UIViewController that will present card scanner

    +
    +
    + + animated + + +
    +

    pass true to animate the presentation; otherwise, pass false

    +
    +
    + + completion + + +
    +

    the block to execute after the presentation finishes

    +
    +
    +
    +
  • @@ -492,6 +598,48 @@

    Methods

    Dismiss file picker view

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func dismissFilePicker(animated: Bool, completion: (() -> Void)? = nil)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + +
    + + animated + + +
    +

    pass true to animate the dismiss of presented viewcontroller; otherwise, pass false

    +
    +
    + + completion + + +
    +

    the block to execute after the dismiss finishes

    +
    +
    +
    +
  • @@ -503,8 +651,8 @@

    Methods

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSPaymentCards.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSPaymentCards.html index 283c2697..2eb7c665 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSPaymentCards.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSPaymentCards.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,6 +376,13 @@

    VGSPaymentCards

    +
    +
    + +
    public class VGSPaymentCards
    + +
    +

    Class responsible for storing and managing Payment Cards in SDK.

      @@ -383,6 +391,9 @@

      VGSPaymentCards

    • Allows to edit Unknown Payment Cards Models(brands not defined by SDK and Developer)
    +
    @@ -402,9 +413,9 @@

    CardBrand Enum Cases
  • @@ -416,6 +427,17 @@

    CardBrand Enum Cases See more

    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum CardBrand : Equatable
    + +
    +
    +
  • @@ -435,9 +457,9 @@

    Payment Card Models
  • - + - elo + elo
    @@ -448,15 +470,26 @@

    Payment Card Models

    Elo Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var elo: VGSPaymentCardModel
    + +
    +
    +
  • @@ -467,15 +500,26 @@

    Payment Card Models

    Visa Electron Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var visaElectron: VGSPaymentCardModel
    + +
    +
    +
  • - + - maestro + maestro
    @@ -486,15 +530,26 @@

    Payment Card Models

    Maestro Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var maestro: VGSPaymentCardModel
    + +
    +
    +
  • @@ -505,15 +560,26 @@

    Payment Card Models

    Forbrugsforeningen Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var forbrugsforeningen: VGSPaymentCardModel
    + +
    +
    +
  • - + - dankort + dankort
    @@ -524,15 +590,26 @@

    Payment Card Models

    Dankort Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var dankort: VGSPaymentCardModel
    + +
    +
    +
  • - + - visa + visa
    @@ -543,15 +620,26 @@

    Payment Card Models

    Elo Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var visa: VGSPaymentCardModel
    + +
    +
    +
  • @@ -562,15 +650,26 @@

    Payment Card Models

    Master Card Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var masterCard: VGSPaymentCardModel
    + +
    +
    +
  • - + - amex + amex
    @@ -581,15 +680,26 @@

    Payment Card Models

    Amex Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var amex: VGSPaymentCardModel
    + +
    +
    +
  • @@ -600,15 +710,26 @@

    Payment Card Models

    Hipercard Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var hipercard: VGSPaymentCardModel
    + +
    +
    +
  • @@ -619,15 +740,26 @@

    Payment Card Models

    DinersClub Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var dinersClub: VGSPaymentCardModel
    + +
    +
    +
  • - + - discover + discover
    @@ -638,15 +770,26 @@

    Payment Card Models

    Discover Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var discover: VGSPaymentCardModel
    + +
    +
    +
  • - + - unionpay + unionpay
    @@ -657,15 +800,26 @@

    Payment Card Models

    UnionPay Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var unionpay: VGSPaymentCardModel
    + +
    +
    +
  • - + - jcb + jcb
    @@ -676,6 +830,17 @@

    Payment Card Models

    JCB Payment Card Model

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var jcb: VGSPaymentCardModel
    + +
    +
    +
  • @@ -695,9 +860,9 @@

    Unknown Payment Card Model
  • - + - unknown + unknown
    @@ -705,8 +870,19 @@

    Unknown Payment Card Model
    -

    Unknown Brand Payment Card Model. Can be used for specifing cards details when VGSValidationRulePaymentCard requires validating CardBrand.unknown cards.

    +

    Unknown Brand Payment Card Model. Can be used for specifing cards details when VGSValidationRulePaymentCard requires validating CardBrand.unknown cards.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var unknown: VGSUnknownPaymentCardModel
    +
    +
    +

    @@ -727,9 +903,9 @@

    Custom Payment Card Models
  • @@ -740,20 +916,31 @@

    Custom Payment Card Models

    Array of Custom Payment Card Models.

    Note

    - the order has impact on which card brand should be detected first by VGSPaymentCardModel.regex. + the order has impact on which card brand should be detected first by VGSPaymentCardModel.regex.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var cutomPaymentCardModels: [VGSCustomPaymentCardModel]
    + +
    +
    +
  • @@ -764,11 +951,22 @@

    Custom Payment Card Models

    An array of valid Card Brands, could include custom and default brands. If not set, will use availableCardBrands array instead.

    Note

    - the order has impact on which card brand should be detected first by VGSPaymentCardModel.regex. + the order has impact on which card brand should be detected first by VGSPaymentCardModel.regex.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public static var validCardBrands: [VGSPaymentCardModelProtocol]?
    + +
    +
    +
  • @@ -788,9 +986,9 @@

    Attributes
  • @@ -801,15 +999,26 @@

    Attributes

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    static func getCardModelFromAvailableModels(brand: VGSPaymentCards.CardBrand) -> VGSPaymentCardModelProtocol?
    + +
    +
    +
  • @@ -820,6 +1029,17 @@

    Attributes

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    static func detectCardBrandFromAvailableCards(input: String) -> VGSPaymentCards.CardBrand
    + +
    +
    +
  • @@ -831,8 +1051,8 @@

    Attributes

  • diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSPaymentCards/CardBrand.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSPaymentCards/CardBrand.html index 70137750..8314c190 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSPaymentCards/CardBrand.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSPaymentCards/CardBrand.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    CardBrand

    +
    +
    + +
    public enum CardBrand : Equatable
    + +
    +

    Supported card brands

    +
    @@ -387,9 +398,9 @@

    CardBrand

  • - + - elo + elo
    @@ -400,15 +411,26 @@

    CardBrand

    ELO

    +
    +

    Declaration

    +
    +

    Swift

    +
    case elo
    + +
    +
    +
  • @@ -419,15 +441,26 @@

    CardBrand

    Visa Electron

    +
    +

    Declaration

    +
    +

    Swift

    +
    case visaElectron
    + +
    +
    +
  • - + - maestro + maestro
    @@ -438,15 +471,26 @@

    CardBrand

    Maestro

    +
    +

    Declaration

    +
    +

    Swift

    +
    case maestro
    + +
    +
    +
  • @@ -457,15 +501,26 @@

    CardBrand

    Forbrugsforeningen

    +
    +

    Declaration

    +
    +

    Swift

    +
    case forbrugsforeningen
    + +
    +
    +
  • - + - dankort + dankort
    @@ -476,15 +531,26 @@

    CardBrand

    Dankort

    +
    +

    Declaration

    +
    +

    Swift

    +
    case dankort
    + +
    +
    +
  • - + - visa + visa
    @@ -495,15 +561,26 @@

    CardBrand

    Visa

    +
    +

    Declaration

    +
    +

    Swift

    +
    case visa
    + +
    +
    +
  • @@ -514,15 +591,26 @@

    CardBrand

    Mastercard

    +
    +

    Declaration

    +
    +

    Swift

    +
    case mastercard
    + +
    +
    +
  • - + - amex + amex
    @@ -533,15 +621,26 @@

    CardBrand

    American Express

    +
    +

    Declaration

    +
    +

    Swift

    +
    case amex
    + +
    +
    +
  • @@ -552,15 +651,26 @@

    CardBrand

    Hipercard

    +
    +

    Declaration

    +
    +

    Swift

    +
    case hipercard
    + +
    +
    +
  • @@ -571,15 +681,26 @@

    CardBrand

    Diners Club

    +
    +

    Declaration

    +
    +

    Swift

    +
    case dinersClub
    + +
    +
    +
  • - + - discover + discover
    @@ -590,15 +711,26 @@

    CardBrand

    Discover

    +
    +

    Declaration

    +
    +

    Swift

    +
    case discover
    + +
    +
    +
  • - + - unionpay + unionpay
    @@ -609,15 +741,26 @@

    CardBrand

    UnionPay

    +
    +

    Declaration

    +
    +

    Swift

    +
    case unionpay
    + +
    +
    +
  • - + - jcb + jcb
    @@ -628,15 +771,26 @@

    CardBrand

    JCB

    +
    +

    Declaration

    +
    +

    Swift

    +
    case jcb
    + +
    +
    +
  • - + - unknown + unknown
    @@ -647,15 +801,26 @@

    CardBrand

    Not supported card brand - “unknown”

    +
    +

    Declaration

    +
    +

    Swift

    +
    case unknown
    + +
    +
    +
  • @@ -666,15 +831,26 @@

    CardBrand

    Custom Payment Card Brand. Should have unique brandName.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case custom(brandName: String)
    + +
    +
    +
  • @@ -685,15 +861,26 @@

    CardBrand

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcFormatPattern: String { get }
    + +
    +
    +
  • @@ -704,15 +891,26 @@

    CardBrand

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var brandIcon: UIImage? { get }
    + +
    +
    +
  • - + - cvcIcon + cvcIcon
    @@ -723,6 +921,17 @@

    CardBrand

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcIcon: UIImage? { get }
    + +
    +
    +
  • @@ -742,9 +951,9 @@

    Attributes
  • @@ -755,15 +964,26 @@

    Attributes

    String representation of VGSPaymentCards.CardBrand enum values.

    +
    +

    Declaration

    +
    +

    Swift

    +
    var stringValue: String { get }
    + +
    +
    +
  • @@ -774,6 +994,17 @@

    Attributes

    Returns array with valid card number lengths for specific VGSPaymentCards.CardBrand

    +
    +

    Declaration

    +
    +

    Swift

    +
    var cardLengths: [Int] { get }
    + +
    +
    +
  • @@ -785,8 +1016,8 @@

    Attributes

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSSSNTokenizationConfiguration.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSSSNTokenizationConfiguration.html index a48253b0..e3009be0 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSSSNTokenizationConfiguration.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSSSNTokenizationConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSSSNTokenizationConfiguration

    +
    +
    + +
    public class VGSSSNTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +

    VGSSSNTokenizationConfiguration - textfield configuration for textfield with type .ssn, required for work with tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSSSNTokenizationConfiguration

  • @@ -400,15 +411,26 @@

    VGSSSNTokenizationConfiguration

    VGSSSNTokenizationParameters - tokenization configuration parameters.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var tokenizationParameters: VGSSSNTokenizationParameters
    + +
    +
    +
  • - + - type + type
    @@ -416,9 +438,20 @@

    VGSSSNTokenizationConfiguration

    -

    FieldType.ssn type of VGSTextFieldtokenization configuration.

    +

    FieldType.ssn type of VGSTextFieldtokenization configuration.

    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var type: FieldType { get set }
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSSSNTokenizationConfiguration

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSTextField.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSTextField.html index 19232ac3..bb07559e 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSTextField.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSTextField.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -378,11 +379,16 @@

    VGSTextField

    - +
    public class VGSTextField : UIView
    +
    extension VGSTextField: UITextFieldDelegate
    +

    An object that displays an editable text area in user interface.

    + @@ -402,9 +408,9 @@

    UI Attributes
  • @@ -415,15 +421,26 @@

    UI Attributes

    Textfield placeholder string.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var placeholder: String? { get set }
    + +
    +
    +
  • @@ -434,15 +451,26 @@

    UI Attributes

    Textfield autocapitalization type. Default is .sentences.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var autocapitalizationType: UITextAutocapitalizationType { get set }
    + +
    +
    +
  • @@ -453,15 +481,26 @@

    UI Attributes

    Textfield spell checking type. Default is UITextSpellCheckingType.default.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var spellCheckingType: UITextSpellCheckingType { get set }
    + +
    +
    +
  • @@ -472,15 +511,26 @@

    UI Attributes

    Textfield attributedPlaceholder string.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var attributedPlaceholder: NSAttributedString? { get set }
    + +
    +
    +
  • - + - padding + padding
    @@ -491,15 +541,26 @@

    UI Attributes

    UIEdgeInsets for text and placeholder inside VGSTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var padding: UIEdgeInsets { get set }
    + +
    +
    +
  • @@ -510,15 +571,26 @@

    UI Attributes

    The technique to use for aligning the text.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var textAlignment: NSTextAlignment { get set }
    + +
    +
    +
  • @@ -529,15 +601,26 @@

    UI Attributes

    Sets when the clear button shows up. Default is UITextField.ViewMode.never

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var clearButtonMode: UITextField.ViewMode { get set }
    + +
    +
    +
  • @@ -548,15 +631,26 @@

    UI Attributes

    Identifies whether the text object should disable text copying and in some cases hide the text being entered. Default is false.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var isSecureTextEntry: Bool { get set }
    + +
    +
    +
  • @@ -567,15 +661,26 @@

    UI Attributes

    Indicates whether VGSTextField should automatically update its font when the device’s UIContentSizeCategory is changed.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var adjustsFontForContentSizeCategory: Bool { get set }
    + +
    +
    +
  • @@ -586,15 +691,26 @@

    UI Attributes

    Input Accessory View

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var keyboardAccessoryView: UIView? { get set }
    + +
    +
    +
  • @@ -605,15 +721,26 @@

    UI Attributes

    Determines whether autocorrection is enabled or disabled during typing.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var autocorrectionType: UITextAutocorrectionType { get set }
    + +
    +
    +
  • @@ -624,15 +751,26 @@

    UI Attributes

    A succinct label in a localized string that identifies the accessibility text field.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var textFieldAccessibilityLabel: String? { get set }
    + +
    +
    +
  • @@ -643,6 +781,17 @@

    UI Attributes

    A localized string that contains a brief description of the result of performing an action on the accessibility text field.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var textFieldAccessibilityHint: String? { get set }
    + +
    +
    +
  • @@ -662,9 +811,9 @@

    Functional Attributes
  • @@ -675,15 +824,26 @@

    Functional Attributes

    Specifies VGSTextField configuration parameters to work with VGSCollect.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var configuration: VGSConfiguration? { get set }
    + +
    +
    +
  • - + - delegate + delegate
    @@ -694,6 +854,17 @@

    Functional Attributes

    Delegates VGSTextField editing events. Default is nil.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public weak var delegate: VGSTextFieldDelegate?
    + +
    +
    +
  • @@ -713,9 +884,9 @@

    Manage input
  • @@ -726,22 +897,33 @@

    Manage input

    Set textfield default text.

    Note

    - This will not change State.isDirty attribute. + This will not change State.isDirty attribute.
    • Discussion: probably you should want to set field configuration before setting default value, so the input format will be update as required.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func setDefaultText(_ text: String?)
    + +
    +
    +
  • @@ -752,6 +934,17 @@

    Manage input

    Removes input from field.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func cleanText()
    + +
    +
    +
  • @@ -771,9 +964,9 @@

    Compare Input
  • @@ -789,6 +982,17 @@

    Compare Input

    +
    +

    Declaration

    +
    +

    Swift

    +
    public func isContentEqual(_ textField: VGSTextField) -> Bool
    + +
    +
    +
  • @@ -808,9 +1012,9 @@

    Text Attribute
  • - + - font + font
    @@ -821,15 +1025,26 @@

    Text Attribute

    VGSTextField text font

    +
    +

    Declaration

    +
    +

    Swift

    +
    var font: UIFont? { get set }
    + +
    +
    +
  • @@ -840,6 +1055,18 @@

    Text Attribute

    VGSTextField text color

    +
    +

    Declaration

    +
    +

    Swift

    +
    @IBInspectable
    +var textColor: UIColor? { get set }
    + +
    +
    +
  • @@ -859,9 +1086,9 @@

    UI Layer Attribute
  • @@ -872,15 +1099,27 @@

    UI Layer Attribute

    VGSTextField layer corner radius

    +
    +

    Declaration

    +
    +

    Swift

    +
    @IBInspectable
    +var cornerRadius: CGFloat { get set }
    + +
    +
    +
  • @@ -891,15 +1130,27 @@

    UI Layer Attribute

    VGSTextField layer borderWidth

    +
    +

    Declaration

    +
    +

    Swift

    +
    @IBInspectable
    +var borderWidth: CGFloat { get set }
    + +
    +
    +
  • @@ -910,6 +1161,48 @@

    UI Layer Attribute

    VGSTextField layer borderColor

    +
    +

    Declaration

    +
    +

    Swift

    +
    @IBInspectable
    +var borderColor: UIColor? { get set }
    + +
    +
    + + + +
  • +
  • +
    + + + + statePublisher + +
    +
    +
    +
    +
    +
    +

    VGSTextFieldStatePublisher publisher that emits the State of a given VGSTextField.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    var statePublisher: VGSTextFieldStatePublisher { get }
    + +
    +
    +
  • @@ -929,9 +1222,9 @@

    UIResponder methods
  • @@ -942,15 +1235,27 @@

    UIResponder methods

    Make VGSTextField focused.

    +
    +

    Declaration

    +
    +

    Swift

    +
    @discardableResult
    +override public func becomeFirstResponder() -> Bool
    + +
    +
    +
  • @@ -961,15 +1266,27 @@

    UIResponder methods

    Remove focus from VGSTextField.

    +
    +

    Declaration

    +
    +

    Swift

    +
    @discardableResult
    +override public func resignFirstResponder() -> Bool
    + +
    +
    +
  • @@ -980,6 +1297,17 @@

    UIResponder methods

    Check if VGSTextField is focused.

    +
    +

    Declaration

    +
    +

    Swift

    +
    override public var isFirstResponder: Bool { get }
    + +
    +
    +
  • @@ -991,8 +1319,8 @@

    UIResponder methods

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSTokenizationConfiguration.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSTokenizationConfiguration.html index 073256f6..18a2a57d 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSTokenizationConfiguration.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Classes/VGSTokenizationConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSTokenizationConfiguration

    +
    +
    + +
    public class VGSTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +

    VGSTokenizationConfiguration - textfield configuration for textfield with any type of data, required for work with tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSTokenizationConfiguration

  • @@ -400,6 +411,17 @@

    VGSTokenizationConfiguration

    VGSTokenizationParameters - tokenization configuration parameters.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var tokenizationParameters: VGSTokenizationParameters
    + +
    +
    +
  • @@ -411,8 +433,8 @@

    VGSTokenizationConfiguration

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Debugging.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Debugging.html index 66d65a74..df867e6e 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Debugging.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Debugging.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -386,9 +387,9 @@

    Debugging

  • @@ -401,15 +402,26 @@

    Debugging

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public final class VGSCollectLogger
    + +
    +
    +
  • @@ -421,15 +433,26 @@

    Debugging

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSLogLevel : String
    + +
    +
    +
  • @@ -441,6 +464,17 @@

    Debugging

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSCollectLoggingConfiguration
    + +
    +
    +
  • @@ -452,8 +486,8 @@

    Debugging

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enumerations.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enumerations.html index f4739984..80f007a4 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enumerations.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enumerations.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -386,9 +387,9 @@

    Enumerations

  • @@ -400,15 +401,26 @@

    Enumerations

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSCardExpDateFormat : InputConvertableFormat, OutputConvertableFormat
    + +
    +
    +
  • @@ -420,6 +432,17 @@

    Enumerations

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSCollectFieldNameMappingPolicy
    + +
    +
    +
  • @@ -431,8 +454,8 @@

    Enumerations

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/CheckSumAlgorithmType.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/CheckSumAlgorithmType.html index a8cda2bb..6cfd7bb5 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/CheckSumAlgorithmType.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/CheckSumAlgorithmType.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    CheckSumAlgorithmType

    +
    +
    + +
    public enum CheckSumAlgorithmType
    + +
    +

    Check Sum Algorithm Types

    +
    @@ -387,9 +398,9 @@

    CheckSumAlgorithmType

  • - + - luhn + luhn
    @@ -400,15 +411,26 @@

    CheckSumAlgorithmType

    Luhn Algorithm

    +
    +

    Declaration

    +
    +

    Swift

    +
    case luhn
    + +
    +
    +
  • @@ -419,6 +441,17 @@

    CheckSumAlgorithmType

    Validate input String with specified algorithm.

    +
    +

    Declaration

    +
    +

    Swift

    +
    func validate(_ input: String) -> Bool
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    CheckSumAlgorithmType

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/Environment.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/Environment.html index e7eed69c..d290ae67 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/Environment.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/Environment.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    Environment

    +
    +
    + +
    public enum Environment : String
    + +
    +

    Organization vault environment.

    +
    @@ -387,9 +398,9 @@

    Environment

  • - + - sandbox + sandbox
    @@ -400,15 +411,26 @@

    Environment

    Should be used for development and testing purpose.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case sandbox
    + +
    +
    +
  • - + - live + live
    @@ -419,6 +441,17 @@

    Environment

    Should be used for production.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case live
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    Environment

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/FieldType.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/FieldType.html index 2cb26f95..d9b4f112 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/FieldType.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/FieldType.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    FieldType

    +
    +
    + +
    public enum FieldType : Int, CaseIterable
    + +
    +

    Type of VGSTextField configuration.

    +
    @@ -387,9 +398,9 @@

    FieldType

  • - + - none + none
    @@ -400,15 +411,26 @@

    FieldType

    Field type that doesn’t require any input formatting and validation.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case none
    + +
    +
    +
  • @@ -419,15 +441,26 @@

    FieldType

    Field type that requires Credit Card Number input formatting and validation.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case cardNumber
    + +
    +
    +
  • - + - expDate + expDate
    @@ -438,15 +471,56 @@

    FieldType

    Field type that requires Expiration Date input formatting and validation.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case expDate
    + +
    +
    + + + +
  • +
  • +
    + + + + date + +
    +
    +
    +
    +
    +
    +

    Field type that requires Date input formatting and validation.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    case date
    + +
    +
    +
  • - + - cvc + cvc
    @@ -457,15 +531,26 @@

    FieldType

    Field type that requires Credit Card CVC input formatting and validation.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case cvc
    + +
    +
    +
  • @@ -476,15 +561,26 @@

    FieldType

    Field type that requires Cardholder Name input formatting and validation.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case cardHolderName
    + +
    +
    +
  • - + - ssn + ssn
    @@ -495,6 +591,17 @@

    FieldType

    Field type that requires US Social Security Number input formatting and validation.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case ssn
    + +
    +
    +
  • @@ -506,8 +613,8 @@

    FieldType

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSCardExpDateFormat.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSCardExpDateFormat.html index a31d68d0..76f4ff1b 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSCardExpDateFormat.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSCardExpDateFormat.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCardExpDateFormat

    +
    +
    + +
    public enum VGSCardExpDateFormat : InputConvertableFormat, OutputConvertableFormat
    + +
    +

    Payment Card Expiration Date Format

    +
    @@ -387,9 +398,9 @@

    VGSCardExpDateFormat

  • @@ -400,15 +411,26 @@

    VGSCardExpDateFormat

    Exp.Date in format mm/yy: 01/22

    +
    +

    Declaration

    +
    +

    Swift

    +
    case shortYear
    + +
    +
    +
  • - + - longYear + longYear
    @@ -419,15 +441,26 @@

    VGSCardExpDateFormat

    Exp.Date in format mm/yyyy: 01/2022

    +
    +

    Declaration

    +
    +

    Swift

    +
    case longYear
    + +
    +
    +
  • @@ -438,15 +471,26 @@

    VGSCardExpDateFormat

    Exp.Date in format yy/mm: 22/01

    +
    +

    Declaration

    +
    +

    Swift

    +
    case shortYearThenMonth
    + +
    +
    +
  • @@ -457,6 +501,17 @@

    VGSCardExpDateFormat

    Exp.Date in format yy/mm: 2022/01

    +
    +

    Declaration

    +
    +

    Swift

    +
    case longYearThenMonth
    + +
    +
    +
  • @@ -468,8 +523,8 @@

    VGSCardExpDateFormat

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSCollectFieldNameMappingPolicy.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSCollectFieldNameMappingPolicy.html index 023b91ca..7684b5e1 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSCollectFieldNameMappingPolicy.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSCollectFieldNameMappingPolicy.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCollectFieldNameMappingPolicy

    +
    +
    + +
    public enum VGSCollectFieldNameMappingPolicy
    + +
    +

    Defines fieldName mapping to JSON.

    +
    @@ -387,9 +398,9 @@

    VGSCollectFieldNameMappingPolicy

  • - + - flatJSON + flatJSON
    @@ -407,15 +418,26 @@

    VGSCollectFieldNameMappingPolicy

    +
    +

    Declaration

    +
    +

    Swift

    +
    case flatJSON
    + +
    +
    +
  • @@ -435,15 +457,26 @@

    VGSCollectFieldNameMappingPolicy

    +
    +

    Declaration

    +
    +

    Swift

    +
    case nestedJSON
    + +
    +
    +
  • @@ -485,15 +518,26 @@

    VGSCollectFieldNameMappingPolicy

    +
    +

    Declaration

    +
    +

    Swift

    +
    case nestedJSONWithArrayMerge
    + +
    +
    +
  • @@ -535,6 +579,17 @@

    VGSCollectFieldNameMappingPolicy

    +
    +

    Declaration

    +
    +

    Swift

    +
    case nestedJSONWithArrayOverwrite
    + +
    +
    +
  • @@ -546,8 +601,8 @@

    VGSCollectFieldNameMappingPolicy

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSCollectHTTPMethod.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSCollectHTTPMethod.html index ca2f66ee..e2a37d05 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSCollectHTTPMethod.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSCollectHTTPMethod.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCollectHTTPMethod

    +
    +
    + +
    public enum VGSCollectHTTPMethod : String
    + +
    +

    HTTP request methods

    +
    @@ -387,9 +398,9 @@

    VGSCollectHTTPMethod

  • - + - get + get
    @@ -400,15 +411,26 @@

    VGSCollectHTTPMethod

    GET method.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case get = "GET"
    + +
    +
    +
  • - + - post + post
    @@ -419,15 +441,26 @@

    VGSCollectHTTPMethod

    POST method.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case post = "POST"
    + +
    +
    +
  • - + - put + put
    @@ -438,15 +471,26 @@

    VGSCollectHTTPMethod

    PUT method.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case put = "PUT"
    + +
    +
    +
  • - + - patch + patch
    @@ -457,15 +501,26 @@

    VGSCollectHTTPMethod

    PATCH method.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case patch = "PATCH"
    + +
    +
    +
  • - + - delete + delete
    @@ -476,6 +531,17 @@

    VGSCollectHTTPMethod

    DELETE method.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case delete = "DELETE"
    + +
    +
    +
  • @@ -487,8 +553,8 @@

    VGSCollectHTTPMethod

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSDateFormat.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSDateFormat.html new file mode 100644 index 00000000..51c97f75 --- /dev/null +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSDateFormat.html @@ -0,0 +1,483 @@ + + + + VGSDateFormat Enumeration Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    VGSDateFormat

    +
    +
    + +
    public enum VGSDateFormat : InputConvertableFormat, OutputConvertableFormat
    + +
    +
    +

    Format used to validate a VGS date text input

    + + +
    +
    + +
    +
    +
    +
      +
    • +
      + + + + displayFormat + +
      +
      +
      +
      +
      +
      +

      Date format used for display in UI

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public var displayFormat: String { get }
      + +
      +
      + +
      +
      +
    • +
    +
    +
    +
    + + +
    + +

    Static properties and methods +

    +
    +
    +
      +
    • +
      + + + + default + +
      +
      +
      +
      +
      +
      +

      Default format

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public static let `default`: VGSDateFormat
      + +
      +
      + +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSErrorType.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSErrorType.html index 92812f55..abbde3d0 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSErrorType.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSErrorType.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSErrorType

    +
    +
    + +
    public enum VGSErrorType : Int
    + +
    +

    Type of VGSError and it status code.

    +
    @@ -396,9 +407,9 @@

    Text input data errors
  • @@ -409,6 +420,17 @@

    Text input data errors

    When input data is not valid, but required to be valid

    +
    +

    Declaration

    +
    +

    Swift

    +
    case inputDataIsNotValid = 1001
    + +
    +
    +
  • @@ -428,9 +450,9 @@

    Files data errors
  • @@ -441,15 +463,26 @@

    Files data errors

    When can’t find file on device

    +
    +

    Declaration

    +
    +

    Swift

    +
    case inputFileNotFound = 1101
    + +
    +
    +
  • @@ -460,15 +493,26 @@

    Files data errors

    When can’t find file on device

    +
    +

    Declaration

    +
    +

    Swift

    +
    case inputFileTypeIsNotSupported = 1102
    + +
    +
    +
  • @@ -479,15 +523,26 @@

    Files data errors

    When file size is larger then allowed limit

    +
    +

    Declaration

    +
    +

    Swift

    +
    case inputFileSizeExceedsTheLimit = 1103
    + +
    +
    +
  • @@ -498,6 +553,17 @@

    Files data errors

    When can’t get access to file source

    +
    +

    Declaration

    +
    +

    Swift

    +
    case sourceNotAvailable = 1150
    + +
    +
    +
  • @@ -517,9 +583,9 @@

    Other errors
  • @@ -530,15 +596,26 @@

    Other errors

    When response type is not supported

    +
    +

    Declaration

    +
    +

    Swift

    +
    case unexpectedResponseType = 1400
    + +
    +
    +
  • @@ -549,15 +626,26 @@

    Other errors

    When reponse data format is not supported

    +
    +

    Declaration

    +
    +

    Swift

    +
    case unexpectedResponseDataFormat = 1401
    + +
    +
    +
  • @@ -568,6 +656,17 @@

    Other errors

    When VGS config URL is not valid.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case invalidConfigurationURL = 1480
    + +
    +
    +
  • @@ -579,8 +678,8 @@

    Other errors

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSFileSource.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSFileSource.html index f84748ff..42ac711e 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSFileSource.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSFileSource.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSFileSource

    +
    +
    + +
    public enum VGSFileSource : Int, CaseIterable
    + +
    +

    Available file source destinations that VGSFilePickerController can work with.

    +
    @@ -387,9 +398,9 @@

    VGSFileSource

  • @@ -400,15 +411,26 @@

    VGSFileSource

    Device photo library.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case photoLibrary
    + +
    +
    +
  • - + - camera + camera
    @@ -419,15 +441,26 @@

    VGSFileSource

    Device camera.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case camera
    + +
    +
    +
  • @@ -438,6 +471,17 @@

    VGSFileSource

    Device documents directory.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case documentsDirectory
    + +
    +
    +
  • @@ -449,8 +493,8 @@

    VGSFileSource

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSLogLevel.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSLogLevel.html index 79ab4bf9..72fb8657 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSLogLevel.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSLogLevel.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSLogLevel

    +
    +
    + +
    public enum VGSLogLevel : String
    + +
    +

    Defines levels of logging.

    +
    @@ -387,9 +398,9 @@

    VGSLogLevel

  • - + - info + info
    @@ -400,15 +411,26 @@

    VGSLogLevel

    Log all events including errors and warnings.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case info
    + +
    +
    +
  • - + - warning + warning
    @@ -419,15 +441,26 @@

    VGSLogLevel

    Log only events indicating warnings and errors.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case warning
    + +
    +
    +
  • - + - none + none
    @@ -438,6 +471,17 @@

    VGSLogLevel

    Log no events.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case none
    + +
    +
    +
  • @@ -449,8 +493,8 @@

    VGSLogLevel

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSResponse.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSResponse.html index 528e5f85..62b5171a 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSResponse.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSResponse.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,19 @@

    VGSResponse

    +
    +
    + +
    @frozen
    +public enum VGSResponse
    + +
    +

    Response enum cases for SDK requests.

    +
    @@ -387,9 +399,9 @@

    VGSResponse

  • @@ -400,15 +412,69 @@

    VGSResponse

    Success response case

    +
    +

    Declaration

    +
    +

    Swift

    +
    case success(_: Int, _: Data?, _: URLResponse?)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + + + + + +
    + + code + + +
    +

    response status code.

    +
    +
    + + data + + +
    +

    response data object.

    +
    +
    + + response + + +
    +

    URLResponse object represents a URL load response.

    +
    +
    +
    +
  • @@ -419,6 +485,72 @@

    VGSResponse

    Failed response case

    +
    +

    Declaration

    +
    +

    Swift

    +
    case failure(_: Int, _: Data?, _: URLResponse?, _: Error?)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + + + + + + + + + +
    + + code + + +
    +

    response status code.

    +
    +
    + + data + + +
    +

    response Data object.

    +
    +
    + + response + + +
    +

    URLResponse object represents a URL load response.

    +
    +
    + + error + + +
    +

    Error object.

    +
    +
    +
    +
  • @@ -430,8 +562,8 @@

    VGSResponse

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSTextFieldInputSource.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSTextFieldInputSource.html index 609f6400..875f0444 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSTextFieldInputSource.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSTextFieldInputSource.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSTextFieldInputSource

    +
    +
    + +
    public enum VGSTextFieldInputSource
    + +
    +

    Type of VGSTextField input source.

    +
    @@ -387,9 +398,9 @@

    VGSTextFieldInputSource

  • - + - keyboard + keyboard
    @@ -400,15 +411,26 @@

    VGSTextFieldInputSource

    UIKeyboard input type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case keyboard
    + +
    +
    +
  • @@ -419,6 +441,17 @@

    VGSTextFieldInputSource

    UIDatePicker input type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case datePicker
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSTextFieldInputSource

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSTokenizationResponse.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSTokenizationResponse.html index 6498d32f..1bea722d 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSTokenizationResponse.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSTokenizationResponse.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,19 @@

    VGSTokenizationResponse

    +
    +
    + +
    @frozen
    +public enum VGSTokenizationResponse
    + +
    +

    Tokenization response enum cases for SDK requests.

    +
    @@ -387,9 +399,9 @@

    VGSTokenizationResponse

  • @@ -400,15 +412,69 @@

    VGSTokenizationResponse

    Success response case

    +
    +

    Declaration

    +
    +

    Swift

    +
    case success(_: Int, _: JsonData?, _: URLResponse?)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + + + + + +
    + + code + + +
    +

    response status code.

    +
    +
    + + body + + +
    +

    response JsonData object.

    +
    +
    + + response + + +
    +

    URLResponse object represents a URL load response.

    +
    +
    +
    +
  • @@ -419,6 +485,72 @@

    VGSTokenizationResponse

    Failed response case

    +
    +

    Declaration

    +
    +

    Swift

    +
    case failure(_: Int, _: Data?, _: URLResponse?, _: Error?)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + + + + + + + + + +
    + + code + + +
    +

    response status code.

    +
    +
    + + data + + +
    +

    response Data object.

    +
    +
    + + response + + +
    +

    URLResponse object represents a URL load response.

    +
    +
    + + error + + +
    +

    Error object.

    +
    +
    +
    +
  • @@ -430,8 +562,8 @@

    VGSTokenizationResponse

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSValidationErrorType.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSValidationErrorType.html index 4abb42b4..5b8d6143 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSValidationErrorType.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSValidationErrorType.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSValidationErrorType

    +
    +
    + +
    public enum VGSValidationErrorType : String
    + +
    +

    Default validation error types

    +
    @@ -387,9 +398,9 @@

    VGSValidationErrorType

  • - + - pattern + pattern
    @@ -400,15 +411,26 @@

    VGSValidationErrorType

    Default Validation error for VGSValidationRulePattern

    +
    +

    Declaration

    +
    +

    Swift

    +
    case pattern = "PATTERN_VALIDATION_ERROR"
    + +
    +
    +
  • - + - length + length
    @@ -419,15 +441,26 @@

    VGSValidationErrorType

    Default Validation error for VGSValidationRuleLength

    +
    +

    Declaration

    +
    +

    Swift

    +
    case length = "LENGTH_VALIDATION_ERROR"
    + +
    +
    +
  • @@ -438,15 +471,26 @@

    VGSValidationErrorType

    Default Validation error for VGSValidationRuleLength

    +
    +

    Declaration

    +
    +

    Swift

    +
    case lengthMathes = "LENGTH_RANGE_MATCH_VALIDATION_ERROR"
    + +
    +
    +
  • - + - expDate + expDate
    @@ -457,15 +501,56 @@

    VGSValidationErrorType

    Default Validation error for VGSValidationRuleCardExpirationDate

    +
    +

    Declaration

    +
    +

    Swift

    +
    case expDate = "EXPIRATION_DATE_VALIDATION_ERROR"
    + +
    +
    +
  • - + + + date + +
    +
    +
    +
    +
    +
    +

    Default Validation error for VGSValidationRuleDateRange

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    case date = "DATE_VALIDATION_ERROR"
    + +
    +
    + +
    +
    +
  • +
  • +
    @@ -476,15 +561,26 @@

    VGSValidationErrorType

    Default Validation error for VGSValidationRulePaymentCard

    +
    +

    Declaration

    +
    +

    Swift

    +
    case cardNumber = "CARD_NUMBER_VALIDATION_ERROR"
    + +
    +
    +
  • @@ -495,6 +591,17 @@

    VGSValidationErrorType

    Default Validation error for VGSValidationRuleLuhnCheck

    +
    +

    Declaration

    +
    +

    Swift

    +
    case luhnCheck = "LUHN_ALGORITHM_CHECK_VALIDATION_ERROR"
    + +
    +
    +
  • @@ -506,8 +613,8 @@

    VGSValidationErrorType

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSVaultAliasFormat.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSVaultAliasFormat.html index 01cd8f84..32beb7b5 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSVaultAliasFormat.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSVaultAliasFormat.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSVaultAliasFormat

    +
    +
    + +
    public enum VGSVaultAliasFormat : String
    + +
    +

    Type of Alias format. Read more about avaliable formats: https://www.verygoodsecurity.com/docs/terminology/nomenclature#alias-formats .

    +
    @@ -387,9 +398,9 @@

    VGSVaultAliasFormat

  • @@ -400,15 +411,26 @@

    VGSVaultAliasFormat

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    case FPE_ACC_NUM_T_FOUR = "FPE_ACC_NUM_T_FOUR"
    + +
    +
    +
  • @@ -419,15 +441,26 @@

    VGSVaultAliasFormat

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    case FPE_ALPHANUMERIC_ACC_NUM_T_FOUR = "FPE_ALPHANUMERIC_ACC_NUM_T_FOUR"
    + +
    +
    +
  • @@ -438,15 +471,26 @@

    VGSVaultAliasFormat

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    case FPE_SIX_T_FOUR = "FPE_SIX_T_FOUR"
    + +
    +
    +
  • @@ -457,15 +501,26 @@

    VGSVaultAliasFormat

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    case FPE_SSN_T_FOUR = "FPE_SSN_T_FOUR"
    + +
    +
    +
  • @@ -476,15 +531,26 @@

    VGSVaultAliasFormat

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    case FPE_T_FOUR = "FPE_T_FOUR"
    + +
    +
    +
  • @@ -495,15 +561,26 @@

    VGSVaultAliasFormat

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    case NUM_LENGTH_PRESERVING = "NUM_LENGTH_PRESERVING"
    + +
    +
    +
  • - + - PFPT + PFPT
    @@ -514,15 +591,26 @@

    VGSVaultAliasFormat

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    case PFPT = "PFPT"
    + +
    +
    +
  • - + - RAW_UUID + RAW_UUID
    @@ -533,15 +621,26 @@

    VGSVaultAliasFormat

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    case RAW_UUID = "RAW_UUID"
    + +
    +
    +
  • - + - UUID + UUID
    @@ -552,6 +651,17 @@

    VGSVaultAliasFormat

    no:doc

    +
    +

    Declaration

    +
    +

    Swift

    +
    case UUID = "UUID"
    + +
    +
    +
  • @@ -563,8 +673,8 @@

    VGSVaultAliasFormat

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSVaultStorageType.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSVaultStorageType.html index f47d96a7..be51033c 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSVaultStorageType.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Enums/VGSVaultStorageType.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSVaultStorageType

    +
    +
    + +
    public enum VGSVaultStorageType : String
    + +
    +

    Type of VGS Vault storage.

    +
    @@ -387,9 +398,9 @@

    VGSVaultStorageType

  • @@ -400,15 +411,26 @@

    VGSVaultStorageType

    PERSISTENT data storage.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case PERSISTENT = "PERSISTENT"
    + +
    +
    +
  • - + - VOLATILE + VOLATILE
    @@ -419,6 +441,17 @@

    VGSVaultStorageType

    VOLATILE data storage.

    +
    +

    Declaration

    +
    +

    Swift

    +
    case VOLATILE = "VOLATILE"
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSVaultStorageType

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Error Keys.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Error Keys.html index 06118376..4ff7dd1f 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Error Keys.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Error Keys.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -395,9 +396,9 @@

    Input data errors
  • @@ -408,20 +409,31 @@

    Input data errors

    Error key, used for errors when input data is required to be not empty or to be valid only, but is not valid.

    Note

    - VGSError with this error key can include VGSSDKErrorInputDataRequired and VGSSDKErrorInputDataRequiredValid error keys in userInfo dictionary. + VGSError with this error key can include VGSSDKErrorInputDataRequired and VGSSDKErrorInputDataRequiredValid error keys in userInfo dictionary.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let VGSSDKErrorInputDataIsNotValid: VGSErrorInfoKey
    + +
    +
    +
  • @@ -432,15 +444,26 @@

    Input data errors

    Error key, used for errors when input data is required to be not empty but is empty or nil.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let VGSSDKErrorInputDataRequired: VGSErrorInfoKey
    + +
    +
    +
  • @@ -451,6 +474,17 @@

    Input data errors

    Error key, used for errors when input data is required to be valid is not valid.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let VGSSDKErrorInputDataRequiredValid: VGSErrorInfoKey
    + +
    +
    +
  • @@ -470,9 +504,9 @@

    File data errors
  • @@ -483,15 +517,26 @@

    File data errors

    Error key, used for errors when SDK can’t find the file at file path. Can happened when file changes the path or doesn’t exist.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let VGSSDKErrorFileNotFound: VGSErrorInfoKey
    + +
    +
    +
  • @@ -502,15 +547,26 @@

    File data errors

    Error key, used for errors when file type is not supported by SDK.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let VGSSDKErrorFileTypeNotSupported: VGSErrorInfoKey
    + +
    +
    +
  • @@ -521,6 +577,17 @@

    File data errors

    Error key, used for errors when file size exceeds maximum limit.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let VGSSDKErrorFileSizeExceedsTheLimit: VGSErrorInfoKey
    + +
    +
    +
  • @@ -540,9 +607,9 @@

    Source errors
  • @@ -553,6 +620,17 @@

    Source errors

    Error key, used for errors when SDK can’t get access to specific source.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let VGSSDKErrorSourceNotAvailable: VGSErrorInfoKey
    + +
    +
    +
  • @@ -572,9 +650,9 @@

    Response errors
  • @@ -585,6 +663,17 @@

    Response errors

    Error key, used for errors when response for SDK API request is in format that not supported by SDK.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let VGSSDKErrorUnexpectedResponseDataFormat: VGSErrorInfoKey
    + +
    +
    +
  • @@ -596,8 +685,8 @@

    Response errors

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Errors.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Errors.html index fad443a8..e49e3a5c 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Errors.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Errors.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -386,9 +387,9 @@

    Errors

  • - + - VGSError + VGSError
    @@ -400,15 +401,26 @@

    Errors

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSError : NSError
    + +
    +
    +
  • @@ -420,15 +432,26 @@

    Errors

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSErrorType : Int
    + +
    +
    +
  • @@ -439,15 +462,26 @@

    Errors

    An error domain string used to produce VGSError from VGSCollectSDK - “vgscollect.sdk”

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let VGSCollectSDKErrorDomain: String
    + +
    +
    +
  • @@ -458,15 +492,26 @@

    Errors

    VGS Validation Error object type

    +
    +

    Declaration

    +
    +

    Swift

    +
    public typealias VGSValidationError = String
    + +
    +
    +
  • @@ -478,6 +523,17 @@

    Errors

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSValidationErrorType : String
    + +
    +
    +
  • @@ -489,8 +545,8 @@

    Errors

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/File Picker.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/File Picker.html index 925c0e9c..60e9539c 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/File Picker.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/File Picker.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -386,9 +387,9 @@

    File Picker

  • @@ -400,15 +401,26 @@

    File Picker

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSFilePickerController
    + +
    +
    +
  • @@ -420,15 +432,26 @@

    File Picker

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSFilePickerConfiguration : VGSFilePickerConfigurationProtocol
    + +
    +
    +
  • @@ -440,15 +463,27 @@

    File Picker

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    @objc
    +public protocol VGSFilePickerControllerDelegate
    + +
    +
    +
  • @@ -460,15 +495,26 @@

    File Picker

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSFileSource : Int, CaseIterable
    + +
    +
    +
  • @@ -480,6 +526,17 @@

    File Picker

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSFileInfo : NSObject, VGSFileInfoProtocol
    + +
    +
    +
  • @@ -491,8 +548,8 @@

    File Picker

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Observe State and Send Data.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Observe State and Send Data.html index 6220acac..fb390174 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Observe State and Send Data.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Observe State and Send Data.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -386,9 +387,9 @@

    Observe State and Send Data

  • @@ -400,15 +401,26 @@

    Observe State and Send Data

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSCollect
    + +
    +
    +
  • @@ -420,15 +432,26 @@

    Observe State and Send Data

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum Environment : String
    + +
    +
    +
  • - + - State + State
    @@ -440,15 +463,26 @@

    Observe State and Send Data

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class State
    + +
    +
    +
  • - + - SSNState + SSNState
    @@ -456,19 +490,30 @@

    Observe State and Send Data

    -

    An object that describes VGSTextField state with configuration FieldType.ssn . State attributes are read-only.

    +

    An object that describes VGSTextField state with configuration FieldType.ssn . State attributes are read-only.

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class SSNState : State
    + +
    +
    +
  • @@ -476,19 +521,62 @@

    Observe State and Send Data

    -

    An object that describes VGSTextField state with configuration FieldType.cardNumber . State attributes are read-only.

    +

    An object that describes VGSTextField state with configuration FieldType.cardNumber . State attributes are read-only.

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class CardState : State
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    A custom publisher that emits State of a given VGSTextField.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    @available(iOS 13, *)
    +public struct VGSTextFieldStatePublisher : Publisher
    + +
    +
    +
  • @@ -500,15 +588,59 @@

    Observe State and Send Data

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    @frozen
    +public enum VGSResponse
    + +
    +
    +
  • +
    +
    +
    +
    +
    +

    Tokenization response enum cases for SDK requests.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    @frozen
    +public enum VGSTokenizationResponse
    + +
    +
    + +
    +
    +
  • +
  • +
    @@ -520,15 +652,26 @@

    Observe State and Send Data

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSCollectRequestOptions
    + +
    +
    +
  • - + - JsonData + JsonData
    @@ -539,15 +682,57 @@

    Observe State and Send Data

    Key-value data type, usually used for response format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public typealias JsonData = [String : Any]
    + +
    +
    + + + +
  • +
  • +
    + + + + VGSCollectHTTPMethod + +
    +
    +
    +
    +
    +
    +

    HTTP request methods

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSCollectHTTPMethod : String
    + +
    +
    +
  • @@ -558,6 +743,17 @@

    Observe State and Send Data

    Key-value data type, used in http request headers.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public typealias HTTPHeaders = [String : String]
    + +
    +
    +
  • @@ -569,8 +765,8 @@

    Observe State and Send Data

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Classes.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Classes.html deleted file mode 100644 index 630a8cd7..00000000 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Classes.html +++ /dev/null @@ -1,519 +0,0 @@ - - - - Other Classes Reference - - - - - - - - - - - - - - - - -
    -

    - - VGSCollectSDK - - -

    - -
    -
    - -
    -
    - -

    - - GitHub - View on GitHub - -

    - -
    - - - -
    - -
    - -
    -
    -

    Other Classes

    -

    The following classes are available globally.

    - -
    -
    - -
    -
    -
    -
      -
    • - -
      -
      -
      -
      -
      -

      VGSCVCTokenizationConfiguration - textfield configuration for textfield with type .cvc, required for work with tokenization api.

      - - See more -
      -
      -
      -
    • -
    • - -
      -
      -
      -
      -
      -

      VGSCardHolderNameTokenizationConfiguration - textfield configuration for textfield with type .cardHolderName, required for work with tokenization api.

      - - See more -
      -
      -
      -
    • -
    • - -
      -
      -
      -
      -
      -

      VGSCardTokenizationConfiguration - textfield configuration for textfield with type .cardNumber, required for work with tokenization api.

      - - See more -
      -
      -
      -
    • -
    • - -
      -
      -
      -
      -
      -

      VGSExpDateTokenizationConfiguration - textfield configuration for textfield with type .expDate, required for work with tokenization api.

      - - See more -
      -
      -
      -
    • -
    • - -
      -
      -
      -
      -
      -

      VGSSSNTokenizationConfiguration - textfield configuration for textfield with type .ssn, required for work with tokenization api.

      - - See more -
      -
      -
      -
    • -
    • - -
      -
      -
      -
      -
      -

      VGSTokenizationConfiguration - textfield configuration for textfield with any type of data, required for work with tokenization api.

      - - See more -
      -
      -
      -
    • -
    -
    -
    -
    - -
    -
    - - - diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Enums.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Enums.html deleted file mode 100644 index 74c364fe..00000000 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Enums.html +++ /dev/null @@ -1,499 +0,0 @@ - - - - Other Enumerations Reference - - - - - - - - - - - - - - - - -
    -

    - - VGSCollectSDK - - -

    - -
    -
    - -
    -
    - -

    - - GitHub - View on GitHub - -

    - -
    - - - -
    - -
    - -
    -
    -

    Other Enumerations

    -

    The following enumerations are available globally.

    - -
    -
    - -
    -
    -
    - -
    -
    -
    - -
    -
    - - - diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Extensions.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Extensions.html deleted file mode 100644 index cba223eb..00000000 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Extensions.html +++ /dev/null @@ -1,466 +0,0 @@ - - - - Other Extensions Reference - - - - - - - - - - - - - - - - -
    -

    - - VGSCollectSDK - - -

    - -
    -
    - -
    -
    - -

    - - GitHub - View on GitHub - -

    - -
    - - - -
    - -
    - -
    -
    -

    Other Extensions

    -

    The following extensions are available globally.

    - -
    -
    - -
    -
    -
    - -
    -
    -
    - - -
    - -

    UITextFieldDelegate -

    -
    -
    - -
    -
    -
    - -
    -
    - - - diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Protocols.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Protocols.html deleted file mode 100644 index 142194bc..00000000 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Other Protocols.html +++ /dev/null @@ -1,439 +0,0 @@ - - - - Other Protocols Reference - - - - - - - - - - - - - - - - -
    -

    - - VGSCollectSDK - - -

    - -
    -
    - -
    -
    - -

    - - GitHub - View on GitHub - -

    - -
    - - - -
    - -
    - -
    -
    -

    Other Protocols

    -

    The following protocols are available globally.

    - -
    -
    - -
    -
    -
    - -
    -
    -
    - -
    -
    - - - diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Payment Cards.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Payment Cards.html index 313d9a50..5a70d9cc 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Payment Cards.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Payment Cards.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -386,9 +387,9 @@

    Payment Cards

  • @@ -406,15 +407,26 @@

    Payment Cards

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSPaymentCards
    + +
    +
    +
  • @@ -426,15 +438,26 @@

    Payment Cards

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSPaymentCardModel : VGSPaymentCardModelProtocol
    + +
    +
    +
  • @@ -446,15 +469,26 @@

    Payment Cards

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSCustomPaymentCardModel : VGSPaymentCardModelProtocol
    + +
    +
    +
  • @@ -462,10 +496,21 @@

    Payment Cards

    -

    An object representing Unknown Payment Cards - cards not defined in the SDK. Object is used when validation forCardBrand.unknown is set as true. Check VGSValidationRulePaymentCard for more details. Validation attributes can be edited through `VGSPaymentCards.unknown model.

    +

    An object representing Unknown Payment Cards - cards not defined in the SDK. Object is used when validation forCardBrand.unknown is set as true. Check VGSValidationRulePaymentCard for more details. Validation attributes can be edited through `VGSPaymentCards.unknown model.

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSUnknownPaymentCardModel
    + +
    +
    +
  • @@ -477,8 +522,8 @@

    Payment Cards

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSDateConfigurationProtocol.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSDateConfigurationProtocol.html new file mode 100644 index 00000000..60e86959 --- /dev/null +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSDateConfigurationProtocol.html @@ -0,0 +1,500 @@ + + + + VGSDateConfigurationProtocol Protocol Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    VGSDateConfigurationProtocol

    +
    +
    + +
    public protocol VGSDateConfigurationProtocol
    + +
    +
    +

    Define the methods and properties the date configuration must have

    + + +
    +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    + + + diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSExpDateConfigurationProtocol.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSExpDateConfigurationProtocol.html index 2236f29f..72e4aeae 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSExpDateConfigurationProtocol.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSExpDateConfigurationProtocol.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSExpDateConfigurationProtocol

    +
    +
    + +
    public protocol VGSExpDateConfigurationProtocol
    + +
    +

    Attributes required to configure date format and input source for field with type .expDate.

    +
    @@ -387,9 +398,9 @@

    VGSExpDateConfigurationProtocol

  • @@ -400,15 +411,26 @@

    VGSExpDateConfigurationProtocol

    Input Source type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    var inputSource: VGSTextFieldInputSource { get set }
    + +
    +
    +
  • @@ -419,15 +441,26 @@

    VGSExpDateConfigurationProtocol

    Input date format to convert.

    +
    +

    Declaration

    +
    +

    Swift

    +
    var inputDateFormat: VGSCardExpDateFormat? { get set }
    + +
    +
    +
  • @@ -438,6 +471,17 @@

    VGSExpDateConfigurationProtocol

    Output date format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    var outputDateFormat: VGSCardExpDateFormat? { get set }
    + +
    +
    +
  • @@ -449,8 +493,8 @@

    VGSExpDateConfigurationProtocol

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSFilePickerControllerDelegate.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSFilePickerControllerDelegate.html index 7df7f8ed..4ea61309 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSFilePickerControllerDelegate.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSFilePickerControllerDelegate.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,19 @@

    VGSFilePickerControllerDelegate

    +
    +
    + +
    @objc
    +public protocol VGSFilePickerControllerDelegate
    + +
    +

    Delegates produced by VGSFilePickerController.

    +
    @@ -396,9 +408,9 @@

    Handle user ineraction.
  • @@ -409,15 +421,26 @@

    Handle user ineraction.

    On user select a file

    +
    +

    Declaration

    +
    +

    Swift

    +
    func userDidPickFileWithInfo(_ info: VGSFileInfo)
    + +
    +
    +
  • @@ -428,15 +451,26 @@

    Handle user ineraction.

    On user canceling file picking

    +
    +

    Declaration

    +
    +

    Swift

    +
    func userDidSCancelFilePicking()
    + +
    +
    +
  • @@ -447,6 +481,17 @@

    Handle user ineraction.

    On error occured when user pick a file.

    +
    +

    Declaration

    +
    +

    Swift

    +
    func filePickingFailedWithError(_ error: VGSError)
    + +
    +
    +
  • @@ -458,8 +503,8 @@

    Handle user ineraction.

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSTextFieldDelegate.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSTextFieldDelegate.html index 13f26628..51f2a1c2 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSTextFieldDelegate.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSTextFieldDelegate.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,19 @@

    VGSTextFieldDelegate

    +
    +
    + +
    @objc
    +public protocol VGSTextFieldDelegate
    + +
    +

    Delegates produced by VGSTextField instance.

    +
    @@ -396,9 +408,9 @@

    Handle user ineraction with VGSTextField
  • @@ -409,15 +421,27 @@

    Handle user ineraction with VGSTextField

    VGSTextField did become first responder.

    +
    +

    Declaration

    +
    +

    Swift

    +
    @objc
    +optional func vgsTextFieldDidBeginEditing(_ textField: VGSTextField)
    + +
    +
    +
  • @@ -428,15 +452,27 @@

    Handle user ineraction with VGSTextField

    VGSTextField did resign first responder.

    +
    +

    Declaration

    +
    +

    Swift

    +
    @objc
    +optional func vgsTextFieldDidEndEditing(_ textField: VGSTextField)
    + +
    +
    +
  • @@ -447,15 +483,27 @@

    Handle user ineraction with VGSTextField

    VGSTextField did resign first responder on Return button pressed.

    +
    +

    Declaration

    +
    +

    Swift

    +
    @objc
    +optional func vgsTextFieldDidEndEditingOnReturn(_ textField: VGSTextField)
    + +
    +
    +
  • @@ -466,6 +514,18 @@

    Handle user ineraction with VGSTextField

    VGSTextField input changed.

    +
    +

    Declaration

    +
    +

    Swift

    +
    @objc
    +optional func vgsTextFieldDidChange(_ textField: VGSTextField)
    + +
    +
    +
  • @@ -477,8 +537,8 @@

    Handle user ineraction with VGSTextField

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSTokenizationParametersProtocol.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSTokenizationParametersProtocol.html index d6bc5746..a1c04ed7 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSTokenizationParametersProtocol.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Protocols/VGSTokenizationParametersProtocol.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSTokenizationParametersProtocol

    +
    +
    + +
    public protocol VGSTokenizationParametersProtocol
    + +
    +

    Parameters describing textfield input tokenization.

    +
    @@ -387,9 +398,9 @@

    VGSTokenizationParametersProtocol

  • - + - format + format
    @@ -400,15 +411,26 @@

    VGSTokenizationParametersProtocol

    Tokenization format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    var format: String { get }
    + +
    +
    +
  • - + - storage + storage
    @@ -419,6 +441,17 @@

    VGSTokenizationParametersProtocol

    Storage type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    var storage: String { get }
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSTokenizationParametersProtocol

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCVCTokenizationParameters.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCVCTokenizationParameters.html index d527dd7f..1e6f2e5b 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCVCTokenizationParameters.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCVCTokenizationParameters.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCVCTokenizationParameters

    +
    +
    + +
    public struct VGSCVCTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +

    VGSCVCTokenizationParameters - parameters required for tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSCVCTokenizationParameters

  • - + - storage + storage
    @@ -400,15 +411,26 @@

    VGSCVCTokenizationParameters

    Vault storage type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let storage: String
    + +
    +
    +
  • - + - format + format
    @@ -419,6 +441,17 @@

    VGSCVCTokenizationParameters

    Data alies format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var format: String
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSCVCTokenizationParameters

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCardHolderNameTokenizationParameters.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCardHolderNameTokenizationParameters.html index 403b021f..8db7af15 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCardHolderNameTokenizationParameters.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCardHolderNameTokenizationParameters.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCardHolderNameTokenizationParameters

    +
    +
    + +
    public struct VGSCardHolderNameTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +

    VGSCardHolderNameTokenizationParameters - parameters required for tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSCardHolderNameTokenizationParameters

  • - + - storage + storage
    @@ -400,15 +411,26 @@

    VGSCardHolderNameTokenizationParameters

    Vault storage type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var storage: String
    + +
    +
    +
  • - + - format + format
    @@ -419,6 +441,17 @@

    VGSCardHolderNameTokenizationParameters

    Data alies format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var format: String
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSCardHolderNameTokenizationParameters

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCardNumberTokenizationParameters.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCardNumberTokenizationParameters.html index cff52f20..c34a8669 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCardNumberTokenizationParameters.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCardNumberTokenizationParameters.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCardNumberTokenizationParameters

    +
    +
    + +
    public struct VGSCardNumberTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +

    VGSCardTokenizationParameters - parameters required for tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSCardNumberTokenizationParameters

  • - + - storage + storage
    @@ -400,15 +411,26 @@

    VGSCardNumberTokenizationParameters

    Vault storage type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let storage: String
    + +
    +
    +
  • - + - format + format
    @@ -419,6 +441,17 @@

    VGSCardNumberTokenizationParameters

    Data alies format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var format: String
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSCardNumberTokenizationParameters

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCollectLoggingConfiguration.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCollectLoggingConfiguration.html index 050ddaba..04ad1045 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCollectLoggingConfiguration.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCollectLoggingConfiguration.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCollectLoggingConfiguration

    +
    +
    + +
    public struct VGSCollectLoggingConfiguration
    + +
    +

    Holds configuration for VGSCollectSDK logging.

    +
    @@ -387,9 +398,9 @@

    VGSCollectLoggingConfiguration

  • - + - level + level
    @@ -400,15 +411,26 @@

    VGSCollectLoggingConfiguration

    Log level. Default is .none.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var level: VGSLogLevel
    + +
    +
    +
  • @@ -419,15 +441,26 @@

    VGSCollectLoggingConfiguration

    Bool flag. Specify true to record VGSCollectSDK network session with success/failed requests. Default is false.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var isNetworkDebugEnabled: Bool
    + +
    +
    +
  • @@ -438,6 +471,17 @@

    VGSCollectLoggingConfiguration

    Bool flag. Specify true to enable extensive debugging. Default is false.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var isExtensiveDebugEnabled: Bool
    + +
    +
    +
  • @@ -449,8 +493,8 @@

    VGSCollectLoggingConfiguration

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCollectRequestOptions.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCollectRequestOptions.html index 0ed8a197..a08bb8e7 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCollectRequestOptions.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCollectRequestOptions.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCollectRequestOptions

    +
    +
    + +
    public struct VGSCollectRequestOptions
    + +
    +

    Request options.

    +
    @@ -387,9 +398,9 @@

    VGSCollectRequestOptions

  • @@ -400,15 +411,26 @@

    VGSCollectRequestOptions

    Defines how to map fieldNames to JSON. Default is .nestedJSON.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var fieldNameMappingPolicy: VGSCollectFieldNameMappingPolicy
    + +
    +
    +
  • - + - init() + init()
    @@ -419,6 +441,17 @@

    VGSCollectRequestOptions

    Initializer.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public init()
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSCollectRequestOptions

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCustomPaymentCardModel.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCustomPaymentCardModel.html index 80934ec8..e4549362 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCustomPaymentCardModel.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSCustomPaymentCardModel.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSCustomPaymentCardModel

    +
    +
    + +
    public struct VGSCustomPaymentCardModel : VGSPaymentCardModelProtocol
    + +
    +

    Holds information for custom payment model.

    +
    @@ -387,9 +398,9 @@

    VGSCustomPaymentCardModel

  • - + - brand + brand
    @@ -400,15 +411,26 @@

    VGSCustomPaymentCardModel

    Payment Card Brand

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let brand: VGSPaymentCards.CardBrand
    + +
    +
    +
  • - + - name + name
    @@ -419,15 +441,26 @@

    VGSCustomPaymentCardModel

    Payment Card Name

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var name: String
    + +
    +
    +
  • - + - regex + regex
    @@ -438,15 +471,26 @@

    VGSCustomPaymentCardModel

    Regex Pattern required to detect Payment Card Brand

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var regex: String
    + +
    +
    +
  • @@ -457,15 +501,26 @@

    VGSCustomPaymentCardModel

    Valid Card Number Lengths

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cardNumberLengths: [Int]
    + +
    +
    +
  • @@ -476,15 +531,26 @@

    VGSCustomPaymentCardModel

    Valid Card CVC/CVV Lengths. For most brands valid cvc lengths is [3], while for Amex is [4]. For unknown brands can be set as [3, 4]

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcLengths: [Int]
    + +
    +
    +
  • @@ -492,8 +558,19 @@

    VGSCustomPaymentCardModel

    -

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    +

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public var checkSumAlgorithm: CheckSumAlgorithmType?
    +
    +
    +
    @@ -501,9 +578,9 @@

    VGSCustomPaymentCardModel

  • @@ -519,15 +596,26 @@

    VGSCustomPaymentCardModel

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var formatPattern: String
    + +
    +
    +
  • @@ -538,15 +626,26 @@

    VGSCustomPaymentCardModel

    Image, associated with Payment Card Brand.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var brandIcon: UIImage?
    + +
    +
    +
  • - + - cvcIcon + cvcIcon
    @@ -557,6 +656,17 @@

    VGSCustomPaymentCardModel

    Image, associated with CVC for Payment Card Brand.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcIcon: UIImage?
    + +
    +
    +
  • @@ -564,11 +674,11 @@

    VGSCustomPaymentCardModel

    - - + +
    - -

    Initialzation + +

    Initialization

    @@ -576,9 +686,9 @@

    Initialzation
  • @@ -589,6 +699,108 @@

    Initialzation

    Initializer.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(name: String, regex: String, formatPattern: String, cardNumberLengths: [Int], cvcLengths: [Int] = [3], checkSumAlgorithm: CheckSumAlgorithmType? = .luhn, brandIcon: UIImage?)
    + +
    +
    +
    +

    Parameters

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

    String object, payment card model name.

    +
    +
    + + regex + + +
    +

    String object, should be valid regex expression.

    +
    +
    + + formatPattern + + +
    +

    String object, should be valid format pattern.

    +
    +
    + + cardNumberLengths + + +
    +

    [Int] object, array of valid card number lengths.

    +
    +
    + + cvcLengths + + +
    +

    [Int] object, array of valid card number CVC. Default is [3].

    +
    +
    + + checkSumAlgorithm + + +
    +

    CheckSumAlgorithmType? object, should be valid checkSumAlgorithm object, default is .luhn.

    +
    +
    + + brandIcon + + +
    +

    UIImage?, card image icon.

    +
    +
    +
    +
  • @@ -600,8 +812,8 @@

    Initialzation

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSDate.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSDate.html new file mode 100644 index 00000000..df8c2856 --- /dev/null +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSDate.html @@ -0,0 +1,570 @@ + + + + VGSDate Structure Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    VGSDate

    +
    +
    + +
    public struct VGSDate
    +
    extension VGSDate: Comparable
    + +
    +
    +

    Struct that represents a date including year, month and day. It doesn’t include hours, minutes or seconds.

    + + +
    +
    + +
    +
    +
    +
    + + +
    + +

    Properties +

    +
    +
    +
      +
    • +
      + + + + dayFormatted + +
      +
      +
      +
      +
      +
      +

      Get the day formatted value, for example if the day is 1 it is returned as 01

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public var dayFormatted: String { get }
      + +
      +
      + +
      +
      +
    • +
    • +
      + + + + monthFormatted + +
      +
      +
      +
      +
      +
      +

      Get the month formatted value, for example if the month is 3 it is returned as 03

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public var monthFormatted: String { get }
      + +
      +
      + +
      +
      +
    • +
    +
    +
    +
    + + +
    + +

    Initialization +

    +
    +
    +
      +
    • +
      + + + + init(day:month:year:) + +
      +
      +
      +
      +
      +
      +

      Create a new instance of a VGSDate object, if the date is not valid, it returns nil

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public init?(day: Int, month: Int, year: Int)
      + +
      +
      +
      +

      Parameters

      + + + + + + + + + + + + + + + +
      + + day + + +
      +

      Int. Represents the day in the date.

      +
      +
      + + month + + +
      +

      Int. Represents the month in the date.

      +
      +
      + + year + + +
      +

      Int. Represents the year in the date.

      +
      +
      +
      +
      +

      Return Value

      +

      VGSDate, date reference or nil if the date is invalid.

      +
      + +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSDateTokenizationParameters.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSDateTokenizationParameters.html new file mode 100644 index 00000000..56d4f728 --- /dev/null +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSDateTokenizationParameters.html @@ -0,0 +1,470 @@ + + + + VGSDateTokenizationParameters Structure Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    VGSDateTokenizationParameters

    +
    +
    + +
    public struct VGSDateTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +
    +

    VGSDateTokenizationParameters - parameters required for tokenization API

    + + +
    +
    + +
    +
    +
    +
      +
    • +
      + + + + storage + +
      +
      +
      +
      +
      +
      +

      Vault storage type.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public var storage: String
      + +
      +
      + +
      +
      +
    • +
    • +
      + + + + format + +
      +
      +
      +
      +
      +
      +

      Data alies format.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public var format: String
      + +
      +
      + +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSExpDateSeparateSerializer.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSExpDateSeparateSerializer.html index a41fad83..ee67b387 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSExpDateSeparateSerializer.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSExpDateSeparateSerializer.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSExpDateSeparateSerializer

    +
    +
    + +
    public struct VGSExpDateSeparateSerializer : VGSFormatSerializerProtocol
    + +
    +

    Expiration Date Separate serializer, split date string to components with separate fieldNames

    +
    @@ -387,9 +398,9 @@

    VGSExpDateSeparateSerializer

  • @@ -400,15 +411,26 @@

    VGSExpDateSeparateSerializer

    Field Name that will be used as a JSON key with month value from expDate string on send request.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let monthFieldName: String
    + +
    +
    +
  • @@ -419,6 +441,17 @@

    VGSExpDateSeparateSerializer

    Field Name that will be used as a JSON key with year value from expDate string on send request.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let yearFieldName: String
    + +
    +
    +
  • @@ -438,9 +471,9 @@

    Initialization
  • @@ -451,6 +484,48 @@

    Initialization

    Initialization

    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(monthFieldName: String, yearFieldName: String)
    + +
    +
    +
    +

    Parameters

    + + + + + + + + + + + +
    + + monthFieldName + + +
    +

    key, that should be associated with month value in request JSON.

    +
    +
    + + yearFieldName + + +
    +

    key, that should be associated with year value in request JSON.

    +
    +
    +
    +
  • @@ -462,8 +537,8 @@

    Initialization

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSExpDateTokenizationParameters.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSExpDateTokenizationParameters.html index f96b3cb7..672659cb 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSExpDateTokenizationParameters.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSExpDateTokenizationParameters.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSExpDateTokenizationParameters

    +
    +
    + +
    public struct VGSExpDateTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +

    VGSExpDateTokenizationParameters - parameters required for tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSExpDateTokenizationParameters

  • - + - storage + storage
    @@ -400,15 +411,26 @@

    VGSExpDateTokenizationParameters

    Vault storage type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let storage: String
    + +
    +
    +
  • - + - format + format
    @@ -419,6 +441,17 @@

    VGSExpDateTokenizationParameters

    Data alies format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var format: String
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSExpDateTokenizationParameters

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSPaymentCardModel.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSPaymentCardModel.html index 268dec58..9d1a7551 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSPaymentCardModel.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSPaymentCardModel.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSPaymentCardModel

    +
    +
    + +
    public struct VGSPaymentCardModel : VGSPaymentCardModelProtocol
    + +
    +

    An object representing Payment Card

    +
    @@ -387,9 +398,9 @@

    VGSPaymentCardModel

  • - + - brand + brand
    @@ -400,15 +411,26 @@

    VGSPaymentCardModel

    Payment Card Brand

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let brand: VGSPaymentCards.CardBrand
    + +
    +
    +
  • - + - name + name
    @@ -419,15 +441,26 @@

    VGSPaymentCardModel

    Payment Card Name

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var name: String
    + +
    +
    +
  • - + - regex + regex
    @@ -438,15 +471,26 @@

    VGSPaymentCardModel

    Regex Pattern required to detect Payment Card Brand

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var regex: String
    + +
    +
    +
  • @@ -457,15 +501,26 @@

    VGSPaymentCardModel

    Valid Card Number Lengths

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cardNumberLengths: [Int]
    + +
    +
    +
  • @@ -476,15 +531,26 @@

    VGSPaymentCardModel

    Valid Card CVC/CVV Lengths. For most brands valid cvc lengths is [3], while for Amex is [4]. For unknown brands can be set as [3, 4]

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcLengths: [Int]
    + +
    +
    +
  • @@ -492,18 +558,29 @@

    VGSPaymentCardModel

    -

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    +

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var checkSumAlgorithm: CheckSumAlgorithmType?
    + +
    +
    +
  • @@ -519,15 +596,26 @@

    VGSPaymentCardModel

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var formatPattern: String
    + +
    +
    +
  • @@ -538,15 +626,26 @@

    VGSPaymentCardModel

    Image, associated with Payment Card Brand.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var brandIcon: UIImage?
    + +
    +
    +
  • - + - cvcIcon + cvcIcon
    @@ -557,6 +656,17 @@

    VGSPaymentCardModel

    Image, associated with CVC for Payment Card Brand.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcIcon: UIImage?
    + +
    +
    +
  • @@ -568,8 +678,8 @@

    VGSPaymentCardModel

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSSSNTokenizationParameters.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSSSNTokenizationParameters.html index cc70b31a..9a6a6b28 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSSSNTokenizationParameters.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSSSNTokenizationParameters.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSSSNTokenizationParameters

    +
    +
    + +
    public struct VGSSSNTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +

    VGSSSNTokenizationParameters - parameters required for tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSSSNTokenizationParameters

  • - + - storage + storage
    @@ -400,15 +411,26 @@

    VGSSSNTokenizationParameters

    Vault storage type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let storage: String
    + +
    +
    +
  • - + - format + format
    @@ -419,6 +441,17 @@

    VGSSSNTokenizationParameters

    Data alies format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var format: String
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSSSNTokenizationParameters

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSTextFieldStatePublisher.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSTextFieldStatePublisher.html new file mode 100644 index 00000000..3a1fd72d --- /dev/null +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSTextFieldStatePublisher.html @@ -0,0 +1,518 @@ + + + + VGSTextFieldStatePublisher Structure Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    VGSTextFieldStatePublisher

    +
    +
    + +
    @available(iOS 13, *)
    +public struct VGSTextFieldStatePublisher : Publisher
    + +
    +
    +

    A custom publisher that emits State of a given VGSTextField.

    + + +
    +
    + +
    +
    +
    +
      +
    • +
      + + + + Output + +
      +
      +
      +
      +
      +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public typealias Output = State
      + +
      +
      + +
      +
      +
    • +
    • +
      + + + + Failure + +
      +
      +
      +
      +
      +
      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public typealias Failure = Never
      + +
      +
      + +
      +
      +
    • +
    • +
      + + + + receive(subscriber:) + +
      +
      +
      +
      +
      +
      +

      Attaches a subscriber to the publisher to receive updates on the VGSTextField State.

      + +
      +
      +

      Declaration

      +
      +

      Swift

      +
      public func receive<S>(subscriber: S) where S : Subscriber, S.Failure == Never, S.Input == State
      + +
      +
      +
      +

      Parameters

      + + + + + + + +
      + + subscriber + + +
      +

      The subscriber that will receive state updates.

      +
      +
      +
      + +
      +
      +
    • +
    +
    +
    +
    + +
    +
    + + + diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSTokenizationParameters.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSTokenizationParameters.html index 04f1bdb0..dc3eeb5e 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSTokenizationParameters.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSTokenizationParameters.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSTokenizationParameters

    +
    +
    + +
    public struct VGSTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +

    VGSTokenizationParameters - parameters required for tokenization api.

    +
    @@ -387,9 +398,9 @@

    VGSTokenizationParameters

  • - + - storage + storage
    @@ -400,15 +411,26 @@

    VGSTokenizationParameters

    Vault storage type.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var storage: String
    + +
    +
    +
  • - + - format + format
    @@ -419,6 +441,17 @@

    VGSTokenizationParameters

    Data alies format.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var format: String
    + +
    +
    +
  • @@ -430,8 +463,8 @@

    VGSTokenizationParameters

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSUnknownPaymentCardModel.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSUnknownPaymentCardModel.html index be2ae0b0..24f1804b 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSUnknownPaymentCardModel.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSUnknownPaymentCardModel.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSUnknownPaymentCardModel

    -

    An object representing Unknown Payment Cards - cards not defined in the SDK. Object is used when validation forCardBrand.unknown is set as true. Check VGSValidationRulePaymentCard for more details. Validation attributes can be edited through `VGSPaymentCards.unknown model.

    +
    +
    + +
    public struct VGSUnknownPaymentCardModel
    + +
    +
    +

    An object representing Unknown Payment Cards - cards not defined in the SDK. Object is used when validation forCardBrand.unknown is set as true. Check VGSValidationRulePaymentCard for more details. Validation attributes can be edited through `VGSPaymentCards.unknown model.

    +
    @@ -387,9 +398,9 @@

    VGSUnknownPaymentCardModel

  • - + - regex + regex
    @@ -400,15 +411,26 @@

    VGSUnknownPaymentCardModel

    Regex validating that input contains digits only.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let regex: String
    + +
    +
    +
  • @@ -419,15 +441,26 @@

    VGSUnknownPaymentCardModel

    Valid Unknown Card Numbers Lengths

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cardNumberLengths: [Int]
    + +
    +
    +
  • @@ -438,15 +471,26 @@

    VGSUnknownPaymentCardModel

    Valid Unknown Card CVC/CVV Lengths. For most brands valid cvc lengths is [3], while for Amex is [4]. For unknown brands can be set as [3, 4]

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcLengths: [Int]
    + +
    +
    +
  • @@ -454,18 +498,29 @@

    VGSUnknownPaymentCardModel

    -

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    +

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var checkSumAlgorithm: CheckSumAlgorithmType?
    + +
    +
    +
  • @@ -476,15 +531,26 @@

    VGSUnknownPaymentCardModel

    Unknown Payment Card Numbers visual format pattern. NOTE: format pattern length limits input length.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var formatPattern: String
    + +
    +
    +
  • @@ -495,15 +561,26 @@

    VGSUnknownPaymentCardModel

    Image, associated with Unknown Payment Card Brands.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var brandIcon: UIImage?
    + +
    +
    +
  • - + - cvcIcon + cvcIcon
    @@ -514,6 +591,17 @@

    VGSUnknownPaymentCardModel

    Image, associated with CVC for Unknown Payment Card Brands.

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var cvcIcon: UIImage?
    + +
    +
    +
  • @@ -525,8 +613,8 @@

    VGSUnknownPaymentCardModel

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleCardExpirationDate.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleCardExpirationDate.html index 2711419a..0fa6b5ed 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleCardExpirationDate.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleCardExpirationDate.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSValidationRuleCardExpirationDate

    +
    +
    + +
    public struct VGSValidationRuleCardExpirationDate : VGSValidationRuleProtocol
    + +
    +

    Validate input in scope of matching card expiration date format and time range.

    +
    @@ -387,9 +398,9 @@

    VGSValidationRuleCardExpirationDate

  • @@ -400,15 +411,26 @@

    VGSValidationRuleCardExpirationDate

    Payment Card Expiration Date Format

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let dateFormat: VGSCardExpDateFormat
    + +
    +
    +
  • - + - error + error
    @@ -419,15 +441,26 @@

    VGSValidationRuleCardExpirationDate

    Validation Error

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let error: VGSValidationError
    + +
    +
    +
  • @@ -435,8 +468,50 @@

    VGSValidationRuleCardExpirationDate

    -

    Initialzation

    +

    Initialization

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(dateFormat: VGSCardExpDateFormat = .shortYear, error: VGSValidationError)
    +
    +
    +
    +

    Parameters

    + + + + + + + + + + + +
    + + error + + +
    +

    VGSValidationError - error on failed validation relust.

    +
    +
    + + dateFormat + + +
    +

    CardExpDateFormat date format

    +
    +
    +
    +
    @@ -449,8 +524,8 @@

    VGSValidationRuleCardExpirationDate

  • diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleDateRange.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleDateRange.html new file mode 100644 index 00000000..cb4498c4 --- /dev/null +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleDateRange.html @@ -0,0 +1,581 @@ + + + + VGSValidationRuleDateRange Structure Reference + + + + + + + + + + + + + + + + +
    +

    + + VGSCollectSDK + + +

    + +
    +
    + +
    +
    + +

    + + GitHub + View on GitHub + +

    + +
    + + + +
    + +
    + +
    +
    +

    VGSValidationRuleDateRange

    +
    +
    + +
    public struct VGSValidationRuleDateRange : VGSValidationRuleProtocol
    + +
    +
    +

    Validation rule used to validate the date input in objects +like VGSDateTextField, VGSTextField and VGSExpDateTextField

    + + +
    +
    + +
    +
    +
    +
    + + +
    + +

    Properties +

    +
    +
    + +
    +
    +
    + + +
    + +

    Constructor +

    +
    +
    + +
    +
    +
    + +
    +
    + + + diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleLength.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleLength.html index 2543a655..ecf7ccb0 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleLength.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleLength.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSValidationRuleLength

    +
    +
    + +
    public struct VGSValidationRuleLength : VGSValidationRuleProtocol
    + +
    +

    Validate input in scope of length.

    +
    @@ -387,9 +398,9 @@

    VGSValidationRuleLength

  • - + - min + min
    @@ -400,15 +411,26 @@

    VGSValidationRuleLength

    Min input length required

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let min: Int
    + +
    +
    +
  • - + - max + max
    @@ -419,15 +441,26 @@

    VGSValidationRuleLength

    Max input length required

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let max: Int
    + +
    +
    +
  • - + - error + error
    @@ -438,15 +471,26 @@

    VGSValidationRuleLength

    Validation Error

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let error: VGSValidationError
    + +
    +
    +
  • @@ -454,8 +498,62 @@

    VGSValidationRuleLength

    -

    Initialzation

    +

    Initialization

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(min: Int = 0, max: Int = Int.max, error: VGSValidationError)
    +
    +
    +
    +

    Parameters

    + + + + + + + + + + + + + + + +
    + + error + + +
    +

    VGSValidationError - error on failed validation relust.

    +
    +
    + + min + + +
    +

    min input length required

    +
    +
    + + max + + +
    +

    max input length required

    +
    +
    +
    +
    @@ -468,8 +566,8 @@

    VGSValidationRuleLength

  • diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleLengthMatch.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleLengthMatch.html index 448a4d75..23dae294 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleLengthMatch.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleLengthMatch.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSValidationRuleLengthMatch

    +
    +
    + +
    public struct VGSValidationRuleLengthMatch : VGSValidationRuleProtocol
    + +
    +

    Validate input in scope of multiple lengths, e.x.: [16, 19].

    +
    @@ -387,9 +398,9 @@

    VGSValidationRuleLengthMatch

  • - + - lengths + lengths
    @@ -400,15 +411,26 @@

    VGSValidationRuleLengthMatch

    Array of valid length ranges

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let lengths: [Int]
    + +
    +
    +
  • - + - error + error
    @@ -419,15 +441,26 @@

    VGSValidationRuleLengthMatch

    Validation Error

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let error: VGSValidationError
    + +
    +
    +
  • @@ -435,8 +468,50 @@

    VGSValidationRuleLengthMatch

    -

    Initialzation

    +

    Initialization

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(lengths: [Int], error: VGSValidationError)
    +
    +
    +
    +

    Parameters

    + + + + + + + + + + + +
    + + error + + +
    +

    VGSValidationError - error on failed validation relust.

    +
    +
    + + lengths + + +
    +

    array of valid lengths

    +
    +
    +
    +
    @@ -449,8 +524,8 @@

    VGSValidationRuleLengthMatch

  • diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleLuhnCheck.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleLuhnCheck.html index 52a5a0f7..8b17ac3b 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleLuhnCheck.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleLuhnCheck.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSValidationRuleLuhnCheck

    +
    +
    + +
    public struct VGSValidationRuleLuhnCheck : VGSValidationRuleProtocol
    + +
    +

    Validate input in scope of matching Luhn algorithm.

    +
    @@ -387,9 +398,9 @@

    VGSValidationRuleLuhnCheck

  • - + - error + error
    @@ -400,15 +411,26 @@

    VGSValidationRuleLuhnCheck

    Validation Error

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var error: VGSValidationError
    + +
    +
    +
  • @@ -416,8 +438,38 @@

    VGSValidationRuleLuhnCheck

    -

    Initialzation

    +

    Initialization

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(error: VGSValidationError)
    +
    +
    +
    +

    Parameters

    + + + + + + + +
    + + error + + +
    +

    VGSValidationError - error on failed validation relust.

    +
    +
    +
    +
    @@ -430,8 +482,8 @@

    VGSValidationRuleLuhnCheck

  • diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRulePattern.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRulePattern.html index 33ce9586..b5375946 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRulePattern.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRulePattern.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSValidationRulePattern

    +
    +
    + +
    public struct VGSValidationRulePattern : VGSValidationRuleProtocol
    + +
    +

    Validate input in scope of matching the pattern(regex).

    +
    @@ -387,9 +398,9 @@

    VGSValidationRulePattern

  • - + - pattern + pattern
    @@ -400,15 +411,26 @@

    VGSValidationRulePattern

    Regex pattern

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let pattern: String
    + +
    +
    +
  • - + - error + error
    @@ -419,15 +441,26 @@

    VGSValidationRulePattern

    Validation Error

    +
    +

    Declaration

    +
    +

    Swift

    +
    public let error: VGSValidationError
    + +
    +
    +
  • @@ -435,8 +468,50 @@

    VGSValidationRulePattern

    -

    Initialzation

    +

    Initialization

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(pattern: String, error: VGSValidationError)
    +
    +
    +
    +

    Parameters

    + + + + + + + + + + + +
    + + error + + +
    +

    VGSValidationError - error on failed validation relust.

    +
    +
    + + pattern + + +
    +

    regex pattern

    +
    +
    +
    +
    @@ -449,8 +524,8 @@

    VGSValidationRulePattern

  • diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRulePaymentCard.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRulePaymentCard.html index 4a6fe0d7..76caa9d0 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRulePaymentCard.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRulePaymentCard.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,10 +376,20 @@

    VGSValidationRulePaymentCard

    +
    +
    + +
    public struct VGSValidationRulePaymentCard : VGSValidationRuleProtocol
    + +
    +

    Validate input in scope of matching supported card brands, available lengths and checkSum algorithms. Supports optional validation of cards that are not defined in SDK - CardBrand.unknown. -To edit validation requirments for CardBrand.unknown cards in SDK, setup VGSPaymentCards.unknown model attributes.

    +To edit validation requirments for CardBrand.unknown cards in SDK, setup VGSPaymentCards.unknown model attributes.

    +
    @@ -389,9 +400,9 @@

    VGSValidationRulePaymentCard

  • - + - error + error
    @@ -402,15 +413,26 @@

    VGSValidationRulePaymentCard

    Validation Error

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var error: VGSValidationError
    + +
    +
    +
  • @@ -421,15 +443,26 @@

    VGSValidationRulePaymentCard

    Turn on/off validation of cards that are not defined in SDK - CardBrand.unknown

    +
    +

    Declaration

    +
    +

    Swift

    +
    public var validateUnknownCardBrand: Bool
    + +
    +
    +
  • @@ -437,18 +470,48 @@

    VGSValidationRulePaymentCard

    -

    Initialzation

    +

    Initialization

    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(error: VGSValidationError)
    + +
    +
    +
    +

    Parameters

    + + + + + + + +
    + + error + + +
    +

    VGSValidationError - error on failed validation relust.

    +
    +
    +
    +
  • @@ -456,8 +519,50 @@

    VGSValidationRulePaymentCard

    -

    Initialzation

    +

    Initialization

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(error: VGSValidationError, validateUnknownCardBrand: Bool)
    +
    +
    +
    +

    Parameters

    + + + + + + + + + + + +
    + + error + + +
    +

    VGSValidationError - error on failed validation relust.

    +
    +
    + + validateUnknownCardBrand + + +
    +

    flag that turn on/off validation CardBrand.unknowncards.

    +
    +
    +
    +
    @@ -470,8 +575,8 @@

    VGSValidationRulePaymentCard

  • diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleSet.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleSet.html index 0b69059c..ca4adc58 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleSet.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Structs/VGSValidationRuleSet.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -375,8 +376,18 @@

    VGSValidationRuleSet

    +
    +
    + +
    public struct VGSValidationRuleSet
    + +
    +

    Set of validation rules

    +
    @@ -387,9 +398,9 @@

    VGSValidationRuleSet

  • - + - init() + init()
    @@ -397,18 +408,29 @@

    VGSValidationRuleSet

    -

    Initialzation

    +

    Initialization

    +
    +

    Declaration

    +
    +

    Swift

    +
    public init()
    + +
    +
    +
  • @@ -416,8 +438,38 @@

    VGSValidationRuleSet

    -

    Initialzation

    +

    Initialization

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public init(rules: [VGSValidationRuleProtocol])
    +
    +
    +
    +

    Parameters

    + + + + + + + +
    + + rules + + +
    +

    array of validation rules

    +
    +
    +
    +
    @@ -425,9 +477,9 @@

    VGSValidationRuleSet

  • @@ -438,6 +490,17 @@

    VGSValidationRuleSet

    Add validation rule

    +
    +

    Declaration

    +
    +

    Swift

    +
    public mutating func add(rule: VGSValidationRuleProtocol)
    + +
    +
    +
  • @@ -449,8 +512,8 @@

    VGSValidationRuleSet

    diff --git a/docs/Other Structs.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Tokenization Parameters.html similarity index 56% rename from docs/Other Structs.html rename to docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Tokenization Parameters.html index 040a677b..686a5149 100644 --- a/docs/Other Structs.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Tokenization Parameters.html @@ -1,7 +1,7 @@ - Other Structures Reference + Tokenization Parameters Reference @@ -14,9 +14,9 @@ - + - +

    @@ -44,7 +44,7 @@

    @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    -

    Other Structures

    -

    The following structures are available globally.

    - +

    Tokenization Parameters

    +
    @@ -387,9 +387,40 @@

    Other Structures

  • +
    +
    +
    +
    +
    +

    Parameters describing textfield input tokenization.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public protocol VGSTokenizationParametersProtocol
    + +
    +
    + +
    +
    +
  • +
  • +
    @@ -401,15 +432,26 @@

    Other Structures

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSCVCTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +
    +
  • @@ -421,15 +463,26 @@

    Other Structures

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSCardHolderNameTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +
    +
  • @@ -441,15 +494,57 @@

    Other Structures

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSCardNumberTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +
    +
  • +
    +
    +
    +
    +
    +

    VGSDateTokenizationParameters - parameters required for tokenization API

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSDateTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +
    + +
    +
    +
  • +
  • +
    @@ -461,15 +556,26 @@

    Other Structures

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSExpDateTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +
    +
  • @@ -481,15 +587,26 @@

    Other Structures

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSSSNTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +
    +
  • @@ -501,6 +618,79 @@

    Other Structures

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSTokenizationParameters : VGSTokenizationParametersProtocol
    + +
    +
    + + + +
  • +
  • +
    + + + + VGSVaultAliasFormat + +
    +
    +
    +
    +
    +
    +

    Type of Alias format. Read more about avaliable formats: https://www.verygoodsecurity.com/docs/terminology/nomenclature#alias-formats .

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSVaultAliasFormat : String
    + +
    +
    + +
    +
    +
  • +
  • +
    + + + + VGSVaultStorageType + +
    +
    +
    +
    +
    +
    +

    Type of VGS Vault storage.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSVaultStorageType : String
    + +
    +
    +
  • @@ -512,8 +702,8 @@

    Other Structures

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/UI Elements.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/UI Elements.html index fc834e34..5c57cebe 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/UI Elements.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/UI Elements.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -386,9 +387,9 @@

    UI Elements

  • @@ -404,18 +405,23 @@

    UI Elements

    Declaration

    Swift

    - +
    public class VGSTextField : UIView
    +
    extension VGSTextField: UITextFieldDelegate
    +
    +
  • @@ -427,15 +433,26 @@

    Declaration

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public final class VGSCardTextField : VGSTextField
    + +
    +
    +
  • @@ -451,18 +468,55 @@

    Declaration

    Declaration

    Swift

    - +
    public final class VGSExpDateTextField : VGSTextField
    +
    extension VGSExpDateTextField: UIPickerViewDelegate, UIPickerViewDataSource
    + +
    +
    + + + +
  • +
  • +
    + + + + VGSDateTextField + +
    +
    +
    +
    +
    +
    +

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to show picker view with a Date. It support to define a range of valid dates to select from.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public final class VGSDateTextField : VGSTextField
    +
    extension VGSDateTextField: UIPickerViewDelegate, UIPickerViewDataSource
    +
    +
  • @@ -474,15 +528,26 @@

    Declaration

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public final class VGSCVCTextField : VGSTextField
    + +
    +
    +
  • @@ -494,15 +559,27 @@

    Declaration

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    @objc
    +public protocol VGSTextFieldDelegate
    + +
    +
    +
  • @@ -514,15 +591,26 @@

    Declaration

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSConfiguration : VGSTextFieldConfigurationProtocol
    + +
    +
    +
  • @@ -534,15 +622,26 @@

    Declaration

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public final class VGSExpDateConfiguration : VGSConfiguration, VGSExpDateConfigurationProtocol, VGSFormatSerializableProtocol
    + +
    +
    +
  • @@ -550,9 +649,425 @@

    Declaration

    -

    Type of VGSTextField configuration.

    +

    Class responsible for configuration VGSDateTextField or VGSTextField with fieldType = .date. Extends VGSConfiguration

    - See more + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public final class VGSDateConfiguration : VGSConfiguration, VGSDateConfigurationProtocol, VGSFormatSerializableProtocol
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    VGSCardHolderNameTokenizationConfiguration - textfield configuration for textfield with type .cardHolderName, required for work with tokenization api.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSCardHolderNameTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    VGSCardTokenizationConfiguration - textfield configuration for textfield with type .cardNumber, required for work with tokenization api.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSCardNumberTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    VGSCVCTokenizationConfiguration - textfield configuration for textfield with type .cvc, required for work with tokenization api.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSCVCTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    Class responsible for configuration VGSDateTextField or VGSTextField with fieldType = .date. +Extends VGSConfiguration. Required to work with tokenization API.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public final class VGSDateTokenizationConfiguration : VGSConfiguration, VGSDateConfigurationProtocol, VGSTextFieldTokenizationConfigurationProtocol, VGSFormatSerializableProtocol
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    VGSExpDateTokenizationConfiguration - textfield configuration for textfield with type .expDate, required for work with tokenization api.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public final class VGSExpDateTokenizationConfiguration : VGSConfiguration, VGSExpDateConfigurationProtocol, VGSTextFieldTokenizationConfigurationProtocol, VGSFormatSerializableProtocol
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    VGSSSNTokenizationConfiguration - textfield configuration for textfield with type .ssn, required for work with tokenization api.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSSSNTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    VGSTokenizationConfiguration - textfield configuration for textfield with any type of data, required for work with tokenization api.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class VGSTokenizationConfiguration : VGSConfiguration, VGSTextFieldTokenizationConfigurationProtocol
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    Define the methods and properties the date configuration must have

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public protocol VGSDateConfigurationProtocol
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    Attributes required to configure date format and input source for field with type .expDate.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public protocol VGSExpDateConfigurationProtocol
    + +
    +
    + +
    +
    +
  • +
  • +
    + + + + FieldType + +
    +
    +
    +
    +
    +
    +

    Type of VGSTextField configuration.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum FieldType : Int, CaseIterable
    + +
    +
    + +
    +
    +
  • +
  • +
    + + + + VGSDateFormat + +
    +
    +
    +
    +
    +
    +

    Format used to validate a VGS date text input

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSDateFormat : InputConvertableFormat, OutputConvertableFormat
    + +
    +
    + +
    +
    +
  • +
  • +
    + + + + VGSDate + +
    +
    +
    +
    +
    +
    +

    Struct that represents a date including year, month and day. It doesn’t include hours, minutes or seconds.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSDate
    +
    extension VGSDate: Comparable
    + +
    +
    + +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    Type of VGSTextField input source.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum VGSTextFieldInputSource
    + +
    +
    +
    @@ -565,8 +1080,8 @@

    Declaration

  • diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/VGSTextField Serializers.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/VGSTextField Serializers.html index 522748b2..2f191f73 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/VGSTextField Serializers.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/VGSTextField Serializers.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -386,9 +387,9 @@

    VGSTextField Serializers

  • @@ -399,15 +400,26 @@

    VGSTextField Serializers

    Base protocol describing Content Serialization attributes

    +
    +

    Declaration

    +
    +

    Swift

    +
    public protocol VGSFormatSerializerProtocol
    + +
    +
    +
  • @@ -419,6 +431,17 @@

    VGSTextField Serializers

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSExpDateSeparateSerializer : VGSFormatSerializerProtocol
    + +
    +
    +
  • @@ -430,8 +453,8 @@

    VGSTextField Serializers

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Validation Rules.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Validation Rules.html index f10e4e69..79a6c768 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Validation Rules.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/Validation Rules.html @@ -71,6 +71,12 @@ + + @@ -86,9 +92,83 @@ + + + + + + + + + + + + + + + + + + + @@ -167,7 +256,7 @@ VGSTextField Serializers - - - - -
    @@ -386,9 +387,9 @@

    Validation Rules

  • @@ -400,15 +401,26 @@

    Validation Rules

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSValidationRuleSet
    + +
    +
    +
  • @@ -420,15 +432,26 @@

    Validation Rules

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSValidationRuleLength : VGSValidationRuleProtocol
    + +
    +
    +
  • @@ -440,15 +463,26 @@

    Validation Rules

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSValidationRuleLengthMatch : VGSValidationRuleProtocol
    + +
    +
    +
  • @@ -460,15 +494,26 @@

    Validation Rules

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSValidationRulePattern : VGSValidationRuleProtocol
    + +
    +
    +
  • @@ -478,19 +523,30 @@

    Validation Rules

    Validate input in scope of matching supported card brands, available lengths and checkSum algorithms. Supports optional validation of cards that are not defined in SDK - CardBrand.unknown. -To edit validation requirments for CardBrand.unknown cards in SDK, setup VGSPaymentCards.unknown model attributes.

    +To edit validation requirments for CardBrand.unknown cards in SDK, setup VGSPaymentCards.unknown model attributes.

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSValidationRulePaymentCard : VGSValidationRuleProtocol
    + +
    +
    +
  • @@ -502,15 +558,26 @@

    Validation Rules

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSValidationRuleLuhnCheck : VGSValidationRuleProtocol
    + +
    +
    +
  • @@ -522,15 +589,58 @@

    Validation Rules

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSValidationRuleCardExpirationDate : VGSValidationRuleProtocol
    + +
    +
    +
  • +
    +
    +
    +
    +
    +

    Validation rule used to validate the date input in objects +like VGSDateTextField, VGSTextField and VGSExpDateTextField

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct VGSValidationRuleDateRange : VGSValidationRuleProtocol
    + +
    +
    + +
    +
    +
  • +
  • +
    @@ -542,6 +652,17 @@

    Validation Rules

    See more
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum CheckSumAlgorithmType
    + +
    +
    +
  • @@ -553,8 +674,8 @@

    Validation Rules

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/index.html b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/index.html index 8c23f145..d0943368 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/index.html +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/index.html @@ -70,6 +70,12 @@ + + @@ -85,9 +91,83 @@ + + + + + + + + + + + + + + + + + + + @@ -166,7 +255,7 @@ VGSTextField Serializers - - - - -
    @@ -380,7 +381,7 @@ Platform swift Cocoapods Compatible -

    +

    VGS Collect iOS SDK

    VGS Collect - is a product suite that allows customers to collect information securely without possession of it. VGSCollect iOS SDK allows you to securely collect data from your users via forms without having to have that data pass through your systems. The form fields behave like traditional input fields while securing access to the unsecured data.

    @@ -412,8 +413,8 @@

    Table of contents

    - VGS Collect iOS SDK State - VGS Collect iOS SDK Response + VGS Collect iOS SDK State + VGS Collect iOS SDK Response

    Before you start

    @@ -467,7 +468,7 @@

    Code example

    Customize VGSTextFields… - + @@ -505,7 +506,7 @@

    Code example

    … observe filed states - + @@ -583,14 +584,16 @@

    Integrate with Cocoapods

    Add ‘VGSCollectSDK’ alongside with one of scan modules pod:

    pod 'VGSCollectSDK'
     
    -# Add CardIO module to use Card.io as scan provider
    -pod 'VGSCollectSDK/CardIO' 
    +# Add one of available scan providers
    +pod 'VGSCollectSDK/CardIO'
    +pod 'VGSCollectSDK/BlinkCard'  
     

    Integrate with Swift Package Manager

    Starting with the 1.7.11 release, VGSCollectSDK supports CardIO integration via Swift PM.

    -

    To use CardIO add VGSCollectSDK, VGSCardIOCollector packages to your target.

    +

    To use CardIO add VGSCollectSDK, VGSCardIOCollector packages to your target. +To use BlinkCard add VGSCollectSDK, VGSBlinkCardCollector packages to your target.

    Code Example

    @@ -600,7 +603,7 @@

    Code Example

    - + - + @@ -824,6 +827,7 @@

    Dependencies

    License

    @@ -837,8 +841,8 @@

    License

    diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/js/jquery.min.js b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/js/jquery.min.js index c4c6022f..2c69bc90 100644 --- a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/js/jquery.min.js +++ b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/Documents/js/jquery.min.js @@ -1,2 +1,2 @@ -/*! jQuery v3.6.0 | (c) OpenJS 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=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},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&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,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.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(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(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&&e.namespaceURI,n=e&&(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},j=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 j(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||D,"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,D=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,"
    Setup VGSCardIOScanController…
    @@ -759,7 +762,7 @@

    Code Example

    }
    … send file to your Vault
    ","
    "],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 je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(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 _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.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(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.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,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===_t.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):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]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.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 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))&&v(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+" "]&&(!y||!y.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)&&ve(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(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[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 ye(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 ve(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(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=[],y=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||y.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||y.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||y.push(".#.+[+~]"),e.querySelectorAll("\\\f"),y.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&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.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)}),y=y.length&&new RegExp(y.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),v=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},j=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&&v(p,e)?-1:t==C||t.ownerDocument==p&&v(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))&&(!y||!y.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 j(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||D,"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,D=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),v.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",v.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",v.option=!!ce.lastChild;var ge={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ye(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 ve(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 je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(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"}),v.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||(v.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):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 B(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(v.pixelPosition,function(e,t){if(t)return t=Be(e,n),Pe.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 B(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 0Vault storage type.

    ","parent_name":"VGSTokenizationParameters"},"Structs/VGSTokenizationParameters.html#/format":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSTokenizationParameters"},"Structs/VGSSSNTokenizationParameters.html#/storage":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSSSNTokenizationParameters"},"Structs/VGSSSNTokenizationParameters.html#/format":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSSSNTokenizationParameters"},"Structs/VGSExpDateTokenizationParameters.html#/storage":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSExpDateTokenizationParameters"},"Structs/VGSExpDateTokenizationParameters.html#/format":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSExpDateTokenizationParameters"},"Structs/VGSCardNumberTokenizationParameters.html#/storage":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSCardNumberTokenizationParameters"},"Structs/VGSCardNumberTokenizationParameters.html#/format":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSCardNumberTokenizationParameters"},"Structs/VGSCardHolderNameTokenizationParameters.html#/storage":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSCardHolderNameTokenizationParameters"},"Structs/VGSCardHolderNameTokenizationParameters.html#/format":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSCardHolderNameTokenizationParameters"},"Structs/VGSCVCTokenizationParameters.html#/storage":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSCVCTokenizationParameters"},"Structs/VGSCVCTokenizationParameters.html#/format":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSCVCTokenizationParameters"},"Structs/VGSCVCTokenizationParameters.html":{"name":"VGSCVCTokenizationParameters","abstract":"

    VGSCVCTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSCardHolderNameTokenizationParameters.html":{"name":"VGSCardHolderNameTokenizationParameters","abstract":"

    VGSCardHolderNameTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSCardNumberTokenizationParameters.html":{"name":"VGSCardNumberTokenizationParameters","abstract":"

    VGSCardTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSExpDateTokenizationParameters.html":{"name":"VGSExpDateTokenizationParameters","abstract":"

    VGSExpDateTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSSSNTokenizationParameters.html":{"name":"VGSSSNTokenizationParameters","abstract":"

    VGSSSNTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSTokenizationParameters.html":{"name":"VGSTokenizationParameters","abstract":"

    VGSTokenizationParameters - parameters required for tokenization api.

    "},"Protocols/VGSExpDateConfigurationProtocol.html#/inputSource":{"name":"inputSource","abstract":"

    Input Source type.

    ","parent_name":"VGSExpDateConfigurationProtocol"},"Protocols/VGSExpDateConfigurationProtocol.html#/inputDateFormat":{"name":"inputDateFormat","abstract":"

    Input date format to convert.

    ","parent_name":"VGSExpDateConfigurationProtocol"},"Protocols/VGSExpDateConfigurationProtocol.html#/outputDateFormat":{"name":"outputDateFormat","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateConfigurationProtocol"},"Protocols/VGSTokenizationParametersProtocol.html#/format":{"name":"format","abstract":"

    Tokenization format.

    ","parent_name":"VGSTokenizationParametersProtocol"},"Protocols/VGSTokenizationParametersProtocol.html#/storage":{"name":"storage","abstract":"

    Storage type.

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

    Parameters describing textfield input tokenization.

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

    Attributes required to configure date format and input source for field with type .expDate.

    "},"Other%20Extensions.html#/VGSDocumentPicker":{"name":"VGSDocumentPicker"},"Other%20Extensions.html#/VGSImagePicker":{"name":"VGSImagePicker"},"Other%20Extensions.html#/MaskedTextField":{"name":"MaskedTextField"},"Enums/VGSVaultAliasFormat.html#/FPE_ACC_NUM_T_FOUR":{"name":"FPE_ACC_NUM_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/FPE_ALPHANUMERIC_ACC_NUM_T_FOUR":{"name":"FPE_ALPHANUMERIC_ACC_NUM_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/FPE_SIX_T_FOUR":{"name":"FPE_SIX_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/FPE_SSN_T_FOUR":{"name":"FPE_SSN_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/FPE_T_FOUR":{"name":"FPE_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/NUM_LENGTH_PRESERVING":{"name":"NUM_LENGTH_PRESERVING","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/PFPT":{"name":"PFPT","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/RAW_UUID":{"name":"RAW_UUID","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/UUID":{"name":"UUID","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultStorageType.html#/PERSISTENT":{"name":"PERSISTENT","abstract":"

    PERSISTENT data storage.

    ","parent_name":"VGSVaultStorageType"},"Enums/VGSVaultStorageType.html#/VOLATILE":{"name":"VOLATILE","abstract":"

    VOLATILE data storage.

    ","parent_name":"VGSVaultStorageType"},"Enums/VGSTextFieldInputSource.html#/keyboard":{"name":"keyboard","abstract":"

    UIKeyboard input type.

    ","parent_name":"VGSTextFieldInputSource"},"Enums/VGSTextFieldInputSource.html#/datePicker":{"name":"datePicker","abstract":"

    UIDatePicker input type.

    ","parent_name":"VGSTextFieldInputSource"},"Enums/VGSTokenizationResponse.html#/success(_:_:_:)":{"name":"success(_:_:_:)","abstract":"

    Success response case

    ","parent_name":"VGSTokenizationResponse"},"Enums/VGSTokenizationResponse.html#/failure(_:_:_:_:)":{"name":"failure(_:_:_:_:)","abstract":"

    Failed response case

    ","parent_name":"VGSTokenizationResponse"},"Enums/VGSCollectHTTPMethod.html#/get":{"name":"get","abstract":"

    GET method.

    ","parent_name":"VGSCollectHTTPMethod"},"Enums/VGSCollectHTTPMethod.html#/post":{"name":"post","abstract":"

    POST method.

    ","parent_name":"VGSCollectHTTPMethod"},"Enums/VGSCollectHTTPMethod.html#/put":{"name":"put","abstract":"

    PUT method.

    ","parent_name":"VGSCollectHTTPMethod"},"Enums/VGSCollectHTTPMethod.html#/patch":{"name":"patch","abstract":"

    PATCH method.

    ","parent_name":"VGSCollectHTTPMethod"},"Enums/VGSCollectHTTPMethod.html#/delete":{"name":"delete","abstract":"

    DELETE method.

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

    HTTP request methods

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

    Tokenization response enum cases for SDK requests.

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

    Type of VGSTextField input source.

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

    Type of VGS Vault storage.

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

    Type of Alias format. Read more about avaliable formats: https://www.verygoodsecurity.com/docs/terminology/nomenclature#alias-formats .

    "},"Classes/VGSTokenizationConfiguration.html#/tokenizationParameters":{"name":"tokenizationParameters","abstract":"

    VGSTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSTokenizationConfiguration"},"Classes/VGSSSNTokenizationConfiguration.html#/tokenizationParameters":{"name":"tokenizationParameters","abstract":"

    VGSSSNTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSSSNTokenizationConfiguration"},"Classes/VGSSSNTokenizationConfiguration.html#/type":{"name":"type","abstract":"

    FieldType.ssn type of VGSTextFieldtokenization configuration.

    ","parent_name":"VGSSSNTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/type":{"name":"type","abstract":"

    FieldType.expDate type of VGSTextFieldtokenization configuration.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/inputSource":{"name":"inputSource","abstract":"

    Input Source type. Default is VGSTextFieldInputSource.datePicker.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/inputDateFormat":{"name":"inputDateFormat","abstract":"

    Input date format to convert.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/outputDateFormat":{"name":"outputDateFormat","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/tokenizationParameters":{"name":"tokenizationParameters","abstract":"

    VGSExpDateTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/serializers":{"name":"serializers","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSCardNumberTokenizationConfiguration.html#/tokenizationParameters":{"name":"tokenizationParameters","abstract":"

    VGSCardTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSCardNumberTokenizationConfiguration"},"Classes/VGSCardNumberTokenizationConfiguration.html#/type":{"name":"type","abstract":"

    FieldType.cardNumber type of VGSTextFieldtokenization configuration.

    ","parent_name":"VGSCardNumberTokenizationConfiguration"},"Classes/VGSCardHolderNameTokenizationConfiguration.html#/tokenizationParameters":{"name":"tokenizationParameters","abstract":"

    VGSCardHolderNameTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSCardHolderNameTokenizationConfiguration"},"Classes/VGSCardHolderNameTokenizationConfiguration.html#/type":{"name":"type","abstract":"

    FieldType.cardHolderName type of VGSTextFieldtokenization configuration.

    ","parent_name":"VGSCardHolderNameTokenizationConfiguration"},"Classes/VGSCVCTokenizationConfiguration.html#/tokenizationParameters":{"name":"tokenizationParameters","abstract":"

    VGSCVCTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSCVCTokenizationConfiguration"},"Classes/VGSCVCTokenizationConfiguration.html#/type":{"name":"type","abstract":"

    FieldType.cvc type of VGSTextFieldtokenization configuration.

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

    VGSCVCTokenizationConfiguration - textfield configuration for textfield with type .cvc, required for work with tokenization api.

    "},"Classes/VGSCardHolderNameTokenizationConfiguration.html":{"name":"VGSCardHolderNameTokenizationConfiguration","abstract":"

    VGSCardHolderNameTokenizationConfiguration - textfield configuration for textfield with type .cardHolderName, required for work with tokenization api.

    "},"Classes/VGSCardNumberTokenizationConfiguration.html":{"name":"VGSCardNumberTokenizationConfiguration","abstract":"

    VGSCardTokenizationConfiguration - textfield configuration for textfield with type .cardNumber, required for work with tokenization api.

    "},"Classes/VGSExpDateTokenizationConfiguration.html":{"name":"VGSExpDateTokenizationConfiguration","abstract":"

    VGSExpDateTokenizationConfiguration - textfield configuration for textfield with type .expDate, required for work with tokenization api.

    "},"Classes/VGSSSNTokenizationConfiguration.html":{"name":"VGSSSNTokenizationConfiguration","abstract":"

    VGSSSNTokenizationConfiguration - textfield configuration for textfield with type .ssn, required for work with tokenization api.

    "},"Classes/VGSTokenizationConfiguration.html":{"name":"VGSTokenizationConfiguration","abstract":"

    VGSTokenizationConfiguration - textfield configuration for textfield with any type of data, required for work with tokenization api.

    "},"Enums/VGSCollectFieldNameMappingPolicy.html#/flatJSON":{"name":"flatJSON","abstract":"

    Map fieldName to JSON without applying any transformations.","parent_name":"VGSCollectFieldNameMappingPolicy"},"Enums/VGSCollectFieldNameMappingPolicy.html#/nestedJSON":{"name":"nestedJSON","abstract":"

    Map fieldName to nested JSON.","parent_name":"VGSCollectFieldNameMappingPolicy"},"Enums/VGSCollectFieldNameMappingPolicy.html#/nestedJSONWithArrayMerge":{"name":"nestedJSONWithArrayMerge","abstract":"

    Map field name to nested JSON and array if array index is specified.","parent_name":"VGSCollectFieldNameMappingPolicy"},"Enums/VGSCollectFieldNameMappingPolicy.html#/nestedJSONWithArrayOverwrite":{"name":"nestedJSONWithArrayOverwrite","abstract":"

    Map field name to nested JSON and array if array index is specified.","parent_name":"VGSCollectFieldNameMappingPolicy"},"Enums/VGSCardExpDateFormat.html#/shortYear":{"name":"shortYear","abstract":"

    Exp.Date in format mm/yy: 01/22

    ","parent_name":"VGSCardExpDateFormat"},"Enums/VGSCardExpDateFormat.html#/longYear":{"name":"longYear","abstract":"

    Exp.Date in format mm/yyyy: 01/2022

    ","parent_name":"VGSCardExpDateFormat"},"Enums/VGSCardExpDateFormat.html#/shortYearThenMonth":{"name":"shortYearThenMonth","abstract":"

    Exp.Date in format yy/mm: 22/01

    ","parent_name":"VGSCardExpDateFormat"},"Enums/VGSCardExpDateFormat.html#/longYearThenMonth":{"name":"longYearThenMonth","abstract":"

    Exp.Date in format yy/mm: 2022/01

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

    Payment Card Expiration Date Format

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

    Defines fieldName mapping to JSON.

    "},"Structs/VGSCollectLoggingConfiguration.html#/level":{"name":"level","abstract":"

    Log level. Default is .none.

    ","parent_name":"VGSCollectLoggingConfiguration"},"Structs/VGSCollectLoggingConfiguration.html#/isNetworkDebugEnabled":{"name":"isNetworkDebugEnabled","abstract":"

    Bool flag. Specify true to record VGSCollectSDK network session with success/failed requests. Default is false.

    ","parent_name":"VGSCollectLoggingConfiguration"},"Structs/VGSCollectLoggingConfiguration.html#/isExtensiveDebugEnabled":{"name":"isExtensiveDebugEnabled","abstract":"

    Bool flag. Specify true to enable extensive debugging. Default is false.

    ","parent_name":"VGSCollectLoggingConfiguration"},"Enums/VGSLogLevel.html#/info":{"name":"info","abstract":"

    Log all events including errors and warnings.

    ","parent_name":"VGSLogLevel"},"Enums/VGSLogLevel.html#/warning":{"name":"warning","abstract":"

    Log only events indicating warnings and errors.

    ","parent_name":"VGSLogLevel"},"Enums/VGSLogLevel.html#/none":{"name":"none","abstract":"

    Log no events.

    ","parent_name":"VGSLogLevel"},"Classes/VGSCollectLogger.html#/shared":{"name":"shared","abstract":"

    Shared instance.

    ","parent_name":"VGSCollectLogger"},"Classes/VGSCollectLogger.html#/configuration":{"name":"configuration","abstract":"

    Logging configuration. Check VGSCollectLoggingConfiguration for logging options.

    ","parent_name":"VGSCollectLogger"},"Classes/VGSCollectLogger.html#/disableAllLoggers()":{"name":"disableAllLoggers()","abstract":"

    Stop logging all activities.

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

    VGSCollectLogger encapsulates logging logic and debugging options for VGSCollectSDK. Use .configuration property to setup these options. VGSCollectLogger logging implies only printing logs to Xcode console. It doesn’t save logs to persistent store/local file, also it doesn’t send debugging logs to backend services."},"Enums/VGSLogLevel.html":{"name":"VGSLogLevel","abstract":"

    Defines levels of logging.

    "},"Structs/VGSCollectLoggingConfiguration.html":{"name":"VGSCollectLoggingConfiguration","abstract":"

    Holds configuration for VGSCollectSDK logging.

    "},"Error%20Keys.html#/VGSSDKErrorInputDataIsNotValid":{"name":"VGSSDKErrorInputDataIsNotValid","abstract":"

    Error key, used for errors when input data is required to be not empty or to be valid only, but is not valid.

    "},"Error%20Keys.html#/VGSSDKErrorInputDataRequired":{"name":"VGSSDKErrorInputDataRequired","abstract":"

    Error key, used for errors when input data is required to be not empty but is empty or nil.

    "},"Error%20Keys.html#/VGSSDKErrorInputDataRequiredValid":{"name":"VGSSDKErrorInputDataRequiredValid","abstract":"

    Error key, used for errors when input data is required to be valid is not valid.

    "},"Error%20Keys.html#/VGSSDKErrorFileNotFound":{"name":"VGSSDKErrorFileNotFound","abstract":"

    Error key, used for errors when SDK can’t find the file at file path. Can happened when file changes the path or doesn’t exist.

    "},"Error%20Keys.html#/VGSSDKErrorFileTypeNotSupported":{"name":"VGSSDKErrorFileTypeNotSupported","abstract":"

    Error key, used for errors when file type is not supported by SDK.

    "},"Error%20Keys.html#/VGSSDKErrorFileSizeExceedsTheLimit":{"name":"VGSSDKErrorFileSizeExceedsTheLimit","abstract":"

    Error key, used for errors when file size exceeds maximum limit.

    "},"Error%20Keys.html#/VGSSDKErrorSourceNotAvailable":{"name":"VGSSDKErrorSourceNotAvailable","abstract":"

    Error key, used for errors when SDK can’t get access to specific source.

    "},"Error%20Keys.html#/VGSSDKErrorUnexpectedResponseDataFormat":{"name":"VGSSDKErrorUnexpectedResponseDataFormat","abstract":"

    Error key, used for errors when response for SDK API request is in format that not supported by SDK.

    "},"Enums/VGSValidationErrorType.html#/pattern":{"name":"pattern","abstract":"

    Default Validation error for VGSValidationRulePattern

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/length":{"name":"length","abstract":"

    Default Validation error for VGSValidationRuleLength

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/lengthMathes":{"name":"lengthMathes","abstract":"

    Default Validation error for VGSValidationRuleLength

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/expDate":{"name":"expDate","abstract":"

    Default Validation error for VGSValidationRuleCardExpirationDate

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/cardNumber":{"name":"cardNumber","abstract":"

    Default Validation error for VGSValidationRulePaymentCard

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/luhnCheck":{"name":"luhnCheck","abstract":"

    Default Validation error for VGSValidationRuleLuhnCheck

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSErrorType.html#/inputDataIsNotValid":{"name":"inputDataIsNotValid","abstract":"

    When input data is not valid, but required to be valid

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/inputFileNotFound":{"name":"inputFileNotFound","abstract":"

    When can’t find file on device

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/inputFileTypeIsNotSupported":{"name":"inputFileTypeIsNotSupported","abstract":"

    When can’t find file on device

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/inputFileSizeExceedsTheLimit":{"name":"inputFileSizeExceedsTheLimit","abstract":"

    When file size is larger then allowed limit

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/sourceNotAvailable":{"name":"sourceNotAvailable","abstract":"

    When can’t get access to file source

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/unexpectedResponseType":{"name":"unexpectedResponseType","abstract":"

    When response type is not supported

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/unexpectedResponseDataFormat":{"name":"unexpectedResponseDataFormat","abstract":"

    When reponse data format is not supported

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/invalidConfigurationURL":{"name":"invalidConfigurationURL","abstract":"

    When VGS config URL is not valid.

    ","parent_name":"VGSErrorType"},"Classes/VGSError.html#/type":{"name":"type","abstract":"

    VGSErrorType- required for each VGSError instance

    ","parent_name":"VGSError"},"Classes/VGSError.html#/code":{"name":"code","abstract":"

    Code assiciated with VGSErrorType

    ","parent_name":"VGSError"},"Classes/VGSError.html#/init(coder:)":{"name":"init(coder:)","abstract":"

    : nodoc. Public required init.

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

    An error produced by VGSCollectSDK. Works similar to default NSError in iOS.

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

    Type of VGSError and it status code.

    "},"Errors.html#/VGSCollectSDKErrorDomain":{"name":"VGSCollectSDKErrorDomain","abstract":"

    An error domain string used to produce VGSError from VGSCollectSDK - “vgscollect.sdk”

    "},"Errors.html#/VGSValidationError":{"name":"VGSValidationError","abstract":"

    VGS Validation Error object type

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

    Default validation error types

    "},"Enums/CheckSumAlgorithmType.html#/luhn":{"name":"luhn","abstract":"

    Luhn Algorithm

    ","parent_name":"CheckSumAlgorithmType"},"Enums/CheckSumAlgorithmType.html#/validate(_:)":{"name":"validate(_:)","abstract":"

    Validate input String with specified algorithm.

    ","parent_name":"CheckSumAlgorithmType"},"Structs/VGSValidationRuleCardExpirationDate.html#/dateFormat":{"name":"dateFormat","abstract":"

    Payment Card Expiration Date Format

    ","parent_name":"VGSValidationRuleCardExpirationDate"},"Structs/VGSValidationRuleCardExpirationDate.html#/error":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRuleCardExpirationDate"},"Structs/VGSValidationRuleCardExpirationDate.html#/init(dateFormat:error:)":{"name":"init(dateFormat:error:)","abstract":"

    Initialzation

    ","parent_name":"VGSValidationRuleCardExpirationDate"},"Structs/VGSValidationRuleLuhnCheck.html#/error":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRuleLuhnCheck"},"Structs/VGSValidationRuleLuhnCheck.html#/init(error:)":{"name":"init(error:)","abstract":"

    Initialzation

    ","parent_name":"VGSValidationRuleLuhnCheck"},"Structs/VGSValidationRulePaymentCard.html#/error":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRulePaymentCard"},"Structs/VGSValidationRulePaymentCard.html#/validateUnknownCardBrand":{"name":"validateUnknownCardBrand","abstract":"

    Turn on/off validation of cards that are not defined in SDK - CardBrand.unknown

    ","parent_name":"VGSValidationRulePaymentCard"},"Structs/VGSValidationRulePaymentCard.html#/init(error:)":{"name":"init(error:)","abstract":"

    Initialzation

    ","parent_name":"VGSValidationRulePaymentCard"},"Structs/VGSValidationRulePaymentCard.html#/init(error:validateUnknownCardBrand:)":{"name":"init(error:validateUnknownCardBrand:)","abstract":"

    Initialzation

    ","parent_name":"VGSValidationRulePaymentCard"},"Structs/VGSValidationRulePattern.html#/pattern":{"name":"pattern","abstract":"

    Regex pattern

    ","parent_name":"VGSValidationRulePattern"},"Structs/VGSValidationRulePattern.html#/error":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRulePattern"},"Structs/VGSValidationRulePattern.html#/init(pattern:error:)":{"name":"init(pattern:error:)","abstract":"

    Initialzation

    ","parent_name":"VGSValidationRulePattern"},"Structs/VGSValidationRuleLengthMatch.html#/lengths":{"name":"lengths","abstract":"

    Array of valid length ranges

    ","parent_name":"VGSValidationRuleLengthMatch"},"Structs/VGSValidationRuleLengthMatch.html#/error":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRuleLengthMatch"},"Structs/VGSValidationRuleLengthMatch.html#/init(lengths:error:)":{"name":"init(lengths:error:)","abstract":"

    Initialzation

    ","parent_name":"VGSValidationRuleLengthMatch"},"Structs/VGSValidationRuleLength.html#/min":{"name":"min","abstract":"

    Min input length required

    ","parent_name":"VGSValidationRuleLength"},"Structs/VGSValidationRuleLength.html#/max":{"name":"max","abstract":"

    Max input length required

    ","parent_name":"VGSValidationRuleLength"},"Structs/VGSValidationRuleLength.html#/error":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRuleLength"},"Structs/VGSValidationRuleLength.html#/init(min:max:error:)":{"name":"init(min:max:error:)","abstract":"

    Initialzation

    ","parent_name":"VGSValidationRuleLength"},"Structs/VGSValidationRuleSet.html#/init()":{"name":"init()","abstract":"

    Initialzation

    ","parent_name":"VGSValidationRuleSet"},"Structs/VGSValidationRuleSet.html#/init(rules:)":{"name":"init(rules:)","abstract":"

    Initialzation

    ","parent_name":"VGSValidationRuleSet"},"Structs/VGSValidationRuleSet.html#/add(rule:)":{"name":"add(rule:)","abstract":"

    Add validation rule

    ","parent_name":"VGSValidationRuleSet"},"Structs/VGSValidationRuleSet.html":{"name":"VGSValidationRuleSet","abstract":"

    Set of validation rules

    "},"Structs/VGSValidationRuleLength.html":{"name":"VGSValidationRuleLength","abstract":"

    Validate input in scope of length.

    "},"Structs/VGSValidationRuleLengthMatch.html":{"name":"VGSValidationRuleLengthMatch","abstract":"

    Validate input in scope of multiple lengths, e.x.: [16, 19].

    "},"Structs/VGSValidationRulePattern.html":{"name":"VGSValidationRulePattern","abstract":"

    Validate input in scope of matching the pattern(regex).

    "},"Structs/VGSValidationRulePaymentCard.html":{"name":"VGSValidationRulePaymentCard","abstract":"

    Validate input in scope of matching supported card brands, available lengths and checkSum algorithms."},"Structs/VGSValidationRuleLuhnCheck.html":{"name":"VGSValidationRuleLuhnCheck","abstract":"

    Validate input in scope of matching Luhn algorithm.

    "},"Structs/VGSValidationRuleCardExpirationDate.html":{"name":"VGSValidationRuleCardExpirationDate","abstract":"

    Validate input in scope of matching card expiration date format and time range.

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

    Check Sum Algorithm Types

    "},"Structs/VGSExpDateSeparateSerializer.html#/monthFieldName":{"name":"monthFieldName","abstract":"

    Field Name that will be used as a JSON key with month value from expDate string on send request.

    ","parent_name":"VGSExpDateSeparateSerializer"},"Structs/VGSExpDateSeparateSerializer.html#/yearFieldName":{"name":"yearFieldName","abstract":"

    Field Name that will be used as a JSON key with year value from expDate string on send request.

    ","parent_name":"VGSExpDateSeparateSerializer"},"Structs/VGSExpDateSeparateSerializer.html#/init(monthFieldName:yearFieldName:)":{"name":"init(monthFieldName:yearFieldName:)","abstract":"

    Initialization

    ","parent_name":"VGSExpDateSeparateSerializer"},"VGSTextField%20Serializers.html#/VGSFormatSerializerProtocol":{"name":"VGSFormatSerializerProtocol","abstract":"

    Base protocol describing Content Serialization attributes

    "},"Structs/VGSExpDateSeparateSerializer.html":{"name":"VGSExpDateSeparateSerializer","abstract":"

    Expiration Date Separate serializer, split date string to components with separate fieldNames

    "},"Structs/VGSUnknownPaymentCardModel.html#/regex":{"name":"regex","abstract":"

    Regex validating that input contains digits only.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/cardNumberLengths":{"name":"cardNumberLengths","abstract":"

    Valid Unknown Card Numbers Lengths

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/cvcLengths":{"name":"cvcLengths","abstract":"

    Valid Unknown Card CVC/CVV Lengths. For most brands valid cvc lengths is [3], while for Amex is [4]. For unknown brands can be set as [3, 4]

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/checkSumAlgorithm":{"name":"checkSumAlgorithm","abstract":"

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/formatPattern":{"name":"formatPattern","abstract":"

    Unknown Payment Card Numbers visual format pattern. NOTE: format pattern length limits input length.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/brandIcon":{"name":"brandIcon","abstract":"

    Image, associated with Unknown Payment Card Brands.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/cvcIcon":{"name":"cvcIcon","abstract":"

    Image, associated with CVC for Unknown Payment Card Brands.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/brand":{"name":"brand","abstract":"

    Payment Card Brand

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/name":{"name":"name","abstract":"

    Payment Card Name

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/regex":{"name":"regex","abstract":"

    Regex Pattern required to detect Payment Card Brand

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/cardNumberLengths":{"name":"cardNumberLengths","abstract":"

    Valid Card Number Lengths

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/cvcLengths":{"name":"cvcLengths","abstract":"

    Valid Card CVC/CVV Lengths. For most brands valid cvc lengths is [3], while for Amex is [4]. For unknown brands can be set as [3, 4]

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/checkSumAlgorithm":{"name":"checkSumAlgorithm","abstract":"

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/formatPattern":{"name":"formatPattern","abstract":"

    Payment Card Number visual format pattern.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/brandIcon":{"name":"brandIcon","abstract":"

    Image, associated with Payment Card Brand.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/cvcIcon":{"name":"cvcIcon","abstract":"

    Image, associated with CVC for Payment Card Brand.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/init(name:regex:formatPattern:cardNumberLengths:cvcLengths:checkSumAlgorithm:brandIcon:)":{"name":"init(name:regex:formatPattern:cardNumberLengths:cvcLengths:checkSumAlgorithm:brandIcon:)","abstract":"

    Initializer.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/brand":{"name":"brand","abstract":"

    Payment Card Brand

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/name":{"name":"name","abstract":"

    Payment Card Name

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/regex":{"name":"regex","abstract":"

    Regex Pattern required to detect Payment Card Brand

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/cardNumberLengths":{"name":"cardNumberLengths","abstract":"

    Valid Card Number Lengths

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/cvcLengths":{"name":"cvcLengths","abstract":"

    Valid Card CVC/CVV Lengths. For most brands valid cvc lengths is [3], while for Amex is [4]. For unknown brands can be set as [3, 4]

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/checkSumAlgorithm":{"name":"checkSumAlgorithm","abstract":"

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/formatPattern":{"name":"formatPattern","abstract":"

    Payment Card Number visual format pattern.

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/brandIcon":{"name":"brandIcon","abstract":"

    Image, associated with Payment Card Brand.

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/cvcIcon":{"name":"cvcIcon","abstract":"

    Image, associated with CVC for Payment Card Brand.

    ","parent_name":"VGSPaymentCardModel"},"Classes/VGSPaymentCards/CardBrand.html#/elo":{"name":"elo","abstract":"

    ELO

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/visaElectron":{"name":"visaElectron","abstract":"

    Visa Electron

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/maestro":{"name":"maestro","abstract":"

    Maestro

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/forbrugsforeningen":{"name":"forbrugsforeningen","abstract":"

    Forbrugsforeningen

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/dankort":{"name":"dankort","abstract":"

    Dankort

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/visa":{"name":"visa","abstract":"

    Visa

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/mastercard":{"name":"mastercard","abstract":"

    Mastercard

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/amex":{"name":"amex","abstract":"

    American Express

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/hipercard":{"name":"hipercard","abstract":"

    Hipercard

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/dinersClub":{"name":"dinersClub","abstract":"

    Diners Club

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/discover":{"name":"discover","abstract":"

    Discover

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/unionpay":{"name":"unionpay","abstract":"

    UnionPay

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/jcb":{"name":"jcb","abstract":"

    JCB

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/unknown":{"name":"unknown","abstract":"

    Not supported card brand - “unknown”

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/custom(brandName:)":{"name":"custom(brandName:)","abstract":"

    Custom Payment Card Brand. Should have unique brandName.

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/cvcFormatPattern":{"name":"cvcFormatPattern","abstract":"

    no:doc

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/brandIcon":{"name":"brandIcon","abstract":"

    no:doc

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/cvcIcon":{"name":"cvcIcon","abstract":"

    no:doc

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/stringValue":{"name":"stringValue","abstract":"

    String representation of VGSPaymentCards.CardBrand enum values.

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/cardLengths":{"name":"cardLengths","abstract":"

    Returns array with valid card number lengths for specific VGSPaymentCards.CardBrand

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html":{"name":"CardBrand","abstract":"

    Supported card brands

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/elo":{"name":"elo","abstract":"

    Elo Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/visaElectron":{"name":"visaElectron","abstract":"

    Visa Electron Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/maestro":{"name":"maestro","abstract":"

    Maestro Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/forbrugsforeningen":{"name":"forbrugsforeningen","abstract":"

    Forbrugsforeningen Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/dankort":{"name":"dankort","abstract":"

    Dankort Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/visa":{"name":"visa","abstract":"

    Elo Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/masterCard":{"name":"masterCard","abstract":"

    Master Card Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/amex":{"name":"amex","abstract":"

    Amex Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/hipercard":{"name":"hipercard","abstract":"

    Hipercard Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/dinersClub":{"name":"dinersClub","abstract":"

    DinersClub Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/discover":{"name":"discover","abstract":"

    Discover Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/unionpay":{"name":"unionpay","abstract":"

    UnionPay Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/jcb":{"name":"jcb","abstract":"

    JCB Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/unknown":{"name":"unknown","abstract":"

    Unknown Brand Payment Card Model. Can be used for specifing cards details when VGSValidationRulePaymentCard requires validating CardBrand.unknown cards.

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/cutomPaymentCardModels":{"name":"cutomPaymentCardModels","abstract":"

    Array of Custom Payment Card Models.

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/validCardBrands":{"name":"validCardBrands","abstract":"

    An array of valid Card Brands, could include custom and default brands. If not set, will use availableCardBrands array instead.

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/getCardModelFromAvailableModels(brand:)":{"name":"getCardModelFromAvailableModels(brand:)","abstract":"

    no:doc

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/detectCardBrandFromAvailableCards(input:)":{"name":"detectCardBrandFromAvailableCards(input:)","abstract":"

    no:doc

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

    Class responsible for storing and managing Payment Cards in SDK.

    "},"Structs/VGSPaymentCardModel.html":{"name":"VGSPaymentCardModel","abstract":"

    An object representing Payment Card

    "},"Structs/VGSCustomPaymentCardModel.html":{"name":"VGSCustomPaymentCardModel","abstract":"

    Holds information for custom payment model.

    "},"Structs/VGSUnknownPaymentCardModel.html":{"name":"VGSUnknownPaymentCardModel","abstract":"

    An object representing Unknown Payment Cards - cards not defined in the SDK. Object is used when validation forCardBrand.unknown is set as true. Check VGSValidationRulePaymentCard for more details. Validation attributes can be edited through `VGSPaymentCards.unknown model.

    "},"Structs/VGSCollectRequestOptions.html#/fieldNameMappingPolicy":{"name":"fieldNameMappingPolicy","abstract":"

    Defines how to map fieldNames to JSON. Default is .nestedJSON.

    ","parent_name":"VGSCollectRequestOptions"},"Structs/VGSCollectRequestOptions.html#/init()":{"name":"init()","abstract":"

    Initializer.

    ","parent_name":"VGSCollectRequestOptions"},"Enums/VGSResponse.html#/success(_:_:_:)":{"name":"success(_:_:_:)","abstract":"

    Success response case

    ","parent_name":"VGSResponse"},"Enums/VGSResponse.html#/failure(_:_:_:_:)":{"name":"failure(_:_:_:_:)","abstract":"

    Failed response case

    ","parent_name":"VGSResponse"},"Classes/CardState.html#/last4":{"name":"last4","abstract":"

    Last 4 digits of the valid card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    ","parent_name":"CardState"},"Classes/CardState.html#/bin":{"name":"bin","abstract":"

    Bin digits of the valid card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    ","parent_name":"CardState"},"Classes/CardState.html#/cardBrand":{"name":"cardBrand","abstract":"

    Credit Card Brand of the card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    ","parent_name":"CardState"},"Classes/CardState.html#/description":{"name":"description","abstract":"

    Message that contains CardState attributes and their values.

    ","parent_name":"CardState"},"Classes/SSNState.html#/last4":{"name":"last4","abstract":"

    Last 4 digits of the valid ssn from associated VGSTextField with field configuration type FieldType.ssn.

    ","parent_name":"SSNState"},"Classes/SSNState.html#/description":{"name":"description","abstract":"

    Message that contains SSNState attributes and their values.

    ","parent_name":"SSNState"},"Classes/State.html#/fieldName":{"name":"fieldName","abstract":"

    VGSConfiguration.fieldName associated with VGSTextField

    ","parent_name":"State"},"Classes/State.html#/isRequired":{"name":"isRequired","abstract":"

    VGSConfiguration.isRequired attribute defined for VGSTextField

    ","parent_name":"State"},"Classes/State.html#/isRequiredValidOnly":{"name":"isRequiredValidOnly","abstract":"

    VGSConfiguration.isRequiredValidOnly attribute defined for VGSTextField

    ","parent_name":"State"},"Classes/State.html#/isValid":{"name":"isValid","abstract":"

    Contains current validation state for VGSTextField

    ","parent_name":"State"},"Classes/State.html#/isEmpty":{"name":"isEmpty","abstract":"

    Show if VGSTextField input is empty

    ","parent_name":"State"},"Classes/State.html#/isDirty":{"name":"isDirty","abstract":"

    Show if VGSTextField was edited

    ","parent_name":"State"},"Classes/State.html#/inputLength":{"name":"inputLength","abstract":"

    Input data length in VGSTextField

    ","parent_name":"State"},"Classes/State.html#/validationErrors":{"name":"validationErrors","abstract":"

    Array of VGSValidationError. Should be empty when textfield input is valid.

    ","parent_name":"State"},"Classes/State.html#/description":{"name":"description","abstract":"

    Message that contains State attributes and their values

    ","parent_name":"State"},"Enums/Environment.html#/sandbox":{"name":"sandbox","abstract":"

    Should be used for development and testing purpose.

    ","parent_name":"Environment"},"Enums/Environment.html#/live":{"name":"live","abstract":"

    Should be used for production.

    ","parent_name":"Environment"},"Classes/VGSCollect.html#/customHeaders":{"name":"customHeaders","abstract":"

    Set your custom HTTP headers.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/observeFieldState":{"name":"observeFieldState","abstract":"

    Observe only focused VGSTextField on editing events.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/observeStates":{"name":"observeStates","abstract":"

    Observe all VGSTextField on editing events.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/textFields":{"name":"textFields","abstract":"

    Returns array of VGSTextFields associated with VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/init(id:environment:hostname:satellitePort:)":{"name":"init(id:environment:hostname:satellitePort:)","abstract":"

    Initialzation.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/init(id:environment:dataRegion:hostname:satellitePort:)":{"name":"init(id:environment:dataRegion:hostname:satellitePort:)","abstract":"

    Initialzation.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/getTextField(fieldName:)":{"name":"getTextField(fieldName:)","abstract":"

    Returns VGSTextField with VGSConfiguration.fieldName associated with VGCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/unsubscribeTextField(_:)":{"name":"unsubscribeTextField(_:)","abstract":"

    Unasubscribe VGSTextField from VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/unsubscribeTextFields(_:)":{"name":"unsubscribeTextFields(_:)","abstract":"

    Unasubscribe VGSTextFields from VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/unsubscribeAllTextFields()":{"name":"unsubscribeAllTextFields()","abstract":"

    Unasubscribe all VGSTextFields from VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/cleanFiles()":{"name":"cleanFiles()","abstract":"

    Detach files for associated VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/sendData(path:method:routeId:extraData:requestOptions:completion:)":{"name":"sendData(path:method:routeId:extraData:requestOptions:completion:)","abstract":"

    Send data from VGSTextFields to your organization vault.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/sendFile(path:method:routeId:extraData:completion:)":{"name":"sendFile(path:method:routeId:extraData:completion:)","abstract":"

    Send file to your organization vault. Only send one file at a time.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/tokenizeData(routeId:completion:)":{"name":"tokenizeData(routeId:completion:)","abstract":"

    Makes tokenization response with data from VGSTextFields.

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

    An object you use for observing VGSTextField State and send data to your organization vault.

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

    Organization vault environment.

    "},"Classes/State.html":{"name":"State","abstract":"

    An object that describes VGSTextField state. State attributes are read-only.

    "},"Classes/SSNState.html":{"name":"SSNState","abstract":"

    An object that describes VGSTextField state with configuration FieldType.ssn . State attributes are read-only.

    "},"Classes/CardState.html":{"name":"CardState","abstract":"

    An object that describes VGSTextField state with configuration FieldType.cardNumber . State attributes are read-only.

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

    Response enum cases for SDK requests.

    "},"Structs/VGSCollectRequestOptions.html":{"name":"VGSCollectRequestOptions","abstract":"

    Request options.

    "},"Observe%20State%20and%20Send%20Data.html#/JsonData":{"name":"JsonData","abstract":"

    Key-value data type, usually used for response format.

    "},"Observe%20State%20and%20Send%20Data.html#/HTTPHeaders":{"name":"HTTPHeaders","abstract":"

    Key-value data type, used in http request headers.

    "},"Classes/VGSFileInfo.html#/fileExtension":{"name":"fileExtension","abstract":"

    File extension, like “jpeg”, “png”, etc.

    ","parent_name":"VGSFileInfo"},"Classes/VGSFileInfo.html#/size":{"name":"size","abstract":"

    File size.

    ","parent_name":"VGSFileInfo"},"Classes/VGSFileInfo.html#/sizeUnits":{"name":"sizeUnits","abstract":"

    File size units.

    ","parent_name":"VGSFileInfo"},"Enums/VGSFileSource.html#/photoLibrary":{"name":"photoLibrary","abstract":"

    Device photo library.

    ","parent_name":"VGSFileSource"},"Enums/VGSFileSource.html#/camera":{"name":"camera","abstract":"

    Device camera.

    ","parent_name":"VGSFileSource"},"Enums/VGSFileSource.html#/documentsDirectory":{"name":"documentsDirectory","abstract":"

    Device documents directory.

    ","parent_name":"VGSFileSource"},"Protocols/VGSFilePickerControllerDelegate.html#/userDidPickFileWithInfo(_:)":{"name":"userDidPickFileWithInfo(_:)","abstract":"

    On user select a file

    ","parent_name":"VGSFilePickerControllerDelegate"},"Protocols/VGSFilePickerControllerDelegate.html#/userDidSCancelFilePicking()":{"name":"userDidSCancelFilePicking()","abstract":"

    On user canceling file picking

    ","parent_name":"VGSFilePickerControllerDelegate"},"Protocols/VGSFilePickerControllerDelegate.html#/filePickingFailedWithError(_:)":{"name":"filePickingFailedWithError(_:)","abstract":"

    On error occured when user pick a file.

    ","parent_name":"VGSFilePickerControllerDelegate"},"Classes/VGSFilePickerConfiguration.html#/fieldName":{"name":"fieldName","abstract":"

    Name that will be associated with selected file by user. Used as a JSON key on send request with file data to your organozation vault.

    ","parent_name":"VGSFilePickerConfiguration"},"Classes/VGSFilePickerConfiguration.html#/init(collector:fieldName:fileSource:)":{"name":"init(collector:fieldName:fileSource:)","abstract":"

    Initialization

    ","parent_name":"VGSFilePickerConfiguration"},"Classes/VGSFilePickerController.html#/delegate":{"name":"delegate","abstract":"

    VGSFilePickerControllerDelegate - handle user interaction on file picking.

    ","parent_name":"VGSFilePickerController"},"Classes/VGSFilePickerController.html#/init(configuration:)":{"name":"init(configuration:)","abstract":"

    Initialization

    ","parent_name":"VGSFilePickerController"},"Classes/VGSFilePickerController.html#/presentFilePicker(on:animated:completion:)":{"name":"presentFilePicker(on:animated:completion:)","abstract":"

    Present file picker view

    ","parent_name":"VGSFilePickerController"},"Classes/VGSFilePickerController.html#/dismissFilePicker(animated:completion:)":{"name":"dismissFilePicker(animated:completion:)","abstract":"

    Dismiss file picker view

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

    Controller responsible for importing files from device sources.

    "},"Classes/VGSFilePickerConfiguration.html":{"name":"VGSFilePickerConfiguration","abstract":"

    A class responsible for configuration VGSFilePickerController.

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

    Delegates produced by VGSFilePickerController.

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

    Available file source destinations that VGSFilePickerController can work with.

    "},"Classes/VGSFileInfo.html":{"name":"VGSFileInfo","abstract":"

    An object that holds optional files’ metadata on selecting file through VGSFilePickerController.

    "},"Enums/FieldType.html#/none":{"name":"none","abstract":"

    Field type that doesn’t require any input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/cardNumber":{"name":"cardNumber","abstract":"

    Field type that requires Credit Card Number input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/expDate":{"name":"expDate","abstract":"

    Field type that requires Expiration Date input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/cvc":{"name":"cvc","abstract":"

    Field type that requires Credit Card CVC input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/cardHolderName":{"name":"cardHolderName","abstract":"

    Field type that requires Cardholder Name input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/ssn":{"name":"ssn","abstract":"

    Field type that requires US Social Security Number input formatting and validation.

    ","parent_name":"FieldType"},"Classes/VGSExpDateConfiguration.html#/type":{"name":"type","abstract":"

    FieldType.expDate type of VGSTextField configuration.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSExpDateConfiguration.html#/inputSource":{"name":"inputSource","abstract":"

    Input Source type. Default is VGSTextFieldInputSource.datePicker.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSExpDateConfiguration.html#/inputDateFormat":{"name":"inputDateFormat","abstract":"

    Input date format to convert.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSExpDateConfiguration.html#/outputDateFormat":{"name":"outputDateFormat","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSExpDateConfiguration.html#/serializers":{"name":"serializers","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSConfiguration.html#/vgsCollector":{"name":"vgsCollector","abstract":"

    Collect form that will be assiciated with VGSTextField.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/type":{"name":"type","abstract":"

    Type of field congfiguration. Default is FieldType.none.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/fieldName":{"name":"fieldName","abstract":"

    Name that will be associated with VGSTextField and used as a JSON key on send request with textfield data to your organozation vault.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/isRequired":{"name":"isRequired","abstract":"

    Set if VGSTextField is required to be non-empty and non-nil on send request. Default is false.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/isRequiredValidOnly":{"name":"isRequiredValidOnly","abstract":"

    Set if VGSTextField is required to be valid only on send request. Default is false.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/formatPattern":{"name":"formatPattern","abstract":"

    Input data visual format pattern. If not applied, will be set by default depending on field type.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/divider":{"name":"divider","abstract":"

    String, used to replace not default VGSConfiguration.formatPattern characters in input text on send request.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/keyboardType":{"name":"keyboardType","abstract":"

    Preferred UIKeyboardType for VGSTextField. If not applied, will be set by default depending on field type parameter.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/returnKeyType":{"name":"returnKeyType","abstract":"

    Preferred UIReturnKeyType for VGSTextField.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/keyboardAppearance":{"name":"keyboardAppearance","abstract":"

    Preferred UIKeyboardAppearance for textfield. By default is UIKeyboardAppearance.default.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/validationRules":{"name":"validationRules","abstract":"

    Validation rules for field input. Defines State.isValide result.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/maxInputLength":{"name":"maxInputLength","abstract":"

    Max input length. IMPORTANT! Can conflict with .formatPattern attribute.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/init(collector:fieldName:)":{"name":"init(collector:fieldName:)","abstract":"

    Initialization

    ","parent_name":"VGSConfiguration"},"Protocols/VGSTextFieldDelegate.html#/vgsTextFieldDidBeginEditing(_:)":{"name":"vgsTextFieldDidBeginEditing(_:)","abstract":"

    VGSTextField did become first responder.

    ","parent_name":"VGSTextFieldDelegate"},"Protocols/VGSTextFieldDelegate.html#/vgsTextFieldDidEndEditing(_:)":{"name":"vgsTextFieldDidEndEditing(_:)","abstract":"

    VGSTextField did resign first responder.

    ","parent_name":"VGSTextFieldDelegate"},"Protocols/VGSTextFieldDelegate.html#/vgsTextFieldDidEndEditingOnReturn(_:)":{"name":"vgsTextFieldDidEndEditingOnReturn(_:)","abstract":"

    VGSTextField did resign first responder on Return button pressed.

    ","parent_name":"VGSTextFieldDelegate"},"Protocols/VGSTextFieldDelegate.html#/vgsTextFieldDidChange(_:)":{"name":"vgsTextFieldDidChange(_:)","abstract":"

    VGSTextField input changed.

    ","parent_name":"VGSTextFieldDelegate"},"Classes/VGSCVCTextField/CVCIconLocation.html#/left":{"name":"left","abstract":"

    CVC icon at left side of VGSCardTextField.

    ","parent_name":"CVCIconLocation"},"Classes/VGSCVCTextField/CVCIconLocation.html#/right":{"name":"right","abstract":"

    CVC icon at right side of VGSCardTextField.

    ","parent_name":"CVCIconLocation"},"Classes/VGSCVCTextField/CVCIconLocation.html":{"name":"CVCIconLocation","abstract":"

    Available CVC icon positions enum.

    ","parent_name":"VGSCVCTextField"},"Classes/VGSCVCTextField.html#/cvcIconLocation":{"name":"cvcIconLocation","abstract":"

    CVC icon position inside VGSCardTextField.

    ","parent_name":"VGSCVCTextField"},"Classes/VGSCVCTextField.html#/cvcIconSize":{"name":"cvcIconSize","abstract":"

    CVC icon size.

    ","parent_name":"VGSCVCTextField"},"Classes/VGSCVCTextField.html#/cvcIconSource":{"name":"cvcIconSource","abstract":"

    Asks custom image for specific VGSPaymentCards.CardBrand

    ","parent_name":"VGSCVCTextField"},"Classes/VGSExpDateTextField/YearFormat.html#/short":{"name":"short","abstract":"

    Two digits year format, e.g.: 21

    ","parent_name":"YearFormat"},"Classes/VGSExpDateTextField/YearFormat.html#/long":{"name":"long","abstract":"

    Four digits year format:, e.g.:2021

    ","parent_name":"YearFormat"},"Classes/VGSExpDateTextField/MonthFormat.html#/shortSymbols":{"name":"shortSymbols","abstract":"

    Short month name, e.g.: Jan

    ","parent_name":"MonthFormat"},"Classes/VGSExpDateTextField/MonthFormat.html#/longSymbols":{"name":"longSymbols","abstract":"

    Long month name, e.g.: January

    ","parent_name":"MonthFormat"},"Classes/VGSExpDateTextField/MonthFormat.html#/numbers":{"name":"numbers","abstract":"

    Month number: e.g.: 01

    ","parent_name":"MonthFormat"},"Classes/VGSExpDateTextField/MonthFormat.html":{"name":"MonthFormat","abstract":"

    Available Month Label formats in UIPickerView

    ","parent_name":"VGSExpDateTextField"},"Classes/VGSExpDateTextField/YearFormat.html":{"name":"YearFormat","abstract":"

    Available Year Label formats in UIPickerView

    ","parent_name":"VGSExpDateTextField"},"Classes/VGSExpDateTextField.html#/monthPickerFormat":{"name":"monthPickerFormat","abstract":"

    UIPickerView Month Label format

    ","parent_name":"VGSExpDateTextField"},"Classes/VGSExpDateTextField.html#/yearPickeFormat":{"name":"yearPickeFormat","abstract":"

    UIPickerView Year Label format

    ","parent_name":"VGSExpDateTextField"},"Classes/VGSCardTextField/CardIconLocation.html#/left":{"name":"left","abstract":"

    Card brand icon at left side of VGSCardTextField.

    ","parent_name":"CardIconLocation"},"Classes/VGSCardTextField/CardIconLocation.html#/right":{"name":"right","abstract":"

    Card brand icon at right side of VGSCardTextField.

    ","parent_name":"CardIconLocation"},"Classes/VGSCardTextField/CardIconLocation.html":{"name":"CardIconLocation","abstract":"

    Available Card brand icon positions enum.

    ","parent_name":"VGSCardTextField"},"Classes/VGSCardTextField.html#/cardIconLocation":{"name":"cardIconLocation","abstract":"

    Card brand icon position inside VGSCardTextField.

    ","parent_name":"VGSCardTextField"},"Classes/VGSCardTextField.html#/cardIconSize":{"name":"cardIconSize","abstract":"

    Card brand icon size.

    ","parent_name":"VGSCardTextField"},"Classes/VGSCardTextField.html#/cardsIconSource":{"name":"cardsIconSource","abstract":"

    Asks custom image for specific VGSPaymentCards.CardBrand

    ","parent_name":"VGSCardTextField"},"Classes/VGSTextField.html#/placeholder":{"name":"placeholder","abstract":"

    Textfield placeholder string.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/autocapitalizationType":{"name":"autocapitalizationType","abstract":"

    Textfield autocapitalization type. Default is .sentences.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/spellCheckingType":{"name":"spellCheckingType","abstract":"

    Textfield spell checking type. Default is UITextSpellCheckingType.default.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/attributedPlaceholder":{"name":"attributedPlaceholder","abstract":"

    Textfield attributedPlaceholder string.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/padding":{"name":"padding","abstract":"

    UIEdgeInsets for text and placeholder inside VGSTextField.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/textAlignment":{"name":"textAlignment","abstract":"

    The technique to use for aligning the text.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/clearButtonMode":{"name":"clearButtonMode","abstract":"

    Sets when the clear button shows up. Default is UITextField.ViewMode.never

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/isSecureTextEntry":{"name":"isSecureTextEntry","abstract":"

    Identifies whether the text object should disable text copying and in some cases hide the text being entered. Default is false.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/adjustsFontForContentSizeCategory":{"name":"adjustsFontForContentSizeCategory","abstract":"

    Indicates whether VGSTextField should automatically update its font when the device’s UIContentSizeCategory is changed.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/keyboardAccessoryView":{"name":"keyboardAccessoryView","abstract":"

    Input Accessory View

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/autocorrectionType":{"name":"autocorrectionType","abstract":"

    Determines whether autocorrection is enabled or disabled during typing.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/textFieldAccessibilityLabel":{"name":"textFieldAccessibilityLabel","abstract":"

    A succinct label in a localized string that identifies the accessibility text field.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/textFieldAccessibilityHint":{"name":"textFieldAccessibilityHint","abstract":"

    A localized string that contains a brief description of the result of performing an action on the accessibility text field.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/configuration":{"name":"configuration","abstract":"

    Specifies VGSTextField configuration parameters to work with VGSCollect.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/delegate":{"name":"delegate","abstract":"

    Delegates VGSTextField editing events. Default is nil.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/setDefaultText(_:)":{"name":"setDefaultText(_:)","abstract":"

    Set textfield default text.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/cleanText()":{"name":"cleanText()","abstract":"

    Removes input from field.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/isContentEqual(_:)":{"name":"isContentEqual(_:)","abstract":"

    Check if input text in two textfields is same. Returns Bool.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/font":{"name":"font","abstract":"

    VGSTextField text font

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/textColor":{"name":"textColor","abstract":"

    VGSTextField text color

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/cornerRadius":{"name":"cornerRadius","abstract":"

    VGSTextField layer corner radius

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/borderWidth":{"name":"borderWidth","abstract":"

    VGSTextField layer borderWidth

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/borderColor":{"name":"borderColor","abstract":"

    VGSTextField layer borderColor

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/becomeFirstResponder()":{"name":"becomeFirstResponder()","abstract":"

    Make VGSTextField focused.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/resignFirstResponder()":{"name":"resignFirstResponder()","abstract":"

    Remove focus from VGSTextField.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/isFirstResponder":{"name":"isFirstResponder","abstract":"

    Check if VGSTextField is focused.

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

    An object that displays an editable text area in user interface.

    "},"Classes/VGSCardTextField.html":{"name":"VGSCardTextField","abstract":"

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to detect and show credit card brand images.

    "},"Classes/VGSExpDateTextField.html":{"name":"VGSExpDateTextField","abstract":"

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to show picker view with Card Number Expiration Month and Year.

    "},"Classes/VGSCVCTextField.html":{"name":"VGSCVCTextField","abstract":"

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to show CVC/CVV images for credit card brands.

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

    Delegates produced by VGSTextField instance.

    "},"Classes/VGSConfiguration.html":{"name":"VGSConfiguration","abstract":"

    A class responsible for configuration VGSTextField.

    "},"Classes/VGSExpDateConfiguration.html":{"name":"VGSExpDateConfiguration","abstract":"

    A class responsible for configuration VGSTextField with fieldType = .expDate. Extends VGSConfiguration class.

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

    Type of VGSTextField configuration.

    "},"UI%20Elements.html":{"name":"UI Elements"},"File%20Picker.html":{"name":"File Picker"},"Observe%20State%20and%20Send%20Data.html":{"name":"Observe State and Send Data"},"Payment%20Cards.html":{"name":"Payment Cards"},"VGSTextField%20Serializers.html":{"name":"VGSTextField Serializers"},"Validation%20Rules.html":{"name":"Validation Rules"},"Errors.html":{"name":"Errors"},"Error%20Keys.html":{"name":"Error Keys"},"Debugging.html":{"name":"Debugging"},"Enumerations.html":{"name":"Enumerations"},"Other%20Classes.html":{"name":"Other Classes","abstract":"

    The following classes are available globally.

    "},"Other%20Enums.html":{"name":"Other Enumerations","abstract":"

    The following enumerations are available globally.

    "},"Other%20Extensions.html":{"name":"Other Extensions","abstract":"

    The following extensions are available globally.

    "},"Other%20Protocols.html":{"name":"Other Protocols","abstract":"

    The following protocols are available globally.

    "},"Other%20Structs.html":{"name":"Other Structures","abstract":"

    The following structures are available globally.

    "}} \ No newline at end of file +{"Enums/VGSCollectFieldNameMappingPolicy.html#/s:13VGSCollectSDK0A22FieldNameMappingPolicyO8flatJSONyA2CmF":{"name":"flatJSON","abstract":"

    Map fieldName to JSON without applying any transformations.","parent_name":"VGSCollectFieldNameMappingPolicy"},"Enums/VGSCollectFieldNameMappingPolicy.html#/s:13VGSCollectSDK0A22FieldNameMappingPolicyO10nestedJSONyA2CmF":{"name":"nestedJSON","abstract":"

    Map fieldName to nested JSON.","parent_name":"VGSCollectFieldNameMappingPolicy"},"Enums/VGSCollectFieldNameMappingPolicy.html#/s:13VGSCollectSDK0A22FieldNameMappingPolicyO24nestedJSONWithArrayMergeyA2CmF":{"name":"nestedJSONWithArrayMerge","abstract":"

    Map field name to nested JSON and array if array index is specified.","parent_name":"VGSCollectFieldNameMappingPolicy"},"Enums/VGSCollectFieldNameMappingPolicy.html#/s:13VGSCollectSDK0A22FieldNameMappingPolicyO28nestedJSONWithArrayOverwriteyA2CmF":{"name":"nestedJSONWithArrayOverwrite","abstract":"

    Map field name to nested JSON and array if array index is specified.","parent_name":"VGSCollectFieldNameMappingPolicy"},"Enums/VGSCardExpDateFormat.html#/s:13VGSCollectSDK20VGSCardExpDateFormatO9shortYearyA2CmF":{"name":"shortYear","abstract":"

    Exp.Date in format mm/yy: 01/22

    ","parent_name":"VGSCardExpDateFormat"},"Enums/VGSCardExpDateFormat.html#/s:13VGSCollectSDK20VGSCardExpDateFormatO8longYearyA2CmF":{"name":"longYear","abstract":"

    Exp.Date in format mm/yyyy: 01/2022

    ","parent_name":"VGSCardExpDateFormat"},"Enums/VGSCardExpDateFormat.html#/s:13VGSCollectSDK20VGSCardExpDateFormatO18shortYearThenMonthyA2CmF":{"name":"shortYearThenMonth","abstract":"

    Exp.Date in format yy/mm: 22/01

    ","parent_name":"VGSCardExpDateFormat"},"Enums/VGSCardExpDateFormat.html#/s:13VGSCollectSDK20VGSCardExpDateFormatO17longYearThenMonthyA2CmF":{"name":"longYearThenMonth","abstract":"

    Exp.Date in format yy/mm: 2022/01

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

    Payment Card Expiration Date Format

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

    Defines fieldName mapping to JSON.

    "},"Structs/VGSCollectLoggingConfiguration.html#/s:13VGSCollectSDK0A20LoggingConfigurationV5levelAA11VGSLogLevelOvp":{"name":"level","abstract":"

    Log level. Default is .none.

    ","parent_name":"VGSCollectLoggingConfiguration"},"Structs/VGSCollectLoggingConfiguration.html#/s:13VGSCollectSDK0A20LoggingConfigurationV21isNetworkDebugEnabledSbvp":{"name":"isNetworkDebugEnabled","abstract":"

    Bool flag. Specify true to record VGSCollectSDK network session with success/failed requests. Default is false.

    ","parent_name":"VGSCollectLoggingConfiguration"},"Structs/VGSCollectLoggingConfiguration.html#/s:13VGSCollectSDK0A20LoggingConfigurationV23isExtensiveDebugEnabledSbvp":{"name":"isExtensiveDebugEnabled","abstract":"

    Bool flag. Specify true to enable extensive debugging. Default is false.

    ","parent_name":"VGSCollectLoggingConfiguration"},"Enums/VGSLogLevel.html#/s:13VGSCollectSDK11VGSLogLevelO4infoyA2CmF":{"name":"info","abstract":"

    Log all events including errors and warnings.

    ","parent_name":"VGSLogLevel"},"Enums/VGSLogLevel.html#/s:13VGSCollectSDK11VGSLogLevelO7warningyA2CmF":{"name":"warning","abstract":"

    Log only events indicating warnings and errors.

    ","parent_name":"VGSLogLevel"},"Enums/VGSLogLevel.html#/s:13VGSCollectSDK11VGSLogLevelO4noneyA2CmF":{"name":"none","abstract":"

    Log no events.

    ","parent_name":"VGSLogLevel"},"Classes/VGSCollectLogger.html#/s:13VGSCollectSDK0A6LoggerC6sharedACvpZ":{"name":"shared","abstract":"

    Shared instance.

    ","parent_name":"VGSCollectLogger"},"Classes/VGSCollectLogger.html#/s:13VGSCollectSDK0A6LoggerC13configurationAA0A20LoggingConfigurationVvp":{"name":"configuration","abstract":"

    Logging configuration. Check VGSCollectLoggingConfiguration for logging options.

    ","parent_name":"VGSCollectLogger"},"Classes/VGSCollectLogger.html#/s:13VGSCollectSDK0A6LoggerC17disableAllLoggersyyF":{"name":"disableAllLoggers()","abstract":"

    Stop logging all activities.

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

    VGSCollectLogger encapsulates logging logic and debugging options for VGSCollectSDK. Use .configuration property to setup these options. VGSCollectLogger logging implies only printing logs to Xcode console. It doesn’t save logs to persistent store/local file, also it doesn’t send debugging logs to backend services."},"Enums/VGSLogLevel.html":{"name":"VGSLogLevel","abstract":"

    Defines levels of logging.

    "},"Structs/VGSCollectLoggingConfiguration.html":{"name":"VGSCollectLoggingConfiguration","abstract":"

    Holds configuration for VGSCollectSDK logging.

    "},"Error%20Keys.html#/s:13VGSCollectSDK30VGSSDKErrorInputDataIsNotValidSSvp":{"name":"VGSSDKErrorInputDataIsNotValid","abstract":"

    Error key, used for errors when input data is required to be not empty or to be valid only, but is not valid.

    "},"Error%20Keys.html#/s:13VGSCollectSDK28VGSSDKErrorInputDataRequiredSSvp":{"name":"VGSSDKErrorInputDataRequired","abstract":"

    Error key, used for errors when input data is required to be not empty but is empty or nil.

    "},"Error%20Keys.html#/s:13VGSCollectSDK33VGSSDKErrorInputDataRequiredValidSSvp":{"name":"VGSSDKErrorInputDataRequiredValid","abstract":"

    Error key, used for errors when input data is required to be valid is not valid.

    "},"Error%20Keys.html#/s:13VGSCollectSDK23VGSSDKErrorFileNotFoundSSvp":{"name":"VGSSDKErrorFileNotFound","abstract":"

    Error key, used for errors when SDK can’t find the file at file path. Can happened when file changes the path or doesn’t exist.

    "},"Error%20Keys.html#/s:13VGSCollectSDK31VGSSDKErrorFileTypeNotSupportedSSvp":{"name":"VGSSDKErrorFileTypeNotSupported","abstract":"

    Error key, used for errors when file type is not supported by SDK.

    "},"Error%20Keys.html#/s:13VGSCollectSDK34VGSSDKErrorFileSizeExceedsTheLimitSSvp":{"name":"VGSSDKErrorFileSizeExceedsTheLimit","abstract":"

    Error key, used for errors when file size exceeds maximum limit.

    "},"Error%20Keys.html#/s:13VGSCollectSDK29VGSSDKErrorSourceNotAvailableSSvp":{"name":"VGSSDKErrorSourceNotAvailable","abstract":"

    Error key, used for errors when SDK can’t get access to specific source.

    "},"Error%20Keys.html#/s:13VGSCollectSDK39VGSSDKErrorUnexpectedResponseDataFormatSSvp":{"name":"VGSSDKErrorUnexpectedResponseDataFormat","abstract":"

    Error key, used for errors when response for SDK API request is in format that not supported by SDK.

    "},"Enums/VGSValidationErrorType.html#/s:13VGSCollectSDK22VGSValidationErrorTypeO7patternyA2CmF":{"name":"pattern","abstract":"

    Default Validation error for VGSValidationRulePattern

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/s:13VGSCollectSDK22VGSValidationErrorTypeO6lengthyA2CmF":{"name":"length","abstract":"

    Default Validation error for VGSValidationRuleLength

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/s:13VGSCollectSDK22VGSValidationErrorTypeO12lengthMathesyA2CmF":{"name":"lengthMathes","abstract":"

    Default Validation error for VGSValidationRuleLength

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/s:13VGSCollectSDK22VGSValidationErrorTypeO7expDateyA2CmF":{"name":"expDate","abstract":"

    Default Validation error for VGSValidationRuleCardExpirationDate

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/s:13VGSCollectSDK22VGSValidationErrorTypeO4dateyA2CmF":{"name":"date","abstract":"

    Default Validation error for VGSValidationRuleDateRange

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/s:13VGSCollectSDK22VGSValidationErrorTypeO10cardNumberyA2CmF":{"name":"cardNumber","abstract":"

    Default Validation error for VGSValidationRulePaymentCard

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/s:13VGSCollectSDK22VGSValidationErrorTypeO9luhnCheckyA2CmF":{"name":"luhnCheck","abstract":"

    Default Validation error for VGSValidationRuleLuhnCheck

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSErrorType.html#/s:13VGSCollectSDK12VGSErrorTypeO19inputDataIsNotValidyA2CmF":{"name":"inputDataIsNotValid","abstract":"

    When input data is not valid, but required to be valid

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/s:13VGSCollectSDK12VGSErrorTypeO17inputFileNotFoundyA2CmF":{"name":"inputFileNotFound","abstract":"

    When can’t find file on device

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/s:13VGSCollectSDK12VGSErrorTypeO09inputFileD14IsNotSupportedyA2CmF":{"name":"inputFileTypeIsNotSupported","abstract":"

    When can’t find file on device

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/s:13VGSCollectSDK12VGSErrorTypeO28inputFileSizeExceedsTheLimityA2CmF":{"name":"inputFileSizeExceedsTheLimit","abstract":"

    When file size is larger then allowed limit

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/s:13VGSCollectSDK12VGSErrorTypeO18sourceNotAvailableyA2CmF":{"name":"sourceNotAvailable","abstract":"

    When can’t get access to file source

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/s:13VGSCollectSDK12VGSErrorTypeO018unexpectedResponseD0yA2CmF":{"name":"unexpectedResponseType","abstract":"

    When response type is not supported

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/s:13VGSCollectSDK12VGSErrorTypeO28unexpectedResponseDataFormatyA2CmF":{"name":"unexpectedResponseDataFormat","abstract":"

    When reponse data format is not supported

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/s:13VGSCollectSDK12VGSErrorTypeO23invalidConfigurationURLyA2CmF":{"name":"invalidConfigurationURL","abstract":"

    When VGS config URL is not valid.

    ","parent_name":"VGSErrorType"},"Classes/VGSError.html#/s:13VGSCollectSDK8VGSErrorC4typeAA0C4TypeOSgvp":{"name":"type","abstract":"

    VGSErrorType- required for each VGSError instance

    ","parent_name":"VGSError"},"Classes/VGSError.html#/c:@M@VGSCollectSDK@objc(cs)VGSError(py)code":{"name":"code","abstract":"

    Code assiciated with VGSErrorType

    ","parent_name":"VGSError"},"Classes/VGSError.html#/c:@M@VGSCollectSDK@objc(cs)VGSError(im)initWithCoder:":{"name":"init(coder:)","abstract":"

    : nodoc. Public required init.

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

    An error produced by VGSCollectSDK. Works similar to default NSError in iOS.

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

    Type of VGSError and it status code.

    "},"Errors.html#/s:13VGSCollectSDK0A14SDKErrorDomainSSvp":{"name":"VGSCollectSDKErrorDomain","abstract":"

    An error domain string used to produce VGSError from VGSCollectSDK - “vgscollect.sdk”

    "},"Errors.html#/s:13VGSCollectSDK18VGSValidationErrora":{"name":"VGSValidationError","abstract":"

    VGS Validation Error object type

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

    Default validation error types

    "},"Enums/CheckSumAlgorithmType.html#/s:13VGSCollectSDK21CheckSumAlgorithmTypeO4luhnyA2CmF":{"name":"luhn","abstract":"

    Luhn Algorithm

    ","parent_name":"CheckSumAlgorithmType"},"Enums/CheckSumAlgorithmType.html#/s:13VGSCollectSDK21CheckSumAlgorithmTypeO8validateySbSSF":{"name":"validate(_:)","abstract":"

    Validate input String with specified algorithm.

    ","parent_name":"CheckSumAlgorithmType"},"Structs/VGSValidationRuleDateRange.html#/s:13VGSCollectSDK26VGSValidationRuleDateRangeV10dateFormatAA07VGSDateH0Ovp":{"name":"dateFormat","abstract":"

    Date format used to validate the rule

    ","parent_name":"VGSValidationRuleDateRange"},"Structs/VGSValidationRuleDateRange.html#/s:13VGSCollectSDK26VGSValidationRuleDateRangeV5errorSSvp":{"name":"error","abstract":"

    Error used in case the validation is invalid

    ","parent_name":"VGSValidationRuleDateRange"},"Structs/VGSValidationRuleDateRange.html#/s:13VGSCollectSDK26VGSValidationRuleDateRangeV10dateFormat5error5start3endAcA07VGSDateH0O_SSAA0L0VSgALtcfc":{"name":"init(dateFormat:error:start:end:)","abstract":"

    Initialization

    ","parent_name":"VGSValidationRuleDateRange"},"Structs/VGSValidationRuleCardExpirationDate.html#/s:13VGSCollectSDK35VGSValidationRuleCardExpirationDateV10dateFormatAA010VGSCardExpgI0Ovp":{"name":"dateFormat","abstract":"

    Payment Card Expiration Date Format

    ","parent_name":"VGSValidationRuleCardExpirationDate"},"Structs/VGSValidationRuleCardExpirationDate.html#/s:13VGSCollectSDK35VGSValidationRuleCardExpirationDateV5errorSSvp":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRuleCardExpirationDate"},"Structs/VGSValidationRuleCardExpirationDate.html#/s:13VGSCollectSDK35VGSValidationRuleCardExpirationDateV10dateFormat5errorAcA010VGSCardExpgI0O_SStcfc":{"name":"init(dateFormat:error:)","abstract":"

    Initialization

    ","parent_name":"VGSValidationRuleCardExpirationDate"},"Structs/VGSValidationRuleLuhnCheck.html#/s:13VGSCollectSDK26VGSValidationRuleLuhnCheckV5errorSSvp":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRuleLuhnCheck"},"Structs/VGSValidationRuleLuhnCheck.html#/s:13VGSCollectSDK26VGSValidationRuleLuhnCheckV5errorACSS_tcfc":{"name":"init(error:)","abstract":"

    Initialization

    ","parent_name":"VGSValidationRuleLuhnCheck"},"Structs/VGSValidationRulePaymentCard.html#/s:13VGSCollectSDK28VGSValidationRulePaymentCardV5errorSSvp":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRulePaymentCard"},"Structs/VGSValidationRulePaymentCard.html#/s:13VGSCollectSDK28VGSValidationRulePaymentCardV015validateUnknownF5BrandSbvp":{"name":"validateUnknownCardBrand","abstract":"

    Turn on/off validation of cards that are not defined in SDK - CardBrand.unknown

    ","parent_name":"VGSValidationRulePaymentCard"},"Structs/VGSValidationRulePaymentCard.html#/s:13VGSCollectSDK28VGSValidationRulePaymentCardV5errorACSS_tcfc":{"name":"init(error:)","abstract":"

    Initialization

    ","parent_name":"VGSValidationRulePaymentCard"},"Structs/VGSValidationRulePaymentCard.html#/s:13VGSCollectSDK28VGSValidationRulePaymentCardV5error015validateUnknownF5BrandACSS_Sbtcfc":{"name":"init(error:validateUnknownCardBrand:)","abstract":"

    Initialization

    ","parent_name":"VGSValidationRulePaymentCard"},"Structs/VGSValidationRulePattern.html#/s:13VGSCollectSDK24VGSValidationRulePatternV7patternSSvp":{"name":"pattern","abstract":"

    Regex pattern

    ","parent_name":"VGSValidationRulePattern"},"Structs/VGSValidationRulePattern.html#/s:13VGSCollectSDK24VGSValidationRulePatternV5errorSSvp":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRulePattern"},"Structs/VGSValidationRulePattern.html#/s:13VGSCollectSDK24VGSValidationRulePatternV7pattern5errorACSS_SStcfc":{"name":"init(pattern:error:)","abstract":"

    Initialization

    ","parent_name":"VGSValidationRulePattern"},"Structs/VGSValidationRuleLengthMatch.html#/s:13VGSCollectSDK28VGSValidationRuleLengthMatchV7lengthsSaySiGvp":{"name":"lengths","abstract":"

    Array of valid length ranges

    ","parent_name":"VGSValidationRuleLengthMatch"},"Structs/VGSValidationRuleLengthMatch.html#/s:13VGSCollectSDK28VGSValidationRuleLengthMatchV5errorSSvp":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRuleLengthMatch"},"Structs/VGSValidationRuleLengthMatch.html#/s:13VGSCollectSDK28VGSValidationRuleLengthMatchV7lengths5errorACSaySiG_SStcfc":{"name":"init(lengths:error:)","abstract":"

    Initialization

    ","parent_name":"VGSValidationRuleLengthMatch"},"Structs/VGSValidationRuleLength.html#/s:13VGSCollectSDK23VGSValidationRuleLengthV3minSivp":{"name":"min","abstract":"

    Min input length required

    ","parent_name":"VGSValidationRuleLength"},"Structs/VGSValidationRuleLength.html#/s:13VGSCollectSDK23VGSValidationRuleLengthV3maxSivp":{"name":"max","abstract":"

    Max input length required

    ","parent_name":"VGSValidationRuleLength"},"Structs/VGSValidationRuleLength.html#/s:13VGSCollectSDK23VGSValidationRuleLengthV5errorSSvp":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRuleLength"},"Structs/VGSValidationRuleLength.html#/s:13VGSCollectSDK23VGSValidationRuleLengthV3min3max5errorACSi_SiSStcfc":{"name":"init(min:max:error:)","abstract":"

    Initialization

    ","parent_name":"VGSValidationRuleLength"},"Structs/VGSValidationRuleSet.html#/s:13VGSCollectSDK20VGSValidationRuleSetVACycfc":{"name":"init()","abstract":"

    Initialization

    ","parent_name":"VGSValidationRuleSet"},"Structs/VGSValidationRuleSet.html#/s:13VGSCollectSDK20VGSValidationRuleSetV5rulesACSayAA0cD8Protocol_pG_tcfc":{"name":"init(rules:)","abstract":"

    Initialization

    ","parent_name":"VGSValidationRuleSet"},"Structs/VGSValidationRuleSet.html#/s:13VGSCollectSDK20VGSValidationRuleSetV3add4ruleyAA0cD8Protocol_p_tF":{"name":"add(rule:)","abstract":"

    Add validation rule

    ","parent_name":"VGSValidationRuleSet"},"Structs/VGSValidationRuleSet.html":{"name":"VGSValidationRuleSet","abstract":"

    Set of validation rules

    "},"Structs/VGSValidationRuleLength.html":{"name":"VGSValidationRuleLength","abstract":"

    Validate input in scope of length.

    "},"Structs/VGSValidationRuleLengthMatch.html":{"name":"VGSValidationRuleLengthMatch","abstract":"

    Validate input in scope of multiple lengths, e.x.: [16, 19].

    "},"Structs/VGSValidationRulePattern.html":{"name":"VGSValidationRulePattern","abstract":"

    Validate input in scope of matching the pattern(regex).

    "},"Structs/VGSValidationRulePaymentCard.html":{"name":"VGSValidationRulePaymentCard","abstract":"

    Validate input in scope of matching supported card brands, available lengths and checkSum algorithms."},"Structs/VGSValidationRuleLuhnCheck.html":{"name":"VGSValidationRuleLuhnCheck","abstract":"

    Validate input in scope of matching Luhn algorithm.

    "},"Structs/VGSValidationRuleCardExpirationDate.html":{"name":"VGSValidationRuleCardExpirationDate","abstract":"

    Validate input in scope of matching card expiration date format and time range.

    "},"Structs/VGSValidationRuleDateRange.html":{"name":"VGSValidationRuleDateRange","abstract":"

    Validation rule used to validate the date input in objects"},"Enums/CheckSumAlgorithmType.html":{"name":"CheckSumAlgorithmType","abstract":"

    Check Sum Algorithm Types

    "},"Structs/VGSExpDateSeparateSerializer.html#/s:13VGSCollectSDK28VGSExpDateSeparateSerializerV14monthFieldNameSSvp":{"name":"monthFieldName","abstract":"

    Field Name that will be used as a JSON key with month value from expDate string on send request.

    ","parent_name":"VGSExpDateSeparateSerializer"},"Structs/VGSExpDateSeparateSerializer.html#/s:13VGSCollectSDK28VGSExpDateSeparateSerializerV13yearFieldNameSSvp":{"name":"yearFieldName","abstract":"

    Field Name that will be used as a JSON key with year value from expDate string on send request.

    ","parent_name":"VGSExpDateSeparateSerializer"},"Structs/VGSExpDateSeparateSerializer.html#/s:13VGSCollectSDK28VGSExpDateSeparateSerializerV14monthFieldName04yearhI0ACSS_SStcfc":{"name":"init(monthFieldName:yearFieldName:)","abstract":"

    Initialization

    ","parent_name":"VGSExpDateSeparateSerializer"},"VGSTextField%20Serializers.html#/s:13VGSCollectSDK27VGSFormatSerializerProtocolP":{"name":"VGSFormatSerializerProtocol","abstract":"

    Base protocol describing Content Serialization attributes

    "},"Structs/VGSExpDateSeparateSerializer.html":{"name":"VGSExpDateSeparateSerializer","abstract":"

    Expiration Date Separate serializer, split date string to components with separate fieldNames

    "},"Structs/VGSUnknownPaymentCardModel.html#/s:13VGSCollectSDK26VGSUnknownPaymentCardModelV5regexSSvp":{"name":"regex","abstract":"

    Regex validating that input contains digits only.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/s:13VGSCollectSDK26VGSUnknownPaymentCardModelV17cardNumberLengthsSaySiGvp":{"name":"cardNumberLengths","abstract":"

    Valid Unknown Card Numbers Lengths

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/s:13VGSCollectSDK26VGSUnknownPaymentCardModelV10cvcLengthsSaySiGvp":{"name":"cvcLengths","abstract":"

    Valid Unknown Card CVC/CVV Lengths. For most brands valid cvc lengths is [3], while for Amex is [4]. For unknown brands can be set as [3, 4]

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/s:13VGSCollectSDK26VGSUnknownPaymentCardModelV17checkSumAlgorithmAA05CheckhI4TypeOSgvp":{"name":"checkSumAlgorithm","abstract":"

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/s:13VGSCollectSDK26VGSUnknownPaymentCardModelV13formatPatternSSvp":{"name":"formatPattern","abstract":"

    Unknown Payment Card Numbers visual format pattern. NOTE: format pattern length limits input length.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/s:13VGSCollectSDK26VGSUnknownPaymentCardModelV9brandIconSo7UIImageCSgvp":{"name":"brandIcon","abstract":"

    Image, associated with Unknown Payment Card Brands.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/s:13VGSCollectSDK26VGSUnknownPaymentCardModelV7cvcIconSo7UIImageCSgvp":{"name":"cvcIcon","abstract":"

    Image, associated with CVC for Unknown Payment Card Brands.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV5brandAA15VGSPaymentCardsC0E5BrandOvp":{"name":"brand","abstract":"

    Payment Card Brand

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV4nameSSvp":{"name":"name","abstract":"

    Payment Card Name

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV5regexSSvp":{"name":"regex","abstract":"

    Regex Pattern required to detect Payment Card Brand

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV17cardNumberLengthsSaySiGvp":{"name":"cardNumberLengths","abstract":"

    Valid Card Number Lengths

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV10cvcLengthsSaySiGvp":{"name":"cvcLengths","abstract":"

    Valid Card CVC/CVV Lengths. For most brands valid cvc lengths is [3], while for Amex is [4]. For unknown brands can be set as [3, 4]

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV17checkSumAlgorithmAA05CheckhI4TypeOSgvp":{"name":"checkSumAlgorithm","abstract":"

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV13formatPatternSSvp":{"name":"formatPattern","abstract":"

    Payment Card Number visual format pattern.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV9brandIconSo7UIImageCSgvp":{"name":"brandIcon","abstract":"

    Image, associated with Payment Card Brand.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV7cvcIconSo7UIImageCSgvp":{"name":"cvcIcon","abstract":"

    Image, associated with CVC for Payment Card Brand.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV4name5regex13formatPattern17cardNumberLengths03cvcM017checkSumAlgorithm9brandIconACSS_S2SSaySiGAkA05CheckpQ4TypeOSgSo7UIImageCSgtcfc":{"name":"init(name:regex:formatPattern:cardNumberLengths:cvcLengths:checkSumAlgorithm:brandIcon:)","abstract":"

    Initializer.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/s:13VGSCollectSDK19VGSPaymentCardModelV5brandAA0C5CardsC0D5BrandOvp":{"name":"brand","abstract":"

    Payment Card Brand

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/s:13VGSCollectSDK19VGSPaymentCardModelV4nameSSvp":{"name":"name","abstract":"

    Payment Card Name

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/s:13VGSCollectSDK19VGSPaymentCardModelV5regexSSvp":{"name":"regex","abstract":"

    Regex Pattern required to detect Payment Card Brand

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/s:13VGSCollectSDK19VGSPaymentCardModelV17cardNumberLengthsSaySiGvp":{"name":"cardNumberLengths","abstract":"

    Valid Card Number Lengths

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/s:13VGSCollectSDK19VGSPaymentCardModelV10cvcLengthsSaySiGvp":{"name":"cvcLengths","abstract":"

    Valid Card CVC/CVV Lengths. For most brands valid cvc lengths is [3], while for Amex is [4]. For unknown brands can be set as [3, 4]

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/s:13VGSCollectSDK19VGSPaymentCardModelV17checkSumAlgorithmAA05CheckgH4TypeOSgvp":{"name":"checkSumAlgorithm","abstract":"

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/s:13VGSCollectSDK19VGSPaymentCardModelV13formatPatternSSvp":{"name":"formatPattern","abstract":"

    Payment Card Number visual format pattern.

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/s:13VGSCollectSDK19VGSPaymentCardModelV9brandIconSo7UIImageCSgvp":{"name":"brandIcon","abstract":"

    Image, associated with Payment Card Brand.

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/s:13VGSCollectSDK19VGSPaymentCardModelV7cvcIconSo7UIImageCSgvp":{"name":"cvcIcon","abstract":"

    Image, associated with CVC for Payment Card Brand.

    ","parent_name":"VGSPaymentCardModel"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO3eloyA2EmF":{"name":"elo","abstract":"

    ELO

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO12visaElectronyA2EmF":{"name":"visaElectron","abstract":"

    Visa Electron

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO7maestroyA2EmF":{"name":"maestro","abstract":"

    Maestro

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO18forbrugsforeningenyA2EmF":{"name":"forbrugsforeningen","abstract":"

    Forbrugsforeningen

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO7dankortyA2EmF":{"name":"dankort","abstract":"

    Dankort

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO4visayA2EmF":{"name":"visa","abstract":"

    Visa

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO10mastercardyA2EmF":{"name":"mastercard","abstract":"

    Mastercard

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO4amexyA2EmF":{"name":"amex","abstract":"

    American Express

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO9hipercardyA2EmF":{"name":"hipercard","abstract":"

    Hipercard

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO10dinersClubyA2EmF":{"name":"dinersClub","abstract":"

    Diners Club

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO8discoveryA2EmF":{"name":"discover","abstract":"

    Discover

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO8unionpayyA2EmF":{"name":"unionpay","abstract":"

    UnionPay

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO3jcbyA2EmF":{"name":"jcb","abstract":"

    JCB

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO7unknownyA2EmF":{"name":"unknown","abstract":"

    Not supported card brand - “unknown”

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO6customyAESS_tcAEmF":{"name":"custom(brandName:)","abstract":"

    Custom Payment Card Brand. Should have unique brandName.

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO16cvcFormatPatternSSvp":{"name":"cvcFormatPattern","abstract":"

    no:doc

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO9brandIconSo7UIImageCSgvp":{"name":"brandIcon","abstract":"

    no:doc

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO7cvcIconSo7UIImageCSgvp":{"name":"cvcIcon","abstract":"

    no:doc

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO11stringValueSSvp":{"name":"stringValue","abstract":"

    String representation of VGSPaymentCards.CardBrand enum values.

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO11cardLengthsSaySiGvp":{"name":"cardLengths","abstract":"

    Returns array with valid card number lengths for specific VGSPaymentCards.CardBrand

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html":{"name":"CardBrand","abstract":"

    Supported card brands

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC3eloAA0C9CardModelVvpZ":{"name":"elo","abstract":"

    Elo Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC12visaElectronAA0C9CardModelVvpZ":{"name":"visaElectron","abstract":"

    Visa Electron Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC7maestroAA0C9CardModelVvpZ":{"name":"maestro","abstract":"

    Maestro Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC18forbrugsforeningenAA0C9CardModelVvpZ":{"name":"forbrugsforeningen","abstract":"

    Forbrugsforeningen Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC7dankortAA0C9CardModelVvpZ":{"name":"dankort","abstract":"

    Dankort Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC4visaAA0C9CardModelVvpZ":{"name":"visa","abstract":"

    Elo Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC10masterCardAA0cF5ModelVvpZ":{"name":"masterCard","abstract":"

    Master Card Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC4amexAA0C9CardModelVvpZ":{"name":"amex","abstract":"

    Amex Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC9hipercardAA0C9CardModelVvpZ":{"name":"hipercard","abstract":"

    Hipercard Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC10dinersClubAA0C9CardModelVvpZ":{"name":"dinersClub","abstract":"

    DinersClub Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC8discoverAA0C9CardModelVvpZ":{"name":"discover","abstract":"

    Discover Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC8unionpayAA0C9CardModelVvpZ":{"name":"unionpay","abstract":"

    UnionPay Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC3jcbAA0C9CardModelVvpZ":{"name":"jcb","abstract":"

    JCB Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC7unknownAA26VGSUnknownPaymentCardModelVvpZ":{"name":"unknown","abstract":"

    Unknown Brand Payment Card Model. Can be used for specifing cards details when VGSValidationRulePaymentCard requires validating CardBrand.unknown cards.

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC22cutomPaymentCardModelsSayAA09VGSCustomfG5ModelVGvpZ":{"name":"cutomPaymentCardModels","abstract":"

    Array of Custom Payment Card Models.

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC15validCardBrandsSayAA0cF13ModelProtocol_pGSgvpZ":{"name":"validCardBrands","abstract":"

    An array of valid Card Brands, could include custom and default brands. If not set, will use availableCardBrands array instead.

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC31getCardModelFromAvailableModels5brandAA0cfG8Protocol_pSgAC0F5BrandO_tFZ":{"name":"getCardModelFromAvailableModels(brand:)","abstract":"

    no:doc

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC028detectCardBrandFromAvailableD05inputAC0fG0OSS_tFZ":{"name":"detectCardBrandFromAvailableCards(input:)","abstract":"

    no:doc

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

    Class responsible for storing and managing Payment Cards in SDK.

    "},"Structs/VGSPaymentCardModel.html":{"name":"VGSPaymentCardModel","abstract":"

    An object representing Payment Card

    "},"Structs/VGSCustomPaymentCardModel.html":{"name":"VGSCustomPaymentCardModel","abstract":"

    Holds information for custom payment model.

    "},"Structs/VGSUnknownPaymentCardModel.html":{"name":"VGSUnknownPaymentCardModel","abstract":"

    An object representing Unknown Payment Cards - cards not defined in the SDK. Object is used when validation forCardBrand.unknown is set as true. Check VGSValidationRulePaymentCard for more details. Validation attributes can be edited through `VGSPaymentCards.unknown model.

    "},"Enums/VGSCollectHTTPMethod.html#/s:13VGSCollectSDK0A10HTTPMethodO3getyA2CmF":{"name":"get","abstract":"

    GET method.

    ","parent_name":"VGSCollectHTTPMethod"},"Enums/VGSCollectHTTPMethod.html#/s:13VGSCollectSDK0A10HTTPMethodO4postyA2CmF":{"name":"post","abstract":"

    POST method.

    ","parent_name":"VGSCollectHTTPMethod"},"Enums/VGSCollectHTTPMethod.html#/s:13VGSCollectSDK0A10HTTPMethodO3putyA2CmF":{"name":"put","abstract":"

    PUT method.

    ","parent_name":"VGSCollectHTTPMethod"},"Enums/VGSCollectHTTPMethod.html#/s:13VGSCollectSDK0A10HTTPMethodO5patchyA2CmF":{"name":"patch","abstract":"

    PATCH method.

    ","parent_name":"VGSCollectHTTPMethod"},"Enums/VGSCollectHTTPMethod.html#/s:13VGSCollectSDK0A10HTTPMethodO6deleteyA2CmF":{"name":"delete","abstract":"

    DELETE method.

    ","parent_name":"VGSCollectHTTPMethod"},"Structs/VGSCollectRequestOptions.html#/s:13VGSCollectSDK0A14RequestOptionsV22fieldNameMappingPolicyAA0a5FieldfgH0Ovp":{"name":"fieldNameMappingPolicy","abstract":"

    Defines how to map fieldNames to JSON. Default is .nestedJSON.

    ","parent_name":"VGSCollectRequestOptions"},"Structs/VGSCollectRequestOptions.html#/s:13VGSCollectSDK0A14RequestOptionsVACycfc":{"name":"init()","abstract":"

    Initializer.

    ","parent_name":"VGSCollectRequestOptions"},"Enums/VGSTokenizationResponse.html#/s:13VGSCollectSDK23VGSTokenizationResponseO7successyACSi_SDySSypGSgSo13NSURLResponseCSgtcACmF":{"name":"success(_:_:_:)","abstract":"

    Success response case

    ","parent_name":"VGSTokenizationResponse"},"Enums/VGSTokenizationResponse.html#/s:13VGSCollectSDK23VGSTokenizationResponseO7failureyACSi_10Foundation4DataVSgSo13NSURLResponseCSgs5Error_pSgtcACmF":{"name":"failure(_:_:_:_:)","abstract":"

    Failed response case

    ","parent_name":"VGSTokenizationResponse"},"Enums/VGSResponse.html#/s:13VGSCollectSDK11VGSResponseO7successyACSi_10Foundation4DataVSgSo13NSURLResponseCSgtcACmF":{"name":"success(_:_:_:)","abstract":"

    Success response case

    ","parent_name":"VGSResponse"},"Enums/VGSResponse.html#/s:13VGSCollectSDK11VGSResponseO7failureyACSi_10Foundation4DataVSgSo13NSURLResponseCSgs5Error_pSgtcACmF":{"name":"failure(_:_:_:_:)","abstract":"

    Failed response case

    ","parent_name":"VGSResponse"},"Structs/VGSTextFieldStatePublisher.html#/s:7Combine9PublisherP6OutputQa":{"name":"Output","parent_name":"VGSTextFieldStatePublisher"},"Structs/VGSTextFieldStatePublisher.html#/s:7Combine9PublisherP7FailureQa":{"name":"Failure","parent_name":"VGSTextFieldStatePublisher"},"Structs/VGSTextFieldStatePublisher.html#/s:13VGSCollectSDK26VGSTextFieldStatePublisherV7receive10subscriberyx_t7Combine10SubscriberRzs5NeverO7FailureRtzAA0E0C5InputRtzlF":{"name":"receive(subscriber:)","abstract":"

    Attaches a subscriber to the publisher to receive updates on the VGSTextField State.

    ","parent_name":"VGSTextFieldStatePublisher"},"Classes/CardState.html#/s:13VGSCollectSDK9CardStateC5last4SSvp":{"name":"last4","abstract":"

    Last 4 digits of the valid card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    ","parent_name":"CardState"},"Classes/CardState.html#/s:13VGSCollectSDK9CardStateC3binSSvp":{"name":"bin","abstract":"

    Bin digits of the valid card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    ","parent_name":"CardState"},"Classes/CardState.html#/s:13VGSCollectSDK9CardStateC9cardBrandAA15VGSPaymentCardsC0cF0Ovp":{"name":"cardBrand","abstract":"

    Credit Card Brand of the card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    ","parent_name":"CardState"},"Classes/CardState.html#/s:13VGSCollectSDK9CardStateC11descriptionSSvp":{"name":"description","abstract":"

    Message that contains CardState attributes and their values.

    ","parent_name":"CardState"},"Classes/SSNState.html#/s:13VGSCollectSDK8SSNStateC5last4SSvp":{"name":"last4","abstract":"

    Last 4 digits of the valid ssn from associated VGSTextField with field configuration type FieldType.ssn.

    ","parent_name":"SSNState"},"Classes/SSNState.html#/s:13VGSCollectSDK8SSNStateC11descriptionSSvp":{"name":"description","abstract":"

    Message that contains SSNState attributes and their values.

    ","parent_name":"SSNState"},"Classes/State.html#/s:13VGSCollectSDK5StateC9fieldNameSSSgvp":{"name":"fieldName","abstract":"

    VGSConfiguration.fieldName associated with VGSTextField

    ","parent_name":"State"},"Classes/State.html#/s:13VGSCollectSDK5StateC10isRequiredSbvp":{"name":"isRequired","abstract":"

    VGSConfiguration.isRequired attribute defined for VGSTextField

    ","parent_name":"State"},"Classes/State.html#/s:13VGSCollectSDK5StateC19isRequiredValidOnlySbvp":{"name":"isRequiredValidOnly","abstract":"

    VGSConfiguration.isRequiredValidOnly attribute defined for VGSTextField

    ","parent_name":"State"},"Classes/State.html#/s:13VGSCollectSDK5StateC7isValidSbvp":{"name":"isValid","abstract":"

    Contains current validation state for VGSTextField

    ","parent_name":"State"},"Classes/State.html#/s:13VGSCollectSDK5StateC7isEmptySbvp":{"name":"isEmpty","abstract":"

    Show if VGSTextField input is empty

    ","parent_name":"State"},"Classes/State.html#/s:13VGSCollectSDK5StateC7isDirtySbvp":{"name":"isDirty","abstract":"

    Show if VGSTextField was edited

    ","parent_name":"State"},"Classes/State.html#/s:13VGSCollectSDK5StateC11inputLengthSivp":{"name":"inputLength","abstract":"

    Input data length in VGSTextField

    ","parent_name":"State"},"Classes/State.html#/s:13VGSCollectSDK5StateC16validationErrorsSaySSGvp":{"name":"validationErrors","abstract":"

    Array of VGSValidationError. Should be empty when textfield input is valid.

    ","parent_name":"State"},"Classes/State.html#/s:13VGSCollectSDK5StateC11descriptionSSvp":{"name":"description","abstract":"

    Message that contains State attributes and their values

    ","parent_name":"State"},"Enums/Environment.html#/s:13VGSCollectSDK11EnvironmentO7sandboxyA2CmF":{"name":"sandbox","abstract":"

    Should be used for development and testing purpose.

    ","parent_name":"Environment"},"Enums/Environment.html#/s:13VGSCollectSDK11EnvironmentO4liveyA2CmF":{"name":"live","abstract":"

    Should be used for production.

    ","parent_name":"Environment"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C13customHeadersSDyS2SGSgvp":{"name":"customHeaders","abstract":"

    Set your custom HTTP headers.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C17observeFieldStateyAA07VGSTextD0CcSgvp":{"name":"observeFieldState","abstract":"

    Observe only focused VGSTextField on editing events.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C13observeStatesySayAA12VGSTextFieldCGcSgvp":{"name":"observeStates","abstract":"

    Observe all VGSTextField on editing events.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C10textFieldsSayAA12VGSTextFieldCGvp":{"name":"textFields","abstract":"

    Returns array of VGSTextFields associated with VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C2id11environment8hostname13satellitePortACSS_S2SSgSiSgtcfc":{"name":"init(id:environment:hostname:satellitePort:)","abstract":"

    Initialization.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C2id11environment10dataRegion8hostname13satellitePortACSS_AA11EnvironmentOSSSgAKSiSgtcfc":{"name":"init(id:environment:dataRegion:hostname:satellitePort:)","abstract":"

    Initialization.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C12getTextField9fieldNameAA07VGSTextE0CSgSS_tF":{"name":"getTextField(fieldName:)","abstract":"

    Returns VGSTextField with VGSConfiguration.fieldName associated with VGCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C20unsubscribeTextFieldyyAA07VGSTextE0CF":{"name":"unsubscribeTextField(_:)","abstract":"

    Unasubscribe VGSTextField from VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C21unsubscribeTextFieldsyySayAA12VGSTextFieldCGF":{"name":"unsubscribeTextFields(_:)","abstract":"

    Unasubscribe VGSTextFields from VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C24unsubscribeAllTextFieldsyyF":{"name":"unsubscribeAllTextFields()","abstract":"

    Unasubscribe all VGSTextFields from VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C10cleanFilesyyF":{"name":"cleanFiles()","abstract":"

    Detach files for associated VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C8sendData4path6method7routeId05extraD014requestOptions10completionySS_AA0A10HTTPMethodOSSSgSDySSypGSgAA0a7RequestK0VyAA11VGSResponseOctF":{"name":"sendData(path:method:routeId:extraData:requestOptions:completion:)","abstract":"

    Send data from VGSTextFields to your organization vault.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C8sendFile4path6method7routeId9extraData14requestOptions10completionySS_AA0A10HTTPMethodOSSSgSDySSypGSgAA0a7RequestL0VyAA11VGSResponseOctF":{"name":"sendFile(path:method:routeId:extraData:requestOptions:completion:)","abstract":"

    Send file to your organization vault. Only send one file at a time.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C12tokenizeData7routeId10completionySSSg_yAA23VGSTokenizationResponseOctF":{"name":"tokenizeData(routeId:completion:)","abstract":"

    Send tokenization request with data from VGSTextFields.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C8sendData4path6method7routeId05extraD014requestOptionsAA11VGSResponseOSS_AA0A10HTTPMethodOSSSgSDySSypGSgAA0a7RequestK0VtYaF":{"name":"sendData(path:method:routeId:extraData:requestOptions:)","abstract":"

    Asynchronously send data from VGSTextFields to your organization vault.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C8sendFile4path6method7routeId9extraDataAA11VGSResponseOSS_AA0A10HTTPMethodOSSSgSDySSypGSgtYaF":{"name":"sendFile(path:method:routeId:extraData:)","abstract":"

    Asynchronously send file to your organization vault. Only send one file at a time.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C12tokenizeData7routeIdAA23VGSTokenizationResponseOSSSg_tYaF":{"name":"tokenizeData(routeId:)","abstract":"

    Asynchronously send tokenization request with data from VGSTextFields.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C17sendDataPublisher4path6method7routeId05extraD014requestOptions7Combine6FutureCyAA11VGSResponseOs5NeverOGSS_AA0A10HTTPMethodOSSSgSDySSypGSgAA0a7RequestL0VtF":{"name":"sendDataPublisher(path:method:routeId:extraData:requestOptions:)","abstract":"

    Send data from VGSTextFields to your organization vault using the Combine framework.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C17sendFilePublisher4path6method7routeId9extraData14requestOptions7Combine6FutureCyAA11VGSResponseOs5NeverOGSS_AA0A10HTTPMethodOSSSgSDySSypGSgAA0a7RequestM0VtF":{"name":"sendFilePublisher(path:method:routeId:extraData:requestOptions:)","abstract":"

    Send file to your organization vault using the Combine framework.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C21tokenizeDataPublisher7routeId7Combine6FutureCyAA23VGSTokenizationResponseOs5NeverOGSSSg_tF":{"name":"tokenizeDataPublisher(routeId:)","abstract":"

    Send tokenization request with data from VGSTextFields to your organization vault using the Combine framework.

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

    An object you use for observing VGSTextField State and send data to your organization vault.

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

    Organization vault environment.

    "},"Classes/State.html":{"name":"State","abstract":"

    An object that describes VGSTextField state. State attributes are read-only.

    "},"Classes/SSNState.html":{"name":"SSNState","abstract":"

    An object that describes VGSTextField state with configuration FieldType.ssn . State attributes are read-only.

    "},"Classes/CardState.html":{"name":"CardState","abstract":"

    An object that describes VGSTextField state with configuration FieldType.cardNumber . State attributes are read-only.

    "},"Structs/VGSTextFieldStatePublisher.html":{"name":"VGSTextFieldStatePublisher","abstract":"

    A custom publisher that emits State of a given VGSTextField.

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

    Response enum cases for SDK requests.

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

    Tokenization response enum cases for SDK requests.

    "},"Structs/VGSCollectRequestOptions.html":{"name":"VGSCollectRequestOptions","abstract":"

    Request options.

    "},"Observe%20State%20and%20Send%20Data.html#/s:13VGSCollectSDK8JsonDataa":{"name":"JsonData","abstract":"

    Key-value data type, usually used for response format.

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

    HTTP request methods

    "},"Observe%20State%20and%20Send%20Data.html#/s:13VGSCollectSDK11HTTPHeadersa":{"name":"HTTPHeaders","abstract":"

    Key-value data type, used in http request headers.

    "},"Classes/VGSFileInfo.html#/c:@M@VGSCollectSDK@objc(cs)VGSFileInfo(py)fileExtension":{"name":"fileExtension","abstract":"

    File extension, like “jpeg”, “png”, etc.

    ","parent_name":"VGSFileInfo"},"Classes/VGSFileInfo.html#/c:@M@VGSCollectSDK@objc(cs)VGSFileInfo(py)size":{"name":"size","abstract":"

    File size.

    ","parent_name":"VGSFileInfo"},"Classes/VGSFileInfo.html#/c:@M@VGSCollectSDK@objc(cs)VGSFileInfo(py)sizeUnits":{"name":"sizeUnits","abstract":"

    File size units.

    ","parent_name":"VGSFileInfo"},"Enums/VGSFileSource.html#/s:13VGSCollectSDK13VGSFileSourceO12photoLibraryyA2CmF":{"name":"photoLibrary","abstract":"

    Device photo library.

    ","parent_name":"VGSFileSource"},"Enums/VGSFileSource.html#/s:13VGSCollectSDK13VGSFileSourceO6camerayA2CmF":{"name":"camera","abstract":"

    Device camera.

    ","parent_name":"VGSFileSource"},"Enums/VGSFileSource.html#/s:13VGSCollectSDK13VGSFileSourceO18documentsDirectoryyA2CmF":{"name":"documentsDirectory","abstract":"

    Device documents directory.

    ","parent_name":"VGSFileSource"},"Protocols/VGSFilePickerControllerDelegate.html#/c:@M@VGSCollectSDK@objc(pl)VGSFilePickerControllerDelegate(im)userDidPickFileWithInfo:":{"name":"userDidPickFileWithInfo(_:)","abstract":"

    On user select a file

    ","parent_name":"VGSFilePickerControllerDelegate"},"Protocols/VGSFilePickerControllerDelegate.html#/c:@M@VGSCollectSDK@objc(pl)VGSFilePickerControllerDelegate(im)userDidSCancelFilePicking":{"name":"userDidSCancelFilePicking()","abstract":"

    On user canceling file picking

    ","parent_name":"VGSFilePickerControllerDelegate"},"Protocols/VGSFilePickerControllerDelegate.html#/c:@M@VGSCollectSDK@objc(pl)VGSFilePickerControllerDelegate(im)filePickingFailedWithError:":{"name":"filePickingFailedWithError(_:)","abstract":"

    On error occured when user pick a file.

    ","parent_name":"VGSFilePickerControllerDelegate"},"Classes/VGSFilePickerConfiguration.html#/s:13VGSCollectSDK26VGSFilePickerConfigurationC9fieldNameSSvp":{"name":"fieldName","abstract":"

    Name that will be associated with selected file by user. Used as a JSON key on send request with file data to your organozation vault.

    ","parent_name":"VGSFilePickerConfiguration"},"Classes/VGSFilePickerConfiguration.html#/s:13VGSCollectSDK26VGSFilePickerConfigurationC9collector9fieldName10fileSourceAcA0A0C_SSAA0cJ0Otcfc":{"name":"init(collector:fieldName:fileSource:)","abstract":"

    Initialization

    ","parent_name":"VGSFilePickerConfiguration"},"Classes/VGSFilePickerController.html#/s:13VGSCollectSDK23VGSFilePickerControllerC8delegateAA0cdE8Delegate_pSgvp":{"name":"delegate","abstract":"

    VGSFilePickerControllerDelegate - handle user interaction on file picking.

    ","parent_name":"VGSFilePickerController"},"Classes/VGSFilePickerController.html#/s:13VGSCollectSDK23VGSFilePickerControllerC13configurationAcA0cD13ConfigurationC_tcfc":{"name":"init(configuration:)","abstract":"

    Initialization

    ","parent_name":"VGSFilePickerController"},"Classes/VGSFilePickerController.html#/s:13VGSCollectSDK23VGSFilePickerControllerC011presentFileD02on8animated10completionySo06UIViewE0C_SbyycSgtF":{"name":"presentFilePicker(on:animated:completion:)","abstract":"

    Present file picker view

    ","parent_name":"VGSFilePickerController"},"Classes/VGSFilePickerController.html#/s:13VGSCollectSDK23VGSFilePickerControllerC011dismissFileD08animated10completionySb_yycSgtF":{"name":"dismissFilePicker(animated:completion:)","abstract":"

    Dismiss file picker view

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

    Controller responsible for importing files from device sources.

    "},"Classes/VGSFilePickerConfiguration.html":{"name":"VGSFilePickerConfiguration","abstract":"

    A class responsible for configuration VGSFilePickerController.

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

    Delegates produced by VGSFilePickerController.

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

    Available file source destinations that VGSFilePickerController can work with.

    "},"Classes/VGSFileInfo.html":{"name":"VGSFileInfo","abstract":"

    An object that holds optional files’ metadata on selecting file through VGSFilePickerController.

    "},"Enums/VGSVaultStorageType.html#/s:13VGSCollectSDK19VGSVaultStorageTypeO10PERSISTENTyA2CmF":{"name":"PERSISTENT","abstract":"

    PERSISTENT data storage.

    ","parent_name":"VGSVaultStorageType"},"Enums/VGSVaultStorageType.html#/s:13VGSCollectSDK19VGSVaultStorageTypeO8VOLATILEyA2CmF":{"name":"VOLATILE","abstract":"

    VOLATILE data storage.

    ","parent_name":"VGSVaultStorageType"},"Enums/VGSVaultAliasFormat.html#/s:13VGSCollectSDK19VGSVaultAliasFormatO18FPE_ACC_NUM_T_FOURyA2CmF":{"name":"FPE_ACC_NUM_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/s:13VGSCollectSDK19VGSVaultAliasFormatO31FPE_ALPHANUMERIC_ACC_NUM_T_FOURyA2CmF":{"name":"FPE_ALPHANUMERIC_ACC_NUM_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/s:13VGSCollectSDK19VGSVaultAliasFormatO14FPE_SIX_T_FOURyA2CmF":{"name":"FPE_SIX_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/s:13VGSCollectSDK19VGSVaultAliasFormatO14FPE_SSN_T_FOURyA2CmF":{"name":"FPE_SSN_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/s:13VGSCollectSDK19VGSVaultAliasFormatO10FPE_T_FOURyA2CmF":{"name":"FPE_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/s:13VGSCollectSDK19VGSVaultAliasFormatO21NUM_LENGTH_PRESERVINGyA2CmF":{"name":"NUM_LENGTH_PRESERVING","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/s:13VGSCollectSDK19VGSVaultAliasFormatO4PFPTyA2CmF":{"name":"PFPT","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/s:13VGSCollectSDK19VGSVaultAliasFormatO8RAW_UUIDyA2CmF":{"name":"RAW_UUID","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/s:13VGSCollectSDK19VGSVaultAliasFormatO4UUIDyA2CmF":{"name":"UUID","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Structs/VGSTokenizationParameters.html#/s:13VGSCollectSDK25VGSTokenizationParametersV7storageSSvp":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSTokenizationParameters"},"Structs/VGSTokenizationParameters.html#/s:13VGSCollectSDK25VGSTokenizationParametersV6formatSSvp":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSTokenizationParameters"},"Structs/VGSSSNTokenizationParameters.html#/s:13VGSCollectSDK28VGSSSNTokenizationParametersV7storageSSvp":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSSSNTokenizationParameters"},"Structs/VGSSSNTokenizationParameters.html#/s:13VGSCollectSDK28VGSSSNTokenizationParametersV6formatSSvp":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSSSNTokenizationParameters"},"Structs/VGSExpDateTokenizationParameters.html#/s:13VGSCollectSDK32VGSExpDateTokenizationParametersV7storageSSvp":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSExpDateTokenizationParameters"},"Structs/VGSExpDateTokenizationParameters.html#/s:13VGSCollectSDK32VGSExpDateTokenizationParametersV6formatSSvp":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSExpDateTokenizationParameters"},"Structs/VGSDateTokenizationParameters.html#/s:13VGSCollectSDK29VGSDateTokenizationParametersV7storageSSvp":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSDateTokenizationParameters"},"Structs/VGSDateTokenizationParameters.html#/s:13VGSCollectSDK29VGSDateTokenizationParametersV6formatSSvp":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSDateTokenizationParameters"},"Structs/VGSCardNumberTokenizationParameters.html#/s:13VGSCollectSDK35VGSCardNumberTokenizationParametersV7storageSSvp":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSCardNumberTokenizationParameters"},"Structs/VGSCardNumberTokenizationParameters.html#/s:13VGSCollectSDK35VGSCardNumberTokenizationParametersV6formatSSvp":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSCardNumberTokenizationParameters"},"Structs/VGSCardHolderNameTokenizationParameters.html#/s:13VGSCollectSDK39VGSCardHolderNameTokenizationParametersV7storageSSvp":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSCardHolderNameTokenizationParameters"},"Structs/VGSCardHolderNameTokenizationParameters.html#/s:13VGSCollectSDK39VGSCardHolderNameTokenizationParametersV6formatSSvp":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSCardHolderNameTokenizationParameters"},"Structs/VGSCVCTokenizationParameters.html#/s:13VGSCollectSDK28VGSCVCTokenizationParametersV7storageSSvp":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSCVCTokenizationParameters"},"Structs/VGSCVCTokenizationParameters.html#/s:13VGSCollectSDK28VGSCVCTokenizationParametersV6formatSSvp":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSCVCTokenizationParameters"},"Protocols/VGSTokenizationParametersProtocol.html#/s:13VGSCollectSDK33VGSTokenizationParametersProtocolP6formatSSvp":{"name":"format","abstract":"

    Tokenization format.

    ","parent_name":"VGSTokenizationParametersProtocol"},"Protocols/VGSTokenizationParametersProtocol.html#/s:13VGSCollectSDK33VGSTokenizationParametersProtocolP7storageSSvp":{"name":"storage","abstract":"

    Storage type.

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

    Parameters describing textfield input tokenization.

    "},"Structs/VGSCVCTokenizationParameters.html":{"name":"VGSCVCTokenizationParameters","abstract":"

    VGSCVCTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSCardHolderNameTokenizationParameters.html":{"name":"VGSCardHolderNameTokenizationParameters","abstract":"

    VGSCardHolderNameTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSCardNumberTokenizationParameters.html":{"name":"VGSCardNumberTokenizationParameters","abstract":"

    VGSCardTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSDateTokenizationParameters.html":{"name":"VGSDateTokenizationParameters","abstract":"

    VGSDateTokenizationParameters - parameters required for tokenization API

    "},"Structs/VGSExpDateTokenizationParameters.html":{"name":"VGSExpDateTokenizationParameters","abstract":"

    VGSExpDateTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSSSNTokenizationParameters.html":{"name":"VGSSSNTokenizationParameters","abstract":"

    VGSSSNTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSTokenizationParameters.html":{"name":"VGSTokenizationParameters","abstract":"

    VGSTokenizationParameters - parameters required for tokenization api.

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

    Type of Alias format. Read more about avaliable formats: https://www.verygoodsecurity.com/docs/terminology/nomenclature#alias-formats .

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

    Type of VGS Vault storage.

    "},"Enums/VGSTextFieldInputSource.html#/s:13VGSCollectSDK23VGSTextFieldInputSourceO8keyboardyA2CmF":{"name":"keyboard","abstract":"

    UIKeyboard input type.

    ","parent_name":"VGSTextFieldInputSource"},"Enums/VGSTextFieldInputSource.html#/s:13VGSCollectSDK23VGSTextFieldInputSourceO10datePickeryA2CmF":{"name":"datePicker","abstract":"

    UIDatePicker input type.

    ","parent_name":"VGSTextFieldInputSource"},"Structs/VGSDate.html#/s:13VGSCollectSDK7VGSDateV12dayFormattedSSvp":{"name":"dayFormatted","abstract":"

    Get the day formatted value, for example if the day is 1 it is returned as 01

    ","parent_name":"VGSDate"},"Structs/VGSDate.html#/s:13VGSCollectSDK7VGSDateV14monthFormattedSSvp":{"name":"monthFormatted","abstract":"

    Get the month formatted value, for example if the month is 3 it is returned as 03

    ","parent_name":"VGSDate"},"Structs/VGSDate.html#/s:13VGSCollectSDK7VGSDateV3day5month4yearACSgSi_S2itcfc":{"name":"init(day:month:year:)","abstract":"

    Create a new instance of a VGSDate object, if the date is not valid, it returns nil

    ","parent_name":"VGSDate"},"Enums/VGSDateFormat.html#/s:13VGSCollectSDK13VGSDateFormatO07displayD0SSvp":{"name":"displayFormat","abstract":"

    Date format used for display in UI

    ","parent_name":"VGSDateFormat"},"Enums/VGSDateFormat.html#/s:13VGSCollectSDK13VGSDateFormatO7defaultACvpZ":{"name":"default","abstract":"

    Default format

    ","parent_name":"VGSDateFormat"},"Enums/FieldType.html#/s:13VGSCollectSDK9FieldTypeO4noneyA2CmF":{"name":"none","abstract":"

    Field type that doesn’t require any input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/s:13VGSCollectSDK9FieldTypeO10cardNumberyA2CmF":{"name":"cardNumber","abstract":"

    Field type that requires Credit Card Number input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/s:13VGSCollectSDK9FieldTypeO7expDateyA2CmF":{"name":"expDate","abstract":"

    Field type that requires Expiration Date input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/s:13VGSCollectSDK9FieldTypeO4dateyA2CmF":{"name":"date","abstract":"

    Field type that requires Date input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/s:13VGSCollectSDK9FieldTypeO3cvcyA2CmF":{"name":"cvc","abstract":"

    Field type that requires Credit Card CVC input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/s:13VGSCollectSDK9FieldTypeO14cardHolderNameyA2CmF":{"name":"cardHolderName","abstract":"

    Field type that requires Cardholder Name input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/s:13VGSCollectSDK9FieldTypeO3ssnyA2CmF":{"name":"ssn","abstract":"

    Field type that requires US Social Security Number input formatting and validation.

    ","parent_name":"FieldType"},"Protocols/VGSExpDateConfigurationProtocol.html#/s:13VGSCollectSDK31VGSExpDateConfigurationProtocolP11inputSourceAA017VGSTextFieldInputH0Ovp":{"name":"inputSource","abstract":"

    Input Source type.

    ","parent_name":"VGSExpDateConfigurationProtocol"},"Protocols/VGSExpDateConfigurationProtocol.html#/s:13VGSCollectSDK31VGSExpDateConfigurationProtocolP05inputD6FormatAA010VGSCardExpdH0OSgvp":{"name":"inputDateFormat","abstract":"

    Input date format to convert.

    ","parent_name":"VGSExpDateConfigurationProtocol"},"Protocols/VGSExpDateConfigurationProtocol.html#/s:13VGSCollectSDK31VGSExpDateConfigurationProtocolP06outputD6FormatAA010VGSCardExpdH0OSgvp":{"name":"outputDateFormat","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateConfigurationProtocol"},"Protocols/VGSDateConfigurationProtocol.html#/s:13VGSCollectSDK28VGSDateConfigurationProtocolP11inputSourceAA017VGSTextFieldInputG0Ovp":{"name":"inputSource","abstract":"

    Input source type.

    ","parent_name":"VGSDateConfigurationProtocol"},"Protocols/VGSDateConfigurationProtocol.html#/s:13VGSCollectSDK28VGSDateConfigurationProtocolP15inputDateFormatAA0cH0OSgvp":{"name":"inputDateFormat","abstract":"

    Input date format to convert.

    ","parent_name":"VGSDateConfigurationProtocol"},"Protocols/VGSDateConfigurationProtocol.html#/s:13VGSCollectSDK28VGSDateConfigurationProtocolP16outputDateFormatAA0cH0OSgvp":{"name":"outputDateFormat","abstract":"

    Output date format to convert.

    ","parent_name":"VGSDateConfigurationProtocol"},"Classes/VGSTokenizationConfiguration.html#/s:13VGSCollectSDK28VGSTokenizationConfigurationC22tokenizationParametersAA0cF0Vvp":{"name":"tokenizationParameters","abstract":"

    VGSTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSTokenizationConfiguration"},"Classes/VGSSSNTokenizationConfiguration.html#/s:13VGSCollectSDK31VGSSSNTokenizationConfigurationC22tokenizationParametersAA0cF0Vvp":{"name":"tokenizationParameters","abstract":"

    VGSSSNTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSSSNTokenizationConfiguration"},"Classes/VGSSSNTokenizationConfiguration.html#/s:13VGSCollectSDK31VGSSSNTokenizationConfigurationC4typeAA9FieldTypeOvp":{"name":"type","abstract":"

    FieldType.ssn type of VGSTextFieldtokenization configuration.

    ","parent_name":"VGSSSNTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/s:13VGSCollectSDK35VGSExpDateTokenizationConfigurationC4typeAA9FieldTypeOvp":{"name":"type","abstract":"

    FieldType.expDate type of VGSTextFieldtokenization configuration.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/s:13VGSCollectSDK35VGSExpDateTokenizationConfigurationC11inputSourceAA017VGSTextFieldInputH0Ovp":{"name":"inputSource","abstract":"

    Input Source type. Default is VGSTextFieldInputSource.datePicker.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/s:13VGSCollectSDK35VGSExpDateTokenizationConfigurationC05inputD6FormatAA010VGSCardExpdH0OSgvp":{"name":"inputDateFormat","abstract":"

    Input date format to convert.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/s:13VGSCollectSDK35VGSExpDateTokenizationConfigurationC06outputD6FormatAA010VGSCardExpdH0OSgvp":{"name":"outputDateFormat","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/s:13VGSCollectSDK35VGSExpDateTokenizationConfigurationC22tokenizationParametersAA0cdeH0Vvp":{"name":"tokenizationParameters","abstract":"

    VGSExpDateTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/s:13VGSCollectSDK35VGSExpDateTokenizationConfigurationC11serializersSayAA27VGSFormatSerializerProtocol_pGvp":{"name":"serializers","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSDateTokenizationConfiguration.html#/s:13VGSCollectSDK32VGSDateTokenizationConfigurationC9collector9fieldName19datePickerStartDate0ij3EndL0AcA0A0C_SSAA0C0VSgALtcfc":{"name":"init(collector:fieldName:datePickerStartDate:datePickerEndDate:)","abstract":"

    Initialization","parent_name":"VGSDateTokenizationConfiguration"},"Classes/VGSDateTokenizationConfiguration.html#/s:13VGSCollectSDK32VGSDateTokenizationConfigurationC4typeAA9FieldTypeOvp":{"name":"type","abstract":"

    Super initializer

    ","parent_name":"VGSDateTokenizationConfiguration"},"Classes/VGSDateTokenizationConfiguration.html#/s:13VGSCollectSDK28VGSDateConfigurationProtocolP11inputSourceAA017VGSTextFieldInputG0Ovp":{"name":"inputSource","parent_name":"VGSDateTokenizationConfiguration"},"Classes/VGSDateTokenizationConfiguration.html#/s:13VGSCollectSDK28VGSDateConfigurationProtocolP15inputDateFormatAA0cH0OSgvp":{"name":"inputDateFormat","parent_name":"VGSDateTokenizationConfiguration"},"Classes/VGSDateTokenizationConfiguration.html#/s:13VGSCollectSDK28VGSDateConfigurationProtocolP16outputDateFormatAA0cH0OSgvp":{"name":"outputDateFormat","parent_name":"VGSDateTokenizationConfiguration"},"Classes/VGSCVCTokenizationConfiguration.html#/s:13VGSCollectSDK31VGSCVCTokenizationConfigurationC22tokenizationParametersAA0cF0Vvp":{"name":"tokenizationParameters","abstract":"

    VGSCVCTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSCVCTokenizationConfiguration"},"Classes/VGSCVCTokenizationConfiguration.html#/s:13VGSCollectSDK31VGSCVCTokenizationConfigurationC4typeAA9FieldTypeOvp":{"name":"type","abstract":"

    FieldType.cvc type of VGSTextFieldtokenization configuration.

    ","parent_name":"VGSCVCTokenizationConfiguration"},"Classes/VGSCardNumberTokenizationConfiguration.html#/s:13VGSCollectSDK38VGSCardNumberTokenizationConfigurationC22tokenizationParametersAA0cdeH0Vvp":{"name":"tokenizationParameters","abstract":"

    VGSCardTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSCardNumberTokenizationConfiguration"},"Classes/VGSCardNumberTokenizationConfiguration.html#/s:13VGSCollectSDK38VGSCardNumberTokenizationConfigurationC4typeAA9FieldTypeOvp":{"name":"type","abstract":"

    FieldType.cardNumber type of VGSTextFieldtokenization configuration.

    ","parent_name":"VGSCardNumberTokenizationConfiguration"},"Classes/VGSCardHolderNameTokenizationConfiguration.html#/s:13VGSCollectSDK42VGSCardHolderNameTokenizationConfigurationC22tokenizationParametersAA0cdefI0Vvp":{"name":"tokenizationParameters","abstract":"

    VGSCardHolderNameTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSCardHolderNameTokenizationConfiguration"},"Classes/VGSCardHolderNameTokenizationConfiguration.html#/s:13VGSCollectSDK42VGSCardHolderNameTokenizationConfigurationC4typeAA9FieldTypeOvp":{"name":"type","abstract":"

    FieldType.cardHolderName type of VGSTextFieldtokenization configuration.

    ","parent_name":"VGSCardHolderNameTokenizationConfiguration"},"Classes/VGSDateConfiguration.html#/s:13VGSCollectSDK20VGSDateConfigurationC9collector9fieldName19datePickerStartDate0hi3EndK0AcA0A0C_SSAA0C0VSgALtcfc":{"name":"init(collector:fieldName:datePickerStartDate:datePickerEndDate:)","abstract":"

    Initialization","parent_name":"VGSDateConfiguration"},"Classes/VGSDateConfiguration.html#/s:13VGSCollectSDK20VGSDateConfigurationC4typeAA9FieldTypeOvp":{"name":"type","abstract":"

    Super initializer

    ","parent_name":"VGSDateConfiguration"},"Classes/VGSDateConfiguration.html#/s:13VGSCollectSDK28VGSDateConfigurationProtocolP11inputSourceAA017VGSTextFieldInputG0Ovp":{"name":"inputSource","parent_name":"VGSDateConfiguration"},"Classes/VGSDateConfiguration.html#/s:13VGSCollectSDK28VGSDateConfigurationProtocolP15inputDateFormatAA0cH0OSgvp":{"name":"inputDateFormat","parent_name":"VGSDateConfiguration"},"Classes/VGSDateConfiguration.html#/s:13VGSCollectSDK28VGSDateConfigurationProtocolP16outputDateFormatAA0cH0OSgvp":{"name":"outputDateFormat","parent_name":"VGSDateConfiguration"},"Classes/VGSDateConfiguration.html#/s:13VGSCollectSDK20VGSDateConfigurationC15validYearsCountSivpZ":{"name":"validYearsCount","abstract":"

    Amount of years used to calculate the minimun and maximun date picker default dates

    ","parent_name":"VGSDateConfiguration"},"Classes/VGSDateConfiguration.html#/s:13VGSCollectSDK20VGSDateConfigurationC23minValidPickerStartDateAA0C0VvpZ":{"name":"minValidPickerStartDate","abstract":"

    Minimun date picker start date, current year minus validYearsCount

    ","parent_name":"VGSDateConfiguration"},"Classes/VGSDateConfiguration.html#/s:13VGSCollectSDK20VGSDateConfigurationC21maxValidPickerEndDateAA0C0VvpZ":{"name":"maxValidPickerEndDate","abstract":"

    Maximun date picker valid end date, current year plus validYearsCount

    ","parent_name":"VGSDateConfiguration"},"Classes/VGSExpDateConfiguration.html#/s:13VGSCollectSDK23VGSExpDateConfigurationC4typeAA9FieldTypeOvp":{"name":"type","abstract":"

    FieldType.expDate type of VGSTextField configuration.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSExpDateConfiguration.html#/s:13VGSCollectSDK23VGSExpDateConfigurationC11inputSourceAA017VGSTextFieldInputG0Ovp":{"name":"inputSource","abstract":"

    Input Source type. Default is VGSTextFieldInputSource.datePicker.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSExpDateConfiguration.html#/s:13VGSCollectSDK23VGSExpDateConfigurationC05inputD6FormatAA010VGSCardExpdG0OSgvp":{"name":"inputDateFormat","abstract":"

    Input date format to convert.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSExpDateConfiguration.html#/s:13VGSCollectSDK23VGSExpDateConfigurationC06outputD6FormatAA010VGSCardExpdG0OSgvp":{"name":"outputDateFormat","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSExpDateConfiguration.html#/s:13VGSCollectSDK23VGSExpDateConfigurationC11serializersSayAA27VGSFormatSerializerProtocol_pGvp":{"name":"serializers","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC12vgsCollectorAA0A0CSgvp":{"name":"vgsCollector","abstract":"

    Collect form that will be assiciated with VGSTextField.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC4typeAA9FieldTypeOvp":{"name":"type","abstract":"

    Type of field congfiguration. Default is FieldType.none.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC9fieldNameSSvp":{"name":"fieldName","abstract":"

    Name that will be associated with VGSTextField and used as a JSON key on send request with textfield data to your organozation vault.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC10isRequiredSbvp":{"name":"isRequired","abstract":"

    Set if VGSTextField is required to be non-empty and non-nil on send request. Default is false.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC19isRequiredValidOnlySbvp":{"name":"isRequiredValidOnly","abstract":"

    Set if VGSTextField is required to be valid only on send request. Default is false.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC13formatPatternSSSgvp":{"name":"formatPattern","abstract":"

    Input data visual format pattern. If not applied, will be set by default depending on field type.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC7dividerSSSgvp":{"name":"divider","abstract":"

    String, used to replace not default VGSConfiguration.formatPattern characters in input text on send request.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC12keyboardTypeSo010UIKeyboardE0VSgvp":{"name":"keyboardType","abstract":"

    Preferred UIKeyboardType for VGSTextField. If not applied, will be set by default depending on field type parameter.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC13returnKeyTypeSo08UIReturneF0VSgvp":{"name":"returnKeyType","abstract":"

    Preferred UIReturnKeyType for VGSTextField.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC18keyboardAppearanceSo010UIKeyboardE0VSgvp":{"name":"keyboardAppearance","abstract":"

    Preferred UIKeyboardAppearance for textfield. By default is UIKeyboardAppearance.default.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC15validationRulesAA20VGSValidationRuleSetVSgvp":{"name":"validationRules","abstract":"

    Validation rules for field input. Defines State.isValide result.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC14maxInputLengthSiSgvp":{"name":"maxInputLength","abstract":"

    Max input length. IMPORTANT! Can conflict with .formatPattern attribute.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC9collector9fieldNameAcA0A0C_SStcfc":{"name":"init(collector:fieldName:)","abstract":"

    Initialization

    ","parent_name":"VGSConfiguration"},"Protocols/VGSTextFieldDelegate.html#/c:@M@VGSCollectSDK@objc(pl)VGSTextFieldDelegate(im)vgsTextFieldDidBeginEditing:":{"name":"vgsTextFieldDidBeginEditing(_:)","abstract":"

    VGSTextField did become first responder.

    ","parent_name":"VGSTextFieldDelegate"},"Protocols/VGSTextFieldDelegate.html#/c:@M@VGSCollectSDK@objc(pl)VGSTextFieldDelegate(im)vgsTextFieldDidEndEditing:":{"name":"vgsTextFieldDidEndEditing(_:)","abstract":"

    VGSTextField did resign first responder.

    ","parent_name":"VGSTextFieldDelegate"},"Protocols/VGSTextFieldDelegate.html#/c:@M@VGSCollectSDK@objc(pl)VGSTextFieldDelegate(im)vgsTextFieldDidEndEditingOnReturn:":{"name":"vgsTextFieldDidEndEditingOnReturn(_:)","abstract":"

    VGSTextField did resign first responder on Return button pressed.

    ","parent_name":"VGSTextFieldDelegate"},"Protocols/VGSTextFieldDelegate.html#/c:@M@VGSCollectSDK@objc(pl)VGSTextFieldDelegate(im)vgsTextFieldDidChange:":{"name":"vgsTextFieldDidChange(_:)","abstract":"

    VGSTextField input changed.

    ","parent_name":"VGSTextFieldDelegate"},"Classes/VGSCVCTextField/CVCIconLocation.html#/s:13VGSCollectSDK15VGSCVCTextFieldC15CVCIconLocationO4leftyA2EmF":{"name":"left","abstract":"

    CVC icon at left side of VGSCardTextField.

    ","parent_name":"CVCIconLocation"},"Classes/VGSCVCTextField/CVCIconLocation.html#/s:13VGSCollectSDK15VGSCVCTextFieldC15CVCIconLocationO5rightyA2EmF":{"name":"right","abstract":"

    CVC icon at right side of VGSCardTextField.

    ","parent_name":"CVCIconLocation"},"Classes/VGSCVCTextField/CVCIconLocation.html":{"name":"CVCIconLocation","abstract":"

    Available CVC icon positions enum.

    ","parent_name":"VGSCVCTextField"},"Classes/VGSCVCTextField.html#/s:13VGSCollectSDK15VGSCVCTextFieldC15cvcIconLocationAC07CVCIconG0Ovp":{"name":"cvcIconLocation","abstract":"

    CVC icon position inside VGSCardTextField.

    ","parent_name":"VGSCVCTextField"},"Classes/VGSCVCTextField.html#/s:13VGSCollectSDK15VGSCVCTextFieldC11cvcIconSizeSo6CGSizeVvp":{"name":"cvcIconSize","abstract":"

    CVC icon size.

    ","parent_name":"VGSCVCTextField"},"Classes/VGSCVCTextField.html#/s:13VGSCollectSDK15VGSCVCTextFieldC13cvcIconSourceSo7UIImageCSgAA15VGSPaymentCardsC9CardBrandOcSgvp":{"name":"cvcIconSource","abstract":"

    Asks custom image for specific VGSPaymentCards.CardBrand

    ","parent_name":"VGSCVCTextField"},"Classes/VGSDateTextField/MonthFormat.html#/s:13VGSCollectSDK16VGSDateTextFieldC11MonthFormatO12shortSymbolsyA2EmF":{"name":"shortSymbols","abstract":"

    Short month name, e.g.: Jan

    ","parent_name":"MonthFormat"},"Classes/VGSDateTextField/MonthFormat.html#/s:13VGSCollectSDK16VGSDateTextFieldC11MonthFormatO11longSymbolsyA2EmF":{"name":"longSymbols","abstract":"

    Long month name, e.g.: January

    ","parent_name":"MonthFormat"},"Classes/VGSDateTextField/MonthFormat.html#/s:13VGSCollectSDK16VGSDateTextFieldC11MonthFormatO7numbersyA2EmF":{"name":"numbers","abstract":"

    Month number: e.g.: 01

    ","parent_name":"MonthFormat"},"Classes/VGSDateTextField/MonthFormat.html":{"name":"MonthFormat","abstract":"

    Available month Label formats in UIPickerView

    ","parent_name":"VGSDateTextField"},"Classes/VGSDateTextField.html#/s:13VGSCollectSDK16VGSDateTextFieldC17monthPickerFormatAC05MonthH0Ovp":{"name":"monthPickerFormat","abstract":"

    UIPickerView month label format

    ","parent_name":"VGSDateTextField"},"Classes/VGSDateTextField.html#/s:13VGSCollectSDK16VGSDateTextFieldC13configurationAA16VGSConfigurationCSgvp":{"name":"configuration","parent_name":"VGSDateTextField"},"Classes/VGSExpDateTextField/YearFormat.html#/s:13VGSCollectSDK19VGSExpDateTextFieldC10YearFormatO5shortyA2EmF":{"name":"short","abstract":"

    Two digits year format, e.g.: 21

    ","parent_name":"YearFormat"},"Classes/VGSExpDateTextField/YearFormat.html#/s:13VGSCollectSDK19VGSExpDateTextFieldC10YearFormatO4longyA2EmF":{"name":"long","abstract":"

    Four digits year format:, e.g.:2021

    ","parent_name":"YearFormat"},"Classes/VGSExpDateTextField/MonthFormat.html#/s:13VGSCollectSDK19VGSExpDateTextFieldC11MonthFormatO12shortSymbolsyA2EmF":{"name":"shortSymbols","abstract":"

    Short month name, e.g.: Jan

    ","parent_name":"MonthFormat"},"Classes/VGSExpDateTextField/MonthFormat.html#/s:13VGSCollectSDK19VGSExpDateTextFieldC11MonthFormatO11longSymbolsyA2EmF":{"name":"longSymbols","abstract":"

    Long month name, e.g.: January

    ","parent_name":"MonthFormat"},"Classes/VGSExpDateTextField/MonthFormat.html#/s:13VGSCollectSDK19VGSExpDateTextFieldC11MonthFormatO7numbersyA2EmF":{"name":"numbers","abstract":"

    Month number: e.g.: 01

    ","parent_name":"MonthFormat"},"Classes/VGSExpDateTextField/MonthFormat.html":{"name":"MonthFormat","abstract":"

    Available Month Label formats in UIPickerView

    ","parent_name":"VGSExpDateTextField"},"Classes/VGSExpDateTextField/YearFormat.html":{"name":"YearFormat","abstract":"

    Available Year Label formats in UIPickerView

    ","parent_name":"VGSExpDateTextField"},"Classes/VGSExpDateTextField.html#/s:13VGSCollectSDK19VGSExpDateTextFieldC17monthPickerFormatAC05MonthI0Ovp":{"name":"monthPickerFormat","abstract":"

    UIPickerView Month Label format

    ","parent_name":"VGSExpDateTextField"},"Classes/VGSExpDateTextField.html#/s:13VGSCollectSDK19VGSExpDateTextFieldC15yearPickeFormatAC04YearI0Ovp":{"name":"yearPickeFormat","abstract":"

    UIPickerView Year Label format

    ","parent_name":"VGSExpDateTextField"},"Classes/VGSCardTextField/CardIconLocation.html#/s:13VGSCollectSDK16VGSCardTextFieldC16CardIconLocationO4leftyA2EmF":{"name":"left","abstract":"

    Card brand icon at left side of VGSCardTextField.

    ","parent_name":"CardIconLocation"},"Classes/VGSCardTextField/CardIconLocation.html#/s:13VGSCollectSDK16VGSCardTextFieldC16CardIconLocationO5rightyA2EmF":{"name":"right","abstract":"

    Card brand icon at right side of VGSCardTextField.

    ","parent_name":"CardIconLocation"},"Classes/VGSCardTextField/CardIconLocation.html":{"name":"CardIconLocation","abstract":"

    Available Card brand icon positions enum.

    ","parent_name":"VGSCardTextField"},"Classes/VGSCardTextField.html#/s:13VGSCollectSDK16VGSCardTextFieldC16cardIconLocationAC04CardgH0Ovp":{"name":"cardIconLocation","abstract":"

    Card brand icon position inside VGSCardTextField.

    ","parent_name":"VGSCardTextField"},"Classes/VGSCardTextField.html#/s:13VGSCollectSDK16VGSCardTextFieldC12cardIconSizeSo6CGSizeVvp":{"name":"cardIconSize","abstract":"

    Card brand icon size.

    ","parent_name":"VGSCardTextField"},"Classes/VGSCardTextField.html#/s:13VGSCollectSDK16VGSCardTextFieldC15cardsIconSourceSo7UIImageCSgAA15VGSPaymentCardsC9CardBrandOcSgvp":{"name":"cardsIconSource","abstract":"

    Asks custom image for specific VGSPaymentCards.CardBrand

    ","parent_name":"VGSCardTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC11placeholderSSSgvp":{"name":"placeholder","abstract":"

    Textfield placeholder string.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC22autocapitalizationTypeSo024UITextAutocapitalizationF0Vvp":{"name":"autocapitalizationType","abstract":"

    Textfield autocapitalization type. Default is .sentences.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC17spellCheckingTypeSo011UITextSpellfG0Vvp":{"name":"spellCheckingType","abstract":"

    Textfield spell checking type. Default is UITextSpellCheckingType.default.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC21attributedPlaceholderSo18NSAttributedStringCSgvp":{"name":"attributedPlaceholder","abstract":"

    Textfield attributedPlaceholder string.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC7paddingSo12UIEdgeInsetsVvp":{"name":"padding","abstract":"

    UIEdgeInsets for text and placeholder inside VGSTextField.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC13textAlignmentSo06NSTextF0Vvp":{"name":"textAlignment","abstract":"

    The technique to use for aligning the text.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC15clearButtonModeSo06UITextd4ViewG0Vvp":{"name":"clearButtonMode","abstract":"

    Sets when the clear button shows up. Default is UITextField.ViewMode.never

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC17isSecureTextEntrySbvp":{"name":"isSecureTextEntry","abstract":"

    Identifies whether the text object should disable text copying and in some cases hide the text being entered. Default is false.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC33adjustsFontForContentSizeCategorySbvp":{"name":"adjustsFontForContentSizeCategory","abstract":"

    Indicates whether VGSTextField should automatically update its font when the device’s UIContentSizeCategory is changed.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC21keyboardAccessoryViewSo6UIViewCSgvp":{"name":"keyboardAccessoryView","abstract":"

    Input Accessory View

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC18autocorrectionTypeSo020UITextAutocorrectionF0Vvp":{"name":"autocorrectionType","abstract":"

    Determines whether autocorrection is enabled or disabled during typing.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC04textD18AccessibilityLabelSSSgvp":{"name":"textFieldAccessibilityLabel","abstract":"

    A succinct label in a localized string that identifies the accessibility text field.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC04textD17AccessibilityHintSSSgvp":{"name":"textFieldAccessibilityHint","abstract":"

    A localized string that contains a brief description of the result of performing an action on the accessibility text field.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC13configurationAA16VGSConfigurationCSgvp":{"name":"configuration","abstract":"

    Specifies VGSTextField configuration parameters to work with VGSCollect.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC8delegateAA0cD8Delegate_pSgvp":{"name":"delegate","abstract":"

    Delegates VGSTextField editing events. Default is nil.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC14setDefaultTextyySSSgF":{"name":"setDefaultText(_:)","abstract":"

    Set textfield default text.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC9cleanTextyyF":{"name":"cleanText()","abstract":"

    Removes input from field.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC14isContentEqualySbACF":{"name":"isContentEqual(_:)","abstract":"

    Check if input text in two textfields is same. Returns Bool.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC4fontSo6UIFontCSgvp":{"name":"font","abstract":"

    VGSTextField text font

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/c:@CM@VGSCollectSDK@objc(cs)VGSTextField(py)textColor":{"name":"textColor","abstract":"

    VGSTextField text color

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/c:@CM@VGSCollectSDK@objc(cs)VGSTextField(py)cornerRadius":{"name":"cornerRadius","abstract":"

    VGSTextField layer corner radius

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/c:@CM@VGSCollectSDK@objc(cs)VGSTextField(py)borderWidth":{"name":"borderWidth","abstract":"

    VGSTextField layer borderWidth

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/c:@CM@VGSCollectSDK@objc(cs)VGSTextField(py)borderColor":{"name":"borderColor","abstract":"

    VGSTextField layer borderColor

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC14statePublisherAA0cd5StateF0Vvp":{"name":"statePublisher","abstract":"

    VGSTextFieldStatePublisher publisher that emits the State of a given VGSTextField.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/c:@CM@VGSCollectSDK@objc(cs)VGSTextField(im)becomeFirstResponder":{"name":"becomeFirstResponder()","abstract":"

    Make VGSTextField focused.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/c:@CM@VGSCollectSDK@objc(cs)VGSTextField(im)resignFirstResponder":{"name":"resignFirstResponder()","abstract":"

    Remove focus from VGSTextField.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/c:@CM@VGSCollectSDK@objc(cs)VGSTextField(py)isFirstResponder":{"name":"isFirstResponder","abstract":"

    Check if VGSTextField is focused.

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

    An object that displays an editable text area in user interface.

    "},"Classes/VGSCardTextField.html":{"name":"VGSCardTextField","abstract":"

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to detect and show credit card brand images.

    "},"Classes/VGSExpDateTextField.html":{"name":"VGSExpDateTextField","abstract":"

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to show picker view with Card Number Expiration Month and Year.

    "},"Classes/VGSDateTextField.html":{"name":"VGSDateTextField","abstract":"

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to show picker view with a Date. It support to define a range of valid dates to select from.

    "},"Classes/VGSCVCTextField.html":{"name":"VGSCVCTextField","abstract":"

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to show CVC/CVV images for credit card brands.

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

    Delegates produced by VGSTextField instance.

    "},"Classes/VGSConfiguration.html":{"name":"VGSConfiguration","abstract":"

    A class responsible for configuration VGSTextField.

    "},"Classes/VGSExpDateConfiguration.html":{"name":"VGSExpDateConfiguration","abstract":"

    A class responsible for configuration VGSTextField with fieldType = .expDate. Extends VGSConfiguration class.

    "},"Classes/VGSDateConfiguration.html":{"name":"VGSDateConfiguration","abstract":"

    Class responsible for configuration VGSDateTextField or VGSTextField with fieldType = .date. Extends VGSConfiguration

    "},"Classes/VGSCardHolderNameTokenizationConfiguration.html":{"name":"VGSCardHolderNameTokenizationConfiguration","abstract":"

    VGSCardHolderNameTokenizationConfiguration - textfield configuration for textfield with type .cardHolderName, required for work with tokenization api.

    "},"Classes/VGSCardNumberTokenizationConfiguration.html":{"name":"VGSCardNumberTokenizationConfiguration","abstract":"

    VGSCardTokenizationConfiguration - textfield configuration for textfield with type .cardNumber, required for work with tokenization api.

    "},"Classes/VGSCVCTokenizationConfiguration.html":{"name":"VGSCVCTokenizationConfiguration","abstract":"

    VGSCVCTokenizationConfiguration - textfield configuration for textfield with type .cvc, required for work with tokenization api.

    "},"Classes/VGSDateTokenizationConfiguration.html":{"name":"VGSDateTokenizationConfiguration","abstract":"

    Class responsible for configuration VGSDateTextField or VGSTextField with fieldType = .date."},"Classes/VGSExpDateTokenizationConfiguration.html":{"name":"VGSExpDateTokenizationConfiguration","abstract":"

    VGSExpDateTokenizationConfiguration - textfield configuration for textfield with type .expDate, required for work with tokenization api.

    "},"Classes/VGSSSNTokenizationConfiguration.html":{"name":"VGSSSNTokenizationConfiguration","abstract":"

    VGSSSNTokenizationConfiguration - textfield configuration for textfield with type .ssn, required for work with tokenization api.

    "},"Classes/VGSTokenizationConfiguration.html":{"name":"VGSTokenizationConfiguration","abstract":"

    VGSTokenizationConfiguration - textfield configuration for textfield with any type of data, required for work with tokenization api.

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

    Define the methods and properties the date configuration must have

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

    Attributes required to configure date format and input source for field with type .expDate.

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

    Type of VGSTextField configuration.

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

    Format used to validate a VGS date text input

    "},"Structs/VGSDate.html":{"name":"VGSDate","abstract":"

    Struct that represents a date including year, month and day. It doesn’t include hours, minutes or seconds.

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

    Type of VGSTextField input source.

    "},"UI%20Elements.html":{"name":"UI Elements"},"Tokenization%20Parameters.html":{"name":"Tokenization Parameters"},"File%20Picker.html":{"name":"File Picker"},"Observe%20State%20and%20Send%20Data.html":{"name":"Observe State and Send Data"},"Payment%20Cards.html":{"name":"Payment Cards"},"VGSTextField%20Serializers.html":{"name":"VGSTextField Serializers"},"Validation%20Rules.html":{"name":"Validation Rules"},"Errors.html":{"name":"Errors"},"Error%20Keys.html":{"name":"Error Keys"},"Debugging.html":{"name":"Debugging"},"Enumerations.html":{"name":"Enumerations"}} \ No newline at end of file diff --git a/docs/docsets/VGSCollectSDK.docset/Contents/Resources/docSet.dsidx b/docs/docsets/VGSCollectSDK.docset/Contents/Resources/docSet.dsidx index 76a384fea8336f04d6121785d7e62c50bf2d1851..18b76f7ae4f55ecd698744300806af7410ea1eb6 100644 GIT binary patch literal 131072 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 XmxOTVYM#4XI_v~HIH6f+A@KiyjiUbb literal 77824 zcmeHw31D1jb?&`)bZ5~>qa;QsVluIeaBRnR6vta6Teh|Di?!I1H)S-smL?j_$TK6` zigC=nW(@^i%UW8((zFyPG<2a*3N)1E0bOV*g|d}bwlYQ6qSSOgmtRg6oAz?Ia6Hc)Yii;+{uelo+l2r0KLY+y zrT>DzdFJ09{{+T8C;Myhtx$IlSNAA>Z2Z}1fsGc}Xn~Cu*l2-`7T9QkjTYEwfsGc} zXn~Cu*l27EKp={coO)g8jnu=>H__>lSF77Dup@wE)w-l3e8Hu4~{wZh$Om%b) z_po@|)AJ~9s;94KqG^0$V5DPWrfH~WW>*s_rfI6@fhn~t?VqGT`p+FA+B{VEdD8Nm z>i(nd>ALUMJyrMhy054o{kQLs4FNY=V50>#T419EHdqXjlvV50>#T419E zHd^5S_ZGNCNuvqsl!N$LqXh7?S{}sDuzWjyhUW1jxL>IK1{bP*Fo<7nt$Rc4k-F*H z2kXMI&&BrOlZ`(cEwIr78!fQW0vj!`(E=MSu+ah=EwIr78!d2SEf9N{`_7Fa{NKfW z+rzS)a?4V0 zI$tPGNQIRguG90|wMHp{>CVPqKy7PxiS_XgA)CueJsF9}*pppdF0@dQrf~1BiA4zb z9bky|i!JdapU$qVLhg(-nk)9^R(?{Kb$0x7#8Q#3#)nc7t-=f zQd?ND7h!oit{z>?6!@nI~3wMN`3cW6LD)^n?3xZAJ zAB!&(9}tDAk5s+1YJcFVz?%Z+1C7F`g|`Z8!XEy!yux?VYWn$cuedwDM;I$EO8KVA zVtzGMT+K^`Nhw8|g8jHatHwXN7YqkAhMvnsDO&)cmBIX2<$3WQac6wL#$!xIOBu$e zD#uHXihCPI1g3-ZVNd(Qr9<@ZRsM?;Vo&2N!#^plB+;YNq?Au5GwFw=yjofHC!JYZ z*E%UFB=>8l#i2x+88en~qRVgpn?-hIpx}*t;-Q9VMqCT2N0lu!YPBEUEpDwpL}er^ zAel~Nda6^@G0CoM7ZVK!4QfX*1cKr|j5)mdEFtX9rB>;}gcVoH8~v<~6XREPs5Fz+ z*2?g#Vex3=45??=YN4209#5_jw60`+ek3<9WgLCtPNsIqw_3&B4Sf`>)Qoj$rnLdF zz40WePZwGKQ^m>dA-eu_=a!S{Y+oifm(0))n3}kfK6j8HsWMQc3F*SBR49(o#i`(| zk6NCUO6|Mbrp1BA6eHAdZeantnnivuKsQCa`b_md8&pd#g%XgRTrm~6OGx*Usi zZWVGb$-+hp>orFuT25QBduf=Rbu8JxrQDOp$*w>}J<;X29lR(hV(kfWs6lc;w21Dg zu@%!oOJREsiaQ&6=s*XlzO}i*=-*K`{?dMEXVd)j^gy>=zdDgz%@D;hSx}pcGBmdk z(ycqh=J;-5dZ0;T(sy&_6BYlt&0<5t9)W6D7HLeKi;wLfyNaMIVpcL%JLBux#YFrp zKhbe=wgQQD^5^Upw?T8!wvZ+=Q+2s5pQ(~xQ(I=dcYMlc%MjA$4si>V*YTc-$$`nK z9=L+CIxqGQ+NzVqTt2xVG0LmSaM!)!9<;5tL1HhKRJ~Fc)%-%!uU@29OZ}WSo=qFm zK2xjp!U3@>J|c|G6{P${2?`uk9Qel0H%&_T0nIk4YgyhDD$*k-#e?xn{OI(^>~PO$ z-&FtX_(acS&%}v=(LUE&JI9hM@3T9_=6XpO!C7n3oTyqQh=!nR)cQznVMtZc#=FIx zn`iiuWMN4%*KtGJ@K8Q%h6-ub8XEUFuRld4i++4q3FiutG;%0oL5?)b9XzzH>?9^=U z*z|YPxss^cbF{4iM$~G)3JJs)-hNLxpF`zW` z1GRIn@50<^6?(E4)A<}V2$YGJnw zh`a04ly)GM%MRyK^!!a^XBG>>WbB76;>)g{dU#t10n%?L)qi=~$MxR;z*VTpUyCa{A zyg1Sxek%Od@KU%X^sn59Lr;X3gja`l1)mPSIXEcva*uJv5wWA;G*KDIVxq1t7R7?L zBGZ%}WNHnzs;B%D$xM2l_CwReD#9nUabo{i<&k^E{fS8;fzdp=UCs4W?4VL%F7FYy zHXOCU*hM!uRgPlS$2gIj5l0#qh$g0QD2z#`gu-5un&RKmf~CJ*Z`pzD`J7!I(v;+L zRh;d{VcycjnyJx^*XS*cM#Xu~sJJJwAS73b?J}QNcM3B1(3<6}f=(uWemOXnkVPRm z{}9gJ&;qkC#8De4PT-TUh;%`BzzkpW178kyVQNtt zPA{j6%wgMH`Kalj4CDDB@lYc*O0a~wdC?!NPCc(Kv=}_9nY3Uvo9G{^{c@|JoU==b zyb@?j+j*8R9sn4@(!N3|X1Tf7HsPe@KaEJH;KF zsflA?8M>)D!pf;kKxU}p!8^D+y-kQ+VtbrgUyRuZrBgSq87l>|7_eWfE%`ht*p-lZ zI<@E-&IGWp7!b|19128-i>h2Y5xBS9D{iYd=I>-~HJ`F}FCCfmV^yqeXNaXwpYZm{ zS#nKtoAEk>3Vs(_w1RvsC&bo7PF(|%E9oNEW7SAq$vWU*T$<|Y z!DQR3n_DRRN4v!>jaVe-=eOsvL+Lj@j9J&*tjHENDHXLLW3q6sIVNtYPYE-KIrMi# zF)7tfJ+7W)PmB$BObrb8xa#1}Q=(43?U1;)et^tt`*G4TzwKYrqW4*O>7m4|gRwTa zp8ofDiu)VK$T)Yjk;BgDprEC5uQlxKRsyEC%Rn)dD&(&iCRICR5f-;>SvX3iLcM-e z>}aGqkrirqbup`|t@OgfbFdh6D%`JnRCZX(E)*9>lEu_w8R-~G74nz+v58T`zfD34 z=?hH-dfkJ>Wa;cnq9Q}ZNvl=|a@AD^)XAV0@P-btwSG(;q`Fc_&nwo`fMqZl-&2T3 z4vTvls72YVE2W@=mi|j$8Js9rjjo)|E@g9A$PjxUSl%PD1f-A0n3}b{S24M@PDgL9uQd7ke70 z<&z~Uc|PzYq=18F1L}sG0dmFbvb`GnHbX!$_8R6`*bvy_O4QMlk|N$}m}6~pC2LxW zmckA!!IXZL^n|WzPG_adE6~WLd40?fqmsJtmRCJXaW9?}`x@yrqh6NUq)=5mF2ccq zY^&up;7Mh)r&z(s^l~PRsJx?tH0f*w*R!OPAY0w+`sJ8C;4jxk^1y zK$BD|vdNUhb*_5HqsvQlH?o)kc5-!PC6`CfT>>x$fTBQ?bWl zQ!%mjy|weTx7B>I=J_@EML!vRD0)lv2dnedcSJrIITyJ#{NeCiI2igs=;6@*;Mal| zgS*7P7vCiIi?>z%b=6~4XR7WDd@1mnK(FvU;RC`8h2z5Q{FnJR@~8O*?u#g@l0R+x zMGhJVU1hDe0+yA}RcUD3XW?bE8YeIFC7nl|dqob*E?ITgy=ZjaXJ9Z(s6GoVGO$aE zPC(^2yhr44xd}NOx0e7VG_RO^@|z6%wvur% zUBR6jAwB#YDz$$7=2|Lq{LtD>C*Rjh%dGJJ?ZmT14!2US7fU_`aOFL=g|?x23E~sX zWaw`aIb56Egj!fT>@o1A#%7jp=DVvKPrK@ zFm~O6>Arc!c5heCW@RJqh@&+(pTyG6ShC7tSgHG-g{5rsS$t@9Uh;urWjNI+axf$T zNHa29v`}5wxBuO|Pv{cAPWM2y#0Uax_g2 zG&c@!gPGbCFX7off&3^xL{icDuB^BtAmh6 z7QMys+fuq@6OkY!lS6s|+7iWz<{wgDrot}Elnt@e7_&6pNXTsotsG60tv^U)yX4t` z<>!jta)TlfY|Xpj{6J~k-BqPWS?P5_m#8;TW|WnK(WL1Rh%{->Hgca>mR{@Pi6~3n zjZ+dsVAo5zu>jl zDD)30?ZI;*2X}9)1b)1|$Irs5(|BP%T_EWJfGz-uDr^%E)Sy)U`3#H>;(G5T)-gSx`IeQ$TN=!>?GoO&$H-mW} zAG(yxXW^c1Kg3vCxw%E7+Vub}Ar04$G7N+yeKN=$O33x;f_9R)C{c&2o-Ao|5~N0T z>Yj!-Fyu#rTu)ryoJG8gG(R{w zHcCP-JM#JD+So-Ye+j;VUgpsf{np%43h$wjAlDw38(e5cr2N9oDvx4~3=<>K6|*Qu z3#lu&&&mu8k?y*5K9ekxwptIE&O0`Ujj@3o&{$=}VqLJiBY6_i0XsbaOGSeOK%1gf z60;O7g+1Gk!&w74oVjR}C85jFQ}|RLy#5*rfOkLpl`O#r3oT@+SL6`iq7~wPmMdG3 z4>q+Qdh~vF?B2yx|*m%N_GI%myQ(F+|^^qua-xrts`5w5iuJVqM*T8T zXs)ONKH*)3KXHT_sX_=V(ZXd5F3sd?mcj;Tf@IohMH0R%;fFbROSeriFs`$c`Q9|uk@NpP694~rT_?`}kHn6~gxdGj zK3u!M=6f~2UUMe;pV2o(r=vpkuT_s$H$}b|c~9hJk=aOn`19e{gwKVa8TwGD5UL73 z8O#TF!xpeo_3f(PsFJEefe!}O0u90!g*OVbg1~>2e=dKJ`#uU<|DRqNHwo}T!v<%% zWf4zF)mP1NTy-O&yTmaWR|fDWbO6ESvJ8sul-VicngH&crfa4eaLgQuti|h$a0WFT zKzrqSk=xpcgdpi6^$9Ih;1tR-waL%G(X(-uex@bO@F9sxeoBU!e}AKl#1{}_Ih}1= zPF`-4NJxEIanzRAwq7^>b{W?GhD3_O>4Vl&Gz%PMX_aB&-;|hzNR@Gep;d-0pYW!Q z+#CK%2E(jeM;iqHjz)F{-+l5H6qNT&>YeM16KmS||7bz?CpU#|>fJdEBN z_BvoR&eL)YtuO9+P+vH55C>MD^&MBK*}B>Qj>xdhHzXu~b+zJAo=&-%)HAK&maV51 zLgSKo8HV_ijq+|Fo~{BqpZpfea5Skt$8`rQ5lB&t&LY05z0;2 zk|pg(%OM;z6Y?gnn)qleBejKA6ECPv8J2zDW7a7*ZJc2lM*Xdgmnvuht9LVONo0_! zExqHI47+|qB29lSTUR?0<;utb*t;6#%@mi62G#oFbNp+T6~=Ly9S}~q0U5UchQt+r z5__Uk_9>YUa$9g)WfoJm4LlJ|j2;8@P^Y$AMkp~QY+EDUGfBs53h8K! zotjm(jifl*gwY6hT_$>P7x_&eDjr;fWY;B1?WKM*We}3di_p;G*gxsOv1p;w6T_Av zpjUDVY}&~2U^}}C8&dqzY6(Z?a>%84j~6l4;!92vB3b3YglnKcOsJ^>jnu*&l;I9t z4$jGOHcu;04@5Nj%Ndtg4zv{S=?fy)6<;+-ROwm2V&CXa*1i>Dnns!;IHwTV_1ie# zkUGOq4tG9ri2`-Q4cxrQ@&#pO>BtgmvP6~{x(wMNZ0iN7mNq^Omab)DZ(T@1Sx`+E z{xM9R_6)hkNlI#3H~$D4L*EjXfcTQCzd#JcCKpftK0$ZwE^*fI4^!n{PoaKh!6fjun^qN{gd#~ z=y#)Uj-Eo!zt2>^yn0{ctC8nN4u-!RehI&YzZ&`^_gdjqRae5@p%+zchR44WI4S&R z-5=H!>-NRIBlHVZ{2#%e;B+ij`-$3@)gGw%Zq3`nk(yl1o~l17YXs;QcP5fTDuWxX z&edWuhdV9T?aJ_j)~2Y9gMScZ)##<|L#~SvA%$qne9}HtY15mLwaqOm8Q*w1*g^t- zQ+AC<-#eKjWvMtW0NN3_w;mCgjaBn5;zFmC2J;53k#0`spiD2frAaEG88cIxH8&_3;-Iio)V)X9G!{p-;L5I4Olq>wwokz}yoFFM(sm-}Cx7#}l0hO5uAmI}zFW}1qt zk1&>+`|0W6o;Vr(^waHgBuNR$%+{vIHZbF?bPG8ExIZPsS3)=6pxeb6Oz(m|#eYtJ z?-n;Dx`a8?u%x$xeW-zi`{!erUo*m7E)PW=t!4CLBn>9x(Lw9SUTNW%tA?>3udcd6w@72vPI&wy=OWwqS#dzk3AhG=?BP zv2_453z$}NE(Q!M_m{nx($LO;Mn{N;T7|FO#)rNH%;M8Pmi(z%^JUy;#`FZt#)O&ld zK&4A9P(+2cr@+y64r8rq>cQYh^Tg7rB^vS{6lpT;I1wZ^SAl$@DUME;NOP=`J4(_j zxU6;>iA@YnJ|xByCxMz>g72L_-A^OtKG!YA<4ZcP)}zemC^>F*kPi=wTgVK!n6ga( z|0|He%KZkKIw6$?W29m?MN3|$KEPPe?72%9Y>zJh2s<) z-7*{i6Y=HMEKL3@$+Zd*bhd684u61wJ9sJw7tjh}bhdsOj(uC=@J5H;hQ}9HE3J{q z*o&luuuJ9^)9|e(yGDf~8GMIjxaJ{I6-hc(AqHXTm*IkkDlI4BE4v;+Ovb}<7nS59 zeC{ihgs^nVoy54fq^(XBB4}JQGCb;2+sT*LBFV#r<98Yu;!N+n}i+vFp3a!Hv=#+>Qz*X1$lD(o0*1 zd>CUmkunZN{uf7sWdOS%!ZDW6+{?+L%^<_9)gF>q*pAC>xPeF%916UDxg4xrG91#d zv7wE;H%SlSOrGO1ywQkcnCKRby#mSXtgZ4va<6pOuo!lDsd($?c6wExpPlcx_akHcLOYIhv`>Y|1uA7quCK$;FGK z{&SQ=ZOd>@%!Iiq?m&0P}5U>uY8kV&S8XsQl8m7-a?=%jov z8PL}polz;O17JW#DjMj3W{+14X-w6VGP2VUDeZHoVn{o{Q5h+0V5Re#d?ovZGPTRd zW>cS#Jf>ht0K#)r-bp2(om^>sC{wq5HyNeN-lMd%jZfq2myx{&)nxd>Al$mEo_ zlX1Fc8EO^7S-5B9Z9xnHnRg7dig6tXgYsQus1`~N)zVcrS!d*}nxOWvR=J>dgk$n^ z$XG!tHTSKew2Ug3j66AN?gh;W+xZ-ox?MAywkIV$r>Ep+2RV{v7nYu0y8SzI@O0v?+}_AvcjR zebrKwOP7`_%ECV-liWOsYu2LIfocUfBHxL$M)f0I_Pa}RiPe)`T_*pPatAvnBl(V+ z^`e|T#4%XPG0-tHEZ-q=NS$gi4pOIZ-M^y@?yycr;l^cTw+SP1m_!W`l3 z##utfXU+ym)*bb!$Zm%bP+z0`3ca8-gmA&;y8^H-s(R%mbxr04SHdQC!v)52WBQkgj?obs3tckIIFQ2T9_k(rD&g zln=z}GRc)XBms}A;F+I6xES|} zYeA_|Zcs}|&$mhDQ(J9|$c0O{p8|A|Oa|F3#&LnD8^0`T6n*-Y-PL?T@q%0*yn@&% zR{?N|i9|{ZxRSYICcc*)io8*3CCS$XBuuy z%{R(jhGdCbdx~%4=eHo@2_3GjBX0V{dH4aS4mstDGX-O3L^(`;^C9%kB$QpM&{P(E zvvycSpsv~z0a5yF6cP)`r6l?kTv|#(N;SuQX5(9EF$NX~DQz z^tVG9 zem(lGXg0d5`k$+xsD5tsvB)K$=*VTxot!8 zu?eV4V@2DX57euQ5ah^~>n7FDVaIJ#kl%4jVzQ_^@4LB#YNJJ4zD&|%3IaIc{hd=E z)204c<@qht{W5|#TM|j_LuwVJIQq%Ov%wu4$7IBFLYfroTwWH&LcL2yKquC&O!}f^ znKJg*MVng)$$c_HIFTf;00-f@obCsqPBJHlMs-j|v}SW+i1Apn3+dt5)*&Nub9Z9; zqBR=T(c&z-o%W!NpiY!d?J}yFu2ks^S&NL2&Um6LUFc5di;hP zr5pz(X^|1yNjaz@Q&KX7Eg-1APe$D4-o)v2!SZU$ST<8eLI?SN86lcm5(6eu>Ed;O zy)xo3Hz)dxt)dj0LDVKA2pa zNy4L&!LYNDy@~BZhV-C}$VkM#q(IV1oZ-vy8iYG#gh3*RVa`_!LyL@v$A(0oYqjk1 zQKDWM;f*cv+4J_NGAxr9`<>;v6J*)7(|5`Uble#~ZF?c342+HXh)jYU8y8eP%Arb^ z*PN1anx^9k8N*~Gxv~N`qVZfNoiYYAvkRBPbO#xh5e=zcWq54i4%@y59o-HFWduB` ziPqhXT@EyNG75G?MwBDo1Vx82S`XEa958kQ3b0>B5aZ5<9xDJ`=8^^VhsWEC&z0wc z+-##9pNGeAit1@}pj-4bG6D5Ax2P4f+QSxyBJp(;1{RO}q82-6r9>WBj}k_scJ zj_wnrhP2*3L&9uKCuO7(Mwpp4NwDAXE zknfdG5g(D`xT>z;<<3zQfK8C73>Ci`QtFaA0jg-|`hvadJR=`8N*#&5L ztA?YXKXJ$lD+X(qjGVqshd94Tnx|2pJW8gM(;?0;j^SuDEsqcd{wjcb*#oj&pDNp6 zHvSoTSam;E4>LD4g0@p0LK~9ICG?q5O(XJKb&adK_T7m8zb@2H)cm04{fN$Qh&~z3 z#9E?l(Qx$}YQJ86AoA15`y&@3cL=W!KNWswcrARe?j1r;=)0j0hF-@1K6gDd9ts6N z7`z-D;4koZ2CK#QiL!X4>PJ-{sJc>hZ{YjU83hC@HyI?IO|F&8U z28ti<2F3-i7GuKwTX4VS)m}Y=;tm8ABTwD{aX)ZBaALT-UFBMt_@fiJ(#i??qj4Q8 zD-b)GO}Q-)Zg5UUzMbQS5xgl0Y4Sch-svNQpeI|*8>%+b1;zl;8p*-KCtKm;F(Z&W z5`9LiYAZFEF>5Frg+!>i_Z$VMwTAt3|iMaedyT1*{ff< zb8kF^2=rM2nU-9z=>Qms`(<&V5#mm(zHiQ;``H&Nxqvi~HkF7`P?g$O~jYl$squQ+F|$9}Jf4 zLCobD3Sr@P^|;d)0l2JP8yAuFpVw3B-+0>pi6gk_oizY0!jNSE3$Zpv9Sag!rN-|; zJ$eM6<~i;sJqVVE_&4?*!*o9)>BvGzUNtwA8)jyk9bnD`>LsVQq{_*?3?4`EC5WRv zkG}3?N=vxjA+1P(>}_aD;}{N<{-Jx(C}=~!wj=Ie_kf|#oq=>1Yc-;%+;`NdWPQaY zBT`>Lm<6@eB28HMLme0_60gJ9D{3srbZb%X;MEA5g1E zx=quNf%`!x)=%6d8s=4doytnZA3O+%ff5kzGH~BNA0%(K@IT{6TTVO_B(Kn*n4Zf; zDO-SD|0cW+qTN7x6HBiCr7+E9VAaQs-BnD zG!z&Q)K$JBH&hj3(@BCFazkb2oUX1iiN!6o(xyDM%V`(#L&zSG!v!`pPOGp^*fLQ3 zy{*6+QnB2%SIg)%m0a#eXGG*YR4Yf^56F^6Qwkc7soNJc`+7|);LdvCoQPzVCivvd zP1u;nk!i2x_*DLvL8OpKVV3u%^M#^nZ->)@%W`3?+j`I0Sop%QxQ93(6wo=Ck;R@1 ztI3R+9G2-sCzPFqUn&I2qddI%Y|YR9Ri4qMAbFI>t<0PMD$gi%5g1y% zSMKH^as&*RX!Ra-F#hr>=Q9L){dBgx7VKHxSHRsIiil%`>_`v7gmr8 zpIo6hPw4j1qfzqbM!|TEw>^1iS?GMZVrl>lYMQn}L65jrFNkS}Fv>c<=kFO5k>*3b0GxERL12*b4SR4L9iY4}&E~?!KNE-Zc!4+G z!m9YB;N(1h49A|N3F#Qu9%lsuX{;4q!zTey@k@E9wT+2+sKuond~Qq($Psm8Vm|SP zb=#O2Mt-kc8!R-+TZMv@ohMyF^64+OElb74+#%qP3yH`$iTEw3OS z4so8;Ji?ffV0G|V2O?iB?+VGcHp*R89#Uc%dGgYQRU|YRTOlG9Di!a>3g9FAkjG|7 zsK{@F``?{72c?A@h-Ty-SF^WyK`_S))G!m%@@7zb-!Jrj6=922v z=WquD={<5dm?W;RD|rb6gQi$kEuY&ll#;6C?C54aQZ5YKV%LmBy@UZ4~_+pGM|kJ?(jYCv0FDz4_UL(-bZ0C1bF79RdE2J*)%8_fSL zsi(wNxR+xWO)nt3HhW0+kww*=jn9vXJBi-CO3!JSujGGv+GJyYV^1sU$-JPyHelnt zyBm0?1>2|g9j7z~_iZ)BC36w)vLrIPj`Qk+VdXyEh3$7KVmpm7+b>%?M{J$O)(4CW z_7fe0Q7)oUg9!`)XRQQ|z63DFDld^l*Hb1V6Iq!?>00BbhM~z|oEX!*+lk=$jBC_D zBITN`Tx6q$6II{;dkI(fwz`Sfk7AF-W^3PF`|O(c);wBswx+eFF8a0Td!kG5{r?tT z0K8DWKl1&^ha&m#Pr@$_*M>eEIu`tK@D0ID;w!{H-1z@$)l$`=s#xH&fwu%M1r7wF z!k-DUup1u#FXg-WTJBG|mw3+qV+yiY!JvHu_Ut1Hl2~m{oIS5!le!FUw?)mM-=`p# zRXtqp{a=d^(r#rR@eWE|T!3ASMxMB)_;xFrWf@SABnswH<}B$_0c{++fiaAe3Q|Qu zIkRh5l>yqhk1I$Uh1>zu{E35}E%~W)!*!F=#yp@PaTIEOGi<_#6r_r(Pb5A1uSC-k zj_t}lBz4|VALgJV3bH*Rk#5Q|aV?86)ib65s~uddq}vrFdqP?8H!96_F?FwkyiW0W zpXBmTjJ*(z=754kPDp}G%2d~>(uEjgcPmKUR3GnfsJr%p2*GXz$(foP+HudM8=mM0 zV1|MIIcItsn_Y%V;$KEjor|8+B>BnozhT(JlR6Nv7b}BB_mfkJt$#pn+K*+ z3{;vSWh=a`8%W|93#}Ow=vEm+29u1U^(aWFbf|&6O=>|yHb*Q7`I1l?4aJc;rI|V$ zZ-dk6a=K73(YD|4iQXrq98{2piC7l=n*bbs&!*g11K1iixA;drr65(4@ib}b=0=is zDagZwl+t=`XqTn2L?v{tYszN&rlgupDy1*~Om>X(h6%&Pyk{xFHm0ORlG+mU`}!-Z73u~!s30HIp13rh zORX-$Y)68&5ZQp69LplDtt1xXmy_i_1sS36s!>Ic8XZw?Cn;xVSX)}zvRUF*rGX5& zN#kC^W5~H(VYDdEBzyD#;q}MXq12P;!P8^_X_xnA_HM7uMjdYkd8hIWvR5q-Q=Ik` z4t)r6OpT9hqQ;&k1W+ND9DWcZHeHXKTNsYR$|kHB4avbmE=wqUBIxA(%58cgFilM) zP93JDT|Hp1#|(8fu~Jd7?pAI^b?RF&Nc0n*Wh2!;q{KUvThLn#t>lzJ>uK4Ij87@; zHl>bK@gPoJPE!3tO1VXeAtbC}j|*85nxQ6UEftfAxHQFNKBUAul^Q554dks%t$8eR znjcf@1tl8f#*ojWs2=DfdheiLu2gWPQkGwiD%C-bTErt#!D-#B|f36YSv!fLj#I!A&m=cJBI#;{D5 ze=yCP@q`j2;c*uj3I-RZnlfGI$v35lWSZyP2+R$IS+}f1!i#N6!8^x*MIf3X=S@h0 zpyvO7l&gCO^8as*eI@qlSZD1Ia9=-A^SPRI^xM%FM2}VfsQP!R&sRS?@`cE&BIDs7 zhu<1L6K)KBKJ@(1zTkI)j|Wc$qvA*K2Ec);zpMJCs`jd?z=r}C13QHG3+IIf{yqFj z{xbka@*ag*B; zXD#Zc4}J^%83pl@9f?at-QujeYozDW$j-CYpZ1k&(3|<3f@sRF#F{(BaB@z{_>i~+ z_pmZg!mk#Rc$N;&Oc4bIm%-#X>jT%xG@+!BM>MhQ>V)D0(UosWnZp)-?e3VcYV^Bc|B_a|W!393R9X!1Xq9*aeC0Q14=z+^l z1tF9etfVWUjx1z}M(IN$3;h8FF_m!0sn{Q9LP0nsx)u4uu{6W4VSc=#yC7G-K?PBk zXlTcMlaFdSc%~EtT(%~1bVw#w(nYvlK1{E3D;diU#v=;iF!87#bD8BsI)-{sK}aT^ z5F-{E<}EN65Tc(=>8psg-r2ai6+~yk{zyJ1;XY*OSAe9m3@ZrN#A8!Bj2>lGA(YP6 zryzoJcYT^vfDJ+-8X&v-vGsG0@ak0%xrvLy8@?y(RuIOCV6z*HH5*Y7$GJ0+BN>>f zL8#J5GaKV^1u>p@48jqB=F;+-4bwg%9IQta1b=R+PnkD~wsyAz*<;O)DJ0&rUSh)8 z${{eMbfEStB*-&<2_1f;*RtcvD5QyByNRKAlgdaCr(jw2W4l>5y&cLh8De}qQcb2mA|=# za&{^`q`xnCEGgwt2xCg=4&p2#M{pfv^aYGyU5iOPRAe3+&|ap6+a%QN;M(TkiE%~g zqNd6%Hj19?e9wHk2ou{_c7pl@+*pb3cuPuW5bv+cw|bU-vq~j6IR(!?4K>R3w$eJ0 zq%y13_QuMyBb`%@k)!H0nqns9Vh46RP%^0zwchh)?^lkJ6#om>;9IvT#M;RSCUZs^*=6spF0&Wl%o(biCl2Ge{c|%T} z6K^aajpYAt;a<++|DURRW8GZr-(%Nfx79vg+g9_Lnsm)`qMwPrC^{Z}cJRBWIEO?+f9_!d;<%3cWIPXYg&ov%z}tZK5RJUiFt%vwg!4H8jt-Z~|-ab8p&9yr=m~$vk=D&Ti8m z&Mgd+fLl!>jcTR`57j0GHc^Sc>?AA)_t(f+i!2W8XHNB}q-PP!%6(`*;v9}sIRC zSvu(MV2HsCe`^^IDDFjl$ZwoBiZaI?(XmUt_S4*=$xU@u?s-F4G8a@FL(uglFysEd z7$mpDLW$d4mr>w+`8%wIy4~j9P@!&seEb0s*Ajx;JwU2Tg;k>^eAZuPAx|YSb z^LhcbwgV_Bcu1oGc`@@X2mncRd5S?E9MINNQotodLLs)(qb$!t_78#WnpYuY?HqNu z8+(Br8xPhKcVjOZ0Osy%>;>3avNvsx#$F)Z=^(kS7s_6@s|%{<@>Z6gkDd>p5D5O%@i^vcU4 z3zXZb$e`yB><2)fHvnrGG`P5bL&9V7G^72&4Ew>IJ>KY+1MS4>;N95|%vr(lxgE0{ z4);%LQVm!vU=?r}DNM_x-CUtDWbT9UrcZEV?7s2aSf`*^L}9%YsA>>Ln$Bk!eaoDe1p*UyLCB8!Q4yLOf>$au)o=-%JBS3DxxO7V^f-{ATK|P zills2La&up_uOaHRG;9{h8{C7na*>@r-Ot0 zATnm)8ps(fV;{z3hL;Jj;h%LFf#oy8x~_itHd!D~%xweve^oRe->lj&Awep4QOf(X zVd~V}msK04{(FVJp|f%S^SHRT@dA(ElXDs3!;ibj1*GcGgSwdR)fRJ=KpT`Ud}r14 z(d&PUgZq-2%i2V!xN`cl9^A(t36eKz1mEwuM@Y=3yv(1=QP> z-9i{L?mvkC|CaEZxVk6nigg`zRk0^y&x;+ceX91=wS%>{*Lj+HU6W^`zz%NG1)0;*c7jc-O3_GtQ+;p2> z4^1tzl%Rb^sdrpQ4C&T*3%S;}0ka=b+UDyB4BZ^xK~v+yyLmxFHGZd5TdxO5N|>EJ zUI)~8Jcpq-M z4EIgM+2_+F7z>90O<=FDDaK9(uMwmDG(EYAoH=zy%V(6jPk99Kk@1ld;r)8smq`Gy zO~Jdv&GFsjsMthd0tYhp>U7?S9S(KUSH`{6=EaSkeL=(GmX0VM$}UsBF)<+8}_PfW6X zqdQRPvq=A&zB6ESuuer`_A8e#De3E(4#&LWiIiFs2yJEMCz>>Eq%Osu2ba6d?=l3dj=(s*HbRG_dJ|rh( mg9@HBMx^^qc}C%|f~Sp}8)s;S1yV~FlZvDA2s_TIwEqX(sWi<1 diff --git a/docs/docsets/VGSCollectSDK.tgz b/docs/docsets/VGSCollectSDK.tgz index fa83820375d295434a19664cba4939ec49baa9a4..cc42d6fca7dc8b23c2bd12463fda0c14e314e10b 100644 GIT binary patch literal 242816 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%0AmqfiR{vnS}&Vd7=uW97VcsZUAXin$4DNc z#8`=&Dl1~xql$L{>#XF##)>ul`&nCs75x`{T-mpLI@v5122@83;^cc>Ac6JW8tn5( z={(N%_e)z$-rrHD=7Sf5^kHE;1ThB!%4LB=bi|Q-Ys1`ArBU$BswLy%+B>2m5#w%e&b_lVG z*`fO=i+>H+8wx#iYPq3L7m#oSbgMU@&~+Q1)%z;BwV#9%68RIu$hXtb_i8S=2(L{` zpR`vS(uih$M#zomcfA(I9Y81*rmvp2*%vf z&^DD0;#w+Opbnl%ibA|aYnN!tADlL$SRAqH2Fk~Ba7HFymz|X5P)iuL5|=&AAR0>o zOQ{=0JGDlsBLXeOL~(nmi6(Sw>qd{#)We)andf_l%t~IXjXrz45XKOyp_(|QBr&>` zN^A}rTfFd0$KIlnEXn7LAn%oi-$&zv;xKJAm|xgPN&9-IQr3=5#!O#-TAn!+t2Y8b3bDYQ=hbF_`OkmguG>Cw| zGKU28RX4dY5f2!q{O*LV7!085Y~D#k{>z2HZtKgA?gxaOMKxmwsxI-G7+%gwKd3LF z`!}^-kGA$1stjyvofyNbP0>`+S8Pr2uqDk=vT6RBHwQ-{T!g6t(uwNX=G&#eJ7cfO zY~4f1uzhIp>25z`)jV3XFbZ!7v`f0#AmzP*lJGi>mfl9W9GQH+hk@aphXY<-Fa+?< zG$xIEVsyx(7Etx16rF1z3w=hyl7`_H>Go*g5gZJu#;y(ohPkT@Z*9zITb#YPhm=iw?e|4 zUBomsjBn>$eFLvceqv5<*$4ALIb=%6CvXM*IVE2dZ?5g?OP_wihL%cDthKL$(%c^g zA2B*T{&3o*ea}ObDH3|s9gd)Fd%?cH`T3}cK7t02n6aSrO5^tI5%&qhS#2=#2T}tl zox!8KOZ`MOu-3U{B(*VOV4BTXnMF`h>?aSjl%O~lmsHTSP!3P7#*{q?HX%r96}k#p z5CziKs2)nxtKZqu7<>wqv5v~-rCoWrMkwrdJ9*P(EGfp88IuvF>#FkAuH8>Ra0d)W zaIFLG?{D^=g}e)?n{e}a9-f~NMquoriJSfhv4qDe8YKkMgU6%pvLqfL1CvZ|1S3{8 z2ucDt>WJoH3?9YnN@yqPL1gTqo36zE%|e2pxtw+if>@{8=L*prSkbZRI~ki)R?#Vu zNJ%sbF)zUKhA5h=wyPyO_g6-;@?Yf0)bCQJLq|1!Xm}T2V(dSBG7oSY!6SLJe(E9^ z6c7)hP5dqpiK}^M#vH*bGg3aYoHY=G!m)rnGgp`&Y*s}=pG0dc4QNm!xJ7pGo+y3wqd5L8dE;le(h|7hUH=LVM|q8szzn<_f9I zH;dw0zgjg)s~ij2-A8xjd&b1cZ%46_GYVmr!*HExeKYbD&s_&LBohpr87g&7R9+rLj|uz(F(K2$_Z2sxvvYd za5VS>qO($R0$^c!?42?+;@Hk=I@go{73#|IK<1(P=z58jI-tV-g{aeMUS_)+k65n) z>K8O`wa0WyR-JmpByWqb&J z@oyiA>zd32kBF#dBUPj=IG~FNZw^^)uACT*G+Ur(w^9@xQhSrf$iG4cG*t*U|7XC7 zZZNmce~Ovv_Dvya>oPGz`CWJlmDV(4Yxl-k>?W{IIFsTQl9~s?`0ib2V}u!UJqfsa zeViGg4YF7gKrQ{5*Yz~RAY68KvFK<|{teIe9RG*h1jQ*8$f^!N2RM>J^k4vg9URIO zmB&&wZ%$iRLjztHH{oR8O3?pF6-&Jz-cU|t0XREwtmz-j*9F^lP6-trverJOu?XQd-)weVDh6UHxE7C)&Yb< zMp2!3MU`}$-c(lk_ANOm4)ivSP;&k85HQ8XleyubLoK8r zwNMCHynfT`MjyA#ia(%6>WDVS5;Ey$S;2iobEpz5PwqT12QfyN?W8w!p}k~*u)CBz z93jfy7`1F=osV2}Z-(;^qWeU~g&64GUK!{s$}R$l5P%cGK*vCuiRbA4v5B;$Zv7c^ z8ey{3Z3#-d+JS45%fCFQSo)p{B}y1N8ww1OQ%&4oq8@WLP9Z~Y94KZ;t>`1l>EUi8 z4Ny#&c5wR4hES81FmNw_)(4<_qH_&sBzMlfq!NjjSPBH1szC1Kko=@_wdthH)-PS% zR(yZAgZ%r0`ctPr3`Nlj8XM_E>?u$q@jbyT(?VJwXmfRv^FHfnArLu@gjR|%)jF~2 zuqny#>F%DbYdS=Zbg_^qY-mJEO4&e5qgb#;8&SF}cXKw;(WxK3h9_5F&(d)r6|Ype z5^_U#XNb6c41k3pbmTSHtPl?nNcCQ|T=tCG1Y4Dd(%_*fNnS%1RG zkqs+mmWzIcx(fbNCT((VB3T@h_H>Zg!ig>Y7ZI%ei{3ILWG1?z zz7cWo?6`C4%o+Caf%@gq>+9<2^PKe4(EjCX*R!&*adD}Yz5V?yaHF>T?J2MNGeysZ zBq@)jmSs^j=k~Y%bhY|(j>h*x=jY?=^Sn31hK4G8JeHLDI&gob|7aNo%ta>0uYrTKF{HP< zGAQNkm{{j;(lrvl{I!c@BqWGW+in;^PH`u{wV0RsRhw{of4+3TBHVhs0wnMHz4|Fk24jw&^Y4(sFxm|zRDk(AHo>&W#w*MIk= z%p)5J@UgSvenicnEXpoL>abU6tkraMER1HZ&T(Jy_f)wGq##lsfY82;JBL?>nNR>R zU_k^R`+@uObNLYdTzS55hIe#GtIP<9Hn@lo%!kO#!oK*S`3(ez1OTl`T_QP-SjSF_T$;~%5h}=PP zsSKy$*}c@^T8{tuvii|@E641$bp_&LSX_ix=jlWvX;9V_%X`T0BA?VSfZ?az4R5a- zXc>WON86C7ZZzf3IEZI5C|D+jUsyBQ~2&hl#+Lg|E}etcTvL_qSAl0{`K0mN8tGcIZCG{;UF!le$;Qfi46 z0D(6B@xwqvI>05&SOf|fvLzGYdTE}ce@`=RyJ~?->GL}jrr1Dr7ZpPSTwk_Oy?k&` zl-GhdOub64L4S0lQMKIF+U<5w+-*|$zrYq2a%R8h;G8Vwc+2qc;}9Dd$A$mn#kfk|U0r);vR)SAY{RhA*&F4OSag5Ow`!9;Ztn)r%J_1cEfNucVomsi0fT`N#G)B1Z!4XHvs=AuyVGHd*#3AUiD z^+$Af|C;CRBYJS`N!e4+QBk>zrnbUXIMhE#%rATZ0Be7+^Fq*O31&TpN*=7CV;4* z5IbChK~yYLCRHIcd!aa1P?lD`ew&y)_-W1nevs%aK~3BLLb=s%Bj1RB+}l*S$z;Sp z$pSg>BXQV&&rGis4B83%$T83aCM~TXAGNp~Q2Avu7hylKxFp1pkpreHtiWB{vr&R_ zSj%u;)fyc5|NIY8s4=Uv6l0<=u}%=g-!&rMBEtR;rrB${sFFTSM)peq-DAw1a4Qqz z;=HA4JfC+J>ekbyV4fjLknD`^^R^p!PBDcn3C((E;7`;HEza%Up#RRYSG!|3TB(n&*S)d^gfaeoJMO&b%PyF z`W-8K)UysrR2R{6x@=&~kemSCy^7fAtMiMc%jnNey++R)Q8lmxwx0&l)twQk=n2e? z6-+r@Xo#PaN5I9WkK51Qlfe1;rEFzPu3n6;cz^C)Add!7+%m{TTIcBE%rp+(uTI-) zy~)mYn%1XW)KV(!nGPznuRITPWoFGLSoKG20a%?k=jaC zE3>wum@cBu2$EHsTtbg8`R!zGhX%F0BGbF=1b3W{F;~(utNiT_*Hdi(xW5Ks5ohiq zdLiN}I=D~gVB^AsH-@<5IP6A#l>cB#I3&4up^r=UpIrxMXg_#!UQ>z@yegHc$x9kJ z)bYKEse+l}vX+r#8**-NR-9zcxePP;T7ff_N3lC9H-*xm6eje+^#cv&pciXjtDyVD z!iouHYIu_arlAJQVr}uKgoKYy2%Hhqh5l$lN*PD+ETqly=B)Qcgc8vMrSJhBuQBZw zIm&1lkZyGbOOKn;C;h%gr7;KC++kwQtg9u--U3FhfeKRUXR!D>8@^oMZkIG7{A8#h zoNXrD4V0FFVMRN_7e!Iw7fAK-kfJl&^dU-hiV0+pC|)Q&m01FscBP6ADtP8^k3?ef z-;$#aW{khHLNZ6hzpRVu9_@9T0eDy*e{kvo;UCszlQ=?+%|xi@bkSewcekQRvqn@K z(?S{j3VPAKXzNb>-15_Bt?Fw7DqDae8LVP5>Pc8a ztcc5|5#4>MqCl))9UD|^%qzxKWf~N!EDAZTS<6Wp4_U5MFL-on9=g>gjT<~{oF5Fq zEWgmVF4bAq>M|adG+U~=WV@QHKDVOk9zbc4+@VuZwn%1A>6$tu)qzGr*dRQh{V32N zpgIdx3y((+s;{`aDcR`0_e2vk+6aTrys)_@E;%28Qi~aJ_xBr+o}Dbo4pLk|Klacc zE`jOcuVkpQ8M>A9A>!)@a^{zu>kcc>$YNlPZ4|&1(bNmyDkUD)YEq9IivD=9=&deY z8NJ=DxT@==Ce@_%nfhrxeT%x0XLRP|juU-wPM1rIiMj0E11(? zww1gF0Ifa?`d=E|`jc3KFHv7If8+lV$(o*p5KS2ARDuvAAFKx|tY;C}o_X-omWVPb8Z0#sqU z1`QDEz9c@#K2CB^mi9`fs{DQ~dVaoYe(J8ds%(G3LUityOAx){Tq_TQC%di@T=rI$ znEqV)E#>C|4bzU)tB%=hr6%fh0JN|2x0Y_d$Z(6ce59m*KEwUNgQXr$3eLEk4G=V3 zLOK44=l_2bP2YCkUQOlKQ-1bW=1^}BKqMAWOZ$H~hOO!U;TR4QzCT63Y50ElXqcWJ zckUm0c5bklA9^Bwr<@*4gz9lNe_XIH-?>k`OM`sQpRkXx{}Ss&aX-F$4?p)SCo8`` zytk7<-PAM5ckQh+kQY1GTPHTs#?c2ePk^xi0L=vtMq)T{nr!k?oogury$JsQR@8gT z@V-WNk>T0}ei`+Ah29!z8;iOA=RaZMavbOMNQtYbnm9wHg_DVU*9qWFh+GM5Awmkj zwlrYbGZHpqp@-EzNL8*r02)J(5U7>PY)GKa;`-`PF36nX4u7;wRv;>vJ;$!0q1be5 z9#W~gx2+yyb`(tGs%)Age;tJww8)wuBr(NZ^t_{VQh~`Z!l#tt*%Bl-=l{$p+ML-Y z=TvrNR&~0&i8b8vvCgCl|MH!g6Jiz5_KYcI9Jgze`anEw&|5i1X9EpH2oghNW@1g0 z+9P`m+VAH!SEa_HzuYRz?6{1v-*2nbxc;oqIJTvkx?R z0cIm;_CJMVM?E20@<>v+{*x0Fu9y=x{%pRPL8!LQTj}bGxNT7pwCVYqQl%nO{4c3) zo!@)DH<_V$0y`~GjWk8-hEa)uP_Kz}K(R?GHIEF9p$BFo{r^lL3yNNe`;Wvk)!gK} z*Qww;|HQ3mYZq8=E7-=d2BZxbmoT&}kZ0mje^ZIH-hxZ;vi)(XDdc4;$Z`(i?SJbd zFzWM`@JR@U5n238kyl`(GdS-MU!N(R4_g}vg9@}&{;YbGs{Z-=z`_FD{DnF=pdP^= zWt<{;0sfe4z_qA94QU172q?A~gVW8U%ih7mG{#i+J99Me#S#8@=CDtwR@|DIj*t_T ze5bD}hfSu9)a$k$ypIvD1u~auVgYCe-scRAD({PX>wTn0%0jk<#fk83UgL_nf1!g`Cu z%(8+jXw`>VbJ;Wp`di2?JCIv7ZB^nZDXVpblr=3-o279qwFd5dML~kXQ=@IlGA9XRHkCtOit!1Pd z$2*-}xzz6-DoTdSGM=9lp{9Y~<~2^Sv3dSTZ|@!r~!)0!4IImWCZ)Rp3isv3h-c|ouJ z7n5eEzY&eo)>P(oC@c=uVapGIqzB7Ha4&aYb?s`0vux}A0#l)U?k*T z20^AhD5MigUSpr|(ZS(*pG&j(Cki}uMVCsE(NDC}Kj)FJw?++r75rbr8zpb4@67)R zZ^D*K`uDeAQ{@ylq-bb0wP~{Ai%0{}dk8)cAZL`9fj^co>cr|N{Eqly+Q0_&Qklt# z@TFMB66PZ^Q$Hb?WXi(@sYkY{-f(J`q5%SE$&NfR*#E3O%$z59{$1QNK;$u{Qpd$e zW3JA1_>24{lZhfKvPIx|mJ<~XqG`O6ABLDNbJmYX)4|pkn@ZNbm?c>T_p5fi|Bq;g zLC7;R6nzz8CdEU8w6rlx-8mW~_dEV7mxKZe@<>m7m*yh16*cMi+Yi!Inz-KH08I%5 zBt@lfBNLThug^{1=%um9;wS#kI7f%M*4DzTT9kzW3JOO8byjjG=1AB_go16qrBV83Y`8MK~7C6Hv7 z&`R~Q5H@A8*~^I0N!Q^Z=vAZ&^E7K6T^S}S7>YvWHRl&_)9N8Q*m|(h?aq%eo^~ki z_{^#tB3qW>pTw$smZ7_61>A8Aexehpxp_?G6H@s)C)ytuvBG$Nqk$`KL$`DszddfI z0mwc{m8vpoenx+umOl_IPsz+Xz(wXRhLLW~=A-oiUl;yEXslxaZ){FuE$972vD`f~ z0*%9ROjb021xMh8H|ZTyP`h70j_Bu!?6T%E`_1yJ(@P!|Ttc|D2C-4EM&o|T>zCI- zR`_Bv$pcn9bO}=>8eH_FzEEq8{V(t(?IUxKV55vzhl~{R5q*;ALhp9g);*8AQ??JWrEIoi89AHRP^DZb?Q2QwmH$nHzUjP6Ul)V!<`(7y;pZ0Sx5{D}VJXqFLb ztf|=gO0)$AV5c9y&^KXv0?hX&NHrXNKnPX9P3;?8-&RtDiZ~#{l@NLUJjY&`(F4Q@ z?qQ8EaN+k4_22HY=Lh`+c<6@NnmwL~jx+n)ii;k(7RE2!_su~nd+d|0wPFPER_vRJ z2p)?GsH+NaQhtfHzZD{Mr8G6h-zHmLn%u-r^C;n<<$H_;Xek(J{-0em`5N&s(l6@qFxK;v zf$6;Z4I*VD5USXaAdW6zT_BFA@*rqB@5#SXRHi{&6Mt^}Bcw9G5+uY@AB0-?vJ4`# zg7X2XwEC%!)uUUo79>hV$pFNt9P1Z|P6iCLt33IKhQDY$OvQhcpND>H`72jM}iwU$5w7})=LUzdUUe?Y5QG*Te#xu!sSZ*o9# zC{S>0nr3+Qe`Pzw!&&b$Etaxd-wgX$n=;O(oWeKihKRVR*?r7YjJ<$9F2ho1SYa?X z$ty2vQQ%@1P>dk06^vVNXoVAu4j@kf1MJi)63670Ej0*`OQG9$RGf}NRL$xEb}G}c zw;8ynUJ7A*7AL}#hSy01=RYpy1>cA2Ub>G7*EM03&+-j8; zv{!rQ?!IdC(l<~gQhoIf&7YoNY+f zITEc=Ol)7=RBQrTQ_I#ENq7I!^i*>nPI0YQ$%wMaPLnG1hAeHA22Qyt)Pn~1m}hi|M@peUnvYZBtEoPC2l(ekz9@@@gP4%t zH9oEmPdXStAFPjw-aY4(Y=lK+Y5T_hb&|Wt-eq%b76cot^3r8FE9*EDE6?TgyY;QK zoAVj3vb*^~%{F_hLaQIv6%1Qsp32pc4I^ypduh7DRmTTW85uk97&VF zj;>7s^BX_A9Z)1w&85ijCg$;R3GviXJpt4;v%9Pr0d|D@p^O6Q>c7W>y=wt2{>&Bppv3gkt;g03y@u%>rSX zx*0(bMQae{ymAT%To!ByQU={0ggYfy#L}PM0|RmXmq!D5*9dqgW|0L*>Zeo?@nGWu z=t_D3Yy`pSX#dspQx*sh+JMbo&XV-6COX&F|A3kfM`u9VBmbd*Y34PLhj=qcegaX{ z5o}RUvPpESWlJ^~X%a+B+vGq zi9|2nMBcAzDM(-sWs7L<%6zYLS~*R1sU5mVHSyeNeVA0VCd%>twQTt?yRVdu41TeM z2d}7wE@m|qT`7QAwMmybTiN@Zx2$Q^+K|N1rgztv^xsqE&YM{8Y@u9}A8KtcYjp87 z;)RMNzRniJ{2iM2xZmhtz1anPP}29ZEQ;FZ&7k&tec;L(>3iP|fZ_pj7+s|UJ9vw(-`$@l> zR~}k=?K8ZSJ~J&WEl!PocR*tDPkf}C`BWsM1PrMs6gShHnPaR2Nt1#nxYE~T z1Tkc80AbZ(L2AqglDIROrC`8gUVh}{X(MJ7YW>c)7P)wsA zx;~*4(b08-c#9db{H2Z8k~X3HD@#m;?;nvJm9$$u3Ft_?IM+pg3Hkskqk$6qfnexG zL=@6H3M2Ej&*vQqO!qC)mC7ls&j|eBH-0D@XHsUh#rF~wTrKMlimRuE!HSEA0(}TB zqP;H_QZ#bvmsd$6k{a1F)kMx|FT5|3d854;_mkYo`JI}$Ct8le!Xrw1zxZO^W>+#4 zLa+w1FJWvTl9d<8pD`=Y8Ne$H(9A3=T@H$pHgqF=I^vs6AdpXdIZJZ#6Umdv-PD6t zr?xJb*Va=#hOkl!Gb!zT^C$MNa3&`GYRJ}wR3c#Z+^WWr4vv)^ht#KZ?ZYs+`{zxM z@#c)ZCy#i)dOk`$ay^R!pWu!KUJFUosH`!9y4vMFW-fo*r%7_kRO5$dq0fpPScugT zwqtt90IM22#%TE@trd}1V6y5YmE)%VkYZfn&#tqpI|E9N(BKLYJmn zD#aS(@@UL11@gm82Viq&T>R`}oBoP5Nt8=BaQOSKc*%$GB!(^7e2zFJ3Gig|N61W? zBqZ$QiO=kH<5^zhASu%cK@a{CCi}Cv8^>u*Ux;u~ z%_8;ngwM*ut3$=sb2u>H%q-C8`E^{a=@gjh9_&X`jrD|uCpI+`6qVlS(Ba@x9PpXq z!4j`G*qb#>Y2TbN1Iwe`~D`_RpzXt^!{%7vB|L42iD>7!wws}Q1+ zIAWirFMixv7aoxh1Rnp5@6(T5V2^O)@zEf)HiUpa>2sc%19c}*40 zU8ROT{~`A_C*)6<{J5_{f@Kgmtk%CO?Xs$HHoW!5czsdRNJHjadEGXj^`zmoWg$wQ zcdZj2@QlB7%|_-)e%D3u<#3_LE}AS|S`T@&vDc+OArXMf*6ff&+9>>rFJ3G=1Fu@* z@&URf+HFm~@T{Vk83nW7DiH8T0wsFu1S6w<5U?WZ~H0+-o#XsDi z>Nq@mINZE;eVjh}y>qmjyS(OK#8_MfnR9iG`Bhn|5BQz(wFRtaRMY^Mn`mnRx@-Yj2p?qgLjus2N)@KAwR4?G*JdT#_B<;{-dlbMA)nvmo8D!ra zZ*64D@9@a?i%iZRIJo`&>OLBCwdr-^acx(&UF+P2t#8o;n55ET67kD1r@ctmj3 z_}d1c4^aTX^7Zn*#rBlKNX(P6UC8?L^&s?6ht|o2keP*p_Q|lhyKHDge(5e`AmaNh z{z&WF)^t=8>~6}DjcTh@Xk)M`kM+_@^XT^n_9^7 zyNDg5QQCA(KMi?HPy`)Krss&G(Mq9jphZRP%jL_bB=m`CHm}wgZ4q&uE(1OHz8bgu z-=bP}dk^AZ&yaM@C{5vCkm~j6Vhs@{+E-*FmN_VfMYbpWJz z!swLx&a|K*@;t3=)HsKd$ZrBw8R<@)lYo`;LN-jNC}?Ni>x55r$zEsqDK+ADM^`mr z#@HtFv;-;&M_o#KDKQ>i^5C%%{29s;V_pUbhiZowyQ%idOkbmqu$T3*_-2!~dT#ql z1iT6v?$crMs2wDO(~|a!=+h%xV^O6^Y*sX&f+k|rMIAKEuh6q;Yujf?OtnqP2I%EQ z8nTZGgqsk`5|z}U5|2J>d{6$Z2>-2T-K-NUbpS)2G_3lDZG@)OpE-VH5(;C4y3ijD zidA0r?FUY*{pX%#MB*8CG_JhwX>zhBF)C#`BoHWbkiOba9WL@BplK04QNcAmH!5T& ziR~t{)|tV%954wUJV=V4oVF`GVX+*#Uv_gIW$P{A+yEiilkw*og;*bXO5}oDmF**f zByAa=pot^u(CFe-M4+w<9lXmZpd@MXl$n1eQzfV9hl2e+(Co6bj%l@n}XhMAHr)-Rc!DGC3LsX?lIcF)pHwRGW? zDzs&h^3m zg+^E%P9+rE4=7Yq>3JvH>1R>l-bx)gBI7smO-qJH!R9j>Hhq-ebMnT8F|rc z=W(J!$%H2+*F^5BAf9kjwL9Cz&088=M3@Eb*J#Vw=`P^&bafGVL0_Sfx6xF5VUYRw zD*cxI)Tj`;&~_!$@ny&l_`B@S_`H|<3Gx2w$(*JIrcjDV)V7G?RwJLm+k2;t>;BP% zsIT--L8dGVt_Ia-T&N(vP0p%@xQGm2UGN@qi^`@rDfki&_poa;VtgB6Ej+#a2s=S= zk_=VLA0yKwbb;M)>CHEVEjGvcblaI6m5CWD-5+oBN8z2O3}{DMxabHABP8%E`YDZp zjf8+T)RhhPzA3Nhh02)meU_dG#r5s+XB=uK$PNR@m=N4ZY{}{8CR|#-3}Y7$Ot5i>Ol-Wli{C zCLy0Y=qUe$Pkh2K6dEu_O>Dsbwc^8i&tT=Loeed~y8La2;bq`{jJhIA+^VwpEP(!Z@_juKwX1>eHKAV z?fx_%_YLo;zo?v0;CMPW#=P-I(%uhvjZ1HPnjOv4iC+vYgXhlEDA+Pb*|AQjE{=-% z7j%Z&^tohqx*IbRESnFoNgBK?axM@W!^M+bez!jT#C~=p?S;i=3TR9lU<|1wS8pJLJtygkzz?kJ7Cnp;|IDwz))3i?h4 z8t85h?&JW=0vrq3$2i+4s5)j3tJ&7RF%OE>@<|av2&?14gjw|W&I`F7>GLRjUCK+z zGR-zUnZfHJ9sKVc@AP+;M((V~6gfHsc$59Hbvnh3$BRU-$pNPR2sAQe9}Yr6ZqV&I z(nL-vvm9GYmZ^94Kj2RF2f7l1&2W;cWi zwy0rV1;@aWSO0E66WTl4x+++*D7a?a69R>gWvyOg&=X>#Xk24(ibvHA0;!f*)EHP1 z5_E^Ch_clf%qxAeRtH7V_^O~N`d{iwP!t`4>5FK+RHiiOk5pcusNYwX2ewp09frbg zO_~>gw7RE^@|QNE44mCM=}5mX07*-<@+Xp(G%biX&T>ykB{?DeQVksr;!;iOia(MT zZ4fwq}hIo|B{c>71bsEeJ(G{`g>d5P{pb-0E9!cSGX(H7`S=;)esAx{egfmZ0Q8` z^X`)H!z~|b?M{bfpg;j^W|vD35R+`5J~JVmgICh)dYPg0sZ7y0v;3IbxE`c&U0-&z@NvbV zkw_m8YZA!4B0p;i>tgwGpC`U(jU6s54M5s&0Zl=2Lei^M@6$YeFaln9ZzU{h!go=% zY*Sbp7kr&;{o^raZl--kGmgO9^I|dq++A5&iR3U$FbN7ef>&% zg~*HH>T*D%f7AL;^dr(lYoGDDj&$3#daOPDJzJR|pv4f7v)urm`%717VxfM)nsHk= zG7;TozQ=q2qh(-m_n+7DIiur)tqvWn7aJ>5J`+ntQv~NJF?&~&OhPH#-h*(bPU@i` zBPBp7N0Zhoz1@J9p+|9Y!vG=ZbDE2kr!MyXGMwKfvQa7AhJMxNYB~lE-Ehb}JOswQ zE*!wtyHMRr%1p`H2V;)E&MeaM7>@!m)o767n-Maro8y``G7*P%0e-qiMZ?MkvI{J) z=QJ+(mu{cbc{^sNb@I4;fjNz(uZOKccHNQjCp2p^>LAqrqBe1X zRxPq43s>z{L+mWfLfm)pt3Z&|G(`Zsbgk29^DSUp}6)=<&@U~9{0sMY&C zjOr3iOUSSH!=1juIV?!^nQ-YH8zj$G=|oJS8rr1Nl2SZN4R5d#4k4H_WL4c#5_vLVX%C*ci#WW59$JmnoUGF?Rf5 zE$a7&qlYQuflN6-{Kvev=$?_0Ey%ZM3Vxnz0Z4SPo86xz0+9IMq@RB@;rsJ}J%BCc zJJyJMn(@FkaEIa3suSsZ`0s-!!Kf3-{6b6;*CB=a3krLE?Y=2-vIheQW6pQq$jiai z@Xjeg)1qMZ!q)J1-+%$~>$o8R!cR;!yk))vFtjKjV*$}ZfoMU-!i$HBNgMswSU}7b zK*qvbCjtY2pp6C@3vD#WSoRe_#*!pXcP!O?V-7Nwo8dWV5CUW@M1PINgB4^fL?B~{ z>?)`j%wzkj(it7SI?;FpN|HDz)0q?s%5?5egEE}}qraI>Kt3qb3DQc~kmaw)*ncve zf1g2_&cDinGM)M!piCz%%5~9Sf*w$&^Cpap`ctRTX2r?u;bzw}|4u?zQWT&Ytu+A^uC!o^*$qMpfN*o_}F)r?f}4*?dqN(X9K2kbN{(~x>yOE=_c>A(M$ zMYDqT7fI79t@;^92B&R$O;W9tI9<_hUmvUt3!e2r88u}=Vi%aFr1JE-eStb9A2AuF|pk9URI8)+V;crY|t^o$|SLLmA@l3!qoVL?g%K%IM#c?KjlU1)ErOOX4SdRDc zHj9h&#kWW+N5D+8lPWGgQdsgv5G*8XRzgynbJBww%w%R(1MbADF8Af0`E(kv%0}XQ z9;jgkoFNljYdnkrso(adU`d8m4FL`LOPoZwF`AL|=dnAUWV!6GDdA9`RK%FaLzzZ! zpurJ8;o#-lYg#31%QI}*7~U+9l>lasCDPCJ&34x62rV+!POj3A#|DSj8dZ5jIACo$ z6Q>T+qpd#AtySkxu;qD(LEsI9)xkrul0X}89#ZU7;(1u3#qzm=^^EnwnwqB*XX@!Z zPl^w()y1R8xq4d1`9FQ(Zb_b&aF*{Dj(;FZ3*(b?H+5tVQbXoj^~7Bc!|so0YdQEb zEl$l^Zi-E(LU#Tw!zFlvyF@vZ>DVlt$|Y&h4f9F&V3e)?39FxEjQwdY&71l%sFRfY z+o{8%K|s!@RbWkU^%7R+)Kze$ci#qtv(JdzUUan~XaB8Fao)~2wWISue-v?mS-B(L z2_|LZ<4ImmQKok<FtsVgZ2=;wRSrz12B~zx)(wX@kw)oQAKwUIN3dsDLH)~25eDu6(QbK7KGg!AUgbgIRhTg?6T#4f)_1xu=J zg%Wwdx2Q_Kq@Zj7fz-N;(fVerS$f~ARw~r4YS%!DcG%Eh@qr-PK^tqyy=yL0%y+13 z9UZUP1K0F|S@kH{3c60Pzpt$3#PHz#_`iGL0WB6Wd_a*+{C zI)0WbeJF~9o*uKxrBc^JJ9fVn(sxJSysEAIpkD*oBudN=I0B1IwhUA-J-cO_BFLNC1clKSKV@6REb)G|TN%e$&I z*@chaSrjM&v#(vvoNNqqHr}lw&fuxlaxiw-T6|N^Jbd>y}T}G-sT6N7Q zOg_Yf4;x>n{5`DTPPpFsREZm`SGXQNKWL1embL~_JnXaXyG=KH-2xU7D-r%)S-cCL zf*_%SV8hp+rW+mxKiSNbkt-+k!D7GL_q_jt{0vQ&zTFcH{>;=3rey_HOr<00)#OKF zd)#4#1X0I2>b3Wa@yp|{ywnyh1%QrxbV(b+$}ty_vyGP3x+{{{d|vSqdqT>ko((}V z?H?_lZ`w--ucCXtJOYcG+AGL1Tv+%dj z;;Wx0FWqPSh#V=IXK@M?(8JK8<)_OiJ-U}oZO`qC2c|9<8wK=}Sg0&-_!DJ9X7@dM z%R5q7oUDg4w|sPvYFyL>-zA#`PJgti!Z?J^4Vh)ts&6C->7J zgal9p>Q7x7|5TLkVGVr46(Iko#C`)#PGf_Gb`-<^sY{y}{;6qfT6#wN@2mdJ1 zTy02%3+v`A6$Pd5yY~6P14UIwYO5gm;{FZf*Y~ciedK2hJ_2xCfDTwr;JB<8p_Dn$w=@kWB_s@f+KzuGpQ;KHG7rg**q@ z)`!{nr;}BFtNJ__0j_S8zG{8O<+EGrEfaXm7=@d^_3Z9{8!+h0cvh3e8>a9vBcnN(T}ha<fV@9ZprZzrP!kfxpE z%@ztQ!0+!0udUT-=gJ)U-xilPbiT6S-a!lZ$j~C)Hub5W_NNCm%zkxXdlhrjBl_@^ z;lb<}Tu5d>(fDGTz7m&`)Ufc(=`C7KAut0N>F>&#_e##7OYS$N01a(EeyHR>jT2A) zV=!VmPC-$BsNF1UCk^zXb>^jhi$2?^Ky2v*#Ol`2X)Pv|=gX}uR=W-C9}bLM0$-{( zf%ltxjf>~et-?h;=-hszA0{78I(^h1T9?b1X9w0@yOb*d>+@)u7te-8x#z0TfO z@qf4by`%iEx(q)qv7h*$3pJ59JMuZVazd&o&uE2}77Mqr^6azt87h+xiH^W>jmQB&C@At}vpMu&K4_hnKX?gD?J=K^N_dUq| zt>Y}N3wQR!OyHHqbEk33Zmk?;X93S{0>ybYNDw3Qn{opbLtCe;L%9HvJeRzDh`p($ zHWe0RHgbAIzIn`VPQrb^E=C#KvX78VrCA<6Fc|*tWgO_^|5?WI>DZiM;61!t|7JwE z8G&sq9N_)+Ycmr^Typ6114c`fMCs~k3-2pMf95ngZ5`#R08eIvO$F<#YznWn5p7on zjwSAaG;n7!G`O3K*%tn~{_|xh>YXN|{}Xq=D!rWyHwEr$xs-K;O5CDzsK~Ahk$15S zZu(H?mFeMXmBWt(DVs6|PL7lP?I1mI(+~fPuGcYL?em~P@(I`!Sc84rKA=r_JG`6{ zZSjm-O2Ys}Aj9u@nKPK*R7wetFrGI@rqep<9Dn$eoyo3>tU|@7)3tG18B-&q(^+eO z^+P{!qn>MY)`m1V$pqdn&uvsxHPzYD7ml=Ypg-O#?5BacI>tEE=wNC1No`|%uS(tu6Pg3tgBV>mk(9)1% zz+x(j#`Yt)3kdD>4fbvS(i7WHz$eolRnFBlU?WXJNt0H`8cRV#gBRP-Z>Vipmt6-Y zpYNW58IQr_sLsX|z0`zY*_6DX?5*YZ3Ug1o$!u1X<*dWg)Wo35JY4?P;LN7Yi`0#znKvJrw;S}kqbNw}J$ zPE|d)*SRwn=3d$s!s1%Mp=EZnu1@~2M=ly=#}}Sl;`~#Npyq?~Xdp|1Xp~5es^JPd zlN#=m-M$Pm+VVaI%Voj250OpmkZkjBG9`L0S zdtMKq3@VyA1T($MH1(CZm7-sUDLMo(&Kr?_TC|+mUlvFY7bDn~D%lFpG)TF5tg53qBvlH0f3*`IP9O4f(s5-{ZPSSjN62Ik`eX$-TPsWh9yZXFK z&d=@%yK}UoCGQVgoQS9B_~!>8xF=3Yv=-1xIG)D9Q||x%Tt1DSNnT|Dgl49|s)!fG z_|wDqh;P&Om|jSw0eu<~NWXg`! zEsd0mAur?Uk~NteIwt%gTUGvSDsw~>CE^?9$G)jS7Q@}Konky3{5MMOayjli{0&Vn zXM8DLiTwlvp^n8d{8D6tpRR{3YZw&i^UF7bbx3ZtXj$onSxS=)osBj$i2Lmfl3WS~ zX#<7mJJ=5m_b$lvqIV7!?j>y7jW%g$OAiw-q%SB8ccYpXAzZ0zRYrC-@MiOKc|ca? zZ&$sV)&=r?LWVc}#Fdn?)ZAiI!>@KPI>rTG&iobgMTKTq$uy&FT&`s@F4K$=e6S}b zlK@(zXGpjvn&;?TFAl#ggdQIGZKSJoTx@N`6_KfP zGQ6dAVg$n9;K!l4sh^DNb+sDP4U;VX|JH$Q*^EZe$S9Siu@p4ga!c05m4J0cL-!h2 z((#cbA9;G(lNG%u9(QUl_Xh`qjCS5`M80aH>6A@%+L|03J9wsh_NTE#n7fKym}<{~ zr0`=k!DV^pv_5W{nm_nRP4BC`dV>v0?SD`yZSZ41s_MoV(%rYfazfZrirAg z;iBRx&T35-+vmAW>Q1}BUZg9dpwkOLfUW#(WHp_`XXc_wCy0DvQo3sczQ`-(RaONm z=i-dG1ZiI9N0ZJ5)h)T8(8mnib8wIqOD1Sqs%aPj=$LPx{cHGJ5cD!!yUw0XZ;fV* zr@-lq>eQ+S-%StYPBH~;*x6#FvXTCq@59ISEU2s_UwQU^{`9@GlhTLM&2A(8ZlXcZ z?B;HS8_7m^_6ejU{>11`7_+@1$ zBX(+==w+>2Y!6*#6Nf%VWsRzHnX#yQ#C3MOH@+=2RAwGpCU_9(wjwiRs%#dv-z~RA z+{kh>sFAPLmtAlHY`0P_lZ_@!srAA6*slq+_sOQ#S2@f!IvU|zP&;mZbxSO67dVx* z|6F$d**^5m-{w%yL|*b z&PTGI{p1@%Ms<77W&G{hpwHQQ|sCKE33V_&V(w3*Qf&L z58$24MdHl*(hKoYWM-7#YTqpNLNEM1Gpe+?UY`6+L_X=UQH*1cZEa8oD_rzGjgdGPL5dY`EG#10Vdk$P-t(9NjTi# zQTN^d@aQAMQda^fWFnSO!poOAT3>Ij7Ohsij@cSJy*+;53pdHwNJs-TPrcha^VH&r zkN1st^d?U_qz);h3|V-Lth@*k+5dX;b9lq1e6!j<4;cuH$C1Z=(ZNKr!NAz{^u(`= zZd@}6&=#jFjxKi+uP^si&2R0T&+mG`dr-4g`r1S5yMo&=tGm#j47~$^MYf8auKO&V z9!gHD)tCOGvj5d+1uNy#4f5uB{7BX-0YwI_Ud|UL9!^mkr%{`9dK$Cizlb9$Ql7Q& zNjjM8bO(Jw9z9{SSkSwdBkuw50eZvD^~8M&Kkmbv6$b^n&%jRFvu}6fYL91TRi|<% zJ5m@w^cQozxzgC*b}O-#>8?S*wBfDCpbxLfkEct%=k}*2HM>cHxA%3c9gUg4Zu&xn6;dQ>XQ!TlbUqcAAd1nu(oz@c(kubyg%wk_#MY&#}an zhTyoBngE?1nT>#G;&b2RsYmh4KQlTjvDj(nHL|S^hndBpJ&fE9k!(nqXH;Dyl++^v z9L^%ARfzSk;TuMS%EqT1?KyAM^j&A4mQ?_e7Rm4As^EB5byW-&7F2{f^~DGyF3!W( zoM}Nw16m%RTh$E$n7EhZRkU(}*>*9>KI#F1S~Ur-36ltg4vv?97Q3cGWZ= zN)Zt);;m$K9q>xkzKmnNH#3+3yJ*DrfCy}%xT%q9D4KA&(#AXmpnht7ioNyp?MdnjRN6-1`qHZ=DQ<^$6xqT5dDA9S3EzHhe zPk#5irKy9=&ujhn1K*})AAD<(!hp4x)}-?FpRW|5xwcC@ z9f_tH>QL!Di$s_6+q^za>m5tIQ}otIXDAkQnh-?R?fotaVGHlJFq@Cz5jGbkr%%(S zL8HNJ{!VxvCt=LY3ZSY8Q`LBuCEe{<@igulz(PWpTOfN(Y!`VdZ{$y9U27oqz10YBIVohBS4MLG(n2uw)3T}Sh{#+31()4H^7!0T0JO&r4W-uv z4<3{rmZkVgzw27SYw0S=cO1eDD5Al;rWlX0DAda^%by{P;>L=eLUlft>|SYf-_vI& z%9xrWe6tA(NKTo$=j2^c}TO{EX*J2 zFRYXX&X3`~7Tx;clx-~b|81)hl0sDtsX>EB;rs|m?MF^q7=Lc?uv$tQX-o|YySWPc zR5X^poctSD86X{>O=|e8hZ*x*Monb8_wrYNV$TeG@-d+o&!9$FmYQPDy{?d`S2d3n zz&YqEsMjUH*-#`af%Uus4{IAG@bccz)_KUM%@mD0T!GoMRdghxwKO4_GW%n`R$BEt z4=>V(a*v}ooZrjU_B#H$j(WYwxt-klWZLCpDzw0LM-6hN&vtrT?G(>>6qjBZCVpq& z#uo9u7cfDq50ivYPgdb>NdfB3SeoR51GrvRM!fUqH9Bhm)y%zJ(sRW`kX!n^l9t?UH zt4YXMWE&p!h9eqmh|_xKSx2-Hgs&W*S!%yz(dHE~DK4A#pacH;<9G&t{qZu~?5S^B z3aJGke|#9^kB8uj4*ctnqp$FkSFQcykMlC*f~RV^a{)*D{@YPwT6-MzN#CAlbt;DEKEtBgFlw{&b~?o8T^`*IzOCQCVTbb)6H9G;6_5HwL`6aW;U)0cqTQ1dv~z+K zs?mGMYFLo6^9xx-bh*#V(oaAgpQSX*UD2U1bt!RrQApxj54^ z<)GU8eR65lWCjYt`;0oSZCMu8K89N2Z6*X}`#Zy*+=;*bc%2aCACNz;-IH6g_22$D zMj{gR2b!Vwd_}J$_v?TA<8s8lYU9(CkMsZd<9X(LHSp7468Avt1WYk} z?U$M6KQVF870S>ROJ;Y-*Y62VPr)+F7ZVNLh z8{}h@9qLffWLZ8AA|@zZPq?xW4NGKAyJn%>7|h#PBku$w4yTzYwxZfr>l)W=Yt23M zFVC0UGtAfU-!k}G>`C?#gxSd0bwefhKUtC|Dv%jCSmv!I1TriXn^jriFXF3Vf03^e zE&7N)rM=Ylui5gF?AUYBJy48_NV_f0&qi|VQCdM2c=u9!oVya0kr~!urgKC;jv>D% zKHw&DqlXb?tlOVOx?BhB=tzAVfuZ8pB_BFHpPEp7H=~HLgJRsAJVv{G@iBVkKUvnO z_H)GaQ@bzT(82b}&9|OCwwuy2hJLG;|5j!5PG=)vZmeN6VTT0DykG{N>LC6q+iZ$Y2^^kTi-(jG! zt77MN@kF(%dij!c)MDRG^tKo~04r`Of&2ufU$GsnZPr%!ih%gk&0~2lgQ6j`6;l?S z`-wE3GR=~TE#=Z_jNatlCcml)O805Nt0CH}eB257z5Gao6+AxlJZ0aP?2K=LvSJ-Q zpw0~ZsG%(&+s$$!Fc~!20togl75YIgU5I#G9hM1x3DZt|<%_iS{>ynVP<}bEnJw^` z60@OIra}K@o{TERSO4Yb@nUPiyK)Iv#&^6p4C$^x>rc`GjPIH=5YhrF_u#W~ znVg^%(a&R;BH|QZFY`}Ddb@Rj$A^UAv(-xksM1}o z2SNHTY!+1dFH|gB{>M#5>pzdx#F!c1E%EPq?#h{xzoht9Y9OchdccDa6f>ZGS+Qu+ zT?fW6vnbL67f5o znuGE0EB&Jr=oN`O0*)7dx9h)P8om@3gf+{3>AD1+y#OD&%t0R0lYCbmdqA)~tI4SS z+b9@*x~?mA&*%YH<-Hwdz+Gi3JG-rBY4Fak3mHBTl|tPwH5j)5MzUwO^jh@A@7i$f zr*Ym#?_Ior#li2c=NboREP*vgg*Wmzy6g3e?;aR4Ow2ycRi9bx8Vmh-ap2B z*uAKv(OEI7u`Oj0{9heok5E74RXS>}9aA2hLN`*JHUFsg)}EL%NtcEP^g$~i!E*V0 zyr*B1@})(OMK1t`EPS3~Ydxih!pw1bV!Zlq5Af36M2-MT<>%ru5^A;O%%SJQ(yO_AL=PND&UyFDY|52d*6UxRm zao_gk*3AU=Sz)kbX1kkIA%Ry(p|momJsV-OxMBK@X@J!Oy~+xk7a#n^Q%~EjnPrR7 z=N7>|=ve&hxa?uZW(XjU0G~Gz@D&tcJQ}@S?oPWyez>7$XFhMHBB9`L>TkJnBl6DL zO2+m8G`}!zcLzbBZ$MJCTTk-BvI&Hxv!`q;DwKO!pp0Fm{U3zAWmr|gyYMa2NC-%G zOLxb%=#o}YLb|)V1q39dVWV^--E2ZoQt9sQZrIPD&;LBq(rO6Z3a;hX+#(9I>} z>ToR)=IYSURzTu?$9~6=w5T5vNYWC@s2?K8A)2%}hs)Iw(U04PX=|#4X5to?@X(}= z2N64IQFM$VY0;P-k+-SlIaS{QspFSGlDU*sKaz~R$Do6jf~#Yjgc;nYKsz-Na4!5{8M&`>qi8pA6V0br^E~KyIP` zT)W-=VNF`>|M|$ojoZX+KwkbFomv-}RxD41Wi8m&H=xfcA@(4Jl**ufbM59=9`w7? z<1NaC)zj;n2SNi0v*|;%>>iwGR_62t!yM!v5}9Q; zGjPUUIKyLnW*0Xj_j*b%2Sc&m=l|TNfV^@zR9Zd{TWTB5Ao5UpOlTr*#_ai`jKHibfIv^p>3QG zH_*dh8^kwIMv2BF-wIO76RO|7Lz|Gdnrb1pYC~7g?hr0fSD+|AAq>~6&-2fp&y=^_ z#)NCnc9GfnTEsq?p|bOZ-I~82y8iHF;ckRpv<`wLi?OF{D1fksQwL$+MA(Ziyz;xw zQcC;V;BKqqcU@`O?|+>&^ntbxV!_P^yG1xhoq>w;A)M#ggS42#D8Fkpt0=TRWl_f$ zcD^Z9Pwaf-N$g;^li&AXx6E`Tb&zVTEAX-;TeKPI7#p}(EEsg)Z-V;n7VfH;#eq;VID5)EaWZzkJ-<-zrBsdlCj%IZ`fH4T zL%NpEh?0gLs}Vfm#R@}*XwGiUjt<49rpG7lZQ`rKV63_Jbs-Ne#F$Dc9=*m5H;{Z z(#1dVrkvIPiBb0VG`Fb>L57`#S4{>JAeWb+~Bt`a9G zQEFi=ix>7)#JL-9%HepUkCp!=RSnTxnq8VTd!-E{Q;`&P7su+7@M;DDqwJ)wpLzz} z@0vOQr`5~aTy2c6N3(vj9m%PBcl6J2>N~6d+;X$@@E-Z|mJBbl4@&@oT4|X0*t~^% z_$9R?2froyk7bo9d+nH3xdQ5t8xse58R9ST?r}0ltkF~gm_}u2RhQB`Dc;G(k@vISaSMaFUGf?U$ExiLiZI?YWh6e ziFOwwqz)t*q*pJ;XnlWg%<~e?9x}bSR$N*+*D#?>Ebz#^N$MY6OmS+_>P{K@{t_B9 z_-OWAvrqhTSd@!I7E40TX8Vic;mN1QFB!|f&U8MwXw^$ou!NAJEa3V{KcGCEyu~LW z?>(lfj6=F^jp^_uhmtd0M0do|Ttq8+xvWCu$S4n_VN}D5(W-IGFMZeyU11UruhDi4 z5huEN(vPUsuc&QC^(EvaOKgVulcM=$G1lmkqV*+eI5xexF}SEKV=4N&L+Fu@zjLQP zIL7VkPB?jRtfJu!^HOIT_}kDVXx-*DQ@sXS%(-#(bkqJQ~WL`>UQ)c zJfvY>Yy#3q$KTV1X_BH9wK0;SdoYFcCHCI9>PsZVVD@!Sp?HIr_3@*x8CoVFt{G;$ z03BgYFt1|MY;d3OWSbY#u?qT2@Pl9(@mK}7zRk-@+JTE|I-atxn=l*o_0TyqeJWk1FCjq3nG_wI6ivb@GRL%Fh%D3nDJ4H`T}V(N z9c1|yUr-W;?vv!aD0Q|VXy{P>KGR~vg7Hd|tefG{t^k2Y4&n0QOvUMm!V{m2P1E$= zyGmP(<$S_5PH$`u{v+4hmhaxRCp*RCkoxde*DJ$)_6R0dgI7(*R@Zwn7ct?VAD=Q? z7`0e!M<5@)G(SQtGhE7fzm_b7;7%=C*W59z(?9TR2feEiHP~QKa74{F@b1Dl8-B64 zi8Y=1*{3Ha?OW~jV5p+k&(oS)e{FSC{`U(L2SmoVVVI}b!%z=fCc)9V=H19?2k&Hz zu7S2yjlCl`8OVCIJd+7qU7q)R@HyS78{|(y(ShIPq&0o(F_GKz{fe6A1!7&Ud0BED zvRXz#;#Nl;A1<9A7qV{cEZ=>b92POawu%t~#uAbiuACvNG)}L=1Wu%NoU~RCA>WuN zm5*>uE^)sDvdNp;xH_bQY9-~ap$M8Xt!Dem zGatlDtd&}npSBEFE6?+fpU>nY_{0H2JRt8k4-D~wpx^uhAIran_(AI^y(r8U7~%sR zV2BUMV79;zAEXvuJ-EpQhWNh0y=)rcrpB@#;U*UtVwkPP^Y{loh!%8Xc7s<33*#3Vt$-s`ZB@PHA+vLVr}n}!lj{e1-4^u z{iA*ckw|(9h--6_j>tiFK_i>@_mBKcr1ji3&b-UmT9*Z|o9i4#a;=E$^F!L7O)i~$ z)VejKDp2_1D_1TQk_@ObM<~;?olzN0A>mrhadkgagVk2iGrSqNvbCW4Lto~NpN-PS zPC-`O&8-iF^D!K#8y_7YH!kV8-)W3-XX~<+FFL_*DjrW$cf-YuQeXoTX1~=Ucz$Q- z30?Y26_V-94{~1!77X)#47l=b7la9-5zX+AGU zBt|Gfd9+N)%DZql*{XHjs+7ckA*E(KQEygXVeg!A@$g(Pom;TGw(a0%?$*O)%yU+h z>KHZrWcw&|RxILNq(6qUKdXdmkZQck)UrWWHQw{^a>|62&(32MP_LD#PlMb8Kir#qy{gstNBjSJrl(TH-e`-@9k*#AC`O!gVVY&4!aVm|Hj)o$=r z68+(I{K}fG*V*(>&&Ml+8)zc%WlOiR3CBGW+Rw1sB5WlBH8SOrNTLg}5IFgeIg?6y!WhwUS^R#N(` zw?Jj`SbO1p1F58UQUdT}x8GDJ%Qu5@f6y9aog5N)vV)qQV6!PD|rJz;;mxB6) z{5NnZsOrF_AZP%Wa^KKYTh@j!3tS3<25>3lud92SUe*V}z%~Oe1=}p+1?T`S1)&7E6x1r< zQV@_))qzVvRR=BwRUNn#1Z!yryJx_qkpBiQ1+@ye6roJuQh-pe3#9(Z0LB7b%D*Aq z%LJ~0OIh#(E=4FaSSXXk_Iid1Z)5IR|0j>9sj=_-F5eGF7=7swX}0JuMa3!mO|xx% z#5)ab{9ON|4!gb4dupl<)vn*McPu*FR(E|(=-`+evinuykOUO}<&g zz9~_?>A;nU5qsCtayFN7b-qC0u@Z^o4d=5l^^e7i`+T^qChpp=?et|%IW7*I3i2BD zu=UX~f#UzDzEn7%!JjHT)CUfO4}oE}=kVPd^~v5MH$jVE1+PYudKs;rPs4KJotdp9 zBhBPrx_;DZJb0Ro9qmvwsTz%!#7{1#gKb=#@Dd>d#f_BzkndvTCJfWo_!1(y0GVGs z_VrlSO@s4pMZ@6c_a-0pfC}a-2lG8+f9viXqPeSakuEhHRbQZv`LWNKJ>O5^C4B(jfx2j;n=jh0r5ERlac=2h`>hR zrJ7+W4VSNWB{`Sx(UXVAc?#KxYs%tu3`vmwU)XCnNf0?=@QgxYsw7DGPpma%(b&Mt z;oK7-6t#E~#9EQI?S`2Nbn4&9@IU;|FjSs1|Bqo6Ks=C-^GMvm|90LW957|!Q9jv4 z&8MO%b4HMRv0eek%!HzZVHy_1%rW&S8?gIbAS~s5#GfrB8VjC!hC=N#b^0!Rk$B{o z@f>AOO&#^K_p`H06bkg85+zqLc@~$r`rdx02xF+wVr8SpY`t)FS0NKP(A9OL5weWV z3rO?fFZ2t@y|Ti~b5VCutDx#rIJ{9jR#eH{{ws*FI5HAgpS_GI4ye@+sBPL7&SZeD zE@Re-16{SjsS{r~tNI)M*?C&TQp{ukU9HUnx>}1mlL2(KRvPH)t_slA`-Y}k2H5T- z(A8ZPpsO>K)x^XLXMWR&HiJM{r-y;Ap1DcGcA0^$*5(0StrG{jS|@(5t7khvSI^>O zFlRFEb=A|Nj|j;|8R)8wGSJntc%ZAh1wdD8^MJ1IBGgI)U9FV{x>_p@bamGp=&I*b zJmpLV(AC;JpsRJ_Kv#iKlt5Si$^ga!boJkm?qvek_quwz}QkGO`C)%}0*QQel*?>fU*|CSykgf5|u) znL#NyWO;|56zzsN3}KexV9PweHF;(odiTd7HSjy>I64x9XO5kyn@JaBj>*mD-N%*?Q zyR<{^60s9G6ejn@entHzy=2&LlQo8%)cum-nEw33N+;Q6ry}&NKek|vi>tNwF9D-* zL$hD<eo{_R6F5N#H{mJcjO0$*NpxIO&Y-|PG8+~<0O z^W9Va4wb4@UK^y8C!eYH-fPq5De9Ox`DR~qrOxWTd)9IN!_3hW@mz3jPeIl=H9ceS z46*8gBRl_P?YWpPy_S_EM|TG@KLwUN)XhJi;$U&Y1clV4D@(m&h1)`N)R)eZqr+g` zVW!d5k^|<0c#X9qDB*e3S~-V6mCjP3y4k;{EUgTRIP^lF7YbzT z!kXj11|@O{`*k2-qY5=4*tvyCxIf zycdol4A1tROL=EAoqiZmDqR4>+(6o6wnIjCWHx(a6!P*;*J9D~&R!Xm1UKtI3Gntc zE>!s@{$2!mF=ZOi@k&HLY@AmW+?Tea9~Q_^8blMoP#S*d&rtet2FOS!{AS5o4ky9w z(NG}6+!#F`+o8jeKLd6`ojTn=8OYh}3F03DG420zeR!3nRoz%r zLf(>w;uk|GgkCGN!_<}F7~f{Gv*q;(*ew7NU!^ z`6Ft=P-7{_Xmaf7{F9jKC`vmHuz{-WP!M@rlbn-ZD517z^v$~c*`1N1547QGuc`lP^8G@y(qy+P|SW?4RWB)n zFsM4&N&A=z@<**39v&Ak%C>nuJVx)!8)InZltNfjQ>+NQ9QmBBFTrnuuP@<$ITA~$ zFHum4lcc=WNpjy1f1Zn#q}(`0o}|pe&KPi+O$b5mW8#9syry2_b3sWHDf*c9(UO#Z ztbNp%sODutIxdivM>v*EMnLV$qu9po%j1dlzf_;j#932|tj~pcS@b)=yn58oKt~LA zlJe=Nc<^#2(IjPk31$QEjDind;4fOiB;{Qh>@~I2As}GD33xVt72K2IU4DEq0CX}1~iOpSa67l#57TCUtXg2xKNFU!wzFwVbvn|F94RSZKGBnq9V zrikjIKgp9hQ}xv>N=(^P1yasPk3IHMuB!-MK~*PwJ!#wT{#14;P=2bH0c$b#i15oq zA9c`o(pIHUzp_ai*qYBBJ@(g~)l6K6IiAFHm?Wp&;5;xx$ZUqrS!+Gm^^v#v<2bgs z**k*Ix_nT@beYV=uegp8PMC_=Rl1q0sWY-mX@<8MnHm~i%1T#${ zdwlQ=hKMjP^iU#8nlgx#s#B2^(+y0=<{)$wFU8mZ1RNAlx35IrL+{f=%!?EwRKyk< z*)~7hK1LWQ{@21F4)fE}pyFB>4dcCUkl;MVCO!buk@(<#IwF)2DwF)H6gUs2;{sVC z1*Y3R8u7vXbcEG{>4?|@rX!**n2wkiU^-%6fa!>!2c{#6S7iMD@c3*rXz|Mn2reZU^>ET!E{7y0n-tb_~RT!`zHe` zqAr+@_eBf;bKL@_BjyE|j)*>}C|-3_*M2ky1{5>$7&qbKrkR8aGr>w@87$FOw^Hz< zi&Uu&)M)Nk0$x;B7bq%k=-#HjOTTb=gOF*To+zW{u$<|0{83Bt%Nu#Bh)W21l!kfK zsHcEjOu32wcMHOyx~PlhC7Woe9WM!#!Vd&Kk1{WI3@$P*=-aZeLcOx6T=;>#bojMQ-f3K%>EJIwG+?|^gkxpfd)pHG6&+8cZZU*D6}{Yns8 zyFo!{?FPLMt-bF*gT29LaMK_Nt-;IscroToL1;Z^3PNk|`_JI(d$PJ;2}0{@qwacTUMT>v>`F?dpZaWaYprT2(*eTfSyK zofZ+%)*>VkH7XNE9h?2`wnzlQwdqAri~A+>qGEfm`YB6bjCR587t+mcv3wy>sF|y& zY4c`LUR&;0y>ZB$HkSJ*_>0KS@96~i*@$MC*vmSO#5}*j_vF*(ci))qVqBhYy)$dv z<~k+vK^S3W8x{)wWqWnquRmlp^`WxFgXSBbIT!DUNhNOO;VZV| zqU#P_T+(K49Dma2K?ik=)fYyZ?nW*GsXw}vf=oxt=%_ME1wK8%YkwQJ-FFoN7j1xAC~zLe#KRK53eRbYO1_CyxYGmWaVZ%td~fH_ zZd&idDEN{h&JERpZ^1=t-Pic9Z~|@~82kYo@um#nLN8{(?Jb6coUsIoB)JTx8op;+Gz!0)DGl6jDov>Fbduy zgL0+^!YJ^vHFBiuG7v^xbAm7m-UGrY_$UaYZpT3w1^2(r17Xx{9tfju^FSB{uci~8 z@C9MinH~tEZpT3wwbKg1C?FIRgi(KG0Am4R)W0F!%Y?JjdLKr?Q(}mAT3_t6t}M5s z2H(jSLZkYA_SKQM%8IQ!7!$Yg#=RM53uFC$$}ewkS@CJ))lA4&3DpBY=vPcaSDx=5 zy1=|Wrs~CfP*U_APXg{LkQu^i@0Q##~0?_Qx3A%v8AN$GD3UL|69A+;)ZRFXV*xnr7n6>PI4 zUZk>Q8%kdT|D8}rn7qlM6Wg}Jcss;M5oUXKK#%1fi|>XvX*L5%4slOuVqX||)tE{Q z+1u5|JGUO|H)2T;LZ(vxinF8>bQ6YAW`sA!Bc@oH!T94hYe2bP5)Z}=r=3d9`*@2_ zN;&V;Z9POwCIo{8ttOar3M<4>1l6O-L|R24BCQP=H?I?K^e2ssg*g@nNywuW70q6L z&d~}Y#=h)6NMu?$4#+W19X>K;6{-9XD&6XY-rCXSnJ8TMD;_&=T*Tff(QIdn$>`+K zJKbdtn$99z?8cJ|>*kfDp2;>?6Fhl9@q z9x}R%os-34@b%TlzXJ-DJY?H*@jFk}oLXv+%TD}P=AP#Na24s%LsFb3o>ykSbE%qP z>uaoRyWB$kwVm}|v)wa(5E<9GKIwWWIiUb`UGx*ID2z6{RnDs4GYcp*9c}seB zYu@t;yY0t#jdkboOl?TzpM=gLQ0NuPG&wei$UL-LI@(vgtR?Pr(ob9g2l4N)vPorV6&6ePyzXi4IxHEVK<_--ObUurVH zvDe$7S7siaGd^*3wEFcfSaG+Sft!6RaCPrVH3@wPYl=D9T49U`)He)X=_IqvyI({__*`QFMY-hU;yNA8XB ztvQ=_3#W)geVz#MIc{)Hq=HP{au~dN+&nDjYObYcR@2dN*p=>@fwDa`Fd{I<=U1M0 z!wAi%htK@xE^FlJ+hg*GCQ*wKuUbZ4)v~`dCi+>bZKKe*!}%TK_nSaxZ&`Wy&5acC z_cEnffw8ujoJ}e{jfq}8OK)GU>C-@eAPKII9Uqk!PfG4pEPVR9n-<`W|IXwDDdO$V zvq2?OYckgU7X0>aC7uVpKaRNn?nQ;{63qA*H4!wmJ}wEm^JPzx_L8e2h-|>_P5TjK zSajG~^QOdo*IkBh&!EoA0KZ$U*=AE&k zl_+<%fohOOQ>0!E!%?BQVr^RCJPk`^-gj_*qW7aY$h!R zr-8kw*I+N|VRgW44QSVI3wiiS6qgzml#Lze1OB2RiL`>G_b z*irIyH5BPfZBN4P7u2s~sP>g-!x*5Xs1q@6V_re9@dmU@(JLS&ft6#bSi`jP`aj9- z+%bB;{wB9qTe++kf2RB)k^3NY#Lxfx=KJvYm<|lNo_b@e=LBfwuQi=-r46f#5df|Z5)5tYwU99KfFERsxb zan1ztmf89)9b5ieB?HN-Z_6eK&OCAjUr}94FT;%p)n3L?WAmSvM(DKJ8aelrxs zlX^UP{X!Cp)?TXJ9?6u~E8?Nk^ha!SO3?x-P-^pd{@6{)ZIJP1uED4Up%eF^TsdNp zw1-NPaWAZ=e69U;dSzBqBqFnalbxn4QixFat^IG$yveH1jmEwa>%Y#5Eh57HpeIlt zYp$%6$Glg6G3_JV9^6ewaP#r`g`C-oJA6AmnUZ)qn;!VCS3tQu&; z34OHaOED8P>lF4Uig*TIoHWHgEIG$x(SC3>i$O-N@?3B(nlhlvRtQYfyD*#*nw5%-kdJ`lc=(tp+yVO??Kir!EW9K&;1 z@j-j`YUe${|4eiDFppbpm&bT2oc7UxfQl<{_e4ojY&q-~K9wUc>1IrLRzo#-CBCZEeB+U2@-T`K zc9Fy44G&*sph`sFP1n%c6HF29$IT#8Q9*=2(-l12J!FyTam3T#U6p?fCw*r_$T%3s zTAiNh7d}*}okQ2W$i6OJJG$~kU4@Eq+_S$arVy9V%sZ+{ZOM3*eBW}qrv2mK^|zD= z0!Gt!&uF>~^mGJ+o_*ekn>u)%dSp!|$bhkzeky%JrMvN^dI%GeXP^DqPV=qgl`>ri z5@+#`E^K2321eDJL!YJWhAfoG5qR#rWEXZjcD{fQeUKveSA*!?mc#yZ+XExk(7#(s zr|EY{NQ|fUsDxRtGjhY=bEvyL1ekJ9OXuv87`&9|q{5j?H=e1-i#O$+od;HP$8Ci% z5olRVME~j!kzl$0zdK5y=E3S(4o~8I|3_ufw+WZ(;%Yt2rCSThnE|!%V1bdz5)-y+ z%fi?1dW~>@5Rivs`2453sItmr<`O4OmqtHJadzc@RTn)!S#%vG_jb_hzppOJ5iW&Y z^cYK37E~8K#C>7+Dsr;^wLw)|4riqNBWCm8#b?gSEnFT1*aaqI)6z$CcuG@`bi>qG zh-+<$ZrU(CPnRQWbkz{uP1z$i-?w`WMQG?hTbd-2RzEw4fL`&vj!<+E^>N96Nkd{2 z)7KxvS37sPpxIeHmQJA85lOc54SJj(Lio{APbk`9G5#lWXrYq5g0iTWdQ2|sKxwGc zo;kOY_VOTVM2@DC;z_E*!H+AaMw{NV$}ReQnx&vtc#zO`&SC|h`w7?j%kyNLx2N@=9DG4BZ+v$u&6>f$Tn@u1xBEjjhRil0 zTeiXd`w>evk(;R6n`%7Quk|!rPRkp-C_Ljo^_XmZ89@cwxrOf3fbS}TPB)b$1b>=q zFuUXn(>vx!%A2io^eH}XA^LX==VVYKag9B1s`T3*tEwa~3Kn`j?2ono2JZ*Pt=5W< zb$uCM32o>?leUv?F~dURle72VOCOGpR&9F}CTz1jTW6M7jv!j@O-Vj(`Mv!vDWtck zXTQ6kI`)U=fd!opv|WkC`YM&RWn-L{D9kd__h~K}+1C(rLD7?|b@LMrA1WiGGy`pU zBAx2XHIvO|T(Sj1qUOruUn}FkI@1U88YRW&L=B};N=~K!%)3#Nyo5qDjcB2z9w|4R z5_;1r(hC$GpMDp}Sr`8acn--d5H#-C$059}nGL&) z=jk6XZe)5$VPmzsH+2CcH4XU9srS}@_&-H6Ok42VsF^#p#hR3hA5_&ANL*XJjr-nD< z%Wd2jWszWUwRMeOoU0rL%l)8#jG2dtBUeYA=4dsx^}17IOp4SvymKSlCerU||Oft>8pCfQ15902X3R z16bHm17IOp4SkFtN<4NzXGkuWHkU5T1^00NLKThOu+Z+-gBA{$3$&4i7;cGY3br0vD;1G`7I&VN5cl|74xjIf+XbQE6M3-+#UA* zl&+)u{VxU`T*kJ~YdF@|zMZ?+3e27DIWOw73_B*Qe()}Uc{2BV;?{nT5qcz=Z~II? z<;QGTjV@k2ZTqAvwmy{*OPT7pM=@dKGh=W-!e#8p-A^qasEc??egua*3Skvqljhqp zh8?A2Dz0`({_SsGsdL?;8s}CdcZDLpr_ws-bgQF*kEjT^Hi9m9zg__OMY*vb?lQ*~@b?&kUVvELClvMYEZ zm!EoH*Ub~l`MxUXHM^XZ4LxZ1&^GmsH{t5jbN0aGm=aFGsG=voD+nC%q-Si~a#cf| z2T6lawORPDUS=n03Nv`R%+!13PE=vOR(qzn9h9=9c7adg-gBh4dZ|m>8q@D9z6U+& z;=bE9<0AJ12d0^7-C0@;BVJ)_ShAe(k81aP)_s&pc2Ejye7HaLV6NIO8YI+9d`#s_ zD!osrFLwfH(CU?h{8F0Nzv>zfT-}Z`sH2DAy9;&0I^6INETJH=XXYe1@w5-gH79)&O{O zSOehAVGV#coj{fk*L#3B6~+PH9IggSpuqKrPyqODr{ns_XoB9m^ zZzh!nCzZy|vf*H?uoMJ_#}wV|hOOE@Z9wf)AAchv4cY9iwh@)Kb?d5lnBJ@0F+(K* zvU#K>-E1>gIi`%dgfDlgq68kFJO z$=`3i;4DzYd4TzVYx6;px+AlsAG4L+GuQ(JL?i`#w50a;Ah-CE+GbcEcAs2=k3!4^ z2sjERF_%8uBHr4MK&iUOdO z;O%P}2#C3WRw6Pg(|`^@D`6vmRw4`oS_vMR1!yHg7NC^~S%6l;s_2A?xd5$1Q2?|O zVHnU#%p^c75fD*6snh+F0SpGvN+9O_n1D<`UO+3k^Z~8JO!|OH{EKcd6xlyU{Y4K! zvh2PZrI#&qR^wB=fi1sqC)avYFZZLbzA?<>LB+R`B&>HI-*`{;)f;dB!g_r7{FmA_ z_2^-pqdVqrg}{PiR73Nucade2d-0W(cS2(+>&@eaEsn;%Q<(6u28SK3%$aJVz$i`( z)x$)kADnxbC!7RsSUynAT!{db8)cy=42o_~&8*IO3t20;KNp?xfKy_RG#7$g zYnANyQmVL@d{&Dw(tNBq&$)80fy7hWqI%vxdyHMto}#Ip-qUts$y*FcZLAs_UoJxE zeR(=qlY^=;=ZA~;Ww}rAd_HDegj)6Qw8!HL`T7q}jhd&!%vV2cHE-@#eXu2%D<=^A zQuzCfm|RUfYV&66X5(gyQCf9<%RE15LTM53jYgkvQ&kLzm7`nh7Qt%woeqQl8+1bLa z!#dxg>&d`?hvD7Q+|q|mmxRBN5_cIgG;~vvSqdO!GQpL?KS&w9u}eG*Amx=}doDSE zl-@0H04ar6=IZi)oa^@JDJoW``B)s*W`PnpbLm(ES`Zmsv)u~3IYtDIkNLenW)cUg z6vTz*4Hi!OhZx4v4n!*&&}^B>W02l9-fTD|Nf0)zbRnT&TU$NTrWg*k)*B#<2_Z`BGZV! z@Yu+L$bjt=64-ZgFgbMNRZ??r6O0kJH=@`S=Hd1 zWjkrCx~$_O$2&AU8(9bQ4jkgecy$N4aCY1-HSuiScP9+{ZrmAc^v4?eztis{U3`n{ zTaju_o~FUhqR0zxjO)xQ!8yktM6;SJwA_K+RNXzb&U{HHaip>S-M;v(`~nE=C0wt zS~{-YZJuAaB`MMIdHS|(Zqb_Ea~@x#AIEk()z|yeL`Ba85Alu@*>k!AF*Ck(U9FfP z*XW@rtrHfDoeHMvmQ?kN?m{o0*B8<{lL$~6B{EOktn&(NWxa%}m@oEjA~VlNJu8s2 z^ml*aef<4(U|Lmuh|5x^*K1~_iQ6-Y$bBn0tEsml4@GWfVrsVfl)*E}wX9_Fy(YS5 z*8m4ByzeO72xT6m3oWc52v42tY2rQ&YjxqwygsyOCf*!R%Mf@ zqHK?rWtZG8X8R9|{dtgsevT(4{4^gYB%O23p10{0ePmgg7ThR|u9dW*x3RD!#8$Z# zDCqyj?buF%##;XMp0Za*$Y(qUpGRE>IHYEGc(us=xdSQIk!SOXcmlrH`-*Lpok?&S z()P4>}I$5 z{}pSL_*<-Tk<2G~=#iA!|4(t3Od6R1&SU5{spjFl$6%?xAd}_v2MIILwO4?8$BbX< zk$=zmd4Gb|WsO8kOqpn9Zq(k;_b8@q*ZbNokQXf#xv2yY%>e0TxK!D=C}kwt_4$fh zAAA?9X@6(LO^iI|zt?m*w41rUFRl1MB+XKQz}VyuCC~QM*rzB0vRlh0a&`fz=}fm; zNDzE3ZZN{v^YrYdV}8DwQ5V%0Fz+3IdJ4g&&~#41hBZ`N&Wo4bKH7?AG|UqEdaf!M#bU2>l{fZ8s(I;}g25q}c@9;QXLjDDzT zG(ynML8E|)SXQl1OJ7rK$Vz%T2~N{O?;hg}v;OXJJazKfY^K_AvfU(VS*J-5ua;u- zANqbHf91%D!*nCUb1WV(@5A?bNaX8o*mwFk+Ttbag*x^atzGkmRrOnJ{6L|Ut~axt zKCp%Bp}@TtgH*F@4VK3tV_UINWV*$^;5e;8aGVyezf50AST(&s<#@MQ_i>3pai%5d zW`FLPiE}f7s}9a|CElY?N$EmDp|Kyel_w<<@>^~`XC7%z9^HbZ{%dNR2?@6R zu!-l2>})ULd^Ss>4nq@me?m%9bk7f$q66o)a|R6QT2mmppBFw_oHRIU{!Bga$rMjj zo2%)6AVv_l3GR~|jh0XeO6Zg7HvxuXl;HSyWE&L9G2gwP!kSOBHDP1-li9g@K zqTnLL#h@#)TFn3E08eii3YwS>w2)!v#zNj*(k1-??7$Q?6S;=+0Ns_OK)d8%)l<(0 zDW5zVwXRh2>;p5FP6O1!M`|(mbqF`6N6Hy-g+Q4Q2UE0?{7yEni!kL5Vueja&&77% zENK&VaLkspsI8~$^L_^m)^7w9f{*g!ROGP4>m2*F=qr;*Q;-bawD7nyjQ%#|xvcl& zc$+iwJIfD`#o}=oFJ2U#Q0k&i%_}Q_q>m?L`77kA2O8H8(+)5s!693}ybwS3$)~I%mP7ZM6_&!M5bU9OazAtFHB=WB5!oKo~31@{(5f+m__ZzolPly^}k~CB>9G zwG>CR6+S7IBPG|;GKEI&I9L$-vJuNyDQn_N@_p{QE$Dgjv?NORSH51Znx-uONtkq^ zdCJe;{I4&;GIOq!2{%7qSnyACZJCJtug^0sdVWzhoUzs*Tv?f$DT(ogLsg`v!Yn7J zA~}MRnN8y{pZRblh&&Sev}xNw5%N<$-A!8k5nqrnZQKxkthH+8B%P_J&Lt?6lQb z)J%K!h}YsLt9ysDXkB)O*2}YK%G@{qy&B9}oVEzFJrS-_k-*QDr?CmFXF>g*mk#qa zPUX~x1E~b^1BC`3?<~$==~Zemo|J$Z_J>Be{E^(9{zHUbt#7x!;@Sv*y(zcoV&d!3 zRA=0L70t%etyEwjrSiSWNR;PmbLAGuKyb_xZa=1Fu~=Y&#L03>^RrO9Z)~m%g-WWA zEI3qhxwlgk>>?qn$7hVPP;6q^3PT!7!0J!<6<7V7K;yV|ViRKx|Yx!~lgC=M1l>nZ|o;PA6UreCf$1cZmCn(<|}5NZlxB%K)nT z#Z8N6`?IgM2wfEW$}8?NO6HIFK@)ogdD7wo8j3hPEN0hw2a%*1MA@{m>l;Hu?}HtY zd5Z(2dzW4yQxP3^sj2hiZ^(aC(g@4mGbnAYoZM9_QzWEumjoab?tj&1sQEp1hPfQDST4qj9 zoUu%M&p^MH=xAi+Ae4U6K-29J(Yc9(lc%bH$yIMOC*Ew)__;{&soDv;^+_2Dsd)#V z>P*wennF}odfkNHZ;{6f=hc2J)`;`Ef@ciFWZMJy1J+C4yiuHA)*`;ak_F}R=ubbt z5oc%3+pzL2R!A^98s?REk;xd}tqa5$8LUL}(tPBdU{c~~T#>F6NZL;rTrZST`cc^2 zMWxn6OouCtDB}fN&#z9ZP$+Uuq!$p#PW;mBgWQh&NMtE=VE8H;DMUJZh~i~4?wrKMS;{nS z?fK$gWo(h~A{zsb*6>N~>}TqQph`$erT9uVew<9GGI`bIyg4*aKe)sien1@ zn_6|A)J?~u`HIOFpM_TErM$Oyse>h`XJqB`Vw1KKXG3V`B?xhdYh+yWewSkiYdVPD z71Ja2)8->E&trmWXEF}|^D#zQ|8tZk!G&f?j!g${jD_ZES(k-oXBk!SqmR)K^woYm zc`!#-cJ*LC5-Nn~W()HyI!~ZDm`kx1UT8i9(56YSWkMF_i8x1gFqe>telRD(A$l-Z zMF;bIBq)tEr^Dy?0z7O;)$hEk-w&~=mT?-}%{Ed7Jh=wz3g&5Pm;oLnX(9|BocH)( zjx@~4?|clDnsKvDkE6JM-*Wq7|MRYhLxlZE{CfX$!pIevXN0N;xQSZ)VD4MWtB3m~ z+?V&V3hG7v{k6~x{uedpzy8L$e~hK?2}V=xz|TibwXd55=kr3=pKSNn5@`3ilX1|w zhpcEwhQFbCYuc+}Wi12uFq&5O_jnz3$I+`1`}H+TgggBgm1=6**tRE%7Fx0D>T33X zHUr*B9goo!y?y&9rFTl^^>9nK%zWga`VSU7bytghp>Mq(JrE)gEEXM_l1<2!=j1D1 zID~51BjtAC9mIZrH%(=rd03EBOtYEIsmWek%5^ z92^hJ5UM4FXx>Te!-5V-ow95{5BO2=rBgwBy+U$?Dx6|Dl@LP*7)GJI^Uud?YV(KN zm#V6Kf6a9{&&r4?XZn=V+R3v!$@3ivGQCihw0UGqk=19c< zqVUjRbX{985YckV-x%gUO12PJfB7y#Jkh<)>|H{h)EKv&>aMdYUAGh-U3V0T5=+$C zA4&G=aFd@ysfGPjk6UQ+^EGICZ3T^O=KPh2WPC6x&;;JKtMNDpc{-B+Vch_y*h-!d zaCwjJ<@RC6HfV<1-CbxA)FCT1BX`MCJ-l-Kz|);9X-gh;-9r1M6u*fF_MOJ}>Mox<}T^GsQkNgo-du0}l z(7hXXbhp+RLOIKkA<2zqgc?rS4zJpAuL;5x|1)Aog)FYIDR=y{rRI=5S6PBIoP!!J zBf0jEQaNtazjSJs#I6E@intOXyE{&$5XCzQTChSJ%)Q&mRlCX+K}MRXNYE(;-pU-t zf_n|M)44Zr7|e^7?++Sm8M@cb(9%LzE_ZkM)XUp?K}E&%AOBTD0kA|_6c zLsr`&8?NTe?(j5&rR4}zkR`f~GSR~?kvbgOj3lQbP5JO|9B73hU0Fp@Y}t-w>RElC zF5-qyr5WOU=Gkc4@9#bLPffJ%fjHT_G z4$}gv7apxT6L2)qVS(@O3)c76D?YHY7$y6u*Id+CMUR$WS=2UZ;?D#ysXOEwl&p2M zhBkZ9Zf5!xbK{j;O<4}ir?H%)u2Of%ceyjjM7C#K#^d<$=L?HHME{L?H@ zNQgj!1$~ePZ%AuYu6);hSD$6K2l+9X8!uwoq$oc{ zS-4rlN#?vwoeQliA-PIfmaXTPUlnIM_Qp|X8R2Ua&0Z`auLF!%#qFP9npz%(@YBH`|n-Z-U@{YW^4|nt`#yqY~yCGM;+EO ze=O5!tCgGEE?;F=)pyf;;xGB&eK5MO+J6>~pJ?~gR& z3-IgU7j?ndU`+Ai=F)U}@4?g$!KmQ@>=#%T);mo3j;ns;g|gO%RFq%tf1w1qR%z~z=#-hl;ShEArI(osqU^$#zej7^X#8hx#=FtF4p>#n z87S{Qi~R@N5;76^C;dPFb!6N1v_(4NmpZF!NMBya$kVlH?tC|j08{^9T} z^Se~^QLdyRxA1%PmA(xEiHp3CLg2=@^h~>%(3$ltx`NU1eyu+dHB)L@I6LBuOvCzr zOyNF_bJLwgJLb!wq4NE#p>07X877O7E=2##lh3@R#Uq9TX4y8jwTc_IGCNf9PvXne z7-~wI{B8*zw_&atcxP1+2{vZl+}4_ZL(TVRTZxlT%#9ka#fxCo^g)Nos>1Cq>{Yz8 z{AEh;tXKmfjmxXTPOx9LU6R8wFk~sMZ}1|PCTV~N4==%(V!b1N-)5FR8*o82bxED7 zc_)QMM>|EJ{{DiC(IL08=96g(%_*b+dG_K?HMk|oaN^~!RQeK!AE^6t!AtCg8qAc0 znb_Zdj4>C@47?aRI%kbkI z{ySkw8BlS8zD+USjC-_OPM-R9Z2R=ews-#tgr}Ifg<~kPYyAgi@t$9y^e1J0V}o%n z7OK2o^&j&hY4rE;?gm;kx-L^{BalOwZPbrc27{;%ikGL10$bivYa2BYb}y^lyqDxU zW@-D5r16a;Ga)L0VrS&WJ0^T8%O+-CxjTq>zGw2h=pMZ^;hYunF*Bu@RHi{>L z2*5etKv)io&JJI2Fck%__EWOi{Z%b_HbT_o;e+{SozZ%`;zEr$DW727puqFAauTz^ z{@s50+^C&Va3pi6wWRj~>WVHK7hg64=R2(1*NxP#1LlC!DM4BBV@-_|%Jz;Q5_;Od z(3L&NGS5n~WrA}HT{ z6_R6$qieQvcFHFe92i`0@RTl_^fI~*_v2TFMDerap|*50%I?L|pfG)#Uej%rW01b# z=bccGaFUoR$=X^Ms%!UgEIm?>V&Bp&lpCbxCBCaTnyQtNP%omm-d788qp!xg&Cli9 znERxFe{m2K@ZsZ^1FwU9zM$Jz-B_?Eda>=n6~L zi`EdqdXeygCz`pDX`4`QXH%~f8KpZBi@xG$2USS9IFm4W>w0fK(?||w^{q#~O`}Jx zC=X_Ub7v?)|gRQeWyBE7P#x>5=kgqL7N-zA`E7yHh)+Pav!~ zxMZ!3$Q=)+xkD9Ys)^rIurKi(nymTlCn;L$)>*kM0ZTZ=eIH;k*AX4o|2@}_K?Csq zB-NBqO<8d)@_=DCqzk~^{aqC?Ba|_96aku#Co*yl@U|5i2lzd0eujc8 zlO*RvFn^In1N00QsPcl+MR&v{AkSx5>fG8B9E8#Fb5fWx z93)@93K5bo7K;GMhXpu2UlY$kwFkJ*pf-p+bQ8nk>P{3}>)HM8r>uwIAwl^);%iT5 zJ>zgE*!BQez8;c1?25xYEM$)y_QD1}8hb!iG9GL*Sk~ear7a5C+SB`aS6FVJI43L< z&t@F;M3M9Y6CT3IIRtyXP$2Bx(mAlYuEXOy9{1CZp3lQ3`iZtgsUHr@%S-FWTmpWh zgS{($5)s0Pu*T-RiB2@+H_h4YNhbcs{M9ZYNFH*?CF2D3R&~ z6+2FZ%Xd8S+TT}}wDYc2<}{=~*DAc>#78Zsb5V?fhw;<-O+VtQQKo!S;!%`$zb4t~ z*T9}!n?ZBwF%wEVrkicoQ#WAbEHiI;gFhuXvOG(0i4&4jJ?j1q$C2*SgILzxgV$)K zDyQ8~_O7l0U!Q1!=rmoP%TkhUH^`~3@CdwbAy}U- zO_7>Gno+Q0<}`x*aUt~wdLf%yz1C`LoG(P-Zdm~AcDh7yE8Yg)u|Ih4>?t|X5_z4U zm+p#REDfE*g4e`AtZ?u~-8xv4#W0-y7nSks`mr#xk)-#wG2X ztg^D;i`!4`&r4iBcU)dJ)kL)6Em03CJk=dfPS`GruxPmtP1DtCA<2!~e_6e;BQfN% zBJJpAj3yAn_oqu(SOveI55G3TF18?gR3mXaR9YiFa=m)O*PB0Oc8u|uLaM8W=1Xv9 z;f-nvHXEhXB0~k=Z|%VDsM~bah71#qr~35$5Y3y%t%V${6s;0kA>)`(CVW|v9{&HS zn=?ekJ@DpwY-*qjf|hk{y>xU?RW_;GohI?KHsg&SmqZX$%aXpXJ71Nmi3qmbs32$%JHSl4rd!>cLEcmzo8$>oVnp6Vi8z%6MiJ(i?1->%K~CMO1B zXnEx#s7L0W`?y*DN=&Q60x`lRui!HCpAypU%D*c~vy;Z(Nbx7m8cZJ;DXU^+X-2%m zKNnX}ONP8YVsNd2tLN{hqM4;HUgl1wZDQn* zDNpZ-HVD4c2-X;MYETPvr=wk`{GqwLH;)G^!Gdbo?evXQoT4UE4J2a~27h&H!Zz5Vvdx0%O$k?Z`_b5jydPX{^x6%AZ#W880n{>ki#!>(OHteDw z)`syr{?&%KgYP=|M zVU3q{`Oa=XJw|OR9}W7UZFO+d_OMd=4zA0jNUKbvTu5)E5z_ME4}t1!Cb(lVuu+yz zz;@%=Aq7vsA^7V6{xtGkZYs#yXrGcVI$Taeb7FWbtvjK2@PQS#Z>un8b;36>tM` zK5ciRRw2R1qcv&l9UlJ#cc0gPbxb*LWvTY&R`ytLH0VfbD1Y#LzpDLAn4p17VXh(+ z>lccu{#9`EE0y6zDitZ5@&|jmzSPJ|PAgIjT$P2Ax%_x+v1yIw{GJycZl7wpo!Nt% zi_a{=cfuBKuwvb6^lbg5I3TaM%h9S8D22&j8OSNoa=#F%>@T(NqMnw+zPngIGhIB8 zEvz1jMaezDsMxVqG+Y33-2Y+^*FFM39C z1L^&JY7@)x7V#Ub!QvLJ%jSe#Yf=x z7)GQQDWixjcCo)uPcOKa5(wOXYbyP-@R-80|gl@3Quu$Ys_ANy%Ua+O_ zx?Zs?VfmmkFpV|gGv5}27-gbQlX_vl%uJVXD+{>HWR@CQ<19(0(;s4_FZAUVV@~Xr zWGhpC_b^B%sp#e_()V7H_?~d<;k+rQNw7<7SDtZ-@61__|ZI zbfUIu>B-88T684@U)S3bU3R|oxZ3=!RA`8p92@qPW@iubC#MS}?$xO!bKB-YdfPsqf&p!rvsI6Rpa?WjQ@_{Y1Jo;Ov6bOw?+;)+Bs-?TU_kS)^J-!&@ z+0#AOHQTOR>dF0(O>%bPc4wB{lS1D}e*9^|i#%1b+SlpRW~Bd^#q@5pga92ry|RS% zVZhMGbXUHgTHpKDJ2p*j&p&ibz(Pzcj4g4$W{SFeX?ne?90iRVyySxg z^6jfaId`FKaX_fN?gxVn7aitZ&&~dfjaMW=%5eWxkTq471 z5S|!DhiwKM9Vx@+MZ~iANwF4KyL(SVZ11zcvxf-EkGTB-J3e_EwsFQM*uHd=u)4e? zW!CPT6@MlVwBnUKg9FD?6?ZC#6{Ny_HH3Q*XqrU z@b~S&s-=kkuk~ML!?Nq`efViP?0r5t_yp+de#rkO{1MYZ;hlE?Nfx!^*xB@r9byCH zO`sK z4p_I4#`Zgf^WLo=FNE`EbOhp}7?ETp!!;uIlZ&2oC>o2@QI{$|DLx)?TnZe30h5LC zanLCc2=xJ|@bDfMv)FRw2Zw+Z&4|D>Zb^~}$8GHkhk)?vm7gC!9D-$oxoc{Qn}9s2 zrf6GMoh=tuh2H`lbA_KDG7{VGetNw(lJIQ5c?Pi9eq()p!S*|H9_jfSehfti!iE~9 zAv_q*91a6bQ}k-31CCIsnjMvmDuWQuAGw=I15s170|9|>9QQpup;DhIDq*xMlBVeT zPH+c8sF?y9+iwN!7ZrXD#P)v3(3uodiq1Dc{X!yliIXG4W;jE_L5L>u#5 z7uOdAi~?Aa@$-4QuW2g$+}{Zs!aLCLR`_MbkZFo4%V4wpM$17ZR8ozTHiYM9pnR@% zs~G3++o6J0`y2mXYxw7Fj-&Mbk*A40{E_iPkyUq>1D#%=s^+tgGSeuf*L_2KL8nSL zCb%~g@j?}H>?s7j5>;%#pMyhjOnM(^*PnB!b;N0e$X)Vs%^waMzjs9YAlU{-Xdsix zv)QBr5xg<-g}Ln;)>6~2Z3J{nRf07nc*bwZoHzM;-E52(`=Vu5Wbqa&v*cAZ5d6724DKtnvbv5D+_FI78 z?G*fuqS!x`_l|q;GX%HwgG@a`aKskMwMX&4A^2kr41zy8!yx#h^D_iTYymz)aO`IY z9`p>sMLO;aA&JOmzRwW+@$4CbQ?|_!cih9TV4wLuLvY_`2<{7m;P>dy5M1#Yfvmw(K11+-tWlr0v3Q2yz-I^!RB8eG z)gCy7Ug3>nML7B{6_4*+G!ssFT$ba+B+e+X&~h_sh|`T_eJRyUV3}(RRV8pi#ofdJ zr|;#du42WLw0IE1xkpBlHumCf5wlL7S8K|rzJ9|I%OrSH7@n-zWKM(kQy1n4Gu&1E>AzE41=9~Nvs?% zM$stYl~0B!F$CFLc~kU*lijZ;ckBm6^T#OLDa;K|O*AVE;88%3Wpa=VW2abPhW)qi z4`;zV;19w=dLtt{DNfo8hwuNA4E8lvKbN;Td39H_P}1APVx?y&*HC}FcM@=KCiHA} zSekams6TP&0M*Wc63n^1uEFMuEs<{SxOK)J9!5cAivs(Z-;a|=6!5-{s-3efjDJ?eVeIbg&Y%FMXc{|7c z8sM5Cj(H8>x{=TQptv)O2*tYrQr`f>d)|*hON?DRph!=QXCeZl(2^dU(nkpiM0P4e+3O4!pFvhb(4m->w5fQfW3wUUCj5O*E@R*p{ zA3D!B?+-gq@y$z|8(_<8$}8B4p(u?rkKy?_!WBZMkdMWte7srfOC1Al1W_bW;qQ=4Q47)jqy9x)hdgv z3H?G0pic~jxuqwjymWL(EEl>gTbVbOrA+8{a*KqP`I3nybdA3eDxQAl$dt|WS;xu= zozX_7cALEZtw*gtB+wceO8a;R!NShJe*iX7{^b}kF$%FZ_2!6KKyy=)NGVj4xT^Ob zl8MLk)iv(eyYpnIf-{XEWbIx`+Qw+RP(kQ$gKN`qeM?0KH-<5I{^uC(#x|tPKAJ-T zDd~hc`CtZ7Tsf-w`fAe9-qUP=V#whu*JyZu$c*xgqPD#YyR(aw<%^89c)ar?>!EzX zH6DRup2udn?-|bJWUefBEH7-w`i^s_)~-J(eETVtmmgJ+a=PGAV)dIpT&}|w+4a!z zLSUpyr!lP$o@b^U%TT3M#!nuThY-%H?wtwQT2#@1!`xnTv?yZ5ezLk`yst`0u-J&b z{95=Yp9KHc1V*aC%C{lPZqBX)s5B<+{I95W5~x1ufB8Wc!gq^JG_?4~EbLF(bw$>} zqd4u2GP2KHXM#(|g9SP)CK@m%o>+Yw=Y&_dL{6Gm9w_u=#&c!>qd@#;x1_V8B+|pxt*`tJTm>$mXP`| z-ThU0=6=WX|3xcY`kGhT4MIW>yaks?)FUU0J{sCZ-)MOR7%CAmFmU~D`$JC0V$_7{m* ziqFd!gW%!Sig^pCE^3TJA@SXBU*BTrZn*N{fsS>y*ABl&GZ&oq63wp}3`* z;Nb=jn1sK&bkDji{)H#`Y(Z#0#>zpw6!cQQ{~9KbdzenGRsT0fILX@(w=fLITmUkG`ikf zp>dhrlm`;8evJ60QSzC#Mo;d0sZN+I%z1Eog#3ozMV{hTwt^GaLLAaPzk+SJc#F`G?uy zgV{gK2H(eL<6pTB!ORAM)+V2x%?2;T{>^MKy}z{nCSixnfNDE9OS13Z%?7l=gnYgK zFdLNBNZ9{vHt-}p3HaM=u=&$lp;M>>7i5WAJl%(2W7dZ?l}A@H%UAW{8z_mwNVP8B zrpn1Rb|$F#?rHu_FH>%sc#tg*=#WRD|*ky$C->+ z%H1n0#$&$^QF??lf@{TOvFH0p@(430h_w( zu+FJ#qb%&d5e-c;p_z^wM;k|;Gnyj+&Pdmf=vyix!8J!n}VbO*B`Ww<|l8$IIpNJCERAR%ic z&}P>SdFL-i&z15Qj3hU`j~RnM3Pz&zUEHXVhOynJ`iS*BEjA2-u*n4jOgOj^iouy7 zwBpy3f9hXQl1$?P1?H2(A8L(U8vdK8h5fgv@!4JtC^Y*?enD!ztD zis=>??Ftc8fIq{8R=L~@6x57-v+hqTl~;p=R5n{5nrJ?h|3&;eqO({@s1ES9+mtP* z-S}s1)t5q;5+}94B62copDf*%fV`4WmyRg1AI-zmi} zNblOovy|1T_AF)j)xxAK+7z;XN?E1{q5mOedH$D_b-)LcvWWkdvMSF1ma=r8rK}+4 z$BFN)Cq32XD+r`r6jwdd0G+!U0&9J`z`JHQVN~^#xKe7Vz!)@U+42Ni;D6c zM`c=AlU@2n*wbM!_x4Cv&woby|6s&Up>*X?{+ zyf#tQpw!vd(*nj%c*$~yo24@Idr+7EUfCf}vhei3%m8R*8G87&X<|W{ksF8A?dTdkU8xS zg-%NT)V97%^*BU_N*Pq5)t6_PDP5aO;~wXWm)cqlN0%9eo#P7rMH`T7yU@{gv;=yBZNig~ zzf8c+qK_-B+5V+Dn0I6^8vth_j}gOt8NrxS&o)ASz!#is4p*P|InPe{@_G>I%!tJG zyC9KZ-0zESC*qAonxI4(a3Jp5{LtkHr!0r8Bj-Y3*3~;68?#3E`@ zNhT|_W)>Os`@*_mz;7^2x&nj@x5K0>4!XddP)1nJ-!&td2^9h?d)z<+r^7fp+cPxC zo7?!=$J7-uLg%>ClFY^5>;F-Hc`|?7qtix%wJt+RN=YtUbym;S^J%>!1dq{I&~4Gi zYob`aL>sVp7i7EF1OZC&=shKr9c1w8g{r&29?yJRG9ff}+lyBTp_t=wsH{+)rwf1D zds=E55}vv01kssu+O^tmZRq&kHXTa6d73YdD+JMTG`QJvJV8^-0XrU1@=Ntb$2+^w zeHBHatKmcryQK@W?e5|GI=b?Ea53cR*rT$N5nHz&;#O}1^c_N6e0n$}5;k899E(}` zG6z}T^}XddZMM7*TXDWQ;CL7+9s_!U{Nn&VD~Wh|8tqPB*NC8Ck&7Jq-af1dU-#3H z#q4Gx<%jnm=s-A&Go%~@otpR6fGRR_jY9>%n-fr++o)^6)o?O&?*#~|ksceVYtZ_% z)~!Gm*Nyyzu}!IH{PeXa_>)9`I&Sed$+Wn^W+Rcu%UxsX!PC&z9Ejn$p{Y2VH0mhR z#$~dYl%u)AHp)dM(WXV$9|doCnQd(*f}w*^WI;+A&~gZrAqelCc(JPDaj3;7J%Ig- zm=2Pw-g{5S0ad~)>|T{tpU3Zy0`_wWgAB2VA+;5k7`J3!cSFCxa zQYmDwNkC`(Zf_R_=IY(37E=!tbH5nRceYJz&2^mh@2#{NcX>&v^fqpqF4Ye5O?=R( z8XZB(Xm&#C%Tm+gqZyLuLdbjJsHTqLh#V3A+Xgi-O_c#yA9tS}#=?RdIS65PM4v!e zVfH|KE3gOzj_ja#Rn32_WLy-8-p4_yHd6d@1e6~OHmWLjq*>NJ*%FfGVGm!}Dd46Dba(n*bQi_y9 z|d6&R1N6+1llxc-5#1W z5F%@T!ldQ!SsvoSUgAEVbZfD`_+urt!VPH)a=IUVd7|Y5;>hqaJDZ5;Yrh)dD0@xe zuIqaq#=7D*;ewb7Jt~SCS)IMAWalzyy1W>BtOkRuZ~7A4p8Bp6M0CjRP60PVL6bos zK_LV8o!I=cLlNkS#`4p}+`LBF-hAUep!HOC?BQ^p_4KLz&*Esi)68f!#@JmqtA_Vk z#(k9Fg@BuZSJY))yQg(e{+O@%(4s*FZS#o~v}Si!%?+vn8oSOMTNX%ea<*~2fI^|U z*GqL-hj#~3JgZJ?Pf@WGNA;`<-$tRu1cl+du3$dqetHs-&WAC&$SV~EXcQvc88rO{ zCN|m`D$NCa_dVJNT%@iFUaoy_f7s@L?kui8MFF7?7_c7$;afW4^X{a!OK_CW(SAPg z2^xGrhf{m8Q!ZqL1=B#N z{YgmC=eAO$X-%<>O0enxThb0-Jrs5QJIQC`&pM#(i3pmYU^xpL{auK@KG&Bo% zy!RSwyF7sS+H?`AVCz+YH@MGvUGq5FO?+oEW|osyn`o==9x#_v)mMEVsuDij%*Pw} z=$sy0aN0%LD0%T(zv7tb(diuIR5XdX4*p(FNv;n`SZ9a$T(0y1uJ?A#=_!0yLS)v@ z!wh(7te3yfEca=B0(5F$* zlKuM8A+XldXd66N#J!wwGQ1+7@927!I752Ub~_t#!P8oED$mh=H7tO-vJ6mZryi71 zk4L5%bmKKrR*xzp4J-BPk~(d@h?JTdj0^(ax9Q|jw4aqF)Vt`pg9oC7TsM;a*>_7H zK^PQ^)uziG!xE@(=KRaN&-b@_ga9!8VX`er_u*9J^}|v3G-@xWM(NQ?)$w(LmvQRo z;@kVCq*b5ol_WC7rHi73)N8W#hm1u7k5b1vfabeEt!>MsQ?tsqZu(6p9b-lYt>*!} z52HWr^dUdHGX#Vk-NtsP)XvID9Lr=$mibx-=d^=ALgf?^h@RE$5jo22Wjh ziV8MfI;%|rZO}G1gY)5u?(*?F7t*q&%Dd6yVhx*S76+%254Q*1R%K+uSG^jow=0;S zw(T}AI|^S@gVp=Hm&)qZS@`?xO}}bnt(Wmcyr>Dc%U0(rz}3J*?U{>X|1JL+qNS&p zMOX5syGPRY+ubpK$K5%_w#MyhBA**RsPB+do$mQ2_QRr7H^llODf_&3f0LsT41Id^ z={vdAJlI;2RS)wjszv<3DG1)sSmnAO99nT6TfAF2-x+!dKU;y&5{q_bE>Hni-#5Dq zu9l@}ue#^fuqz>ZiYsM3_1>!5@}P9z4S{4!ad=D+IbmDhcSsbkIF4ipjRDqof%kz? z2KMXpA=5-TYV+)FBCZ?NeZtNILd6=#K6g%i>cIBG>resX##$>7T2M}RZ!K^6a)ZzP zq33MbValtpa_x3kvCp0opo7{}nGJajVw&{6&>CrRlGOkSPqw;~wXu7O_VY?q<40oy zuf=q8$kA$@%|@u5nk`@BZm$M(U8wzGx_Z1<0MO(z7Nl;c<#ZQiyA)Zsq{UpeF#Gtk zdDQn%tlXgfBoSJocY72zTPEZ!anizm2+Gj(db&Pdhow4$_Z`9LFgHpp~%cC7Y zTDRe5SPI}Me{KuD@QD(x+npRI^fX+`GGwDDy?P+7G1|AJ$th)0JvBA3R(%v+|NhE;spZ z`>=v+d^b&(u}gFTzN;kry;F@-8YGh?kVLb-TD!*cB%r(ZwiTsZo7?xZ(PHRM?W(s) z4<@3yxq=C_@xh_&RD8@ z3aB-BI-=zeE#@r|u(N`ks9Eur>QsLHes?eeSkp1k!euJhKTh zNby!BrXX){-|T%C(tv&z#&eMzf>9AW7_DS+)*Xl99o-s)- zzvc>fWXK``0&s??a>h^`ea>|?yLZdGGkokbKQ?oAwzITzv|kln?bl@CP9&x{k&lWn z&J)nH8fQ^lX#aM~7-?^@Ox)P(xxyUQ{ z_SbME3j5OD?#Y#q+W-b{dGn4uU}~oJymaBuNZ-m+gvwZ(?GRqRh{v`4dPjL%^Vyb! z7#RQg;WF@m zwz`%1&ICpQHpVz^9@_=M$3WqxJE2wgHLGe7MG+?+Xm7ew&K4+^ava_7 zV*BK3c)0Q2ts4Mtm!(9WmhV?@m)66eM{y9KXV(1&P(NQmrbQZd-VhqxC z+ZRc&ySt)?UaiJOwOJgX`Y1j?h^pFeE(}hWT>J7wZoC=$*l;o7r`q zK*oKO6i2c3o!n`uo6uE@n>XMtiUH$P6C5jL=exy$Vs|UP9;o=RPBgl5-s|>wwp*`2 zdDAfk6suqMoVn{(vucN2Kx}UY%{>8WZSFl@ZVx-9cz9HI`!@}U%lN@ zY^&d(6t3NlDPOtdjT7MjnD0C(KG`4BI&nO1%|i8;Zkon?H^+p}fzaw((^dD|;o@1{ zrK@W^O7EjBMg21bPHU(uyK`sMuHq&b=#~fmeTt?JJ?uigKL#5xB%B280?2QPo1C2; zxB4+vjHMTyxx{^`tK=Otz$O!w@M=OAKAVun z)Coxc3kdiy8)}rWyivvDQ!`x=?*`T!%Q<)oPCTd$lSf~(PWNfTXR}b`qOYPws69Bto@W)5h7HP{T=$odQ)av)wSn6pKL++JQ5_A#xGN4EHj`XD8#uBsxi(B`CSe^OakE{k z6Iba;(;XG~K}%{ALlb8w0@p0mN{^r=AA0@3%*LxO50|msY^kV zADs(%=J7;DFkql|Bq>i5cqLQT$U0S|Tt46GTs(Ctf7IsER>=4-WFS>R_};#l5FGs5 zCMSaa2*k$_GR&j1_*32AhW?tzsuk6ZdD(IVC8cu;_}^v|E39C%iSllT^HBd>$-T@+U{p_J&nRxwhd8lKGxoh)BeB}v@{Ik(v9p&R~W8; z!NKnivu~4ptfd(fk>2EEXl}aYa~yC+w9m8OqH&{*yPLwo3wiz82wpw{=8rvboveHI z$9^1)G}4*+%(@s>hM^NV7Y^`dXQ*RNHoELRMeEgtFc$m=M)^3MDtr$stjArML!X-ub#qv|^i0KOt z_YspD$p1cusL=C2jUi6O;aocYV+@hX>@F-vW14%yibfk7=DC~xn1j-X7}+M$TlEZbc)mtUhRF2rm3wZ3}r`}W|-P|V7EY*|n=NapsN zd<;J3dD`l9bVkP}5UcAd zsov#|g!;(bz7_YW_0p!Ze{;V0>R+6}-q9Ns8x)#l@xu&0E69UOcqdOY3-@!r#3D^~ zb}%+qRTwvQ;%*VLNM`L9-)&(gRVSApf5Qd@vY~Xy#{s@bp#ij1-~fHaG@2E&es~_1^;IfVU-YCqAGMWRg8NoV@7_iC~MvgGu<-n z%+Mk`d}8^mrYIzI;814i8Lj+r5gK4Oebz!n5SX0xza;A%8IKoHv;G~dv#^w=nlUBR zdYjBEb-JR#MLjlB8J1PoB`E$~GZx(;!{>(~*}Ado==;}g>unqn_v#yyzmtD_G`k!m z+ZZV+l{#O*jRaxnm(fs!>(pc18UAd!b5JT!t?-u{kYKLgaAu=aqbS~q0 z#B3zzRb@ahcuVZ@)!~ECmxX-upD)|81XOYp57{#f21S%}$6O+K=ye{$KQ1_NsYb8e zNkLCP-_#~@j4Wno#a^a&r0xsm(#Xz*<6oyy*}J3ZlwQdDgX)3Q!v$&*{e1FE>aCyn zO-p}CanTeN8c~c4z8H+_P%ImN)HOl%Qd2E;#Uc>Zfk2(y@> zPEacjwct+=?LHwX09rZDCu356p)C)62NvvXk2JP-rhSp#NYeFy&uyc0W+d?BQ%y8F?A5$DF0aW?^yOHKbUaoloh$w~tC8 zc`@M5LOS*e)0HZ7ly|B;OxE${lwWR?iimM@^YeLI_TN4b?Q35_Kjq=?1Aq#b0F)cb zKHdH32Vy*z8_Hy7p8YL=$=zfJbgx@c~VgaKWo)k-PKjK7{KhB^S&AqoQ<#pBv@l= zM;EmN#3c5p1LPno4|qwEdiQn==>P;5QR^B6{sWHn7q~PXKUWK(4_ZUXc8B( z&Gr!NudBRemOoQkfcCn84MZ7 zEQ7pdmT{wi%rg83YhEC;{PyMz28xRaWS0Nge!EQGTV|Q}EwjvfXvd3dwU72_LH7e-P zTroNp3-bKuIAUe%L{-WC`I1Dj>Aef#-*Xa{+A{A`QKNph1^he_D~*M{-8~a>Ayc#4 z+JMHx3v$0Lzs;!rb?LjA4(GLMaGb$SPbxgTW2=2aF_E_ayFlB=FEo*6A22o>$+nZdX9-Fg@ep zc<7HSi}mRHq43dOp?+{7;>+*;p2gBag7A~qGKf%hjL1_PvHaAnXyvTfXrgdO-%rH!jF@c!J(2{FQIKQ2_FdHwr+$@kRm2H@+PU5k>gM zb6$c_m3ar`8=t|C3SF&M-aQrr`NkWRw|t}LW@s+x5ydwikVg|B-}qPzyfcBqhzvUY}4}pB6Cv>l;?yl<|;zRIclg)*~?{i7!_$02%+neq^L#`+<3 zO8l9=b3)5)`1{e&OJo;F^qg=)c}6aO=_j zN;(Ie?d7Ay(zXU8`4}ysW=B#8NdwhS9_uq9yJ1+(0NO{i!M%&IJO$hvvHC3)`<@GeX~MTV#~`<0p`mYy?TlDkU* z&kSCkhxM+sp+|))s*nmQKVvv4bu`_f;U#i{x{GogQ`qgHMz(EqE7{gb-POFJwO;2} zJK}FKZ?@^5Oa<@Xu*FT@>9;r?*s2%9#i6Ei9uuzYo+YW5O_}wm?>lse;8v0-fG|Bt ze;HH~#60;8ArR)#Rxr3T`K`6Z!0%h`Y-eCj!^ig&IBp(a&Eny6!q7#qJOh7O=S55L z=WQUFT%DttSZ@eSX$h3y*QmH@1Uo!O&;=Rd0ah!2R_py5dR%UK znDyh5mh73k#26Pri6?5KEkse>hZMlK~D@ zfZbzd@)$$z=jImU72G{Mq6VtKlI?0Y2j!zX*c0PBTp`+%kYE_n>wMWB zfdCDpg9#_t%B(A8Zj)O!?2qWt{ItSkr6i;@?%WaeQtOW)rf9f>A^(>24Erxh zPqnwCXK-v+GE?ZrPT}n2Gy>Pv6&OP9y*^ibxY2hA&M4Wv)Pwn6GWI7YJaVI`(A*H> zOwv3o1&h>0I5NZSCt}UK@`Nfhhx1Fl-@$*?7wZbTA*o2M^QxX!|AnDC+*Pyl5MfL{ z8a70_|Ft$R;YBgMw5QJ)FL`V5AV-}lbz3lT0F{N%>R*7o~JGJ;z z%DnS$rOYLg$p4x7G=T>)pLe?E=P8*4)Zh8F8cYwZJZuk$$VVYLXvacARLCRs>+EVT z#oDKvV%0QhLrnQlOFuOYg^>Ju#Z=GHS1p(_6v2mAbC(kMZKf8NPeazBw^3 zTBTz*usvZ&?1iFexP+AKuFT=pAzTJe=l(sONaWH_s+{pAu*N8pD6YLi0o%Q?Y?^CN&wBDLb{!Ziwa2!@jDJuT-P#6lq%bIY$k(vsmR3 z5mr(Z*E{GWzytbh^l>-na%VpjlP*nK;ZGoOd-IakB?QIQcjJnSFADv=$x}JXi&-t? z{@seO<(I`V?S{f?4I!BI{n=) znkP++#|m;u2)3L_eGGP%ibr_)(>l@sQ@%z)r;$i?`N4Kv*1EW2=<9F-NoiceTZ}X` zdJ%c?Updm>FW`zBf?#WnYYNGTb@!9Qc-M~ys9$3dJklof6Ukp3?j|}(L~rCts;~)C z*!cD7>D)`tvi~AcEq?k+qZAYxlf@xGVg$uHC9P~Al!TH_DCP#02=YPfk^j#gkUw*@ z-ao3NgX2=7^hr|qGxV5L5P@>!|5KSXr|o|$la?HtfNOVVPOjK&4)cQ9;kqZC(%$|| zt%=e~o^wrE8T5}$AjQ5qCtwo@pJrSlM1y=;QZg>(e^obq);|OK+r@)ga8;tpxDO{i zp$dS9=joByHsopLyQ}zf!y6&l@mf=vE*2*~}9DrgPdm%+m-#^NfZV;E*afmXS!`~S?EiX_IO z{j!OB%bI?F7;S~Fr|c(}a1D!$j)}g_N;3-X9z*8d#w#vX{JBkE=fqA>LqL~FJzO~a z()IXt-Ih(Ko0{Vrb&PD>*aF5?81#3lU5lvV-0v8@ZJ8r(pTn9}msO&YrVM+z^W8CX z+Lpf1DGdxG=a3bc@vUeE$mlVz{qAr&vo5Dh5jI9AbWLL2(z6U9qmH)!XC-yB3W}~v zh1wa48qJRKi68%GWf5mJplZ5+Qn2NSqE&08aJ!)JGI6yGz*Yg2DwjOMUFrM3YN^Fa zH>0(t5-yLIO%G?c<$!#cPBzzGX`m|61v_J1@PV31BO3*ce4VUr#*9mX&4KfQSzO=` zylIrjiyhtM!Q_O(-VmFC{sFiR%-HxLBJ~+J(DKyZNbf0v6jYx=m9XO_e7|O7WK^=P zt{aH|R3!auJ#uYWwT{Wz_zA6jg-q+>;*06J=(C#5B+Fk#*4<=fK~M%U`nTbhCtH>i z4gawtG!}9DKkW#q@|H=oa)|0@#QjBCj@&_UrQR#+X^v41dcrrSmHE=0z3D9fmP2JY z2L0LiuL!F5Q`^UX@{|An-R5DJgR2`LZ4eoUN7JiW4-{)T>b0Dr4=AzCFBF`&PKQtz zy&rq9j#fCGz={^2Up)#Zp_)J`m7(9N z#4ubC7P`81ZKz|*h_q~T?;ME|OsmW z6BY?ifR)K*?|yW)G1y&g$2tEh&!xkoE%SYrkQ>w~=f; zIp;!Bhn31lTUXkmSeubUB-heJ_h{mU1hRvsZiFU3c0C@n@9Jxl@zDd#chlc#v5u_~ z&6HLS3wrC79ojza7w5{t7$#F@c=+74UPpJG8zdy_oof4?jO(4gN+W{D!O}GDiJrw{ zl@ILp6Fk0^n-j`(4ovKK47)Q44-7x%nGf6gDl)No%I>L;YWg~y>c*S`To}=FOgtq# zlv&n@`{N_K%og*;{n|IDwLjm~AUab3JzWdk6)K>f5V|z(qx1iaXO0=RaD`H=(l5_`&L=tegTAwcHSZmVRX(lr_R(PL# zRvGIP8V?H4Zt3FPs#|^u0VzfcTLzP+sS#0zGw6F4)SI@n1gWCL#QJn~xbGv-A4G8@ zgOAT+yS{!N4W>sj@4IE1zIC`WY{S0hch2_nWX`?J=SC^)&py>}LxW_G{P&Su%G=vR zo3oVZl17+8oo)E~EBt#NB&05IfCu`NLF=Y&Z7&D@z6u_7N|Cx>bQTM&kC_nnO|=-^U2*5cimE zY}VQOPF!gHqUNOI)q+;_W_{yUh(Z zZ@on5GcG2M5??g8S0=tl7u1dCQO>3w3ly8P{7RKJVjR?p8_}14_RyqUbUZ$nk?Org z42?-V#~bcPV~@0GAkVOw>z*|<0;|ZS@*7zj-u`zS&-xpV$DOHOZ}b!aO^~Q^nfkhY zH8>ve@`n6xHQVz381>kGD!GHx;2G+tpp%BXfP z?7Jgn>R`o{Nfyejg%>Kvo0KF$}#Bs6yBv2uPB+Y&{~Wr(f9u{E+rZCe}c7UY#FE*r(s}R zy-T;btnZ9Jzmc@peRzb{LmWGZCBt?^vt>U;gde9A7mXJ4GjU=F1V5B3GT)VQXq%^q zZlRHE_*>3G2QU9EXV1(o-}yf`Oz5d$<8&cXjgZ%GqLm7_8s1KoOHZ>Rg>tN^#);cS z&_~${%H`UvU-W1YX;F=DDA8@o@xy%5gL-s`5Fr*14dIrVR3PrVQPq6PKJajo(5^<>60G(OWphAR39$DNGH z82kOz5XiUo-10GbYkPMy4iibKtD7$z5n&`P22_|t@q(OV-6YY>1Y)a$)XjhE*~`gD zJ)DdvJ9Bt=61p$y0KW$!Ve;1;APsh;aC^XnI}C^HFx;`{CNf@vx)Z`K^60qTdM6G!8j|KyM0RGqGxCmUfRK`qiBh*#U^10X#zH zLgYt*rsp!U6{siUy*>v>W2Hhy3bjS5bI(KYnN0x%ibl??J?n~K$N(tnx89K;q^Lkh}@*!d0h4r3h^X9%#*R|x)IxkOEpwH{YBzlDx`i9#i8Bw^r0holjo;D0nQ zPm0!L3bRt&_qW16wlberb_c=Z^VK9`|G~Z@5xbdes0Sdx9R`o5AHmubDwV-wknuSL z3XdUM=A~B*g)mTXZ1CP7e*{DHEhY2`isLjOU!~}ea`bQD^-Cr}rus}YNX{I<)n_;W z0(?^=78WrsqvjseXN(kArmDB{uCjFaO?17rY=&@ipFC*|TDWMI$w);SamC4v_R+O` z?f;Um25@JRUPz`P6~S64ldd1;`Sak3KeORmU!^lvlru%AUaGig$!{|*8tQI-8X>_= zVr(64(!a98*H7WrN0E3P@X^IyOR+$F7GPEab6RPZOwMpqgCtw404#K-KkKiS zX0wkj_4)S1vC!O5?Q|nv&z_i6^RLDu(tXl|**u|k$IiXC{oLk9TIp@#uLKJACSET` z(-`QM(3A0m+>_+&Oor~`9qOYSv{~N z_OK3c7kME0Mjp`|0AF&{Ko>dc;4gUUG-IX8ztK|}F_(>rZvJ*Ay{`agk{~tB^>1g= zN3Y_F%NIj22~y#FAY}LR+-F1X=rC+H`F16Z+Hkz@xa$^A)=)N&J#teyf31rt z!S~M!*v7A-{4fHa32yS5k^A&zos3(RKN0m4FJCUi-k|{_U)TK4;CjR(pAR#`+zV2RzHtj6ikeX?5MsK9)UH#07{6A0?yCZ>`G;J)--!LnN>H z4PX>&6_?;h%B}3q^pMmLH{FmqSMZv`M7gSMegz;AXb>`U&W`J3PQahZZ>Ce{{_u1s z*|XRIV%#qs{wLAfCo(Qe7y1d?CzgtHFZE#uew;HyruQ{~6{CHk7!}vWhw8%%@#8VJSd*O*aqH@v6BuPn*nFA@} zyEd3JP4Ckh0L6Mb1)x|@bMSy`0w~rq%{LV5T0Vecb;o!^u{OV{h^`GrOD||z-Hou`*n`ic#*>1jP&}d); zE#cRJUXny6KHE~Co{0>8C}E4R@mMsb(kq1&P<#jYCMAHy8ITgD>u-=6rm&NgG&tn;aYje z{SK^AL?Y>l}puGUwBEJpkVLI2`)yJgk5rzb)JAuudQKN?tGNm zQPSr-Fz?3SJ6EiEaw#u+nQ!swJykv+WL}+q*!8-;z1>7`d{MS4;emOo`~y3JZn^gc zzvTX%CgS^EO^PJ0ihKm2L+2eln6(OIhmO?MsHMWKWuXn2#K;?_Y8Na)1;A7#U{>{b zlcE2GsUn*LFjZu80H%s;4!~5s9Rn~`D!KrsiuMzLsrnWSB2l)AqtStE24Jel`T$H- zRnOh##XAXD72OVGb-?mP{tZ~Z$kP$;BxnK4S4H>D@+F%CEZ+o7!1Ar?0W9Bd!Jmn- zs(RimUx~7C_7Pxs!19$S11w);Gr;mqPysC8Z@~`Ij&I|I0hVt9CSdu}egZ7t1Qo#Y zm7oPIUov#S@EMMAc!18^YD`5HlwHyfAPk`n7&-R~b1D0=94`BIL_3&5s95Q#X z`(u<&Bh&4Ag@^o*SN%F!cJ5G==Rwe>x1Vw_C@>5%pco%wy6LS__B|wpO_V7mVBZ}! zmnQxMQdD`*_LU-N+T=8qk)1&uwWQ}nE&6e-QK^~ng*7MW9P8q#fnl7-(#~*uN`!U@ zDb7q$a6~s6)_~syX`?iLRuvm#BB^k>#YR+KP73W(R5m)KRL{s+Tq6ufeSRP_SLSTC zW2<75X0+}bzH$(${T=f2a8|TA)!Ev7Mr-O11! zl##3pE*}WiInL$0Hfco_x7Ztrst=44%sKc=PT-xr&xjwupd0*E!&B{g(E@S%G3$OGeA@In*kiK0J~*0?DrecRyFGIpMvrwQ*0a}W*EEo2CeEaz*j|W^AjwZ9z~AEyg-fl~mx7tmHu%i3+PYGk-;Y)$zaN7oiqJv>nXJ>= zyV=%WLBp`|zEeNtLh)=^S~9N?&IvvgI+`i!({92jex>^^N_LZ<$`{R5NW!8Rt*Dqn z6>?scuuf(15p6kLl+a^k@<=tmey%4R-YeGj@+bL;td*4&jAe)uTq{u@y7hSBRpJdR zs7wO(0;T@ z7w)8TaL98od_&gY(`6I)_NC8ypDGD@%gExo_#D37fd0TpYPDu}!-@{Z``Wun920&L zB1n@kC;5HVORt3Qk%cY*3wGq2J5Dd&k01=0Ayy)6$)W_tY+o#RyRKKg(_gpCEDv-%^v);!0NN7-%DjWgpUXk0m>78&0XghTlSEGcj5cn3L$A39OR zTqD9OmOMT9W_x$dr$|T7pT4eQAHe!EB&k;J9Bgu2 zV>v-?m1$89FBGsloEk{^Uruqtg||94vIE-@2v#WC!#!NrjG0r<*4pN{xK`TR+r6wO z8Y@4;-<%S#yyksA$pPIZ`VJPwc$R$*dEG(4%bLVVFnv$BY~7fL+a)Q0(w;fEc0Lx1 zK~d@D>QW-N_@$2kuAJE(>JS9CpZBD{2YK)P=6L@#_i8TvL}In_)EK&OA_@gAr*xjg z-G$pTL!5L$2i`2a!-f0lv;ay;evMp<0x#W{kJKsh&_Y9eoKUOyX9O2Kx(qUK(fk0XY=P zUl%895+nO7bR(gwmVUsjf>OughPQ z=%#jE^}wEDr+0TkQ!q4+_oCXGN-T4X*rKu=d-NyNJ!cYne zt84NL$?_j5soJxc(p@+fjk}cO2@>Hw;evG^ZY?B%(-S1Xe{F9oqQVBNo=%1t-WO81i3#u`t zxbAsADv4KVF?KP2)Xf@B@oAZ;ZRQ~K!?y8$k)M+&Ng$zkNc7lhjCTW6hq?qZddF(2 zY3Jv*z9M-^hjh`LG)QBic-t3M%J0N4wv*#;G~0LKzJvG@$CLmWqLq|Sii`U2{Bxu%x|z$}p!J0~BVmUY zlE>tfF*0_OYiFIPUu;ZI&!pbgI>t8ovXOE`9v)sPTAO1j@f3OLvOX#*ol7vxFzTV`y-EKuTh!p&hA z;|wH|lz%K1Um5%yny?UCc%CUD@>IeXb2)^2CJngDi!0IBEHZpX8ZM4@-+qU?J87F; zJ)CR3z@0qOms}otS?sg{(H68UDcERto(G;InUX9gTrte6uoncbdQ=Y{w_z`rP*JPg`|2fiFoueZUe;F3HDCW+ieE>PrS+ zY|LWT`Sd85k!NMPpO2Yo8*pe;#xQxhx`&v;oB(jV!-uQ^gYs@TEKv!t#|U0|5w zsC`f%!cYOvobRsX6K1YOEL;Yg-5v8&XQXJVKH^Wi3-e~LGGFCa>PYuAekU*^C_gTd z!9`9s72&54VM%=&_S{Ft+(u`Fi`#OZ+nS@nU^1h_tmGUVMS_XdY;6Iq)*KrKPh$DjTFAfGv2hp zYT?V;#v<+QNN+&!))o0UzU7vsR@>W81%p`R8(Oa^4apl{aJNIO2GgC2%p<~nQ=?)7bsx;S&W z`H$uAB7Ejg6^@?xy+qTGZ>&I2GRRGlbb!I2&+8Si^Fe(vs{eGYy>hR2_*XY?p&KE( z!u%!0%f9XSWnlzlnb2j&Jrg?aoJ#dWu2h0>*WldNneltu7LJiix*#WRpO94=uK0A7 zd#SW98+)Mas5gAai_Z>ctXB9I_pD|?wc=5>$UEX!=5u2`5#Em1~}lo1>*tygT|5t#saLsh9Cma%^lkJ)P%I==-f)Qsj(O zBR)8K@L8&(C@X1YZ7&1VJsATBNnYkHzEW7Vk2_s-l(Et5#>mBPHy4lngpP%k85t`H zy;Ltfzfv;m*tMdiu*eOPLfEMjb=1gvGxhTm>B-$prIsG>NN=Q6+^f|r7%%=f^!rDuDEl`-J-93 zTMd}-2FxtR%=px~a(U*rscbF}M^{0oT3)X=JEhZO2c-m=FK55Vk3=jxoy^3QtP@j< zV8a+0fEo35pbnf!Sx9+OC<6Y9;huH6rn%YI>C?$0+_tBio!?TJShRbV7UI74ElLmq zSYf&m;(824MXNL1Q7`!;o#Z2(K8%n;9M`4Fk+1hRqp5{5EIP=}s!nF;jI?KN2KaF< zzzmspiO}a$Q$9?t#U(HJCp%}22xk9or9!c}-6i5{VuTr@btgC6n3nWqgv4Qj)J`16 z&5N|!YiYT_CAa29u$z{Yf2p;^dT4V;#&LbHT+7tNH+c+y1{0$gE?jc4+f8qtts8(B zmexP88qcQa;`Cvvwm1Gjads5Ed;c;*1by~DNZD#Y%5EG%{*khLspAli+puc>jcQxm zPe!7xXy0Gqhx@pe?suRM$#h_G-57s8_P*Sm+j=~RIUakxKDWO<-@ck)gu7l=d3xg} zrL=AiZ`(P{Yrm>jp268lx}e{+6ADKBC1>|u)-NV8vgmTDL?<(6){O2FW$hfe22KRs zD6YKi8*hi8k~!QrZ}$`~%!Opb(yW-V!y$u$uwS^{tuvokZVtYXe{pyA(l*1#KUrH_ z<6$#ina75FM1Vhi6*F5AdOsqtkI6gK5oF0w1o`p~wQJ=*X$*2Pu$yd0){y!9G5HDa zl*`5D;-N6H5c{~d|1LLM8*IquL9$=3AD`hpuY2N36-5f_fRNh`YWL}7A-NtwJ;dSCc6*TjVU0?4Y9^T1CE}P+u$L_| zu&&bHvgyHx6HJ+AKbGI~kIF?W{+G%{$iWI-Bfi3DmA#tNKY7pkjI87xE~RJ`x0*CG zQSJBAxc)`iIYBNAS}O<-Z1#KA6$$apKl|5+ny9<0%2xz zSj_^xQGv5DPGfYTqsG0sh_iy#n!75CBW5dZqAcc>^xmz@FGXxK3jbYSp3nJpD_;m( z7){Q5?l}w#9?c)Y;pDZ!FY85jT@> zOFBYFL(BD6Lt^f!C?31Clovh7oLx;5@vIzBUV}75hFw&E9JuA$c0H!agnoD1hLief}-eB(CG37k2nwn zwTO8Rk_7K0EnYuvVfe1mPl1m5R?e(KW-)9>94rzeXf)+sWqqMXSE=D+#VbD=oo+v3 zT_8n4P`=qM?#qm$Q(J^Gw2i6qWcOy=dFRH@Hi^YdSW}VM$p!u5S$W#!bQ;4P-d!OR%d71uv{=TRC*Jg>0=0H zXEn6S>~|`D!Hl+1XH1NN0<@>-%L&L?iR8`$KNeJ35_Xnc-R+u&@N-#%AIlZ`zzOk) z+fb`F$c%kRRW=eppoHF3@HenY3rzNimN+%>?_jE-&j#)1Q}BcesCt~k2Wn|*^@Baz z?<7{Ih(*Ur!gub6h@Pm7Xs5Y{YvTO<_}h6BlRw)g233~LYxhjor0uLz9Bb~{$fp(J za&5B>x|q|BD#1(3f3(HN0EBsGC-sGdNV9)S@(K@Kw`IX6QE`3?iVHBe?L0pISgL$` zUc`EMJcNc<>37x}OyS&AskubqNYUcrq?Wue)@bVdh{FtN2pDm)21objZ4qIF|fG zVpI8|7>$2g0z4k3zh;MSpz2x+G|z@`K1t;z4|Zk{-z8xR_z{bOEBJjMJ@%gr#gfM~ ztkq|935}~XE3l1l^1N=CxMlDw=h;j&h{6@#xUJM~cRvx-^NK2dW;?hnyEjB(zsorC zfy=(hZ*dp})~ECLSmMRf`VAqJBOP@VC;i+0_~Th(g9ZwWG?;^v zPmc&TD-s2dn=9`8n`C%s7PY<{mC10P!!}$Ohg%@^3posOAzk87qjl0ABa$) zuw67*He#{K$kC{d*@DG(zsj@sP>Rhl_2UR_5$Blvr&9iY`~RYp(*x}e>^*JOM@!NS zwjmE(4cv11Sp);iBcp>Q?RTg9W1|TgC!MLwXLbtWr_M4UeCWBjT@_eRXyC>^_{2o| zHK=2NON-j(D{(E6d)RF4I(LTmj|$uoC1>0zEMIe^hpHYvRm7>O38!e2&43S@7ut)M z2$BiOySnhis%VviWIU{;5Br}?obfGQi3Bd-B5@e6pWu+6==)KO;c~-yosmqD=NQor z{y2WA_U(PHycp=GvS+nUU>LBAOKbJ>Gw7)_?h&kyVQQjh3JJX>^jdqcqaV&lQ?V_8 zPoZj(y9PNI7h_VH5OVy)P8@LY40enQWKb{ph{>N{btcvWg8E>X;^njQz4^M_ z;_>69%9Q;%QTLFL0nKblj-jsu5$Va*V8nzNmH5(gtZmps!LtkjE-L+H6>O;&4hCm< zv5U_#TqtNNf1>NRV39O9T){yLCEbNl9aVC-6wFbh>V$Jt)UNAs(v(?H(3p$;mi0K; z^CWD8-t{F3w?GZprYt5rN9JSN$TtD?fP6$A{Hw756v2H?(jhSnJ#_R-U3@wkBbSwf zm85=lgh-=cIvh1FicmL2yl^ij9M`8nn_??={Oi<0F6c%4iZ)YbTL~_o>Yx>U3TK7b zSz2lbyY`!-4P`UIf;JcH{k0X3X%D3#v04H-e^mj*Wms@_6>J_a9Pba0;Vl)no4>7L zNvOh*>Y!A>6^JuwtW`~8(5{fW!J6|^&y|}gSM2rRV|fU$8eLLUDSrp8jYScWS@7cUm)X$tJ!dD zf0elSFAH&BRE!8~gbkiQ9`jw&Z1}d|bK(a(HBDywQeH=d_b~R=Pz~9xRO~ditfWe- zFTK2IL`u1A!&;x4T^8hg zt<;A*R zGJRf>tZiLhBVH04JOyMs!grCsgOj_wzTQPbzn*_QBbfgksr|vTT@n@FDy&Bozx(AGD9^>$lvS+Z<8I@>VV=176J5$J5oRiLxr9C||a z=B}Vg-hiO>zVyi*wR3umqDpG^mcD}1)RJmFbCQ>{ivc%hLsIYBrGv;PUl(kS=b1<$ zcS4l4p?5slF1y2xooM$WX54%YTa=(Z{h(iVLL;Wmf|XfAMEQ5F3#jpNgbwaL+qZxY zjM@YlU5*yr-KVpkA@^DrUp(42V@aJRe?2D~mipMBHbcwOyXqu6*2=~K>X zzqfj>=JN`0E(^bE=FdWHsr0>7JZo!!J8jNE@gz!mBBtwwo^FVm8O1A+OKNKnEbh8e zOlpIkcKRLX`H?@H!NV%pG2p;WB#v5gjWZT1;GmSjqoF6L>xzzs2k6M<8Th9|DKQnL z+`u5e!;ydw9sB&Dr*A)!3F$l} z2yeV~F5?6SLK#9WI4!600GgrI{=j*2q#`;G6}qCp6?&%MrkG0weEMs$g24l=z={f7 z4(Km*hgx7Iwy%`bww$e@^I#e48gS73{t!5?9wHhT#qf$sQX81lK=j|MQwBQu0EiA? zF=z#qe}8y;)2a*%%X$SYbvCJOYO#|CI;yhgLTb`2(-rp@*>i;I-B>UlhfMZGv2wM} ziZ-&(2tm!=1#!gXsISf^+geZlc2DxN&b(%r1@G>qAKj49Gzy>WKvKVy5^i9Q8> zprv2@;zd+IjF#qe1I1#?KEe=x!^1_+H|0oaU!CV^&hoICbWT3wsnoeK9U7YTfvo2`G;<(oQkWMe7hwgexib@hHPRMX)uC&*}Ii zsqr#qH-3-oRCb=93I`Ef(LdlMhyL7O^MOb#4v@%iKXskk+3rWlA8KIOv7J;-;mRLG z%W^aIeW=R(AlX!mb<^0>oMb@%jrjiS!87ONqwF4Pjcm8Lva1)T!g0+44GLkZcejTD zXv~QXrfaI~qwI(#+a+?Hb#dH-CgnA7U$b?q>6YW5qWqPnSY6>%@GxFlX8-DOXX@af ze1V<5a^(ODcOra|IW~@`oFlM}{Vfh^kBDxW$JBD;Ct=M z4ekR(ivaIRIs&E_n7#MjBU8|R1Hp#HF{iWU{`-G;Td0Y^hCuegA8!j=F?HNJ&}M?T zXBPW*gGb-7}a5b#NhZ|L(16WEMqPSJDX9NAUx_YzV-DC9NtMCK~sv3@H+vBa6Z z?AG0?EIr^liUNU#kDgXLn1K8G`9HS-#7vn})h^GhUteBcI{CKR=Gcr`;BNtED*>&k zxZUMLJbWIkd(kG}morF0bGtn~4g!4~_{2DYqYI~&%kAF5-7yd-Jk-HWIRXr7!S4fE);M-=4XbBBXbBJe1t$gCgU?)nQg*CTFP|Gw)7 zOQtnB6r3RFcSO|HP8I21Qs$TseC|jW0%dr{$l9J~r!07wxjt;?#RAhuDkB|Lc|y-_ z-w()XAh)A$JV>kpH8;=Z$i3?O8W@3h)&Krf4%f|AND+$8EEp2ug3v5Tmo+0%P_TDO z8Cr3(?h_OZw%dX;g=)Dz=mWT#yK3nusFNvVV$3p zw?Q35a%b|-p03`Au@Fnkw-8jD6BKix1f{|C2^EWigD6XaUa~B=r|_HZ6V=( zST)wjbRj94g)#;|ygqOnwDq*d8>EnQ)~?r(uw|NF1=9=>D=*5jtGf5|e7BX6w9<&b zIRgqM`8~bN@jV&iya#SC={;E_X@Z`ivST+rc&c{ZP7)qWNh<;`&A{{I4MF>y*>rsVp9;)TwS(K65)yamDGaZ`74j06Oi!Ee%aa|OQ z?7YI5AwKS){h>Jrj{LN%lP{0~pQO`T`i2rR65>uWJ8TUHA_x-v4nZd=vo+ik_| zu!~E(s&RANt`~@QlPL`O>XC_#`zjm6h|8}D5q%l*K~7LK8?K&_5WPjtkr21}^vx`~ zw(OSQrE!?Q;p2w6&~A)%yddmHT_dpy+p}m08_g*@@i8%Y;$z!iingBe3$^cCXonTy zx#zy+gyE7tg@tVl5NBf;Qo$g&pmPrQ)o7?k+K}BCeuz>>S}=Z`Y`Ez1k0<6<+`x@iCmez>48!egHMjN?3My4DwMN9Ylxizi&sxPeiDH$&| zPSC?SeLaOiZ@3-6}XYKH5LzE-Fx8`MinoN^IMH|!MvZ=ExDW? z=6l3BP2X$34GE?nkQH|zZdMf3fvEUm!$VGSfV1UG#Sr>`cedjGVn&&>}7@_+Y$Bdr}tV26Y6xxHTzh2dJeNMc50$ts8 zno<1q#;lV^yZO=H0EU1cK;6}H1BGtp;_pJe=(UY_`8y@b@P~%a-f-4DK~2R^sM)cQ zCY<98^0Z&nc!0&XdP|;2MaEKqmWwL#KmGuP3wDu{FNEygFya1(`wb5 za)s@&JsI#x6zem~U$Nr*>DE@Z6n`?uQrf&`GpQKj2G{#sr4gdeCqQLfwCoos@8#v) z?oZr;^`g8vb6I0W+yCm?=tY2EaMr%AwBhxucdc;K>%33-P8+yA**I@+^j-mfHTx+` z^+X@=nt#@Q^6u5lh4qQQ>Rw1K0_{bas5o`myYQ^tGFbl4anzUjIjUz3e}3Rv$j8vH zzauCW@3fuBQJ`NXHoPo?5dvNnl{`^jlwF=+|8!7FZ<4>$&Q!C5el3-Z4F+B{R5<>e zO!ZW`))CzG+GMwc_JZM&bJjkGLqh#jc^n3X_A;+29@6zn9o{7ebXIW!1|p9GI;bl= z08R9*2%udq7SZ*p)*A&}A-FIXn4*XR(7QQTbHfWbD*qt|=pT9pG-D>p&)Vw+es;Ys zkzYf zC_L6T`0ef~3x0hhyr=USc({~lm7IZ4>!W9zI&7x`p#h1JG8`w%hJIlkqU~PH}VxEYWno2^{s2614Lm;FEd51}IhW)%wDh zo5Bi6D-yyrR#ri?gfRU-ES+Ug98I@?gG12Z?(XjHE(z`yAh@%*%L2g(?jGFT-QC^Y zU2~WFet))Rd(WBfu6k;A>ghf+Z0M}xHX2`7YT_Q(TBnHG82~xh@V7L!1C!o^V^kOM z9ior<2OV=8dv4@VDtA1)j4Z@|3#xU;%bu%RCIoBtU#lS{FOJ2)VXq0vwJ zX+f9P(AT>Gttalj9gs6ql{#V39-3CnLsks-&NRf`j1$7mV@bNQBXi`}c8K!XTP{A0 zSpFd%3=dfq9YvCc`Ik|5#*!?$iN{j7^!p%-%82q${J&S56JhG5$<}5Ho$eLPwNxDN zGUA5Ja*-C!>vMm5SK0Zym=4{3G3YwnEbA6qW@U^@8@sNSN@0oGyuUf;iU!24VGG0E;Z{5q+wjNakM!;WT$7C+>|32;2lMQZ4QPbHd&` zU{ZVi3ykRN>+kkyres84sOi!EATVa2;@um+@`WcOF6gWV|M!@^EWP`Wa7}1Q62fz5gN>XYjW&<^T-ID*{8v%1w$+6nfv-Kfi*pbfr%Y zkj|*vwsdk;x1s3T41=-STx5l?a+CqxjpD66@Ev5b82VQk!$Cdp>VR&Y9kFewq(mZ6 zBB2oIkgjb@O$8TS|Eg#qy$7Cg)-)INiSV~?QzyJzu<_De81pDR#%q5T+W8y zFL!(pn3xA=t`B{GAeCje`GNdj4`ochb1S*0EZAwGH*PA7I;IzCdeW3p(X3v=p2}=v z{)^i3MY>Fa|0r_aofAS2xh9wk>|xWtrU*8FONp|^$gBo^<5T(Vgtk1#{piMjr2-hB zx$*5(c=yEFrRCpklm9x|6!fmEU_nmFej!A?7!=aOrVbeB6yrC!cdP9T0&m6naI&?Y zYXe=jeSN0dd}9WDH+-vnv#+u)cP@WiXU&2D%KCqRgo>c{DVruw;Zl0M)RQN_-aaES zXDyya8Nj-BN{`m|crt?IC`<+V#_gvZ&BWLMHEsMSN81iR<*2|WNRD1Uf67q-y0*hl zIhy$?M?D!ovasPI4?( z-4?tlx@8XI5>@XQx=^<5!9BSw4h%nGIMVBWH^MyHK*-y*1rD!gv_%I#&Isi1cdJEq zyXn+YqRvXwI0&krHsBVHpngkgeR@@WOKKa?z-IpZ<7Y9v3EHRRWj_ZNWc~_&fK+9;a2aO+ z`v=5NT~8p*r(9=6Cmj3a#}J(`vL|r)KYsX=Kl$li1M!1=@X1d%HGlFaKZYY9egbJe z`2i)2{ndK{1$^?;o$$#|cLKbQ$Y(HiFwE^IKg^%}1m-A#Vn6wTsr}?9u=$f8=1+c* z4?g+nUIXz1l%M?kH@>|8H8y|p)4c}b2ic5)Klv^G zr!TR5^4r%Y3NNgIfD9`x_26>jJqvap0>mFL&0D=OKEn{iL_T_+uD%&d&!BxNX*V(~ zFT+g?N;3vt_Y=+hk0OC~q>4gJrwu!In|_EsmB#mW%ikQw^KLgcC>Ij4KY$fX_Cf9G-t42y?Li6|`$hOmfalOJ&1)Y9`2o`f6`8H`v%xb$c-+@`(*M#O{^y58rToQE0Gh?x~ zsqw_*cHQV^C-u5dw3NQmFY+$ZUcyi(yE&yVO!QAjii~c-d6tWC?;(!`+;S_$_tA^+ zSp;@Dh5e};_Dpi~T2!jF@v(ox{^A>=vcuR=)6C%&b{i8`TP4}Lkd#Y~4koYqhjQ9W z;B(*dI)ijEACbKlk2RGYL(zl-&B`|~vm&Fqol0Ddi>ewlbCz6(FAsB08&;cRr)9$r`fK<*Uptf@}a&YZ}Dh45IAyx<+jS{jRmcJB8>MOPaK6l;;^SN)y{ zuUt+6M>BQhquk!c%Xhm8aJ_9^q=o8#kTQhA@v!mM$+pvWw4F}~x&6825P&-vG&qBQ z77s$xnJhNESeL7}BnE4Q1uf)s(~1^=D3G;wdPXYc86h~(-f!30uJ|6;>0#Kq21M68 z^-c*!vuqVr{ou2~FC~CKjhgAW_kv5~Lq=kK;fm9a!p6c+Z@l1tHL3rJ#c<)vTX^Sz z*RLabL_qzz82olFE9`L7fr>qFQDK0LHYvZz9k3uAMiex51x;n*##;O&>1_rh+=Z;{ zaNm{kf`z2ijA`AbG>@jLyjpVNK{tDz-cMRtzM{W)=m?E)wW!Vij(ZBD`!!eExz>cj z<;y?zyDmlVBmbf1Z!)oeJwn)LqN-~H&xJ@}pq-0(t><{#p=cz`G#l4adhRbSCSY!U zOrH~1G5LesBJ`WMFl{_bw_IK8DtCx)t~Od4R0~9$smlr5#=kPUzf0O;XuL|&>c;Qc z^DH!QgoOgl#!nO4;P%EC4x6S2N-KW!6Ajo^N@U$vD4bPg z3|(}}q03m6{mA0oYKhG~L7m3vbv7n|rsu_~tJD^kkXS4uLl z+9bwvmVLi7-*k7EZd~2kcZ=640`~7c%59M&K&l1fJH%f)GDB5n9Va%((KYZ|C?PX$ zvhlBOdpj$T4gp3%TvgKl%ok@KV+e9B6>@)ePlQQca0>7G>A{s#Vl!SR*9ug-rb-q6 zym#8n;%>-qu%3c5%tH+hE~~PfXJ%WO)Tb}RSkMV7B*K%sW5Bx8XALy3YiR%e*U{+F=rrht45Wi{6kU_nD@{XEn;4Sdla2*!%=ZHn%U2A ztYVL#CJE(U1RRJ{LvEs;g1a7MMzK0uuV(|>RO4oyIN@sA;==U zv=?TI*ClQpw@EWUA-U%J*$GK+GRmUuv;b?UhA|XH)gYf^ z^g9{#(vm;!aZAkL7YFEbOq6lOOyC4=zO~DMzm0H;^06+xbn8I+(_nWja+YxmqOLmi z223zSFv>3~14wgK*kGk#<9+zZj&IbO#i7l7798U-ws^LBel_FQe0)i>PQIe(dsC+~ zeE1NMoOc3c2X|z>raloLh#b(kzfnr3zePMSJaPg7hNi4ip8JuCLSxCf*|cHanp6ky zUY>}mn%^ngDyEn{IR2gp5DfXpPP6@MM@wJIfe4u<-sK-2b6=Z49CIorTEtHib29DV zIy~s}vdK(taJSS?%~|GR>Iz*Dd)yra=4qroD)W$5A0UL78gt(wt)N0VSdMRdGSia^ zMITQh-yJ4-Y2d@id}E1bcI6bg<_8N*B0P&FIjQ7UzcW8z6Eu6vG-yK!oJ&$yi53A5 zwst4hA)Mz%0uV|EbbFGcMQh)#c>O%~=5IShz|3JIS#`#81svaFJ@DUzc6m!zbPee; zzOW-0H4zsVMEK+FOzd|XpCLgPxO-=}&aZOC**4A#Fjq&l}JviT%6lkoJvpogw`Rm~cR(P+rTBagb+@IY3 z-O!K8&)U_%jJfni^zjk2n#=AB?afq~ANSSf-6OkPD?OSoQd{?PT=st4m^5H?{g}1V zf%crSeXsB7&>76#x~vq~&AeXhPsvo|o@LpWH>h&_4Mn$qhJgLFFr#w~GdV$LO^U4h-+;mc&u04>dvxw^&V zmVrO&ua~5={YD<9O}1lXa^Eqz3TGmOhP6szBe*Bur^{fmXjyCA@nV0o`%nEs~ae6rz zj&KG?ald(=HK#Gw#vt7=1=MwcP4z?!JpIGnz^<1iDuToOi0Nu(1sc`|o8&+t7-Y+| zsKprOfus6PUSU=%*Fd@=535-?kl5tkyI^sP6!G`de0`-W4q?*5L`GJNNjXGTN#&xC zYS5!A9C>zO0nenCVhNNX+=Av^@3KIfq3EHtDSc&|`k)}YUU?f{dHuM*H8;3uJ`gGs zAdjK{U_GxDZn2)iinw)0f6nxO{(ycSFo$S+ zv(hrdZi#%cDFh%631eQmGF+0jG4;lNnvJg}NPmK`Z~04JIz6J`byvKs2`aVwcMnm! zyd<=AkNHT1f5v6sg!@IKi-NiXd7Nb0J0i=<#sc~2Ij%(f&v(8wUwB_lGG<--S$uoi z)fX*@Ls$H!WaQ9Z|BW4d4teYzjhvpCVL`G>7H-n98{xmn^=0ft!s-fk(`U@`ZhQVm zR`}B^Q7#v%HMOLCh^&o6zY!F_@3{V+0>T=ZKA<)#72$*3T5drz2xJz|=41#j+ymJH zSQ3#kMbUNjy(bU3%dqBXGUjE7`ng1V zuaVyKEXx{XWGspJ@Udh(ol=+Et4OI12bVp_PeE&o5_~=clR}~lC@^>-srmG*JupHr z@0lGuZ9leG|vp0_1uI!HkWu$pJ7Qn~;@&hSpb(_g`_V zOWj>6@KLq~V&%zEP=S4Dw{yf1Pzn!bKW*Rfpj#A)=)l&|7gOER1mX^@;N{5V;4$z{ zjQ7N?FCNoIiy-XnfA0ZaYbaNspg`Fa}hnQL#CI6VaxPY2#Q+PYv-zOHi zz3_=Hav}-HiBYwE8sE3_49W$jrv!=itcf6Zut*<}dseeBHOTsmj8pB1u()ZC>?YMnvc8 z?*0XL$M-=_gpZ>ePZKkP3B5#8hjM@rAyXG!8M?-AyFltHunbkFHsc0|xl8o-pw5^^ zC`Yot(AhGMj)lE|oQ>LDv>bp8kx{3xKJ{HFHIlQ7WjYn-Q4`|EkmrngS;+s0xb(nK zz8c{83zVNnJ~eG=5i3h1;tvsAqe^6S?n0h=@0#o+Y$3e68l_8LJTW|-feJ*Am~!gZ zWI!$RF*z~d?CzPe#ecNH|EYUDO~*w;ioxf@e_^((HuEu%=QPE&bu`;0tb8vlgfN(H ztBgE&!Tc9nVAiO{*gcL@q#X^}v?U`mcvjZIV-rXvtu!;rE^726WAyF?=^>)2?NLU(5kcRp`pDJs(r^Y`g+!o4szs9v?q+&q^h32u=e0+>ZQ?v;yNGUK*l8{_bWf z32(;HDE*pJw+iQpa;=5JHBjd1I%$&~4yePGUMu}ci3Ue0$8yC{!Z;XJcNdd^$VB@) zRtwk}0WUU}M&@?&XextOz6CMR{G&#A-W3(RW>)?Q&c@p~iw`aJN6ViL8FXTO@fGb9 z9WF0YfiLS60${<-fw!YeP&XTYI->YTf1z$BAz@=rJc{20d0o#n{_UWlqA(+{shJsj zhuUP;qmvGAfzL&{v4PTS3@!ANhdomzee1Te7rpWg$d3>&f|;Z<|0cM(1D3VOO|rek zKi~B=hi*!XDncF@s_FgD<6~?jma2?&4G(`p7^1`de(rAQ&U8dWoa_Y**Y+L2UW`wx<8Qy-qJZ#@TEybs?39Jk<9r2pJ;AiG-MW^uZv zNQnOJ+=>Go)z;6rxa_Q~xg4KwCwo$h?sml2vB=aLQBr6Cvq%I>UDMJ&4}8-d*hI$lf&oj)C^6?(32!PHeTN?eZOta zTM0@VzMMxhBK2gKg{J2z=@j|=%2?eryy+@GGwc-mqM-nXqULy4CUMpCTUf;N{pVl5pY{b+^_$SIigI$10_Zq40mrN#HdDxRVmI7SUO`L+-Tnq2c zV9ysKP2N)A;%&ejFGJD*q`w~E%FX{58VB(7DE}RY|=Q2S7U_8z-KbD4RgDc zkyBaILb(w=keKBlN94AnmmgkKY9`W22&QKY9eSep5Q8bGc9hc~!HF-t!_gZU|I3DK zO^E9vC)B{9Z0kE;n(_BT!;$wWS&?EO+KSuhQNsqe=c>ndv(a3*-sBy_@s*A9r>KVD zP_4kr)i>LUfx&2Jwn<5s`2Kf<%ZDJx&Gq*D^SoVLvB~fxEc=#!kz=xlm?Jd62yJ?R z%C)FutAxi;fZ{o3;y%)ciOR>VY#@7Y*&f15@g|bV(H?VJUl#EzeB1*Q?GrE00mY&W z5?Q{yW4$Y4{gS1cVztBfi?oL)lz6WoJ$(m&( z0OBCN_`a7?zWwXGDa~&?DEwix7N37zY*;nEa!xJFf&XA)!QCR6H0$+z{+2KOSGpDH zMqI#l9AJbfyG(T}%foOC2pUe06OSut1n3FN;BXLIS{JFjr8N1ubjE9p3Dn+;pn}!< zR0iAFWvi#{sD_~3yy^DdGo(>5V7k7yJAF+2&ZN3E?wR|Sd^ zG7vJCkmR{sa1%~ieP^fDwkc3A!5))!!j*pg4YS~72K3x>%JKx=8k`!amu7CzQY%%$ zt$3TDHNRaTgq`4DkK<6rxZj>BMqv~`$wG0(@-j?h$}7=onQW*8S}eEe6%x|9QJtu` zEg+H_YtW`}&H#|1N&?r%u3lPj_7l~9ckAm1f$Kf0HNWZ4k^M4$FQqG)4vXiSqs!<| zDh483r!5{Zsn1O$><*Q_G_`hF<4?=3(BzjipkYwJ9RjM0*&Q@fxtui`1>P?GdfTB;a7_0>Qkrai5-t*x{*nYk!A~|R=ll&7!+Cq z;fKh=6!HRz+VPm37(GrMMCET(TN^yOgZq`_A=3O4Gc&%VVm=ZUWAbbJR0)gh-%IhKC-`O=N#^v$@oi9U@YR4f1NU$`^Wj9WdL#>>HMJk~1rG9mwiT%t zi7}1&f1f$c$LaiZ&xjgBi{)+3)_JZ*PluFAth&=H#6@-5D6vr$;O%}7Qcp~umEUJy zac*3lpdos+KL)xrHU$3RSA#%wT2VxN6WJOLX&N((sWVeXHdovvXqm_+m{Ku{7<(dn zRfMf*jCbNK2qop~<_#@5JfA&!-^K}}>Vj@&)D~P0R zdFGCm&hesoi{9Bjgw32WmXJ@hU8IHM2rY((3f$e3b#Q!Tt26ju&A6o+EeA$)0r^Ol zuZ1*O`MIB&%1ats%Xv3X#9Csp-^VWk&-yfrgu#y6S`Gk}#5qy7IQZ5vc+Z^4d-wj zl}_eGTp12f8yz&FFqjv}&Js+}u%Rgs%B`F7a%hi*gZ(avt^}o*mgvOGBwsIYp(kVY zv-}k?-eZMH%v|tFX9_D!+tS;7U>(BEYd0Cs7s6cBwVmB61cw+nHoiH$TK zDY|sWVN18^gWvRwYU5o=rSQ}WjnG@JuufaU)a}Oxf^H)){@=L1rN^jq3yeV3+ZB^V z^aaWDqhO|3+za|>c%U?C(5tf=n10{AY8!EBlv$hk9!d-RI(L1-pP(of7be_UWMNS0 zc$Wp+2_QOTRT3Fa=uB(=>qlLzX`9!VnYY}aJ3O;GUaMgC zd=rPKda~Bn@31PL8LQhWY6G)EHxTN3f1bDUmOxl$O5@m^0U3If@tm}WY3=+uKd{Cx za@-@z9Qwt?#O(Neva7%$%;K5s7fAC4DiLRx5$PMhEs`LuT$^OxiQAS#*z2fdm%wg+ zG|$(zH;?*R^U}HM?XC+nOHuEtNz~vcwDt@g0FNs=>GftS#MU6(2h|dmPSu{ZtQCXG zoRRS^K>JQJ0@OwYR%BL)r7G|D5%G7RS8Vr9?LA178Dx*3kF6G`jN-hL#x@wWVt+D% zz35asnxtJiXoi|(VIq0as$krMZo%uPqna2p^9askR<~Z?T&E{s29&H7NG2%{8pG-KD`TK8&qWj~zg!EtJG# z9^&S@H{IiM%>vdTG}_{Kskqu=dVPmaHl-9L8nO_&GhsYYMu4njlM2D#8r%v93+~vu zfPBJez}8&)vz`${^MY*C+VqO3Gt`{%5SsJW%;Ep{hH}sF2)l!CFn$n~Z!!0ESD&_& z&*qULV)JCN`eoQ23tk}5Dj?ug> zMjzRGn?gO85#|E_+#})3tyzQ!y$WF02e-C*|ME59Is={*tCLKJ{L9wPKJv%VMm)-L zS}QOhXr_7}l&fx^cFvbU}?lD^cR3RvE~arDAFc$6y0)yf%Z zXV$0E8`u`n&!cGf-2j#_Uy?5l9_)m7&*+{*`^)`Je>4A9nT>{5-aLQ9^M&G+q#g`9 zyv2`B^N~$ig3IE3uDSXo>qGlLwmSg0XFocp5(`_qsQLK^hIL(;vPlx1$z5_W&O-dNx8<4f)-3k ztg{Cw%F6Ol5*5Z{QWAq5v%jouN!83!)gsV{`Wdc}slTL#gX7%Gps5`rx=QjRe&vwp zrQCn=-nxGAPE#BiSX@FL1O~fwFlBl55_AE^ADzfxwp6nb^_esMX=Q~`y2L+j{qE_x;T2-x0d%5~T8k81A;Ofu6?YNz5oTy5WFx-2CF7 z53k!i@iemzm@(te2Y)=DWiwzNOQ|;T;|DT{?A$@OkGRe43jlzKE^iz?3BwK7g9W?* zV=k3FZ8G2VGz?OQH{wfvrUH`C6#^r)lf6?@BMlH9$prZw?BSB)89SiUu=BJ zh3nhzaq{z&Jy9~dyf)6^Z<*HS`o610Q51dqyZUUbx?Lr4s#H`JOgx?An=)=rg!nt( zzZqoZ}vN}>2p}RlT(Gn3?)z!gz(=)<&jldp5rNc zR0cs@nskLxRB~yw2@Y4q@#~KL`W@BIsq6(gAy#t^15`p@ zj3f4nX5836OMR$^u6q{pFUQY^A24kpV1mFwwm_ppPa*8BdcJxoa^`3fzV8cu*2>#D ze3d=V&vX4iYP8)uiRCww)T~SDjGcjdK;SV<=%eQf6Rz1#Uql6wNIQYV{NHb?GO94V z&v=(E-zYNp5~t8VX49=9kqpTt5@8S$DYp)LP~i9y*oUFP*Ftk*>yEnTl=#-ao}D2o zvs^m(ZpNx3hI*~AnA-I%ST6e^dv9t*+kTn!B0D5&ZEf?a=A~A$Wz35%qw zEq!41I@b9+A#$_*`YONc?SvNaZ^PQzAKx10MMRI1Xc^c1{oD>z1Fv)YOH6Zvrm;9m zajs^g36tpz%{x;ca?+$24`g6;M6Z42PQ0UivG{A1(n(6@O+`=$KCF0*{f;X10X7xW z7(5%NK$7wnMIB{=_b-u5xn5?btz{^0SN};y>4cD<6}*aq#B@$?=ElHccyIoCwX%3z z^2`+2;jOqB1k-wC2-cw=%8Q9COTRt2g=o~z9Ucp$B%#HuVAfC&L^*69b(ELA@fp#+ z<^)EqU{Tkci@?8JQvjR6Igu$qYZiQe5yo*q&xH)Mf!EJWacU}QQf61Unq~D1^*5A0 z+wmvD?{+=34>pM=X|3u0lT#~FBxCqAd?+{6G}LI;ygzQ?&S*18lF3=~I}hGi#UB}8 zeOo3IqjJ}xyPk1{Y1qF`eJHF?jgXbsk;c95a1yrHB7BvtV+vw(=Z8%>j~_gShnUK{t1F9Si9md?ZCtS=DUE<3xhI^^4Rbg*cQRwj)@0t+&0 zW{fz&0l1qxh z4m>4vUhoUW36CoaiByAt{UR&!dS?V{d}sVSlxYg+NW&+@D5<`DMWZvsX&(>@6I!A! z#v?1X(@OZymb4H4?(o2&sa0;6ILSh$AJQz$-0l}b&j^MdV=yI21h$b)7UptD=F-f) z6^%2BkPT+aHVbvhY|{`5-54b4@s9{0EF~ZbSHraI9+sWK|!Gt8s2MMDKQNJ0nu>^ z41^Is$SsqVLh8?4+xX4u1ciSDhZK8a6KayIlS3wEtY%uQ6&}D?YyADyT5LopcisYF zBc9}BKMA$qm@rpJIA2Iy`i*BHXjYX`sBiV=dH&m;J3R`~wW{&dLnNHKPZ_A4J2;Hi*_s9tk}zurTD zvkJ%KD$3IP94`dK`9)r>!WMe2HVpzokW>^sXsc7>mEaeJRdCk%`xzXZ6-C^Sr#gHj zKGtq-`lTsIiutu?ePI)&3y?+Ev1>dz(q0z(B0>DDs?L}o)QAVLQ?xUBtoAg>2ZB)ARu(bLe<25(P-o8-<`{T!Q^**3-=x5`uB zt(?N0(hWHs@UoT&4S5!O!~#Q5@nBd3;&^=Q_NB~Rgq^Rd_=oB^zGZcn^WE@x-JQO+ z(HS$G6N#NaPLE&6$+b$hjjH*+K)MJGwM5g6TSxwLIjK6K`C44XFQ^qn^(Qp5Bf2b{ z+xz>sSFN7{{e^9XQ5fWo0gJ) zDHCe_vq2>?v}4hjXqGVwS`0(vbp0AyZEi5rnq0F!d6eIJHj&BzH#OKqY7Kk?v`w3mT zi3(MC&He3V_--ZyeIS?yl}O;>_yx9J566%M)(|ql2;<}cvI0);do0^a4xo;;z+C3$?+UvPJ{0%^{c*rH*#=!>VnQ|ugUIF zv=!gZ$Ph<2Tf^}D9a`J}#C~|*C%tS^Y1(rI7}YP|9!n0J84f?HB7qR>ZHDzRAh!LM zEHG`&4QF)BFbSg;l~#BKz(n*U;Vx7BSXO=G%Mx*c^$({pqqw^8}cWeyZEp|xOl#Zq^g8G(jlfd8r+S;Aa zcVMw)267Nin&CQstkr%e>e6CvCf8{-0&V{C6zuo}L6>j95M zb8{^E6*JV?Y^5z{K>lrTtqo&3gWwNatAefDW5(4^m8ecYIG{a)x|8all09lw3sC8} zCgAD&FsXkZJN^Ewa=EcH`JK8kFFedPi>a$nZcHv$D_HEEJXG@F8rm@LI9&!pa{7hL zgFuQaFcfCc*tTrFAfDfpOSJNyjvypnd619$w!L+2?G)+F zSZT6vCIDUfs{#&`%AtoBa#JfjzF+VRO89Yvwp|qP1kPMTX_OI$V;*J?cZ#P8b$_2B zY)Bh;XbF~hS&hAdhmzy$wy$G2TZ_f_s$h+R&%_Xhu1-M#soMK1Z)r|W9$<=v_@g&anzA_AU?X$C3 z1=pAfR`VwQpe>v%j`>c+ue*gQ(B!=n*i;Uu`5#!mU|WHM-0nA*ep$pFbo<=-vI)mBYXUUD1IZm z=tl(hH15FAG)0@1Z%`N(FS_3T>!jTkzv&F<%wV zEDj;p&0O*6K-;Bl!-QAF8Jsc#zLxeUz)kC&iAH(#;o=XVVgwo@Zf&bq1hSMR{2CSh z3QUgqMGpn6g(Qb|w#F7kt!BG=Bg1@Fz?BtaM4zFEsn37$0GU}H(wEE`vLTi2q zvuPhI06Bu}I?NkOKxh2U6FtL1n4G8{gBY83_mcZ=dAumS<;2wP6!>#sBWsDlO7{nW zN&;6qM{*+KZ|xyb#p}@;EH5LD$s0G=SB&Ay!g^ZnifJ-)-n6CIy!iU|Chqhb zw8HehySRXuI0&3{QdT&HojREIHS9W6&PcqxnWOv<7srbf8{1ALuSRO$*wD_zSdWfdM6$~=j{D7nR;wfPIVh}pyIB7IjOddd__XIzy40RIf({U%_V zkWND7>B73Fy>g~9KxfTw3el&;s#+<@5*9h^YIc5N+sZj<&+8hg6PX%l77xcBxFg^b z)^V3P&}EyxAw!sfU6~f^4B>-WRK}6=a^Y$}GO$YZrrZCr^ru}D(gm`kOU;@3#$sX} z#tY)_dg?8XE+>vkxnfkaDYhw^$5O`Cyz-q|w|O?-<*Cu$q&{GCC4Pz|=Q>yeMT-yc z{aZ`-95UlDXn8s~A3z(!QAfH4?I&eAmgDmC5d2>d^?Yk9pKY$Sq0@v0?XGtf?(ue; z<&SzepNeUuWb4ZdBnL4nAOQC!fLb^#*%@mh@;)<2sGp!0^tv)*e2VyQ3y14q(Fn%6 zqxgc@YCAvKifU_H2HPQ)G;r`?oYiYQtb%q>s1@Zs2Qh6=OXe${8)x?O0in%H&6 ztT@DX%^DmiEeRzeuqF?{og7yd(rt5qSM1+O-4x?5girdC+QXbhnpmNCL`QeC1~nWb zR;!1jBo4D|6GEJ}`%#xqd9f)%4U4Mg$2d2|5EM2ephkkCWN z3)Yw=zp4S6PyvSS`)(I6`5r@v>+nGrlArrDhyv_Lo(JDtc5-O>Raw zDHG7b*cR|Fw1(1~yH_LV*S(yMc83(C{vemc=Qt+B=bb4uXyvTF*jb4yd%~B@6E#<& zwKn4LEEWs;*E^E@i7?ck`2@}9uo~g{m0ipU zP04q+7|&$tBAjy@R88oQD;c~W>0|D|r#1I=H12`|F zu^5Z!%*4F3S`R2adCvC55w7ClBtINmKZm6FV$C5%C3_QtuhqL59pyu!4i@5 z=^MtjSe6{noV3$Ba;zHN=W3-<1vywsgLZ&>dG}%EZ?A(@;1xu! zbohABV?(i;&-9H)8V5)Sn?VE=xG~t@*V4q#6rz_>2?_9k7$#ZT0)psamK?h@dNAFS zVKe=E1^F7!C|6nBrQrath$3cUB>pDAPfs%Q>#tT5V56Pc*IJmScCTp~N{G3Eoojrw z-^{FY`i1-2$`ilavR=dRXns_JMX+%nK+D=Fqap}$W_BGBh%hlkJZX{-?jd;3C8 z)u!3~7x57jqM}uB?%hlp|J|Y8FF8KRBp#9WAW8Y!Nchnd}nF3aju z@vPFR-(ct3zcJ(;cTON_zC3b<<3Vb!k}RSA-WC7o-&qx}asPlsRqkT2N!FZbtdO+y1aw%W&K5ko9g|oZ2p%b{$;?QQM0{q z$<_%jo>%l~kz8K7$7JvelCEIo?ToIl`MldR62_aY7$V7-%^2`*|I?7B7pboTJ4H)q z%7uHuG*GJba0}}}V@(=C5vcZK(1t$75@xQ)QNShf)cXhNbcu#HawK)bw*(Zf=T$>1 z2&5=DCDC{)nNS+tD;>(7ELQDX&flE@PUIi;&zR^+Hn`y?S^&kcZjLS914IzK{d3a)sF#<`r`dZOLe>AV9DPv_nh)wE%wW!|Ewks!4S zv#Xucp!C%`ODESw>OB;E$_t+}B0Cj~3HB8--1cX_Z>v^Rj1vv3vmYy)@!f}D)Gy@= zAO@jk1#|6tQLcvIZ;zc$5sX8y8VF;KA&QS9Wl*#I98(7zJECs;4Ju8@8{yhM8W{R@ z-4Ib!tNoHSBqtGHXOC-|yHH&j2GwhY>d;KE94YO96?~D*co$p>%Z0mYdg{+L&Nj;O>{oVAxI_Ym=JAE4hYbWv{E|~>V z-RYXb%4dZBwgbc3>|WfZfAeq$Rg*%hdSVjQ8vmZ2|6MhvD%Q(;Z=8rAI`V;x+})KG z>p%6C-jP*ezmC;!(g-^XYGT zfw@iByy|Zpm3^ntJ6Y{9_LW7KOaJzZN9g&RuD@AYswRqWOG`v(m8+ZgFFecd#z!5o zeF49%-UF$TvM#o73idBEvMj<&YGuWTVO>bk|74ss9c{0gvilK%v-IJe@D3Uc7n{zU zFJxOUj~#nYo&776B7uv!pH>pboXJWgvursdWlQN{C&8JO6=Y9j8N7VpSeOc7M_ zLniO1eSillBA-OgW3`|&>nHvA$nfx}i^EPw?Nd{2v7zRx%A*-_@8G9goTxQ0CY5-E z#$NQwNQaxRbTYr#OZ(yRB@oMY8X2!v`PC;rn%sw zjmkPjXP|k2LhjU-4(4k82-*I~B`#$xwV+ljYkz9C>T3qCNeInXqH4n~4oZQ9vgDX$ znDl|zqcJHf^La(bBPr45Dd?-PT(tSK6b)yALcm{s0T;64Ok48QrBfB^;yOmz`WO`4 z!IeX+QJi#XR+msg!G*G8LxG~7@7RZbErK0fFs}hMJ;T5Dzw*Afym1OhBqV%!!M~nx z-yKnC>2-VVKOfNVB1}yj-PdDMgFQcZ2b#eA)6_;n!=^n4Q1aSEDY-7B65j!r$t@AO zP={JeMcu*6)dMFEC_}nBfJG6N(KihS+fiR;jTVx@0C64EPu({0b_4;`4McwVSFFo9Ns@sL9=?~K2YmAWs(B(HQ$T`ENsyP<*~|fR@%%Uei0O4QN&%>5LZAdW>XYPFOZE0kHM~ zk2qI^leHK+@Y!8CHn4WIzI*Je)<>2OwJ=&ul|*ifx^xK9!K@PumGUZYh?2N-pwEu8 zC@mf{T#7J`ysKNOlOdhs5vTq&kHS2V$j}u}7 zZS$ZN9~a}~M6+?Oi|$SgglMxfkq=&O(LwCh3S%9>i1*}8^vh%R*4XG7Ht}P~)JqT5 zYXp=JCYQR$x>@CVrTSIl3j2lo`n!JVN$j!LSx{3jNew0CMO#(i&`B>wv1??5S&J#F z@x>OYNL$ZAzM@Y)lCE3qF*JCOV`G&sKmUoz7(BkxgQtALQ@6R6-&nEUx0=8Irv4u$o0mu!KtcHUo zw;GAtGwDR}tmHYPKPTaeZbl{|rD28HbfQnBaAeb$1%FX~gg2mtn*8%tBuZy~mE@nR z<{Q#6GSS0#Q>E56uRpkMy$Prq#ex>qh>T!+Rg?VyW*;+ZHJ4broXS&gOxu~zA zHKY!S;&D1^N{12Ej+v5%wD9>NGu$g$QY#u`9$D$z{N#QDDpETf?O!HLxR3BQVoLv* z?qkeZI4WmP54}}^DCBCl1az=Qa4&4=S zDDUOs&+^&|>M%P$Gwnc6V#rdK_Z9X7RKwG!>CdoA(1^22X1|akz%HI}Dr6&>6JPhy zphz)^EI!ApyBUxZ_P$eJ9kQh=tjXAki|ho$*2B^z=#FS@_re^P4XSk2z(hN4xQ{N` zx!_^@sxErQ-E<`6MD#n$vWOaCf>**$rw84D_19r`nDfEN0+YTxka29wAivl5BWZ@p zPkPGeuBaw((a8UXEfjSjgH~a=pY9WCq-rWGjyIW`8xTJREkzUZxO^YP)JNzp0M!Op z?5z~uu#u**pZUu$4xI~2V`(A)zAWx=P`Zd$Vb3h0r;cYR;Gb5$omAEp@C;}~)0WYk z=F1sS!*(r=(r#L!~K zN}RcPUxA&?o2D>+)9U$pW-5Uwi;MXxuw4@&zRLtko2iZ#;=t#bTTfnMbtnL0EXT21 znGsWYu#G9XAs_PK2+rkX*Mip_hua#y)=u^C2<@JvxqFxY(SZ`as4?h!7*5^3!V=}v zFERJlCj4cLw{MuqKpQwy{GDaPlgvDS#diO5ViZ>MbujquZ!wz6*AH?;jm=G@9SN%A zXrujc-R0dV0YF+wqQDih4ElaO!x%jL=EnlNm32WMr!k#~(9}6Z2d_n}czdxO>P$5F zmG@>O%x^Fj_pp3<9>4J!uq*uf~1HdxT_v98)73XvZlGcEPs7 z6^-k^CtRD_mjYxGPQ;IBhU=B8wVnGHg=(p6hsh};^8{wm#CC^>`$O}eV3P>EhqHS0 zuuKa$va7Z28}QAu?7<_jrj6map%V44ubJJxG`s7&(y4R>c(+0i2%&wiM$5|y+s#`_ z8J6zl$VqOirsSslK%oLt;PcJes#hV}M$J|5kw)Qj+$0go7DN#z2<|FAQV>e#-iDOd(5P0ReqPTk zwW@~t5I!TsYC$+%l;(FCuixcUHGg3VCor0ge2;x;gee!2?B}sWt zX3mJRPMwF1=JFBR-0b7Ox|`{#@I_7W0eip19`E&8X(Amz z;t#opM2%|R*tP$cjoHLW|V4Nx%D5%*3|DzIuF{VYaXf<^nuEsDCVPI&bJL7?aB$=0xb4sAi!MHh>KS@>?>iWfvk?6ZOCL#>c9Ms&$A5Q@b!vCUev1x?=e zE!UJISG0&E6oj?li=k$$xW+6LPhBUg1ZHIh{s{58D(n)EPzdf${JDowa);O}=d<12 z9X!Cu?$}vSko2)>qpHYk7QzE6nGHk($P9x(Ou%}^UtUrlK|&e-T!NDiELt5ncN7Po zoF(b4R?P+!)ne{YKi1^5!y=P7iIBTBVZELkuk`NjGIc@v@gvM83dBdg8U%EHuE)LUV&Rs8}`|R8cC3pn@15rT2x*iA;*z zI{k=7MN&tx=jt}!cj1$*WMzYn0@BN8bkdQMHFQ6q;|78*xehx2+G3GsR=RTqPfUUCTR-kBWsD3 zcopewNJa;2f+VbFg9gx|Xp!eQj+D(Ym57<_lRXnp;>l_yvLhwuJlP|inZJU~KY;(j zyGvD}3Mh296en-yoi7usfkN%ety{P5{ak`BNl{l>eGz_8d-+T!-wk|O1@i;=kyD}z zV7^S#T++fc8}}ZaA!YppAxiZKUWY+c1ad-z$_RL_K^H^_WRde3v%r6B;I&!(au07B zP&_Lt7EM4!*S&6@55fn_;^w?>OJ7^iXN;@CT+Nt;QO z$!9)sv0Dc;3bg}<%qtz=#a7tFjY9M!>Aney(7cSQ;^_0~(cY3!t@UUMH!l+dX;Fm4 z3L~(;C}=|vsZ8Qv!bXA_pv*S&lKD zjRT@o>@838P7^Ns3VBimZExq=d8LnH>k9RLYi)+jIawrc?Q$9%J^C>32K1&W5zCN# z2WZML&d6jHLi3%Y5c+JmtfCn2;u4d)05Jg68B{7M@%LywoXvvu4WD~dzHV>BNe7h} zHeDeu%GW-^J(T4ysBoeX#hT)?SMG7_DjSEy;R6^QjxZao_o$gDjWZdBqS15cm#4-| z)jZe?(IRh5d{(89v#A1G0;JC5O75rNa=Qi$~N-xJS6~7?LF&k!m^2f~bQ}G#F3AS)3BB zL%4_n<%TcFhZpgI)GEc-i&40VzYY|WIJ_Y)%W{*G;`stch94Osylbf^u2?66O1zLi zQgQLh3hZz%*??7omcQVOO6T0dm5xP#yq6%NM+*aLVu zDv2eIK#o<#{^aZ=689h$Qlp*+C)0 zAekK$LI)Yui##b>fk$Rnt^T?T^qOv#)geqrLhbs#U|ouccwKU}z#ANJ@A4o9C(}fU z&#V_Ko=AgN0Xrq_Tf>)})TEPlVp82ygztE9w=7DlitbHgf|Zpj11r)AFOyshQC%Zh z0;9hW|E+ND=gXxeKj*gc9vXKhoN?__Q|r7$9gaNJi%j3FS9rpaO@vaLu+AhG%0<{C z^rK_Lqoe~m>IN%NhFpu8TxXybv%K*mc7vzEoWSI(yz(-1@u9ynO&jR~Uhebt?Dlce z%Gy5OiMkgiBku%!5{fejgW77&f5uqFshQ!}$P_>v`nTW#HNB=A|uGW4hQtu3g~09HQDYs)DAXG67~K6+L>oqQ{uBCFz-J zQCLH@#dW+Miv`o94MWZvkSGSzGb^}Bn4LHuLQc;n9g=!><0mK;<|{vNhTi2a+N(4% z4gx)F_X^a4g7LbnQ*SO|iMbw)GJAY7B%cW=4OSv7O@HjEP;PI^j~&_&w={r5H0JeU z6xXq9orFEb&BUlo3zL0JM>!`30F_v2Ic|~lBhRWZ5kx)%Mk8Nimh?Ee7qS?dfU zxJACo82lHA)fPDnEBOudV{{sbQ#6rkfnM&c0%m-#%3sCNqf(;7XX|>aCpSsd!4Mvk zMP97q??{bPdM9DKu1X5Y^jGSSjIf03EY*#-x2YK(skP}1jEfC}t%X_^5E3?BDba4z zR>M1WTy&B)FBJVjjV*5sXqriE$T^XkcqL!T+7(jqPKTy;et!T=ubSPY{?M%pobm4b zi@D7-1(vXsOZ8LfSg16e~&Of8s(7XDpWWUPH@iKX- zu|ni3&P%hV92l`~@v1E1SnNlOX8Wi}fyr6@TW<32+q#Z+TROZ=Aq%h&k)AGli#}i6!e$tflL~d0ydc44&!v!04dv8sIHUV2)2&T83+^&W%rB5B*+RCkkSr{87Zz3)9q&k?GoA4>(3j)e zuG?yUW_$iK3-Gr{D)tMg^z~3(M8N)Cbu=WnM?)*0@1K*Goppl$q6UbHvmcx%h#e=b z@Gf?&ys;+EmvF8TP8?6Fn2`=$V9un`D~`NiQ|h=oQR|b7?@x49e?QI`L*RC9peD zax>^A*)o{ z$xgK4JHi144ku0v)8Nvc1Pv+)+=7GzG!$k&q%~zro1@WO^e#ipS(;Jj!cJ5H6pz+k z3BqXWbfh9)EaFK|q!rP+$dhn^PpBzU5f?FJX=Za>t7;hKSc`@Jyjpq zLb>{L@docE)~^f$q9PD?&&&HU&a<$%(HD7u#w$B66RKAbTIBg~=|Y64B2UDxI0ymh zEPBscMwy0;JH~s##9(+X)ckni5a9lt&ZB1M3nBdIpo}51EYF5;JfcrFhKn2->&TVk zVQ!(*^H+ z>yzG#&@eR#H3E7uN~5Ky6T$J*S&NpJ!>;4WO-Ia*9q$=P3|l8~(z6>u8#fVjxV{3! z=6M>Art`?ul%w_Ar%Zmxmw+BQ`f$=BiVK{83x~V;V~Y(J*rBOJp!h{Jq-9$(eL|UCg~Zl0_1{{t`;NZnmf>2EnP$|K$Cur_GT8(i+ zM><%v*Y)VpXnPwz+4d>7&Ib6jv%vJH?0n+w$25)vS#~GtcA^U0 zA8sajGC%@NsyOGuc9y!iRNIaGk^2j=a`+~njv$1}LgsKrop21tSIKHL(5lFf}Y?Z!}3r6V_^T0HGa1}e@VZkJ=EO+d%YbAnW!iPR7APP+kn%fgOm%we`Rhv5={zN>fv=tL(kGL6Q$EkG zB~kYRz2&qMb*YnR`2=iA^7$m?YQCNBE}H?f2qPqe&T%2)QHu+2Dk4sr$5f$lUQgyI z=wV|mV1+KAtMMj1y>gZuCgM{Zue0{D*a^|*lQvF^!V7DzJY2Z6`dHyza7r356)edY z_`s~4o;&LFjAjNTi+C<1*q?wWFUp@3gPon?c+A|@eu#$IIMzDh3>$VUAA}4DRYUc5$C_RG|2!S42Fj!Mf z#M0H|mGcfWyTE2LKVmqA>!DmxwWYV{mnf7cU}B{+*H4NrD#N--%sD${r%#XKh{KG{ zqd*L*R*Ux59**8we0tFU&lJO>;-K7q5cW53%&`v}nsGkEoh;`tvD?+r9l^ii``NK0 z+@ZUzPm4OiT!Nlg_{0Grd%9`Ex3VC;@`m2iSP*@vVN~i3QHtEUxP0PKNC2m^vDg5{ ztkc<5vL;|DC5$pEt;uHfAdgR>s#NBs@(xwb2u(=hpAX%fJ;+bSo@F}|oQBp4-r4fp z^4VgY5_ke_&^)-Dr)f^@SmwmwOm^yGQ`fXmSq9}eo)kO5qd2(==29z%_<3!KMB_0m z625x2->w6f&+rRne~oBMAZ&tb2y+CdvI42s+3TRJEWUh#zm(488mmC+YH05kNTt)rVb(OeLyWO z_T)Iue0v3lZ)ubQxor4dsmPhaVEPeKe}2xfg;-u&1JYQp?ILDQPt1C!>sL<-5QYw z^x(qu4wzW(F)J!OHpl38QTExq)|ZR&&bgTIq0pQ1rtRN^@&xB9@2sJJUD>ORy!Y!5 zW#jpqnO~ZP8{)oF56ZO(*#cJPFa4yW6+Eo4R#$U2`jCZ>Lh@LW9; z|FY7#FYLz>nOp+*5X*`c)pQ)BCt?hq4|$v<#*m228-e)NGNYo82C?M03pgCL=VeT#?k@PfxI{4qap=2zs4nC*&dZOoH%%72$50)tiPlq*T^m+7ojSi}Q5)Uy<>&NXma_wuezT;OKKh%={M=wJ&!&@^SlXzycbS>zX2{pX8H@5} z64;yV5^74>{-v(ML4fNbbk+@jxo_vDT_kAV$LnC2~yiDy*PK z1FbUx(H$!|p@de6h9<5fj!&@rRK4#db_T7A9XvjpSEYeGTTIU=o6(D0UqzDJ)wcFp#15En@#3{B)sElces1fq6(%AhcTOgjStSs3VmGj&xmm79kkF` zL?6l1a0~|0=SJw~xfp5Mn}SGb5lp?ah_)f9pX{d!(wwd2V+3^HNDXh?cy!swv@keG zUKU!Kr-^`|aDz!nv&4+-pxu_VBoyc3C`?gzSp+`C`&|xGN;dNbACj>=%U?R#wmkHA5uT8vq` zO)=kVPmyD|#uy_)YC}>pGTR z&yzF*#lFps$4)5pCZjvN&d%(F+FEm?A2_OCmb*mrGHesgdD{x+b4tF<*@Rz`#Sr?R zc`7fLIC!*17k507eStC%6o+sd!P`?4t+6E3mZJG`&kc)Y8dcF@*6F((Of~bBaEi&maTw0i>j~a5aQ-_97D1xyC>cz(!#Xxf%^5@sovzI@LMXH70# z&3yv6ZHrG0O4ov|rs;MVADf(P7Tt5ep6l6?dz=W3%UtaauMGpjZwc_mRA@N7!ye617>hmOB{Osf#}7kjo171*)y`ZKD*V4b{rinKeR!u6h;n$-CHB zS_8J(ti{XIlLccwUiz15{mYB`mt%`NrO3ggQI>FM}#lJ-FTwCV5R!l-lIVS2B& zaDgGX51CTi@wMNzYvUzvQh2X$*fWVf%_pKEF)c$rl{; zsJKVeU9L;v>WY9#)MpeXtx*)DpId$ zz6k>%)a0%e-@Tw-JoiMC8~2Jp79pG?S8B>qcP2Ik34$dpLoY|_{|cxkR!XL+VDXSLjd8gvaBVkgmZ(l=)&huB`E*(IllYFFx(mjXQ6_MS9F9ddxu@ zH{Tk8Sm~mZXYpI*c3jAzVc0C*i6XmNKd)*@y*lWWiF%T~ziM}qX$R_eD&FiiA(G&8 zJqmnwgMz63B502NCSkB>X5B-2d$yY^8gU*w6#i5%(>_p6{6S=te-qj5>=ZhxYeODOXx5et~C^p%Y-D5Fru;M zzo%{UK1_#rv-#1fDHx?RYaW9KCE$N#YD#RiumFG=R(T~}eut0{*FXUDIeURO$+^2m zPowamXA=Y%l60H~Gg+znCt2Y~#_FVdQ;aC8JE>1%=C=JD`?zPVGCHlNZJgv>-=%cuq#}^U~-- zWh3*J>ADjE-_i5(V`SAnW3WdUKJYevmXcOpcY8T>&3*VF%@b9*04~+b)C9Yr;Z{~dByJv4)@ipf{JIV1Z_CF4T@P{~2PFeUJ#`2^v!%YaP0i)@sx zVfEdISZc&+F-EeB_)bQfx-6wsAcy6d!wzFbohKJI$0yt?632@k{mU+VXu<>{msU(OMSPFY-bonTu8I3v8ryBAY}*pRWLqFvqw~U5 z5i!`tFBqh`gVRjS+)#Ibuviz?sx?QuCB3MdrkRUcD4giN1v^1X5c7_vR=uw0U|wj1 z^;X!lS;LzZGo4Xx7*NtyV#@dbgNdn$NIis@YWAA*oc)>T65VNqi$$VZs^5bV)mjCO z#LY%l0Hv z!(jQTZf6T^(t=Bm(*nV63OgNPUM1e17Rn8fB;JHiT?~&q;;EO0PXy>Zdj%Cc9u+#P z(%jy8I$_ z4Z>jZy1CvwB#S5sL0Otb4j}|?2Rg!YX3GhZnNlCpK=XFVh08#C68L9SjGZ>n})g}}H`zz0O&iV6d zQ#gO#@e&D}ZSXtQ1D^&x@`;yu4js41E{d|^ z(^p2bq?xq}b+A=nQ0c4X(p?0k7A`GB*)~2LLB6;$h^Z?nV;(J#SBhGt^)B;dR$J4?KXL*z!!3;hPZhau*0bz zkkFt>PKJV3JU-o2f^ar}h>uUTdQJF5nxQ?Z*yQrjR(bG2UNRxK$w!Zlb(KdTRGjVV zteX4)6y$`fe?ikwb{>r=unfjH3rmVufR}5$%?ROTrjSn4vb~h1duDVDu80evTqL>{ zDbt*w(WtwmMjB{M^9`TG`D7Fs)AT|cXHrz?qH{m}3|trt$PD2+b__OE$lr3IUx9rz z*56`TWI!EOvS3jMSqThkwgd4dxOY)yJQp+4slY6e0DdaTND1LuOzf5ucVWp0SF3e8 zeF*%2A3jM}0I*_D5?x*rM|tsqezv8D0Q47t%G#S|MQpAqX4J|Q=$zi=vNIlwxn%BZ z(VvH2IE~)Ix1={c0iZ1qx0|82rhQWY?i3++ah5wtge8VY;MiaB1D`OcPJ4JB*0;2e z72d~|!~t-5yyV3cry30Ba?adMkYdWR@2>gFTETeTjOqxeWx|dcQ71x6*JOqp$7+1p z141~!z0$H*R!o2+DHNid3;RjySo2{|>jhu)`U&B=2RL7g)OtW~k1Riu4uiz~hbNsj zuvY^1OM~090#lq17n=q#@JO+w>{qD>of68A!I{3C`VtHa6UroVG~sjrWZm4bG$&um_s!- z&gyxX0x`UwtnWm+>%WcpNO=4Ut6T`K__1`|Fnv5~rOmeTI>c ziX~(`DIIh~*TyKXML6W6M`N@ZRbP%CeU3GS)eJC_C?84E3supDPOcfvty#vA4lRCp z@IJ1slvIRs!#qF~3LVZjaj0X5u)^EhP-S2Z(Y2_)D`gcN44DIMk+U z1kgvQ#kK7winXCE@_SvK(&ieA6PN2CR#YJC8W6Ur@?w|@zdUv!V6LI7Q4yfKmjw+q z+$c@$pf^#|*LK3_npwSse{7@Z!!C);ys@He8CX{yV;(EHRX4SV@en|e*h+hSQ!W zT*zGJpPcB#Z8i@%iH_FM5w>Pk<(b82|~h-@wCJ+*E!n-CJh!kG^JTXYp)g`9=n=*2-`W*Ksnx#mnsWg z*q9L=EMr5wS?sU*g+*ZBF3{P#wa}eh^-c(WFYPU@N13?P*^btO)o>dK3~b*kuqDwg z&yxeMgD!+yt6{gUU;VsRI*hSA{&z?JrfO2p$B>$P?j_-_HzA)$1#Y1oxNDC4{ zJ{HS+amUufNF82!xfdp|QQ{oV`44yz2{IxAzUyN-i zoNnlTvvIm%oGz>~5gu77p&*{>)+KeZkd({VkY>iiFWkW@fy{->a~2XLFDQDpMD5z6 zGR(82@TY*7{KK&+pg=Ff)BiW|5YVN^;mMtE9bK%S_vb%zbn&4{?=hk|6A!iE@K#&M z79VowKZ7|gJ_ICbb=`YP(400tI4m(k7VT7DMs9HtY?ZH)blea@QEyM zeMj!33NsV|AX&eYXht?KJh)qVHJ3}MQV#AC^b=ZAwR){FH-XckknAPICH|hza7KLh+Q+0+sY(H4v+l5 zz-y3hb=$(HG;$#1?GUl+VZIXoHhHPBxw+YZu3T?Gm3d!Vo~fa$O$3v9cJ55$V~&S> zBU&Ys>EPLny`eC>wSgO!!=4m41Rovm622QHt#`bd;?TU8QbPRHB4CJ!@ltRx5MFI| zWZj{3%yV*K34RuqCb>v>#otNJ58m(>zTypM3R^RE> zmklEc$6PCT!frl_QgS_%9NAz%?kfst=s6VhLf~8ybfMKrhJjCr zz(TP$>6W0Y(tsfIGg_Uvj7e4q=e=cE&THN(QMIjnS@$-CWyM7l6>_t;x3|3Y{1vjl zsG)>h6wDHAknTl92V(K%B?E=PTY}ev*)U_NB?#}?~5=#43~MBOnsjEp&qOfY>OUSVTXPINkEYi!Wj zYpso@(n>kU$Q`A&Yx9wdWDj|1v2u%+AmD$!0QW6%KfL3iXu}|^p2?samzHx1gb9Ris3#y?CXGEM4kjEG{q#{ct6B0g-Od_`S{4050Gop7 zGMB(k8`UMqP?mu%S41cBkE+KhsK>ZNysxMsv&$<|3)9m^L913S8S>5H!lG8jefPBJ zfR%a+4zo?C<(o5dYSExd&>hJCBRu*R88*RjgRVfUfU;ye z91$5=1(mYS6nza1BHNGw9Et+3qe)t6SIyRvc(WGHblk=?@|!!fq0*c4WL#5Brhbs` zRNglG*~}Uo;mB-p8BxUylcQzqE^+^|;iLEvm^Qt$rjCcLN1AxZKQ=XWoE*j-e|TzY zd;8(3NATi{OdQf`)qTPU4&{VT$yt(`hk~<%nFd)Qrfa>Yu96ibMM40rq2f|-#g+KT z!V;^~G)i)R(J3-4I7yElC6~}dqmnv00+Q$Ns6Mj<4ZnbUAJzpSM(QzDi&&c6_c=rQ zj`i3>_e6fQnI|1bLZ@Adgmf*aok{0~J5x(IF~noNqem0G zmBlKap#vKqx3mB>c~?y!)rHv8ipOGkhQ>G@l&qbpD&*fID+8JmFv^|z9!-K60lI*Q z(xc|NyhFN8sUK-jw&;hDtrN5ihJa* zpiOFu9ANRVuZ1x9NM}+Y@|ho?;wvLh(Nz(?=Tu2ZO;b9=85cbs{WJr-lK|4hLx@tB z+6r*wxD=o%S&V(Kv$JF7Bj~r|Vb?da9h~hc%=f77MJ>0$7QmJ;XIu4;!;+;_pQ80qaitZx+S#n^D(LF$qx$7p^juhp)v+!e@WJldMHm7vQ<5H* zU%1NKOo9z`D_ZV8O@Ki=x67zFsMwaPSR*@wvbBI7$mr^h+6FkQpkj<`r%P*z&RmjI zD|ZKUa^i(29)B#$HpJml_lZn0@bj5}d5UlxrjH$a7#<$k@m|S_cUw>h`iO(6lBE9F z*ehtRvI$*!G6|udvMA`Js0aK?=3S(OK4gK>L}k^nDjy-C*MT-%=$4vt-rmNH$09>~ zCm9>V`MRMu5sB*Isf66_x)BQ!BNFRHe9Xi*SnG7z9Kj??)6FpH4?Qw(uBt&THa-gL!6co6tImuprU`*l?=7>j0S=V`mr?6DH1c z3ef=izut1-U&n%pA;kN1YZLypw>Ej1;%>#kUx&7Pyo2FZ&}bT}JPL10R9|*0@Tr9m zwD~atTx5BT5HDzQCBn1@zu%sD(6E`Zi#$ZarpBB7ofWzgXEAD(p_jQBtt%q*0_ZY2eC$WLGYm!Da!Z%#HjfSvdrbm96=#Py#w|tV07M{}KZMXI@Mr z8!HEUv%nkV#CUdMJxo?1?jrKP`EjhyB$Q~65El@~G>Aaa$q_F>G>`;&3T;duX9skM zBP68fc<{z^I=@YM_)hB8t|2^XW)=+JjD5g9{nRXMo8Hv%Aa7q;@Pg2!1=$NLo(YL; zy?~S)8mrI?CNQ>}v~bH@jxK&eLD0F{48#E;n`B&txO2&+3j=5Fy+P@K+|_X*fu?9; ze&U@obQH0p&d9~nt-w^&M#qr)0gZGO;HT{*?@Px?JMw6YMer$@tX!U=$7*mQbx)G} zcoyyw9Wn%TN#)@34tgSm8Q;b&qLaHCRL&KBCkZ1fPfBP~y>;jh%E%1aqkJ;*yiN2qQqQW}%6GED zL!ep@r4I10yZH0dB$UImfHd?H+k=#sk^~p+qj4YJ-sa~*Ttc8wi`BBONyMrFP2r6> zyOSw-JV1O#lo86>)A}lTZl8-cl+SjQ#?UAgBcZpoJeIsMq3-5I6w$w`kJ;xIWX-wK zfQW^}B^0BQ*HN}Qgj2ZIpZ8^^q74?O&bxkuUNsU*nf3N|67HC2z{>v|URJ8P?0Cvw z9fynAuUkZB(v~asjVQ=fGQzO|Q#g_nP|{FDXg*-`n;$RE0p$I)HCng0wFYW{cfF`P zIfIlzHp7kKMQdQQ>&2~ZGtrlJUBJ-oAkFctjz2ZfXT%(%UBkHH>KYzgyNm3~b_3RJ z=V|Hvw}cdtDKriC*xapqPb=@xEt>ZE#sZm=n_1*Jw1E^J&6Njcn&3_0SVkK)*k#FT zl@ckhw8Ta`h_;k;@m%n(Jaid1XfX%p$BXyzPj@f0-U zd&*~ANW_p%d@$)Sy_XnoGJt#D0?zMl=ZwP=Y5yi>O&(Qw2K zoi<%_jZZJXE%pjm&HAOaah>huYF|b3o&oEe=@&UkD4UBTJVDjPv`iQZV{>ed*Xx#& z6cVhgs1y)iVmb`*3lZl|9I%XvR4NT_OC_`^t$635ha7QFhXIf^YB@jTP!rbh>R><% z*5h6pBDz6>E1uq9$-of{FOYQdCI2Q4gST096w5*T;dcWal;HzpFYGFy zzj}_Q#8V=fFpIiHdLsH}s)VE3l0(0I@($zahyB5%(wmL8%f;5xof6_qDjQd=BpqOuQaKGltOT zgD4vxZ;ChaD?(}$q#@@U2BT7Dg32YnW^^>G>{$I1l=h4$$X};d1~~CAq0@JW)InVd z{{=+uN9pw@rQcLo{FLNLXk!w!Ee=RH6}$_|@8(!+Xc46079txu23ZA9x}omvK4heP zh__yir9>!WZfKZ8d{U@z?|6<(mrnr(BR_hSe9&*1Zs+%-@)J{fmcU?p48pCBqSgfIv3>6whYtH`|67xDTcqKiNaZ1CxNJj`kq zqt<6W^uPZ9zyHyH&wXKMPn!}P<`k4)F5A9>{1M~)qP_~EIK)TSPu zKKAg`|Ef*>JvyL=zB8aI%V=M-Jdwo9uwV4TSBmi<+RDm+e5f%~HTC;HIhd%V7 z{QR55apu)lf;Pn6s@E=ms0M%0O3gJWYz+unEvLV=qep8w$(5<_PY~bvnk2uqMK4#A z2&VM7_$L)9xO|K-qrUHm=bf5RY*v+8kC%HLQ7Iv3#wu|zN?PLtwrZ^?^GnTF1){@p zbZ9B7TQ|$hb5IGOzvdk#*UqAh{h^&YAD8mB9+Bmfo)8wPHX$urMAWX~?g>rETP}LV z?5ZezB8|ePJ)c6#Np~IMZfB@E)6MFWk-&2aE=Is`#|bI(oLI$gwN}j%ES)7#KDF)S zVzcfpERVYr@K3!38P?~IE!Lni0d&)hQH>q1Q0+%MLH7b1RBN?|Mh|Gf7<{g6Z`US) zb$m#g#bc6zWrb-w*a!(ok1o7NE)KpbhGTMmp@Dck3zG|%7j_ohh5Eun3*!r|g^7iQ zh0iP;S=e5jT=ipiptbh4nIXc7QEM;R>UM+=-FiesA%t_piDWe`bTIy@25Zq= zl16zo#!j-7qV+<1$z_jHHA-YDVP{a=*MkjgI{cX70)hcP;cZ@_Q!bWf0YYP>nXRfM za3jD$*h8|U7nUoCJL6czRMJ|?xeRL`{)s`LdZ}7o2)C$5t4g6-xOr8fJ$!g3sR5?+ zYLo}ov|g2qR$t5BQeEX8%fP7>YioI79MgC`e4rtzsO5j3F&TA4{+kWRdUPqG&4h)R z1yV|S)0w`AE)Ae`mj;$ZRt_T*WmzE?*P>Uuyu;l$u!PkxJG=Zz#9u@%YX}QR*eY?4 z{U{QQAeJq5XpjZ-P6G&fPE2Oa#?5%I~dN6ND-clH|^`1;#3`8ihrX1HD(~} z8R8$&#(}+IHd<0zsDqHxipFuPEJH8<%4CT`?FmFjKuM}@$mWfSW>qB8ZPukRy*+B) zJ=(MqgMc%nA{q9UsM=r}{b1c>@1kMb(_q4}mc&`sv9E(_lBd`UR zTqha9PBcfJ$XYgN0(6R~(69lmp6?GbESC9sKP$gWb2zU&_95z;1Eqv;9D`b;=3=ad zYHdXeO(J5CQzR_avpBEDaTudPlleYY75iDm_sJtXv9^9GTINmTjGcQz3fE}3y_Sf^zKYxGHNlYXZ zgHB41SGc6iAwetD4P>#LjHT2KCDC>Y%sj$cH>n5MnXUPGE$WJ|_*D3aSKa)PF1-u< zSday%eMH~IOCd_yTU~`?5y`DER{ma$NcZmuC@dnX_d-PAT=86japOK0iSxG}MwU&jvUX6(%WUS(+l0VVX9%Dkswv_NsCOF0m;e$}tEkl=FBD)xJeU zOI|!^aUzSHmG3HzxvFO-Yf0P*eWw$p8G4a2v%`2YFSH2w@cp)}JXb6WM-2fWl7PNFth^7y1-rmR6zz_pyDej9#?;6b;*-)hv_w0 zf0FudW&BICYr%5739-BAh|V4@MrXXVe@u_m6JqcDYsUi3=OQ>{o`BtiwkK3rw6`N@ zUqDZF-DO+bN3Jp&;XfHaHrhBoK;=iN2$PNvW)@9PP5r}zO{7=YnKorHbfwVD8KrHV zta618sZS!<3$nEtrKlw93@M7T8eCd!%2L*#%^1&Ec>KUSan~xmmfIT;vI&}VUPUeQ zDSZ~buRv{jNyjBiGjhi=35S>&Gz9$UBi^~G&L^Kb)mc07%!x-&oISyRPft!xZawyq zM^Bul*T*^Z(G&E3_R(`EPW)rt(!3%YZzJST`63B7n0IpS^C+EY?~{X9&gYPQgM%>} zHa-z(hZYqDcOS*QH?@q+l%@RwXu>ib0r(*-a{kQYvW6?f(qD^Fg%{A8BmGGhzT+H| zP@H1Q$=78ocdT|n*@b0BiSKamT68R)2(1UBQ6zX+qdO}mPIjiGGVn8YIa`w2g@e~Mo6bsak^T! zaEG$e$`POfBf?M*@)JU5=)d{J>f4|rgY`!kptaDFsy49fu$UwM2`Sb5A{(z36@yE6 z_xMLWLJc~v(BHT^j_8(3X^?80)tla6>8W+>s#+{pU`YN4D@I9GpX)rJ6D&=^RbZ9^ zy<#r>dGcadbfp@ z$tfyicv9eNI}l{0`9<{6uEwERS_~w7STZg$hG->=1=+oY(Qhw7JSmTEkogov?(APv?1Pqy zmPUkHJo*|bjK$w)!QAHz7NGjpY4btM5`7D*>^r`Vrjq4FAP&=+4op{%=RZCFcj@E% z{ z%G0IR%6-$#3;RGQQn|XGdB0qxhF+dqD$f;BZ95yrj)gkma=FdGFVooNWu;rC4PaAvD_*!3 ztqMkNOs<7Apebd1!UtS2cLwUg?s5bzu6$ldCa%gD;J{ z#dT0gsi%tMs&pk_oFLTAn|^#)j@zT1AjExHS-_6!$mk?!4N#bM?*-8+U&8-m8uGuHJp)?(V%;8}~kU?_clzeE;pY_HTS{ z|K_XvH$S`o?sxXz{b6JO-JkSd`)dEntNkmV?O*v*|N8g(*Z@Wz%LmtfaB%G}hqr!oc>A-9gk9|hK6h~KiwD=fesJwy4sZSV@b+uP zyiQ_XC);{*}-5uUze4`F#J%zxS`g|8MuNf4_hIW`FPc z!5e>&HU5`_-5(z8{`BD5mBzufFC5HtK6^l59MVwlGZ}+`xcds<=e*W%n8+U)d z|MqY8Z+vn8=9i)Jd;P0d`&U2Tzxu2G)j#*I|Db>Uo&Mh5!Ryx!-uT_Y8-Ik3dgoyG zn+Lo9&fRkrnsj*Ur-!$%6iYgdC7llMe6exo^*e7i?)>t->y7umd+$o)-WTq@dGFu$ z-~R3XjW6xr{1%k?-TilO!sy)YzxK8Ml^^x5{JMYTH~p($=wJU~|N6WAy{{j9>8l5? zzj5&T?%}PU9p1iLEa?oEbY^A$4?o<$`ThNyKj>fiQvb?tX@q~&zy7EG-ajAgei^F! zm4n@HAHMZ!468GRBn`sC_+-)p@0le_-+p`l=8vHle!2hdH~LpzZ}hM1_OJh>fBklU@0(c4 z8^1l+{VEjkb()E-XMly!V^;e)rz* z?_Rt6)q7uT+4;%ff zKj~ln8T`E2zxs>*)nE3n{svxt-@keTes1=!zT3YFUHjAi^*{IbzIE`%y9d|4a&YaR z58wLi;ai_Oy!CH~x4%@Z+NZE;pL*%N-!n@1uhL3@(fHcI?zawhzkjg%R zy#0EyICShj|9I!UcN*`%igo?cfBk6x?VI~I|FD1akNY>@g;H<#uUzk6*~6)N^{xKZ zTm9=l@9%xKzxQ2SCA=1|!GK-cgI+nf_6?j0Z@os7?ybYyUn!RN1eW*2`u^MR?BDq6 z{>?u(_TPcU{=@#2ANQ|7pZ~gl^)LPFZ}#_I>+gL}Ex^wm?0)`WclTiT`oZouU|PfU zc=KTQmj}DQKiK`_!7jwOeX#qNgKM890=5hF0lL$m%6#kK+P4p`eIIDr;jMo^y!}S8 zK2KtOp6uTF+MVCN|GCEdU%LBc9Iu;q-`Rir-Tim2K=okG{H1^8pZiz7(ZBw0{k_li z_ki+z_F(t*gIyQ|n5{PscK<|^;%kSuesy?zw^+neSj1ED|9n{l^dg<41SDcK7<-U)=rWy{|OxUAy-&HD3e47P{nxG&A%unU zcK`Y>`g>RUd*45J;|9<>T6Etyy!GqD+t-Q(K8*!Fy|MrHpZ9NkWB;A6LnFS~zw+(= z^Oy#3W;_RnDU&%E5f z@}2(mxB7dZ@9+H(i2dQM-yYunS~2c9jC(G5|LcwSzkTnkjeC3l3FP-L`!{~F{|=DC zcfPy-&iD7<`9c4+H~Uw<3#0&ck$>;+eWAbiBcwLCmk7f9or7!NJ-qe1!`s)3CCp+8 zv+4WaX}tfV_y2P5Tlc>GUq9Y|2e!X=enQ!P7H8M>U-kFC*x!T2@pGCwziQyzx%S+^@Vet&p-ubA;1W;~a@|KrB{KfCvxd*9u^@#_AKZ|=YI3&{Gn`|o~}Xg83@ zU-$RE)ZhCFQSEC)x2_$&b(OMx`|$SHi`hPl**@F5^X8CIoevTXB_22aOzTDsY>A@Sn z2U2u+>&D^je=e5r9G39h#r+#l<)7`pa|^Qg3lKS=W`VLaeye}| zcm2Ju^!I@9yxX9K2s{2C4{v|7n8gd2#S54I>nHo~!sh$#8~xYzaNoN6W`pSN%?6R$ z-}m?4=wj^Z}<0h`+IM~9(8!@ox|JTF6Q)4nA1PK@;(s1KQn9ahd=GV`&FnK zEcc)Gue{m6extv4t-tqgVoy4}_3q*A?<@||DpR~Xa>5z0!ggJw%(pRWIRa)3N;@B3M?hU zVWC9O1Jn}?a4XAUtm&%5r`IIX$>ax zI8l3&^J3?(_?D=bwD))amncFFt)5hUej7 zlC>Fsi*S${2~!G!P++ zEemygl_*L6sUgrhbtn~4xeu8ZC5>|YQ=`vk{PSW4CQySC_JWvGQW`K1QA~HpbV&xG z!{oe7eZ`bUF|SE_HNtBpyOs@$K_r%+7Fm*b-(xa2n-%Pi?6O^1n|%5yVXl21YQ;Ve z6{g*(h-IPLNd9cCBzcq;%0II>?JdW_SeQkei^5=zL@^3o$hVDJ8AF8p+|y{QBu5WT zFBTS-T-3WLX8uwPY=pDzkRe7LVj*gQGeT6SxTUkkl|F$G93|YW(I{-VvSuiEv;=!K zCvr-chdWZBErBdGDdJgFOM4Ings>e2oll2b=qJ%o*(!Z1$=N=R8j`_Mfkiy_j}Q#q zRS13$KzbrPv;W^V5|D9h~rxV`XG^9fPh^ z3xe*-CK0k!VN}pdQDxlc*TU`@L>LX#V6Fuzg}BHTXt_2m7LQyGVvDYH;?2jx&Iai! zk+%O+MyRV*$yS^5?X|Fd;qjom+6z|0Q&AEMGF4tx+H~MukN6?0ktan(cYVAh=ylb6 zCHqfnz}c0vUFf`sH%YX08+et^(50j&VyKroo@ilj0}dmy-+W{;4apm6So_ z?xUTa4h_Ts)*CbGlqAG^Q7q#*M8>h*6B_uhgpiBcy@M4Sp&~Sgjhe_=T~U>)^+4gn zsUOoX{dDo-mH!Yy&sEbY4UN5YBCwFnN#Ky%^w0)Md_D0mjG2VGcT zLPJ#Oi@G9z)Mu?=_+$;>7|i*kYjLl$JSRFp&tRZ(W@aWpvI=cM9cz2p1CceLKhLsN ziq@OFgI8sDIUfA@6PPBa!>xd@S;E>~Lb05+G~yi=Ay>Xj-pVt;8w? z_XumMb1DSQ?<~ud%-A}eEOF|lV{kjsq?|C{0Ff`QJChzTztM?TbgDsj`P#<*LhyaU*hn=XZdQyB2`^3d2mQz zpA}==O9c31ls(eM=}`XpI1X&HjuMiWYVV2BO5arRN3FuZ8CB$owV74?MTDBJCh*!+!dXmZXa;DCc97(xnI1wE#NY#wF z2bq=Sc+ZKbgmNlTaAh)4pK?M~(aNM!c2r1smMtAClIa72?q88{pU7|kxP|N#miT5F zOikc$;dMfO5p}E}vtzk+CJP?a+b3!tA2_YG`tg$}@2usRihlz|;l&*DHYn#A_}r#q zY8yeCgCb4tXnsk9cBmM6AJ7z&yt;4Lrq)d^ys z1y;$yuo22zZw`}w5FJv3YS~_Su&l+E2EmSATr7+u{@*$z7oin5i)FSRQ|T1DZ$T*0n*P%GHhU0puEA+v!fG6VT+31zfk_dfZ zRwhB$skSs2UX|!M>_p^=Nsr3_x6RRLD{yXM z1j;cPR;~z8yYx~irtq+<#QDqWGn$9lt9Y&3g=%xydu1f8#ctZMxNJ+mte;XVb z=1z77@!iZ+c`zi`!wI+7%uOhcvCqbVnqxv?tj19X>y2sV4I|}=5r^jp849HUc@)7r zNfB&i05!EY)~ykfh(;ID`NnG^^`NqcYr*MO(_>?C{%(oeWz`C)KqDFjBW29E(piDh zb|Q3=jDyWjkm@6rXkr17(LK!CQ}We~;se1!+f9T(E4YmIs^~awjQl3jtr^P6W%#1R(8-Lo>nTPKcQ}zH zS5wEjJqWsk9(?e`fUi2}4aVIH{G)wFZ7uDMunFyFXf2ww;~5BW$E;VrB2ruB2A-g`B`ak|`KE;S zLFf)*ggQLUQQc84pa+&IH^@;6eNx07R_dUfXydh=Ny{g1^8!4_7u9>)6POiNszBKm zF230cOPgpM@b{f%Y8;Mq3<^8aB;*SJHIwk~Kkdf`wDxa4DIaiRvGcc4=T)hXj7yRc z`mYMIbtMT_QG!-(nEIq}#DF)^N;xAwk2YGi5yFj77Q$w8&=izwLab`J66`kU2EkQH z>!{2}t4vk%u`qxxvDK_D3?=ipXW}@kh&#$!w~xt4t7zDmc(p=@{jCS-0~w#fDh&9< zuLf)MsWGVS_VppQt~{ z99lYxdANdZP9{)#5Tb#9B*aje4^p`vq;73j zwKk?l^~ji#AidJU8482YqW@6pXS$`RR98{6uPmAwFx=+{3Q6q=*-5V`@3>YsHEqPj zL3N*6CfB(TDv)NQ&My2LhChRU`DuOBnQ`9&I@u>-@{CsdTps3|a-P;ts zYteu$D!mS{MIL;n8$#+;yQ!3+#^+Ibx^U}eesYO*z>tNX|p044{}D~aLbHaDvM@K9j?sud57e; zzXQ1)_&P7*R{F)TLsjKB!`i)YekE*IQ7PA>tAsojO$Jzg=OtT=uD2~>^D%o%s7Hor;E>9rK3`HUL3*Z{a53$ZO3|;F1=J2#mfP!>1P5N zXbyeFq_XGdR^Z*^Ur`Qcspo)$Y*s9xt^@i=@SlNN967&rU-j0MAahr|@dn-PqvoTn z8ms`GFFaN0`&d`HhD$XJ%j9R~&j*cHPBi{$s`2s0;`otCC_Bw4MNv_}Q0RJs!Ithr zn@iOUlMcYF(heeKbBBRf4b>JRwA3htw!hqqY+I1=HUf54m(dZG9)~54w6Cr}BN8WO z;Ws?kKn)uaUz+p^eFxa|9M6$?k1UA43w@_+vr-j?6{KN25N=|fz)uM1r zUwuDOmXV^R3fpUG6*0mq4Y!Wu#b}m=CkTKdZ-;F#^pprXl)nnw8Ow5Ggt=k2jNP=C zgwLThM@L^NMmS!?R3gQ8=HQ46Kaa*)7O#7>5zV%N<>C+c`dC<2tHnP`i+eeo9;Mld zi?BHsiG(bGfRQoTI3?tZg$pV4VAJuojfo_T#GS z|EfY=HGmDRXGid=`$0gj6xaz1Z&i#^#xf~H7=mg-y@3!PZH&wy9+fo5QpMpJugAdg zqgZut&O_a=5qF5&D$}kbu8ktoNQ_t~*q$$j&Zs39DCcO!iu?S+2AR7)8@v_D%}+vc zmgK@*F~ux!K;4Y5T~dq^U6VNuiLNR6N#GR8(-osisa_sa@J1ryXq`DKl1h|51qTX4 zIEVow?z(G1YT2V=$YAge6`N(oRV7-9kd2P&JdIV0e|VkRoj45*8E%{oU?~SNP;{#| zxR#Y0yrrTl>A+=GHiaDok!SntRzTI2+FJ!dSE_=fSm#2Np%gBzwB;5Qv z-cUEDEj)~97D{nszT-9Ot$~qU^*oO5UjL!y8pR8#1AS}M2A8WIk3$WM?GPC?$hk!I z8010W+>r7sfV6t__C_~(0Ol}V`?MR&IFaWGs8A7vcxgC{sEl4ko;6_TY6MG z<+5`8W`zrU{Xo5}fsB|jk?|l}bu1$TriufEvV83@lxioJXIZSHIF}JLSu6|GtX+Be zj(%b*Enyh9PA1{Yb0$m-MzuUoHeMT6)q1_$(HacfT~%w1Pk(Jw|Mrb}AWa$}d4HCo zLj7&{TlVE?q#Ss}kz(bF%<#|7my^v^&uTI{QKO&Z!#xuWl=nfM*Et zgu1;OqtCfww-;_Yc|IsWpB1&IA1N7FizOwKkgu9bLH(c=Lr_(QIATMy)B~-|R3M8)-v3x_wOHaQeG#gvB^$T3*5zI-XyO)vF6EOjK^|EsY zn(LV9s$rqzB{&rQF9}of)8Oz!h4nj?nL?~6b*vFAYOVuqnD4t{HsWQ}3}(aVRjb&p zfWs#>3w3~GTM?@41lOYw7^M^tTnwTPOEi(X_cm%lcezGz)j^WPn+!{n#kFp5F+#E0 z#3)FV;V@aUS?e;o<)FQbC%a|$5{@G7Uz>y6t)VWaanWws;#dovxQN?*CzL5Yipj$q|^DAlFmA6WO@udc)YYpYt8&M$!yTzs=>Azd_dC%hf)WtrI8)nFx%)`yaVYN zxIDS~r$>hq8m{G!f<`($~Gh!xZrpaIwa+5RA zVPgyhV`i zSd<7BlMT$Dx_|&^DH=B}uL)IWMPkhrPSR*{I3D}`02JqIb{)^)D~kW)kN?Cl7%D!&5$|(u0uuhqoV1F?N15QD_fg0}IhR=Z%POs8 zdIszGdbjKfQ6}c}FDWFqQtY-!c0ez|FxSqNvVP3_!OVNX%u#jL7^*7~WeC-*{F5)^ zJro191g@C2mbn~Q2u!~8DMHC}mI5U8CU8R-`ASPiNt&}HLXyT72a?&63V1B7L@J2Q zh8KP+EzHRzV26|H3Y-N}oCyxITNQ9vTKT54*eocEPFT7PU8HP}w8D+H8MqL9W?+}u z+X{kNvXK9CTu0N3KFxhKGAi2ZeP!->6lEh_h+MXQbLTtixV3o{ap|zZnVyjm1R;TTZKj zf+dT24RM|p zr=yzCVmwTv6n=09hbv4nW2)fFt&}4dS1Z{ThkDd4lINrXIaT~_sURzUg${B?-JfM( zskRL(`?P4^u$(O^N9&ZT2xwu`NP)JHyQIaLy5XeG79|TwWH^piSO#yA8_Ed?>0wME z_O?=nkj{80zAzt1yRNw#H9Xl&P`Ys z-j?3})CC;Jf9&*{)D>GyTnloL$`Q)=s&MJh81Oh}RL~VjlZGT_YZ5={c@w|?7y9cw zj>7bXm-dEl{K3JerZdLxnq8c^m3gslpGFT-D&^ncls@*6LL&?Mmj_7ZcUMVlFC5gL zM_%}WjVy`wBZ3r*HA@!I*EE|rmuTbc=_A48Kbhi$$7li}I866AF}`!af4LE&uhty$ zeNwOeqyBUYFC;2`tT?qsy|wZ~gB;1|c6sq18EHKERXb?;pZp#nUdxOUt*dG&DdIOk zKuVl+wH~r(-zcK-7ER%xNh4)*CrA$HF}dn4kfzOi6wHp;OJ^r7qd287zF?YpZl8aW z5hS_BS;{=EYtHct#3=}7N#vH3#?x%(=bGooy|RNDaaEvn^FRP$nt#S1!UT+boE&+; zxuGMr7tZ|iDE900gxjyp>QX~hsn0TVj2}Fdc_-HIC^5+NmC8v`%3Z!@gtA2A7~Nm; zAnC^==#Oq=Gz=|>g4z|FQldCu6!c{e*G)Yeu#>S@vn{82uRY65kX`t^uOCNpGogH? zBD97Q(c0iBN7SOHNgAw_QZtSxM7iQ9Qo!dq0FbFY7oq3BsV&LGnUp52+=$dB{|=%W zq4n&kFo(9zl_mcA%PlxjL$f1HFZoj zBKKsE=J_D&xsBH}Gn`DJ<+9yk3^yMfx64#o2ZGXGaH%gF#!5f*K)nR?sV8Nt>?m9u ziJ}`~9#-T9X4KeSVio%%ZVSI3n@i6^{G$(+N>K{s&J7Eq!|(h|LNnfl&*<#UCwEh ziCS|Q*?OQ%cHMlVdb<+w2L3T9HA|dKWc+6+RQe)H+(FH9vL!{mmwwVcVjBDDFd~nx zjnB&R$9$Ybv;0{?6D93x&}SYB7)a7ZK$$e8?jKY|g`0S{yC%96bN}{o(?hOQh*4e966bM**JDO!76C zEqb6u#Lw(Oyo7Yd2Wt13$9N^c8BfILaomZ7i4Op9qfSfM*~(rVd%_)b(qQ_H6xf=d zGYN@Juih9jA^Wd?{cAmHiAah%_E5Hcktu<|@S!Q08Q7$R@p7$lryD(cOwhsn55pkj zm%P!x4Y{ZAD@p5T4;-5g7m7`XH9;#-4=&AYsOeMo{U`+1oZ{t1y-;K`P3MNROcnK| zSe5h*nfPrG^9G?TZm<8Kdx0lPF*1>I_+}3S-L_bwsSXm9x@UeBzXYSEjzDVTE|cQy zGQ3=zykXQAmj;Nu#Uq{J+Joo|VweyBN^8H6U-IQ^>u>w#`^L-W9MiLDFzRFK^Eet4 zEnVk)h7VWEF(I&!);J+DLK8ZWm%5mQFPBM5DdF+j4SqqJr09A=l;y*Zfy;{^m)Kbn z4Pc5(NR(a*V=SZKQqD#hl=Nx0)bCS=H$k!3Qh)z7NQW<@U(GBhHH|RTIdqNI#EVHR zU=hzTl+Jp1%UGDrF@!ls@Dk{0=w7NJ z%#xW&@-6Xgap)56pbX(-4#!F+)j|X_)629sB0b@EFxKSO066w(%NYayty`SOM8Vz&ks1zI$=T&NeljF3Gu zTpCYhNA%L^_Ci>GgIf^`kB`Y6!wk@8v(*i*3oOoD{hi+s)x*_aTYel_)2&3 zI0LsLC^rp1u;_4@j@Q3tAQo^_wkWv9T_#4yd2KUS}s{BT@v=A=xPhE!IyqIo~)9rH|*XPJA z{ni9#p0Tl;!-xm7;Fs>A(3ia!kUdHkWq|C5vk*<>%7VJfOS3Tr2m=x=GDQ0Q>pVN=IfWe7>HPBd zgP3oqNuj7Tf!I|mOsS#V9@52dm*}BX%rdmqaP;#vFs;@w5==r~%ZHSc<{3C0tEl~? zpwf$N+%FQ798u&`(WM>Gt>87%>5=y=b-X2aZJutWJffXMMH87dSj6E>RNf;ej3}_T zNZcXfL^aD^^+djI1hazsBp`vV1q@X%qi!@pOIKSNv&w59j=h1euN`1kdF@wmFbG0@ z^@!w^*MBWyQ|MaYkt@pEc;kaiH_$&OdFAzw$w|7db^w}G6WztR~jEiF!|SO_Vc(U~h9{jnN5Z`Mmf*>ER!bRkQpukoJ1Zy=@5gV68O zd)H4nP?FjpwN*(4N#w0#iT)+H%56Q2hiB|-ENNHa8aPs-| zq5(9O00ZoipdUY&&of2K6r_?nMMWNy&c)B(>v)V^t0gP>98%({E)LwE>E%q)%GDJ~ zV$R%1T5cf7t^jWU2AP!M>pXHJL~A)J!Pu~o{JlnYwWonJfYJX`_0Q&i?|wN3b%T=S z_}PE9`cV&7!fjYzq_|{hzwwi38u$F9{fs#YOxo|^KkxJBOAtt2+#9yuC$swKbUKeV zHXQtX{AiPWcGl=`{I>zQPIqHtZF6mHeZ8~kbk;lTkJkU>bZ&zH(3>2gT0MOWL8hIO6j=`PXhcf5y>tR-Iv*PLi#5dl00<=~)X5+%_yUMq@hM z_n_o{G`S?sMV&X8;T(p&7N#G+e)d0Bk6<+o!gBSn4{Q>g2N+%I#o^m~_kNI;h$!61 znowEh)gPXqzRIr8ojxSeij+K$Vhrw{)nM8&sXxT5tR&^f-`*TyY0RRE>7hsZ#&Y-M z=w;L~{#zf+cs%={L1wu4Wx|dows3`ny<96TWOrl@jgWxj0L(*l_~{Vky*FzSBjMYXp#|ls~{f^~? zRxvbAi;_N^k$2{gl%Ax9iXC3dK)2DeDa+tH4T5me2;#!|A@P0rP!kWF4IW?4JRC(H zMlxd~h`StM@BjJu)yujV@-4rv2{*us_wOEewcF-_yYbgS%ZPEloW#J9SrAcG*TBNlfbq-z@M za=LsS1M6gfG__rff^h&vyB)a^Het8&GgmH?vb1E&`6A8FEzMk2w_vH7lY&06_cVzn z@){k#QSX=x5|8`YN~5Fb!jJd8;&~XY!NO@_46=*|X*A1>1^=n_kkSJ4b6n?LHUYV_ zC`t&4I@)d6VhznUuV_Pek>(;8^?P32-y(CQMNG>UPi(z?vv+uO`0|&Td&1X^*4Ue5 z_^A>y`$t|pMm<3sWk?Qs4}jhbk~3+2}TPz0-77Yr^7!6*OPNY!^gp{b6=1 zoz6O0$bx`S$KWCe`_V;f6!kpzW{N{06aWyK1B(COwarrfTi(AL+5bc$fUuv#_Q!wa z_W$GVX6KP=|F1pX>^`pS|J(T2{_)3q&W}XKvn2qm0PxrQ1Xlo%w&$D$pzeYXzH=On z;-+&pO`Y)+G+#3IfOBFJaWRZi$4i_ux;$8Q)>`YWpRna@%~0QOIBT7?j`Iqm-p0;L zOa+1IjeIQlA0xVeAd3d)$M(JZ(z1cvXLP00T#^#Icx}~h{fwtLe!R`C_SPhr_@f{s zA)xC%O5gF=kDJsN>0hI`|D5crkpv&J8qJukXJ4yTMSe<83gadzOU{kzjq7c{1*jwd zlUpMw*PzX58jKS6%QgSny71yK1Kw|Z$v^J`eEb$#3DL-Z@PK_G)zn{5@cNX!Qm=UDaV{*2IS0T*T%BSihAJg$rjiz z_1h$Nszx1;I^%#~n0Acq2sg^hRbIEro=Zz0PR~yZPF2;MKlJu1F}pQsjW1%3jZp1T z^)D}85;G=+Q5&RENVGL~g2>tH;milE=X*N0oBSUMKXMirD;#yRU_}EW90MB^|2&J-M+`jCvywLbMaTB@E{M=!&Y`a70h78}J~f?JGe{gvfnH&T5hr{AQ$g)Of7G zrknEf2nyUFOq_}_au4@_WN^95(9Vkz9E$xeBZS{X<7Xgt>T^#@0lf1?T@{gN3O}r* zDRet|P4BEcoLUxf%Ew%ws%o1&4|0o2OK-krSlVsy*;e)KnqSikKS=mP*CA=km>Y5L z(n8vH&HQ)QNyr!dwJr&=AnVbFgxROE+_nf@JY8c--QeNEeONUoclEgn{J+q){aV!Ndr_ z#ftd@OD|@tv0-uuMYS|+84V`pnC;N@8S+!c8n8g7@@gkUXv;YR7y%1z*erUH=0Ov< z{5bGx%Q!)oM1`n>%P7lBEAJ&O8|P~h;b`M@+|J=uIRZUggT0<+5K}4qIpkN&F`S2IDaYz1c%dV=Ce3cLvi<3 zXVo~nii$lnHw>SVK4j}f?=YGaSMV%2_4$j^zv3F!oeJh3&4r{{oOkg9b-);Gfdv?x z@kE=gFBqa+S)b%%ja}qx49>u!YQxsd2Dq&~jA}acS*1$lE7%?nx|?uWGKknTpWw^Q zBir_>q=EqdIUEe@U=BxDR*pFf31-dPgt9I<{);1ww0_b29NXf#&nR3piKTR4L+Dd* z$5$fJyI8XXlIG!GcPvb}Mo$^ge&$1rVtzR;*sb z1JOem_W9wUvXxI7rtA`oaWu&KvO;Q^dkzF|F#lVd|FIUyE-vA+P>`u21Qo2SDs0^W>6Y>+O;-G?oD)IVNJI%76^VNg<-IHznmO_IeWlb9<(eH z2a8j`WWOVrIkVR3R9Vr3jc+TGrI%WZKL%oo&?#mZ9WoHs_>q$Tu;m2MFzZ`1-<&aH150o}Ptu8=- z;)Ibuj1&efJ20Q$#Y9942s;H$gp7@HaybM{B&9ylmqwY?uEhJ(C zpsEN2s+Zg_{dn)a8jZ`H2bJzqyL{KEAU~#1*#9ANeR?h21rFx{L18IIwnOnZk&C<7 z{}rdDCs6a{;Z=FX;^WTnFOkR)HJt@DT)M@78gp z^$s#yEd~^hyUJ!%v+<^79Z-atlAer#Wo|5C8B)_KW?$(Ar_Ht4*8O_0yE6FmunJF_ z=(G`9@5s@mHyV0t|E84MiADS-XWKp~q}Ck%*H-_mN85t6mBRPxLYU6S0u5vd(i8y~ z2h`!-h=gy%A|4#td4dQo_wWWCGp$ST5kfMkfzMpnr@|bpEW)bxhUCjq^yRQHzo`@s zy9EFH6e&4CPCse>44XLP7}kW>FROzsM5DzU*jo7{NKWU-u^*JTSI2d2TYqeSa}U~t z-8i3p)T8=i;S#?8pQ|llCecrbZFVihuw_6kbmr2#9|$n(4kTVT`VEN|taz+kX*mKW zcECxVjr$x~!0KwVRZmVrUF}t&5Z!(UdU8HN4s0yyiJkVCyA|8-AuZ4RKC zxTTUmtg;21RWy%QxuU`slY^Nsm=lIAl8dtLaTmYp5zQ+@RzosP ziNrw@F`=UFD%l1s&cl|Z_PO3vEkzeWdi%ju$+8Ly2S*(H3aGL^MMr&HJe0Yl|i{_!l9w3e5m?_ibUM((Qv!#h~Q4y1yI3oQ^?Fj^@T| zeTa3pAl58l%2`s4OF|$Kr8X#59+G{2=7asC$c=Osm9&_$^D$O(TQkE^d&BZk;eQ-yn8!18(R>x+Y5wM2xt!6 zx*ZTJXVZC8tY%tRxyMARJBG7zk;Pwl^w0e8*7x>X-jeyJ0Qn8v01ZM>$E$;TSP)M= zHS0ZE%Is6Uuixz>!W*AUmjF+f02rA0?oZlt#N8!|-37}20@X;a+NUkDE`m*$L6qCD z`dtLWE{c99)quTP(rQiIB>W;UAhdoH)qtT|P=5`C?Oy^d{YbSnWL1udJv@RoULaUs z19FdGTDlsb&%@wzl=MBdBe-uonOb=1D{w8aJ9wiZ)J>jA(I-k!w*q)2-AI8TJlpMO zGmzZc6M}DjQkgdQh|TfovU8TwX#@^|{my|)?XTgqtTsXq8*o(6=?&v)XC#A7V*Dka zL8(KhQF9Tf#!bI<$DNHsBQJqi45gf{|$d5kl9wDQC#&zm4#S&UCwJWSD=nt$;hYZ5tE; zgK7PmIVgkf z>O;7E1K6?SQMgNu{^EK4l`>yhK$ttVidi9aO|v!e_tzlEbDIlEwGHII_mG9)ZiO>^ ztI$Bp)BY<#vy=O9Ti|}9HRvtX5!*1I)UM9={1#4Ry* zH0?8d0MIAoNG|uYd#IPeJb^hddB*D@^hzwjmUo4n2q#BB7}vZ&jMeV$cORv1>Afoi z{|@+u5YNZkashrG$A6m0R>IO1bLJ{{j%6$NJU1yy{n$+MTSt%A4oF6tTW~c9 z0LT~NF({4*qXAGH$l!BjER77opA{#eKOi>AYmOOD*X7_e&1a6#XUYNT*&_YWhj+0qIv|MH^T!z!7txFK58?w^g};kZ(;Zh|lD`CWuBE>gU;YY~2S47SPp zKz%m}uv5m2grxs@U8rbEfU18QbPtlI$v^ee!ZraO@pVtpvwGHyS24e9yf8yho zdS?6wPg$1dU;q);xtPcgZL;Qn0Mf%7<(|3MkMCdpayK*zavR=km0RyTk9@_UUnUIZ z!`C{N3HlV|BnMejG&GA=))6(xdxP%xsbIVKHK-2zy00jjY zsgM5Av_~#pb%%HsBM)a5D`4rxE1LDoGMW!PWs-AL$(7^t?KujKI&yGkvL0{7)N03+ z+!qBzE$`pDF>RTxR0Mr-?}e937C`cp-FY>HqlX38vPW9lRrT=hprJ*SXGv<)w?ve= zFgi`mI&Sdtxq(2fl3HA6Few$d#U`e?ig*}W9831iaVyozD{-7VmTap-zwD^lBBOK- zzvPT2-J~f|7jdsjNXg)jD}q@7o}rzA+^X-oJ()xV)%>VW87vZjvqn+RU!v%i7iCiE zYWZWlea^B?GQH1A({IiBr*+vTWZSv099re2AGnwSYMzir@^Jwg%33a12e9utCEih4 zbY|YlA*Lo0KU&g^ql4gN^^IcASnPIM-v^5M!$PvPew$7@A}7KXk5r`AN%2u`J16G5 z8_~$qk&sI}e*UkJ)3Cpvad*NxsSIH)1q*#JOaGGJeAY)QS?M$~@fq>+Y@nQx(jQ1^o7pUz z(u%DiB~L;&K<_88)S=G>ocL??Y@s$;^Z6X&nuqhThb&PSl;E75;EDQei2ywX9X)jf-Td_zb?Ms83-=DkMx+@7P}wMhhk^65O*}viceMNyd*}V|4Ix~M z*94{NyHBzqN3bHh&Yo&&Ml(-lJMCCy4y7FSD0{LVr7~$Gh@G-SFDGg9ArW19BI5%= zI^I_m6l?G7zl+P&%F4+RRODF&9ZJu2YUbk@rZ=%rCj{C6s!6Hm?;Zt?6ZNa zH+11ekZR}D-D4qO1~@F9y+7eX*uAmaiIuvKk03?Y?5|Ua#h1Q{t0ZJ$>mtfW-f8As zplcCoSUNIFUN}(hK3Cd(p+cD?w8|i80Zw4?Sx~`!o@W52@mh&ZH2Ede$> zec_X_K`I+}m$d;oS{Z_5ClQs~O7JoK?2w841H_9A5v$m+zbB7Zvi_ z9SrOuEVAJ=*Lc?82ecUzJ9384XPNV85W?iH6EW9I3;6A=7hTRvC^mVSOm2eHk}Qvb z!41h%l?UA*9mFv6Sh2gM>pkyU9%2G=a7e3aJ_|q;y09MymC8y>`o(Y8oZ=_Cpk5CW z)b5-`-IkHnM?0@4Hf?dG&9yvpIt<;Xi1_#RrinGL|FYv(B$u(DfQj@;(itY4r{ps$ zdOI-8m3XW#lClD&0PZk&hNXna6i3F9-68~KLd~^2%t(%atm#C-`4)%NGz}}E<3q`A z^g@8qr}MqMy*p21H0AwnbGcPU*g7MW@#dGm(4cl#!T>$C*EsVvN`b0){g!vn?d{&N zvm9H&JFGHMU1!I6V!|u8qxzV}q}2AOrc%n~Ft>_|socE0ohgjoAc~a($V`q(c)bgz z6E$sNzaKXDGXqUAJfi@&?q|r^hz((%#8OSO0b+j7Cn=@-teVpI;nlcn0h?LY4eGDs zila`Fy*wD%ZFJd1IzAsQn*XD_5sB0}x1|M={}<>9h|dy>qI4lt=)UKpS>9|(g_kL2 z^US%QHYZgQ7tgO(3Aat)O`*VN!92{xMhv*#2%iK$D}p&)b^bA2qTB2Kbh$qpY8(IV zb_}bzhZgz`#4>x#K*zGJ`HvQedg5SI0fl60{PhSw!*{vt0y0tw%}OV zIvwj~@wR_-ecsYn`i+T-QY(ukcTZP&4|H3O)T^1BftMK?UA=mwO7mqOt+$s*?9oAt z`9QAUg&pa~+=m>iH(BQHosAWODB8`Ddw^%Y0iCb4vzECv$C5jVpDIPUl1*9Df}z!A zzbpRNz#tG2;321T76X(!!6zE#x-!yF^dAXkYVRcoIgdPSLh3ib!uylx;iQkfI|)^5 zSJf8X-u=Y3*!t_vat}sTZ-6X|RXoDNQcbzQRrS2rNssC6HGC=CL9p5vMh*gRs_){- za|T~0=#}hFF6(al{`kk0{cgF_SNS(nep=hC=B}eJpF5b-t|dt~`Lo)V>om_hF|fU$ z4m)tZE?nNWXbZ;g&P&6s=c!79(z@F+0#i%e3*ozZInUG%&7!J?P_Da>I&boXl%-?`3IQvhs8>s%xkxLK2U+%_2_A1p zDL#8h1%lcwTg`F`p^Owli<7KY##{=wPlF?@$=Uc@IoCeZRHB?~T6K=YPPj@ZpV>%z zGY~35O0O7d<@A({AD1!Q?%A^DJAYqO<{j4<1ey?M<0%3(Dh}K{koOJeptdOJih7jO z6ROq3=~*Jit((NDGjU>v?gV0^tNTJ??bd>*_l6LYiY~+kA$Ikb8D`1n``fLl&E-Am z$9Mjvi{@063<_;6! z2hFC1dmusVy3e0^LnGAvtNo5~NKqpBAtLbAJ{>rDd)yYh2yoIV#yh!2(|nP%8D!+o z>=`B5+L@HzO_bgatl3ynmRSWsuc(7|sOy5ol%Mc6ib(k^54mnm9r@75lQ9*Hc3u=IriMkB$nF72STvQv zE(z>C%dwu74MthoB+IXZ$AP05R`+3)N&(q$N3Vq}8pK%+68VGdToaeb%V#-KGwy@X zNK^T{@Y*_LG>8hy+^mHb+GexA4bCZ*Gkse@Nn+8OJNZ@)x;a65Cb=2sDWPNCU9`dI zqA+P;owjqQ7ao&Ni(+1w^@XW~*pIPUQ^0Dv@T&>ATj67VB$v_$ zk@9~YkTm1o-8cVH4cn%q1FrwQDJ&Mc_sD!uCMHRgt#Lq%K8XL<#cth{0!k?wu zFiX)+?9lNyu+hV3)UQ2lIL{-wPPHs7&O$*dZ_tGZr8W+oH z!73I3Ix<|KS|MWAH~#u4&j`!0by{KfEPEa@ysUyY)zrlsw)P-P=>&qkADd_SUR4SomxFGnikn6i% z=XArNc=PpF>=?Dzx5`y5edn)!F5gP2H89t{<><(SNa5SP*bDZLbO!MIRhV0Pt?Snl z-Y>1*-8{Cv=QG{3z#%3|23H5IjdH2+r+G&oiLEgj-LKG(qnTO^OkjHeMae3waYOkG zv97&EIS01hV-tS*j;_OG575>HV?F;kY3X>1AVJR#^CX6|dwE9hDi|S!>-bRju6s@@ zTW1?>R>(L#yIe3I9fcLVw;!2{K9ntJBbPz(=KJFeP==-UO&T?0T#=g$Fb%_r;icw$ z=7!HuNaWoJaZ`Ei^8U0JK^G`aSsUez-xzQ7zOwW^Fp)c%er(C`G;|C(X1D#$+B9WC zWl#ht{xR}hrg7m^lW#PCAAH)rpEL|P`!7S_TsN1Tqs_s7jERJ8o=WaT;x_kET#GSz zh1^N2Ix~#@p!g`tL_)|kxD$!OOXH&S4D=}jSJQ{|A7@vCa$n`&E6CXW8MU5wt#X2d{_Ve44L7S!~l;%4I))J)u_*3 z3A$9Ll{90i@S_^tXrfdU1mdLxXdK|XAaK%y{7MY%U1PP`8#GNJ2Ekb}eJ|BDn&X8L zjyI7@WrZr2Nv+f9T6o^FdxS}NR6})kj03|78gQ5Q$*ppTQMES#lv7d_N6YH1F<<^^d8t*u5rfCe#QUziBNCld(XBat}hRDPk8*ye0@ZC z^YF)PYK;~S@{ZAjib){RL$~@#I@V>{9i{lLlyXzrD=@0H z?f*oiaz60AVWOcEiQ`HcguhB!Hc$^^5p6z4A@;Zm2^_>QCFHQ(zvvI#!K*@U#!q>$ zwcE$HOHsh}bwBYHZ=SmV+m(jo)JrgCN3=3JqNy{DwKoFwh5apKCLsLKI>v>KD82(C z?aZH`7%yRmW$(F(RqHrN?#agwEt{uLP-$xp+L@y<#o2913pC_xtZpsO>i9+n8~;kE5Lz zKjz-91E?M$pPHQIk)xw5rI!V$L!QnMR3o|RGFEVk!lRC*A_|H0DXQ_kN8l?##yo>! zWxi8Z0z=}?;SA`Q|D%U=Z10l)L_6Zsnyo3Cc2KKit;L~uP8m$CYj2Pyn1;w5@`t6(A2wBz;O{OLl_wqb<&5dT zN5@k?36T_0>~PMK?omxYvBxcPX`#$r0Wf@SbIt;3|5_S+BChTI^GwkejxH85qk?r+ zk>HZ2_T8qm9Z#nLTt0+5Ml+cnf~O0#=SXD!sKr03(s5KJeZJ1{9$;Z3b7)kj%Y(hY~HsN(?fP%PL37 zP0JW~1)ZEsagNPYDfERvE)}C>hxz7X5enYfsJ-3cg_ilvB;8wS{T#~sF zd%TTh;}R!uSS?TQ^^v3V-#aE~=^1dg(6^~fT7XR$NO-eYxxGYhzls|Ry<6f5oQHiJ*VGVO{%lJO!WFvheoT{SzwC-yuu-P1on z)Y=C)s6-FJ0?)Anz8o(#YiDIRHf-ejlOzw zOI{mMjtiHO+XqT@ptqlxgj0tyenJzsyoyk{?&xm;$bgj{!@kY_cd4GWp8-qlhxiD2 zQisG72Pi<{KfsN3WD2>t#zWwpWwSW#%9Kd@*>7P3jdm~%Bp=0wL}W`lVJQ0Qmoe^D zg~Iw4BcV8=8T_>5m6ePK*1#Y^(smJ+TVkIxC}VWt(w<{0u r<+?Bu4}BDfMV9Qu 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%0A7`|gHj5sA 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≺b?b8t)TRw9bM^ky(pXrJOT$=DO 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 literal 160125 zcmZsiMNl1Fu&oL1?h+h=yIbJk?hXeD?(PuWA-K!I-QC^Y-JJlzo%8-Xxr6s!)vDS( z+SQZpRn=cNX*4`U+(Vox1k~Sd1S8^gjUT$ps?F|n99U8+$#Ij;f-R$|y3uB_W^yf6 z!->>74Y)pnEmCS1%+1zI7uFscax1(uMLzIyYr+Bu=$P<&cfTQSZh!wI6HHa|{I@n} zits^2brZ_;Pt0>)Xm8iW;Yv@7C6Qkl2fwm%hVOaHXSVx!%Vk#Rbfx*&i7n&E^zLrR zR!Kibri-|k{{7+U2^9sk;br&!Xm{t!{4Xqw5Nijsn;($rwBbp}aidOG$y1*<3{%twGJYHg`BFYnLdUAJ|QdJ*n;q(0DAPV5Ny>GxbU< zD1u{=a6*gc{@$_$hvxNB19sXv7jlw`5MgXVo_*~N=rjH##XloKJOKxLraH_Zu+I(@ z4UhkYcqEJ}DQ94mQ+Zg;pH(9G2{;4Wp!A*(EMdgvZZ0zY-dX`PcSC*BdItT!D!s@% z1-M<2jGhw*S6l1Tx6qkW|S~=UAB^q?IxwyC`=Crf1y%NjiuZ0p-eM=Nd zIcRxptm;aW1S`1Qomgem*oeegN}1IS5*VQbge602j?~O35T55?9+b7EjN2s1{XJNi z`dC{aad*F)(ZP)})}qPNBR8W95DR>nT|}?C=yG!xzNAR5<$KLa zYfE)Y*P7<;Tm4E8;7IWQ{`9L_u$o0Jz;8{E_~`ywFGYe-Yh8PmG>z7}R^% z3ghL%o`k_sx)P=|dw*Ag51fi0kn9e*^qsw;njKd=r%%+2b8tiQ~N& zizusmzfH$}In)HeYGDa> zuRK++Wo7FaGrLBB+=OZD@72U46Vp8Dm`VKoYXmyKGps~UGg$c zg=VH$(y*zDU0D0Kc$o$o;*C?xGSj>uhnT5oL5CpoE9{3-7JupCnoRKV=zm_6YlMWz-x0w z;&y4Ga4cljG|{IsY%D9%g?zi=J~`wUcEUla8>qby{KBw03?6$ddd=9C+#1Pd4f4S~h%~i#y013r<QXDT1R?0k4Nr5bh)5;iC`7ZZv= zO)@O7J#>x{+d5uesAPlkv7MjYTLcCW-xxN2iV(e2OA~i|!WffoQ!8e>bz+K?O%pa= zp$(3Iwsk=HEK^ACcuTq1=EUoVxvzizS1{qC!xWRoT-twx$U5l7(z&RgcvY!d2qCF zH+460gkrH}rZeS;u#?|)0k8DT?pJ1)0)q*kLeTV*%J20J zBe=;%W2%z#H4nFNI&9FVpJBc~6OsPl!&xN>Que;IGcR*V>#67O<>v7^+?aUSI9NEk zJ6fpDAX@cpNvE`5)i`;<5ax`3(#?AN`KY{C0INK(aRBXdaz^5vo7CdzSHWE5tKGND z8#R=OWRNz5txo6yEK`Y-(r|n$M>z5Hp@5#;;+zGw%ihWK{}$~{Mdn;vt`jF$^&b5f zrv7?McXF1{|EHyLftKf9GTL99%GKJ*+0M+)+SqN}0(cHTYM#EB16lGr%;Hwvm1^au z)k!<%4=ZV@r2X|7eJmO-?p9u*FmW4aD|25vTVG$4p(@Lb@9I0QSSa&wMOBI8S?H8f z8F4d*_C#k^18y@UmTYU-{91c3 zoxyZIxfQwbnmjrUE4uNEM@c$|WrG+}B_3Ls8ISchYGQqxB8dxPYPBYLFb(x0c;G|u z-fgOUL(9ftwWsFfkV`~!aCNDvyY|Za@>H+4{ZVz&q4{rfc9E2|h=d>LHEDWxO>p_) zyyV78*WTOU@PJ355_{?1zXZ`; zY$prO#x(Du=%DCd%SIsKm-izyO!kIy_c?uJ8cfhMhmO5v?j4n+_m4S`St_YsS;uvn z5Mh(w*TwVA`>%_SOms+GCfEdonv@Al`AQ887af9jy~Ir4Y9kBE1H|og;CGIel6lLp z%ukbBGCbJ1yxoH#0cTyWu#0#yA#IGDIy8XH@33iTmH8x*aSq{l6nr#8!$7etYtGQ( zU!1XYqB5zWX|GO8$d>RoujIf8*zOrN9)W+jQroNmiEqE|jAKp@7ba*#Xl;=ij2o+G zeLV*aAe>B7+t-|Sb%U 7rw&e84Y7~{l!#V`aFBRB$RYv|{l3{%R# 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 – YearFormat +

    + @@ -85,9 +91,83 @@ + + + + + + + + + + + + + + + + + + + @@ -166,7 +255,7 @@ VGSTextField Serializers - - - - -
    @@ -380,7 +381,7 @@ Platform swift Cocoapods Compatible -

    +

    VGS Collect iOS SDK

    VGS Collect - is a product suite that allows customers to collect information securely without possession of it. VGSCollect iOS SDK allows you to securely collect data from your users via forms without having to have that data pass through your systems. The form fields behave like traditional input fields while securing access to the unsecured data.

    @@ -412,8 +413,8 @@

    Table of contents

    - VGS Collect iOS SDK State - VGS Collect iOS SDK Response + VGS Collect iOS SDK State + VGS Collect iOS SDK Response

    Before you start

    @@ -467,7 +468,7 @@

    Code example

    Customize VGSTextFields… - + @@ -505,7 +506,7 @@

    Code example

    … observe filed states - + @@ -583,14 +584,16 @@

    Integrate with Cocoapods

    Add ‘VGSCollectSDK’ alongside with one of scan modules pod:

    pod 'VGSCollectSDK'
     
    -# Add CardIO module to use Card.io as scan provider
    -pod 'VGSCollectSDK/CardIO' 
    +# Add one of available scan providers
    +pod 'VGSCollectSDK/CardIO'
    +pod 'VGSCollectSDK/BlinkCard'  
     

    Integrate with Swift Package Manager

    Starting with the 1.7.11 release, VGSCollectSDK supports CardIO integration via Swift PM.

    -

    To use CardIO add VGSCollectSDK, VGSCardIOCollector packages to your target.

    +

    To use CardIO add VGSCollectSDK, VGSCardIOCollector packages to your target. +To use BlinkCard add VGSCollectSDK, VGSBlinkCardCollector packages to your target.

    Code Example

    @@ -600,7 +603,7 @@

    Code Example

    - + - + @@ -824,6 +827,7 @@

    Dependencies

    License

    @@ -837,8 +841,8 @@

    License

    diff --git a/docs/js/jquery.min.js b/docs/js/jquery.min.js index c4c6022f..2c69bc90 100644 --- a/docs/js/jquery.min.js +++ b/docs/js/jquery.min.js @@ -1,2 +1,2 @@ -/*! jQuery v3.6.0 | (c) OpenJS 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=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},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&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,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.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(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(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&&e.namespaceURI,n=e&&(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},j=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 j(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||D,"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,D=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,"
    Setup VGSCardIOScanController…
    @@ -759,7 +762,7 @@

    Code Example

    }
    … send file to your Vault
    ","
    "],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 je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(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 _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.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(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.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,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===_t.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):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]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.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 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))&&v(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+" "]&&(!y||!y.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)&&ve(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(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[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 ye(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 ve(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(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=[],y=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||y.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||y.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||y.push(".#.+[+~]"),e.querySelectorAll("\\\f"),y.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&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.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)}),y=y.length&&new RegExp(y.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),v=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},j=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&&v(p,e)?-1:t==C||t.ownerDocument==p&&v(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))&&(!y||!y.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 j(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||D,"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,D=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),v.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",v.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",v.option=!!ce.lastChild;var ge={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ye(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 ve(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 je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(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"}),v.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||(v.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):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 B(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(v.pixelPosition,function(e,t){if(t)return t=Be(e,n),Pe.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 B(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 0Vault storage type.

    ","parent_name":"VGSTokenizationParameters"},"Structs/VGSTokenizationParameters.html#/format":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSTokenizationParameters"},"Structs/VGSSSNTokenizationParameters.html#/storage":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSSSNTokenizationParameters"},"Structs/VGSSSNTokenizationParameters.html#/format":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSSSNTokenizationParameters"},"Structs/VGSExpDateTokenizationParameters.html#/storage":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSExpDateTokenizationParameters"},"Structs/VGSExpDateTokenizationParameters.html#/format":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSExpDateTokenizationParameters"},"Structs/VGSCardNumberTokenizationParameters.html#/storage":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSCardNumberTokenizationParameters"},"Structs/VGSCardNumberTokenizationParameters.html#/format":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSCardNumberTokenizationParameters"},"Structs/VGSCardHolderNameTokenizationParameters.html#/storage":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSCardHolderNameTokenizationParameters"},"Structs/VGSCardHolderNameTokenizationParameters.html#/format":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSCardHolderNameTokenizationParameters"},"Structs/VGSCVCTokenizationParameters.html#/storage":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSCVCTokenizationParameters"},"Structs/VGSCVCTokenizationParameters.html#/format":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSCVCTokenizationParameters"},"Structs/VGSCVCTokenizationParameters.html":{"name":"VGSCVCTokenizationParameters","abstract":"

    VGSCVCTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSCardHolderNameTokenizationParameters.html":{"name":"VGSCardHolderNameTokenizationParameters","abstract":"

    VGSCardHolderNameTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSCardNumberTokenizationParameters.html":{"name":"VGSCardNumberTokenizationParameters","abstract":"

    VGSCardTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSExpDateTokenizationParameters.html":{"name":"VGSExpDateTokenizationParameters","abstract":"

    VGSExpDateTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSSSNTokenizationParameters.html":{"name":"VGSSSNTokenizationParameters","abstract":"

    VGSSSNTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSTokenizationParameters.html":{"name":"VGSTokenizationParameters","abstract":"

    VGSTokenizationParameters - parameters required for tokenization api.

    "},"Protocols/VGSExpDateConfigurationProtocol.html#/inputSource":{"name":"inputSource","abstract":"

    Input Source type.

    ","parent_name":"VGSExpDateConfigurationProtocol"},"Protocols/VGSExpDateConfigurationProtocol.html#/inputDateFormat":{"name":"inputDateFormat","abstract":"

    Input date format to convert.

    ","parent_name":"VGSExpDateConfigurationProtocol"},"Protocols/VGSExpDateConfigurationProtocol.html#/outputDateFormat":{"name":"outputDateFormat","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateConfigurationProtocol"},"Protocols/VGSTokenizationParametersProtocol.html#/format":{"name":"format","abstract":"

    Tokenization format.

    ","parent_name":"VGSTokenizationParametersProtocol"},"Protocols/VGSTokenizationParametersProtocol.html#/storage":{"name":"storage","abstract":"

    Storage type.

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

    Parameters describing textfield input tokenization.

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

    Attributes required to configure date format and input source for field with type .expDate.

    "},"Other%20Extensions.html#/VGSDocumentPicker":{"name":"VGSDocumentPicker"},"Other%20Extensions.html#/VGSImagePicker":{"name":"VGSImagePicker"},"Other%20Extensions.html#/MaskedTextField":{"name":"MaskedTextField"},"Enums/VGSVaultAliasFormat.html#/FPE_ACC_NUM_T_FOUR":{"name":"FPE_ACC_NUM_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/FPE_ALPHANUMERIC_ACC_NUM_T_FOUR":{"name":"FPE_ALPHANUMERIC_ACC_NUM_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/FPE_SIX_T_FOUR":{"name":"FPE_SIX_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/FPE_SSN_T_FOUR":{"name":"FPE_SSN_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/FPE_T_FOUR":{"name":"FPE_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/NUM_LENGTH_PRESERVING":{"name":"NUM_LENGTH_PRESERVING","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/PFPT":{"name":"PFPT","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/RAW_UUID":{"name":"RAW_UUID","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/UUID":{"name":"UUID","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultStorageType.html#/PERSISTENT":{"name":"PERSISTENT","abstract":"

    PERSISTENT data storage.

    ","parent_name":"VGSVaultStorageType"},"Enums/VGSVaultStorageType.html#/VOLATILE":{"name":"VOLATILE","abstract":"

    VOLATILE data storage.

    ","parent_name":"VGSVaultStorageType"},"Enums/VGSTextFieldInputSource.html#/keyboard":{"name":"keyboard","abstract":"

    UIKeyboard input type.

    ","parent_name":"VGSTextFieldInputSource"},"Enums/VGSTextFieldInputSource.html#/datePicker":{"name":"datePicker","abstract":"

    UIDatePicker input type.

    ","parent_name":"VGSTextFieldInputSource"},"Enums/VGSTokenizationResponse.html#/success(_:_:_:)":{"name":"success(_:_:_:)","abstract":"

    Success response case

    ","parent_name":"VGSTokenizationResponse"},"Enums/VGSTokenizationResponse.html#/failure(_:_:_:_:)":{"name":"failure(_:_:_:_:)","abstract":"

    Failed response case

    ","parent_name":"VGSTokenizationResponse"},"Enums/VGSCollectHTTPMethod.html#/get":{"name":"get","abstract":"

    GET method.

    ","parent_name":"VGSCollectHTTPMethod"},"Enums/VGSCollectHTTPMethod.html#/post":{"name":"post","abstract":"

    POST method.

    ","parent_name":"VGSCollectHTTPMethod"},"Enums/VGSCollectHTTPMethod.html#/put":{"name":"put","abstract":"

    PUT method.

    ","parent_name":"VGSCollectHTTPMethod"},"Enums/VGSCollectHTTPMethod.html#/patch":{"name":"patch","abstract":"

    PATCH method.

    ","parent_name":"VGSCollectHTTPMethod"},"Enums/VGSCollectHTTPMethod.html#/delete":{"name":"delete","abstract":"

    DELETE method.

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

    HTTP request methods

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

    Tokenization response enum cases for SDK requests.

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

    Type of VGSTextField input source.

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

    Type of VGS Vault storage.

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

    Type of Alias format. Read more about avaliable formats: https://www.verygoodsecurity.com/docs/terminology/nomenclature#alias-formats .

    "},"Classes/VGSTokenizationConfiguration.html#/tokenizationParameters":{"name":"tokenizationParameters","abstract":"

    VGSTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSTokenizationConfiguration"},"Classes/VGSSSNTokenizationConfiguration.html#/tokenizationParameters":{"name":"tokenizationParameters","abstract":"

    VGSSSNTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSSSNTokenizationConfiguration"},"Classes/VGSSSNTokenizationConfiguration.html#/type":{"name":"type","abstract":"

    FieldType.ssn type of VGSTextFieldtokenization configuration.

    ","parent_name":"VGSSSNTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/type":{"name":"type","abstract":"

    FieldType.expDate type of VGSTextFieldtokenization configuration.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/inputSource":{"name":"inputSource","abstract":"

    Input Source type. Default is VGSTextFieldInputSource.datePicker.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/inputDateFormat":{"name":"inputDateFormat","abstract":"

    Input date format to convert.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/outputDateFormat":{"name":"outputDateFormat","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/tokenizationParameters":{"name":"tokenizationParameters","abstract":"

    VGSExpDateTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/serializers":{"name":"serializers","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSCardNumberTokenizationConfiguration.html#/tokenizationParameters":{"name":"tokenizationParameters","abstract":"

    VGSCardTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSCardNumberTokenizationConfiguration"},"Classes/VGSCardNumberTokenizationConfiguration.html#/type":{"name":"type","abstract":"

    FieldType.cardNumber type of VGSTextFieldtokenization configuration.

    ","parent_name":"VGSCardNumberTokenizationConfiguration"},"Classes/VGSCardHolderNameTokenizationConfiguration.html#/tokenizationParameters":{"name":"tokenizationParameters","abstract":"

    VGSCardHolderNameTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSCardHolderNameTokenizationConfiguration"},"Classes/VGSCardHolderNameTokenizationConfiguration.html#/type":{"name":"type","abstract":"

    FieldType.cardHolderName type of VGSTextFieldtokenization configuration.

    ","parent_name":"VGSCardHolderNameTokenizationConfiguration"},"Classes/VGSCVCTokenizationConfiguration.html#/tokenizationParameters":{"name":"tokenizationParameters","abstract":"

    VGSCVCTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSCVCTokenizationConfiguration"},"Classes/VGSCVCTokenizationConfiguration.html#/type":{"name":"type","abstract":"

    FieldType.cvc type of VGSTextFieldtokenization configuration.

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

    VGSCVCTokenizationConfiguration - textfield configuration for textfield with type .cvc, required for work with tokenization api.

    "},"Classes/VGSCardHolderNameTokenizationConfiguration.html":{"name":"VGSCardHolderNameTokenizationConfiguration","abstract":"

    VGSCardHolderNameTokenizationConfiguration - textfield configuration for textfield with type .cardHolderName, required for work with tokenization api.

    "},"Classes/VGSCardNumberTokenizationConfiguration.html":{"name":"VGSCardNumberTokenizationConfiguration","abstract":"

    VGSCardTokenizationConfiguration - textfield configuration for textfield with type .cardNumber, required for work with tokenization api.

    "},"Classes/VGSExpDateTokenizationConfiguration.html":{"name":"VGSExpDateTokenizationConfiguration","abstract":"

    VGSExpDateTokenizationConfiguration - textfield configuration for textfield with type .expDate, required for work with tokenization api.

    "},"Classes/VGSSSNTokenizationConfiguration.html":{"name":"VGSSSNTokenizationConfiguration","abstract":"

    VGSSSNTokenizationConfiguration - textfield configuration for textfield with type .ssn, required for work with tokenization api.

    "},"Classes/VGSTokenizationConfiguration.html":{"name":"VGSTokenizationConfiguration","abstract":"

    VGSTokenizationConfiguration - textfield configuration for textfield with any type of data, required for work with tokenization api.

    "},"Enums/VGSCollectFieldNameMappingPolicy.html#/flatJSON":{"name":"flatJSON","abstract":"

    Map fieldName to JSON without applying any transformations.","parent_name":"VGSCollectFieldNameMappingPolicy"},"Enums/VGSCollectFieldNameMappingPolicy.html#/nestedJSON":{"name":"nestedJSON","abstract":"

    Map fieldName to nested JSON.","parent_name":"VGSCollectFieldNameMappingPolicy"},"Enums/VGSCollectFieldNameMappingPolicy.html#/nestedJSONWithArrayMerge":{"name":"nestedJSONWithArrayMerge","abstract":"

    Map field name to nested JSON and array if array index is specified.","parent_name":"VGSCollectFieldNameMappingPolicy"},"Enums/VGSCollectFieldNameMappingPolicy.html#/nestedJSONWithArrayOverwrite":{"name":"nestedJSONWithArrayOverwrite","abstract":"

    Map field name to nested JSON and array if array index is specified.","parent_name":"VGSCollectFieldNameMappingPolicy"},"Enums/VGSCardExpDateFormat.html#/shortYear":{"name":"shortYear","abstract":"

    Exp.Date in format mm/yy: 01/22

    ","parent_name":"VGSCardExpDateFormat"},"Enums/VGSCardExpDateFormat.html#/longYear":{"name":"longYear","abstract":"

    Exp.Date in format mm/yyyy: 01/2022

    ","parent_name":"VGSCardExpDateFormat"},"Enums/VGSCardExpDateFormat.html#/shortYearThenMonth":{"name":"shortYearThenMonth","abstract":"

    Exp.Date in format yy/mm: 22/01

    ","parent_name":"VGSCardExpDateFormat"},"Enums/VGSCardExpDateFormat.html#/longYearThenMonth":{"name":"longYearThenMonth","abstract":"

    Exp.Date in format yy/mm: 2022/01

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

    Payment Card Expiration Date Format

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

    Defines fieldName mapping to JSON.

    "},"Structs/VGSCollectLoggingConfiguration.html#/level":{"name":"level","abstract":"

    Log level. Default is .none.

    ","parent_name":"VGSCollectLoggingConfiguration"},"Structs/VGSCollectLoggingConfiguration.html#/isNetworkDebugEnabled":{"name":"isNetworkDebugEnabled","abstract":"

    Bool flag. Specify true to record VGSCollectSDK network session with success/failed requests. Default is false.

    ","parent_name":"VGSCollectLoggingConfiguration"},"Structs/VGSCollectLoggingConfiguration.html#/isExtensiveDebugEnabled":{"name":"isExtensiveDebugEnabled","abstract":"

    Bool flag. Specify true to enable extensive debugging. Default is false.

    ","parent_name":"VGSCollectLoggingConfiguration"},"Enums/VGSLogLevel.html#/info":{"name":"info","abstract":"

    Log all events including errors and warnings.

    ","parent_name":"VGSLogLevel"},"Enums/VGSLogLevel.html#/warning":{"name":"warning","abstract":"

    Log only events indicating warnings and errors.

    ","parent_name":"VGSLogLevel"},"Enums/VGSLogLevel.html#/none":{"name":"none","abstract":"

    Log no events.

    ","parent_name":"VGSLogLevel"},"Classes/VGSCollectLogger.html#/shared":{"name":"shared","abstract":"

    Shared instance.

    ","parent_name":"VGSCollectLogger"},"Classes/VGSCollectLogger.html#/configuration":{"name":"configuration","abstract":"

    Logging configuration. Check VGSCollectLoggingConfiguration for logging options.

    ","parent_name":"VGSCollectLogger"},"Classes/VGSCollectLogger.html#/disableAllLoggers()":{"name":"disableAllLoggers()","abstract":"

    Stop logging all activities.

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

    VGSCollectLogger encapsulates logging logic and debugging options for VGSCollectSDK. Use .configuration property to setup these options. VGSCollectLogger logging implies only printing logs to Xcode console. It doesn’t save logs to persistent store/local file, also it doesn’t send debugging logs to backend services."},"Enums/VGSLogLevel.html":{"name":"VGSLogLevel","abstract":"

    Defines levels of logging.

    "},"Structs/VGSCollectLoggingConfiguration.html":{"name":"VGSCollectLoggingConfiguration","abstract":"

    Holds configuration for VGSCollectSDK logging.

    "},"Error%20Keys.html#/VGSSDKErrorInputDataIsNotValid":{"name":"VGSSDKErrorInputDataIsNotValid","abstract":"

    Error key, used for errors when input data is required to be not empty or to be valid only, but is not valid.

    "},"Error%20Keys.html#/VGSSDKErrorInputDataRequired":{"name":"VGSSDKErrorInputDataRequired","abstract":"

    Error key, used for errors when input data is required to be not empty but is empty or nil.

    "},"Error%20Keys.html#/VGSSDKErrorInputDataRequiredValid":{"name":"VGSSDKErrorInputDataRequiredValid","abstract":"

    Error key, used for errors when input data is required to be valid is not valid.

    "},"Error%20Keys.html#/VGSSDKErrorFileNotFound":{"name":"VGSSDKErrorFileNotFound","abstract":"

    Error key, used for errors when SDK can’t find the file at file path. Can happened when file changes the path or doesn’t exist.

    "},"Error%20Keys.html#/VGSSDKErrorFileTypeNotSupported":{"name":"VGSSDKErrorFileTypeNotSupported","abstract":"

    Error key, used for errors when file type is not supported by SDK.

    "},"Error%20Keys.html#/VGSSDKErrorFileSizeExceedsTheLimit":{"name":"VGSSDKErrorFileSizeExceedsTheLimit","abstract":"

    Error key, used for errors when file size exceeds maximum limit.

    "},"Error%20Keys.html#/VGSSDKErrorSourceNotAvailable":{"name":"VGSSDKErrorSourceNotAvailable","abstract":"

    Error key, used for errors when SDK can’t get access to specific source.

    "},"Error%20Keys.html#/VGSSDKErrorUnexpectedResponseDataFormat":{"name":"VGSSDKErrorUnexpectedResponseDataFormat","abstract":"

    Error key, used for errors when response for SDK API request is in format that not supported by SDK.

    "},"Enums/VGSValidationErrorType.html#/pattern":{"name":"pattern","abstract":"

    Default Validation error for VGSValidationRulePattern

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/length":{"name":"length","abstract":"

    Default Validation error for VGSValidationRuleLength

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/lengthMathes":{"name":"lengthMathes","abstract":"

    Default Validation error for VGSValidationRuleLength

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/expDate":{"name":"expDate","abstract":"

    Default Validation error for VGSValidationRuleCardExpirationDate

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/cardNumber":{"name":"cardNumber","abstract":"

    Default Validation error for VGSValidationRulePaymentCard

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/luhnCheck":{"name":"luhnCheck","abstract":"

    Default Validation error for VGSValidationRuleLuhnCheck

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSErrorType.html#/inputDataIsNotValid":{"name":"inputDataIsNotValid","abstract":"

    When input data is not valid, but required to be valid

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/inputFileNotFound":{"name":"inputFileNotFound","abstract":"

    When can’t find file on device

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/inputFileTypeIsNotSupported":{"name":"inputFileTypeIsNotSupported","abstract":"

    When can’t find file on device

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/inputFileSizeExceedsTheLimit":{"name":"inputFileSizeExceedsTheLimit","abstract":"

    When file size is larger then allowed limit

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/sourceNotAvailable":{"name":"sourceNotAvailable","abstract":"

    When can’t get access to file source

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/unexpectedResponseType":{"name":"unexpectedResponseType","abstract":"

    When response type is not supported

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/unexpectedResponseDataFormat":{"name":"unexpectedResponseDataFormat","abstract":"

    When reponse data format is not supported

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/invalidConfigurationURL":{"name":"invalidConfigurationURL","abstract":"

    When VGS config URL is not valid.

    ","parent_name":"VGSErrorType"},"Classes/VGSError.html#/type":{"name":"type","abstract":"

    VGSErrorType- required for each VGSError instance

    ","parent_name":"VGSError"},"Classes/VGSError.html#/code":{"name":"code","abstract":"

    Code assiciated with VGSErrorType

    ","parent_name":"VGSError"},"Classes/VGSError.html#/init(coder:)":{"name":"init(coder:)","abstract":"

    : nodoc. Public required init.

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

    An error produced by VGSCollectSDK. Works similar to default NSError in iOS.

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

    Type of VGSError and it status code.

    "},"Errors.html#/VGSCollectSDKErrorDomain":{"name":"VGSCollectSDKErrorDomain","abstract":"

    An error domain string used to produce VGSError from VGSCollectSDK - “vgscollect.sdk”

    "},"Errors.html#/VGSValidationError":{"name":"VGSValidationError","abstract":"

    VGS Validation Error object type

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

    Default validation error types

    "},"Enums/CheckSumAlgorithmType.html#/luhn":{"name":"luhn","abstract":"

    Luhn Algorithm

    ","parent_name":"CheckSumAlgorithmType"},"Enums/CheckSumAlgorithmType.html#/validate(_:)":{"name":"validate(_:)","abstract":"

    Validate input String with specified algorithm.

    ","parent_name":"CheckSumAlgorithmType"},"Structs/VGSValidationRuleCardExpirationDate.html#/dateFormat":{"name":"dateFormat","abstract":"

    Payment Card Expiration Date Format

    ","parent_name":"VGSValidationRuleCardExpirationDate"},"Structs/VGSValidationRuleCardExpirationDate.html#/error":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRuleCardExpirationDate"},"Structs/VGSValidationRuleCardExpirationDate.html#/init(dateFormat:error:)":{"name":"init(dateFormat:error:)","abstract":"

    Initialzation

    ","parent_name":"VGSValidationRuleCardExpirationDate"},"Structs/VGSValidationRuleLuhnCheck.html#/error":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRuleLuhnCheck"},"Structs/VGSValidationRuleLuhnCheck.html#/init(error:)":{"name":"init(error:)","abstract":"

    Initialzation

    ","parent_name":"VGSValidationRuleLuhnCheck"},"Structs/VGSValidationRulePaymentCard.html#/error":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRulePaymentCard"},"Structs/VGSValidationRulePaymentCard.html#/validateUnknownCardBrand":{"name":"validateUnknownCardBrand","abstract":"

    Turn on/off validation of cards that are not defined in SDK - CardBrand.unknown

    ","parent_name":"VGSValidationRulePaymentCard"},"Structs/VGSValidationRulePaymentCard.html#/init(error:)":{"name":"init(error:)","abstract":"

    Initialzation

    ","parent_name":"VGSValidationRulePaymentCard"},"Structs/VGSValidationRulePaymentCard.html#/init(error:validateUnknownCardBrand:)":{"name":"init(error:validateUnknownCardBrand:)","abstract":"

    Initialzation

    ","parent_name":"VGSValidationRulePaymentCard"},"Structs/VGSValidationRulePattern.html#/pattern":{"name":"pattern","abstract":"

    Regex pattern

    ","parent_name":"VGSValidationRulePattern"},"Structs/VGSValidationRulePattern.html#/error":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRulePattern"},"Structs/VGSValidationRulePattern.html#/init(pattern:error:)":{"name":"init(pattern:error:)","abstract":"

    Initialzation

    ","parent_name":"VGSValidationRulePattern"},"Structs/VGSValidationRuleLengthMatch.html#/lengths":{"name":"lengths","abstract":"

    Array of valid length ranges

    ","parent_name":"VGSValidationRuleLengthMatch"},"Structs/VGSValidationRuleLengthMatch.html#/error":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRuleLengthMatch"},"Structs/VGSValidationRuleLengthMatch.html#/init(lengths:error:)":{"name":"init(lengths:error:)","abstract":"

    Initialzation

    ","parent_name":"VGSValidationRuleLengthMatch"},"Structs/VGSValidationRuleLength.html#/min":{"name":"min","abstract":"

    Min input length required

    ","parent_name":"VGSValidationRuleLength"},"Structs/VGSValidationRuleLength.html#/max":{"name":"max","abstract":"

    Max input length required

    ","parent_name":"VGSValidationRuleLength"},"Structs/VGSValidationRuleLength.html#/error":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRuleLength"},"Structs/VGSValidationRuleLength.html#/init(min:max:error:)":{"name":"init(min:max:error:)","abstract":"

    Initialzation

    ","parent_name":"VGSValidationRuleLength"},"Structs/VGSValidationRuleSet.html#/init()":{"name":"init()","abstract":"

    Initialzation

    ","parent_name":"VGSValidationRuleSet"},"Structs/VGSValidationRuleSet.html#/init(rules:)":{"name":"init(rules:)","abstract":"

    Initialzation

    ","parent_name":"VGSValidationRuleSet"},"Structs/VGSValidationRuleSet.html#/add(rule:)":{"name":"add(rule:)","abstract":"

    Add validation rule

    ","parent_name":"VGSValidationRuleSet"},"Structs/VGSValidationRuleSet.html":{"name":"VGSValidationRuleSet","abstract":"

    Set of validation rules

    "},"Structs/VGSValidationRuleLength.html":{"name":"VGSValidationRuleLength","abstract":"

    Validate input in scope of length.

    "},"Structs/VGSValidationRuleLengthMatch.html":{"name":"VGSValidationRuleLengthMatch","abstract":"

    Validate input in scope of multiple lengths, e.x.: [16, 19].

    "},"Structs/VGSValidationRulePattern.html":{"name":"VGSValidationRulePattern","abstract":"

    Validate input in scope of matching the pattern(regex).

    "},"Structs/VGSValidationRulePaymentCard.html":{"name":"VGSValidationRulePaymentCard","abstract":"

    Validate input in scope of matching supported card brands, available lengths and checkSum algorithms."},"Structs/VGSValidationRuleLuhnCheck.html":{"name":"VGSValidationRuleLuhnCheck","abstract":"

    Validate input in scope of matching Luhn algorithm.

    "},"Structs/VGSValidationRuleCardExpirationDate.html":{"name":"VGSValidationRuleCardExpirationDate","abstract":"

    Validate input in scope of matching card expiration date format and time range.

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

    Check Sum Algorithm Types

    "},"Structs/VGSExpDateSeparateSerializer.html#/monthFieldName":{"name":"monthFieldName","abstract":"

    Field Name that will be used as a JSON key with month value from expDate string on send request.

    ","parent_name":"VGSExpDateSeparateSerializer"},"Structs/VGSExpDateSeparateSerializer.html#/yearFieldName":{"name":"yearFieldName","abstract":"

    Field Name that will be used as a JSON key with year value from expDate string on send request.

    ","parent_name":"VGSExpDateSeparateSerializer"},"Structs/VGSExpDateSeparateSerializer.html#/init(monthFieldName:yearFieldName:)":{"name":"init(monthFieldName:yearFieldName:)","abstract":"

    Initialization

    ","parent_name":"VGSExpDateSeparateSerializer"},"VGSTextField%20Serializers.html#/VGSFormatSerializerProtocol":{"name":"VGSFormatSerializerProtocol","abstract":"

    Base protocol describing Content Serialization attributes

    "},"Structs/VGSExpDateSeparateSerializer.html":{"name":"VGSExpDateSeparateSerializer","abstract":"

    Expiration Date Separate serializer, split date string to components with separate fieldNames

    "},"Structs/VGSUnknownPaymentCardModel.html#/regex":{"name":"regex","abstract":"

    Regex validating that input contains digits only.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/cardNumberLengths":{"name":"cardNumberLengths","abstract":"

    Valid Unknown Card Numbers Lengths

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/cvcLengths":{"name":"cvcLengths","abstract":"

    Valid Unknown Card CVC/CVV Lengths. For most brands valid cvc lengths is [3], while for Amex is [4]. For unknown brands can be set as [3, 4]

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/checkSumAlgorithm":{"name":"checkSumAlgorithm","abstract":"

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/formatPattern":{"name":"formatPattern","abstract":"

    Unknown Payment Card Numbers visual format pattern. NOTE: format pattern length limits input length.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/brandIcon":{"name":"brandIcon","abstract":"

    Image, associated with Unknown Payment Card Brands.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/cvcIcon":{"name":"cvcIcon","abstract":"

    Image, associated with CVC for Unknown Payment Card Brands.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/brand":{"name":"brand","abstract":"

    Payment Card Brand

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/name":{"name":"name","abstract":"

    Payment Card Name

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/regex":{"name":"regex","abstract":"

    Regex Pattern required to detect Payment Card Brand

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/cardNumberLengths":{"name":"cardNumberLengths","abstract":"

    Valid Card Number Lengths

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/cvcLengths":{"name":"cvcLengths","abstract":"

    Valid Card CVC/CVV Lengths. For most brands valid cvc lengths is [3], while for Amex is [4]. For unknown brands can be set as [3, 4]

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/checkSumAlgorithm":{"name":"checkSumAlgorithm","abstract":"

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/formatPattern":{"name":"formatPattern","abstract":"

    Payment Card Number visual format pattern.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/brandIcon":{"name":"brandIcon","abstract":"

    Image, associated with Payment Card Brand.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/cvcIcon":{"name":"cvcIcon","abstract":"

    Image, associated with CVC for Payment Card Brand.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/init(name:regex:formatPattern:cardNumberLengths:cvcLengths:checkSumAlgorithm:brandIcon:)":{"name":"init(name:regex:formatPattern:cardNumberLengths:cvcLengths:checkSumAlgorithm:brandIcon:)","abstract":"

    Initializer.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/brand":{"name":"brand","abstract":"

    Payment Card Brand

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/name":{"name":"name","abstract":"

    Payment Card Name

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/regex":{"name":"regex","abstract":"

    Regex Pattern required to detect Payment Card Brand

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/cardNumberLengths":{"name":"cardNumberLengths","abstract":"

    Valid Card Number Lengths

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/cvcLengths":{"name":"cvcLengths","abstract":"

    Valid Card CVC/CVV Lengths. For most brands valid cvc lengths is [3], while for Amex is [4]. For unknown brands can be set as [3, 4]

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/checkSumAlgorithm":{"name":"checkSumAlgorithm","abstract":"

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/formatPattern":{"name":"formatPattern","abstract":"

    Payment Card Number visual format pattern.

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/brandIcon":{"name":"brandIcon","abstract":"

    Image, associated with Payment Card Brand.

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/cvcIcon":{"name":"cvcIcon","abstract":"

    Image, associated with CVC for Payment Card Brand.

    ","parent_name":"VGSPaymentCardModel"},"Classes/VGSPaymentCards/CardBrand.html#/elo":{"name":"elo","abstract":"

    ELO

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/visaElectron":{"name":"visaElectron","abstract":"

    Visa Electron

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/maestro":{"name":"maestro","abstract":"

    Maestro

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/forbrugsforeningen":{"name":"forbrugsforeningen","abstract":"

    Forbrugsforeningen

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/dankort":{"name":"dankort","abstract":"

    Dankort

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/visa":{"name":"visa","abstract":"

    Visa

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/mastercard":{"name":"mastercard","abstract":"

    Mastercard

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/amex":{"name":"amex","abstract":"

    American Express

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/hipercard":{"name":"hipercard","abstract":"

    Hipercard

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/dinersClub":{"name":"dinersClub","abstract":"

    Diners Club

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/discover":{"name":"discover","abstract":"

    Discover

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/unionpay":{"name":"unionpay","abstract":"

    UnionPay

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/jcb":{"name":"jcb","abstract":"

    JCB

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/unknown":{"name":"unknown","abstract":"

    Not supported card brand - “unknown”

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/custom(brandName:)":{"name":"custom(brandName:)","abstract":"

    Custom Payment Card Brand. Should have unique brandName.

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/cvcFormatPattern":{"name":"cvcFormatPattern","abstract":"

    no:doc

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/brandIcon":{"name":"brandIcon","abstract":"

    no:doc

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/cvcIcon":{"name":"cvcIcon","abstract":"

    no:doc

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/stringValue":{"name":"stringValue","abstract":"

    String representation of VGSPaymentCards.CardBrand enum values.

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/cardLengths":{"name":"cardLengths","abstract":"

    Returns array with valid card number lengths for specific VGSPaymentCards.CardBrand

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html":{"name":"CardBrand","abstract":"

    Supported card brands

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/elo":{"name":"elo","abstract":"

    Elo Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/visaElectron":{"name":"visaElectron","abstract":"

    Visa Electron Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/maestro":{"name":"maestro","abstract":"

    Maestro Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/forbrugsforeningen":{"name":"forbrugsforeningen","abstract":"

    Forbrugsforeningen Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/dankort":{"name":"dankort","abstract":"

    Dankort Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/visa":{"name":"visa","abstract":"

    Elo Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/masterCard":{"name":"masterCard","abstract":"

    Master Card Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/amex":{"name":"amex","abstract":"

    Amex Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/hipercard":{"name":"hipercard","abstract":"

    Hipercard Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/dinersClub":{"name":"dinersClub","abstract":"

    DinersClub Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/discover":{"name":"discover","abstract":"

    Discover Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/unionpay":{"name":"unionpay","abstract":"

    UnionPay Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/jcb":{"name":"jcb","abstract":"

    JCB Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/unknown":{"name":"unknown","abstract":"

    Unknown Brand Payment Card Model. Can be used for specifing cards details when VGSValidationRulePaymentCard requires validating CardBrand.unknown cards.

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/cutomPaymentCardModels":{"name":"cutomPaymentCardModels","abstract":"

    Array of Custom Payment Card Models.

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/validCardBrands":{"name":"validCardBrands","abstract":"

    An array of valid Card Brands, could include custom and default brands. If not set, will use availableCardBrands array instead.

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/getCardModelFromAvailableModels(brand:)":{"name":"getCardModelFromAvailableModels(brand:)","abstract":"

    no:doc

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/detectCardBrandFromAvailableCards(input:)":{"name":"detectCardBrandFromAvailableCards(input:)","abstract":"

    no:doc

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

    Class responsible for storing and managing Payment Cards in SDK.

    "},"Structs/VGSPaymentCardModel.html":{"name":"VGSPaymentCardModel","abstract":"

    An object representing Payment Card

    "},"Structs/VGSCustomPaymentCardModel.html":{"name":"VGSCustomPaymentCardModel","abstract":"

    Holds information for custom payment model.

    "},"Structs/VGSUnknownPaymentCardModel.html":{"name":"VGSUnknownPaymentCardModel","abstract":"

    An object representing Unknown Payment Cards - cards not defined in the SDK. Object is used when validation forCardBrand.unknown is set as true. Check VGSValidationRulePaymentCard for more details. Validation attributes can be edited through `VGSPaymentCards.unknown model.

    "},"Structs/VGSCollectRequestOptions.html#/fieldNameMappingPolicy":{"name":"fieldNameMappingPolicy","abstract":"

    Defines how to map fieldNames to JSON. Default is .nestedJSON.

    ","parent_name":"VGSCollectRequestOptions"},"Structs/VGSCollectRequestOptions.html#/init()":{"name":"init()","abstract":"

    Initializer.

    ","parent_name":"VGSCollectRequestOptions"},"Enums/VGSResponse.html#/success(_:_:_:)":{"name":"success(_:_:_:)","abstract":"

    Success response case

    ","parent_name":"VGSResponse"},"Enums/VGSResponse.html#/failure(_:_:_:_:)":{"name":"failure(_:_:_:_:)","abstract":"

    Failed response case

    ","parent_name":"VGSResponse"},"Classes/CardState.html#/last4":{"name":"last4","abstract":"

    Last 4 digits of the valid card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    ","parent_name":"CardState"},"Classes/CardState.html#/bin":{"name":"bin","abstract":"

    Bin digits of the valid card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    ","parent_name":"CardState"},"Classes/CardState.html#/cardBrand":{"name":"cardBrand","abstract":"

    Credit Card Brand of the card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    ","parent_name":"CardState"},"Classes/CardState.html#/description":{"name":"description","abstract":"

    Message that contains CardState attributes and their values.

    ","parent_name":"CardState"},"Classes/SSNState.html#/last4":{"name":"last4","abstract":"

    Last 4 digits of the valid ssn from associated VGSTextField with field configuration type FieldType.ssn.

    ","parent_name":"SSNState"},"Classes/SSNState.html#/description":{"name":"description","abstract":"

    Message that contains SSNState attributes and their values.

    ","parent_name":"SSNState"},"Classes/State.html#/fieldName":{"name":"fieldName","abstract":"

    VGSConfiguration.fieldName associated with VGSTextField

    ","parent_name":"State"},"Classes/State.html#/isRequired":{"name":"isRequired","abstract":"

    VGSConfiguration.isRequired attribute defined for VGSTextField

    ","parent_name":"State"},"Classes/State.html#/isRequiredValidOnly":{"name":"isRequiredValidOnly","abstract":"

    VGSConfiguration.isRequiredValidOnly attribute defined for VGSTextField

    ","parent_name":"State"},"Classes/State.html#/isValid":{"name":"isValid","abstract":"

    Contains current validation state for VGSTextField

    ","parent_name":"State"},"Classes/State.html#/isEmpty":{"name":"isEmpty","abstract":"

    Show if VGSTextField input is empty

    ","parent_name":"State"},"Classes/State.html#/isDirty":{"name":"isDirty","abstract":"

    Show if VGSTextField was edited

    ","parent_name":"State"},"Classes/State.html#/inputLength":{"name":"inputLength","abstract":"

    Input data length in VGSTextField

    ","parent_name":"State"},"Classes/State.html#/validationErrors":{"name":"validationErrors","abstract":"

    Array of VGSValidationError. Should be empty when textfield input is valid.

    ","parent_name":"State"},"Classes/State.html#/description":{"name":"description","abstract":"

    Message that contains State attributes and their values

    ","parent_name":"State"},"Enums/Environment.html#/sandbox":{"name":"sandbox","abstract":"

    Should be used for development and testing purpose.

    ","parent_name":"Environment"},"Enums/Environment.html#/live":{"name":"live","abstract":"

    Should be used for production.

    ","parent_name":"Environment"},"Classes/VGSCollect.html#/customHeaders":{"name":"customHeaders","abstract":"

    Set your custom HTTP headers.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/observeFieldState":{"name":"observeFieldState","abstract":"

    Observe only focused VGSTextField on editing events.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/observeStates":{"name":"observeStates","abstract":"

    Observe all VGSTextField on editing events.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/textFields":{"name":"textFields","abstract":"

    Returns array of VGSTextFields associated with VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/init(id:environment:hostname:satellitePort:)":{"name":"init(id:environment:hostname:satellitePort:)","abstract":"

    Initialzation.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/init(id:environment:dataRegion:hostname:satellitePort:)":{"name":"init(id:environment:dataRegion:hostname:satellitePort:)","abstract":"

    Initialzation.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/getTextField(fieldName:)":{"name":"getTextField(fieldName:)","abstract":"

    Returns VGSTextField with VGSConfiguration.fieldName associated with VGCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/unsubscribeTextField(_:)":{"name":"unsubscribeTextField(_:)","abstract":"

    Unasubscribe VGSTextField from VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/unsubscribeTextFields(_:)":{"name":"unsubscribeTextFields(_:)","abstract":"

    Unasubscribe VGSTextFields from VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/unsubscribeAllTextFields()":{"name":"unsubscribeAllTextFields()","abstract":"

    Unasubscribe all VGSTextFields from VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/cleanFiles()":{"name":"cleanFiles()","abstract":"

    Detach files for associated VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/sendData(path:method:routeId:extraData:requestOptions:completion:)":{"name":"sendData(path:method:routeId:extraData:requestOptions:completion:)","abstract":"

    Send data from VGSTextFields to your organization vault.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/sendFile(path:method:routeId:extraData:completion:)":{"name":"sendFile(path:method:routeId:extraData:completion:)","abstract":"

    Send file to your organization vault. Only send one file at a time.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/tokenizeData(routeId:completion:)":{"name":"tokenizeData(routeId:completion:)","abstract":"

    Makes tokenization response with data from VGSTextFields.

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

    An object you use for observing VGSTextField State and send data to your organization vault.

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

    Organization vault environment.

    "},"Classes/State.html":{"name":"State","abstract":"

    An object that describes VGSTextField state. State attributes are read-only.

    "},"Classes/SSNState.html":{"name":"SSNState","abstract":"

    An object that describes VGSTextField state with configuration FieldType.ssn . State attributes are read-only.

    "},"Classes/CardState.html":{"name":"CardState","abstract":"

    An object that describes VGSTextField state with configuration FieldType.cardNumber . State attributes are read-only.

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

    Response enum cases for SDK requests.

    "},"Structs/VGSCollectRequestOptions.html":{"name":"VGSCollectRequestOptions","abstract":"

    Request options.

    "},"Observe%20State%20and%20Send%20Data.html#/JsonData":{"name":"JsonData","abstract":"

    Key-value data type, usually used for response format.

    "},"Observe%20State%20and%20Send%20Data.html#/HTTPHeaders":{"name":"HTTPHeaders","abstract":"

    Key-value data type, used in http request headers.

    "},"Classes/VGSFileInfo.html#/fileExtension":{"name":"fileExtension","abstract":"

    File extension, like “jpeg”, “png”, etc.

    ","parent_name":"VGSFileInfo"},"Classes/VGSFileInfo.html#/size":{"name":"size","abstract":"

    File size.

    ","parent_name":"VGSFileInfo"},"Classes/VGSFileInfo.html#/sizeUnits":{"name":"sizeUnits","abstract":"

    File size units.

    ","parent_name":"VGSFileInfo"},"Enums/VGSFileSource.html#/photoLibrary":{"name":"photoLibrary","abstract":"

    Device photo library.

    ","parent_name":"VGSFileSource"},"Enums/VGSFileSource.html#/camera":{"name":"camera","abstract":"

    Device camera.

    ","parent_name":"VGSFileSource"},"Enums/VGSFileSource.html#/documentsDirectory":{"name":"documentsDirectory","abstract":"

    Device documents directory.

    ","parent_name":"VGSFileSource"},"Protocols/VGSFilePickerControllerDelegate.html#/userDidPickFileWithInfo(_:)":{"name":"userDidPickFileWithInfo(_:)","abstract":"

    On user select a file

    ","parent_name":"VGSFilePickerControllerDelegate"},"Protocols/VGSFilePickerControllerDelegate.html#/userDidSCancelFilePicking()":{"name":"userDidSCancelFilePicking()","abstract":"

    On user canceling file picking

    ","parent_name":"VGSFilePickerControllerDelegate"},"Protocols/VGSFilePickerControllerDelegate.html#/filePickingFailedWithError(_:)":{"name":"filePickingFailedWithError(_:)","abstract":"

    On error occured when user pick a file.

    ","parent_name":"VGSFilePickerControllerDelegate"},"Classes/VGSFilePickerConfiguration.html#/fieldName":{"name":"fieldName","abstract":"

    Name that will be associated with selected file by user. Used as a JSON key on send request with file data to your organozation vault.

    ","parent_name":"VGSFilePickerConfiguration"},"Classes/VGSFilePickerConfiguration.html#/init(collector:fieldName:fileSource:)":{"name":"init(collector:fieldName:fileSource:)","abstract":"

    Initialization

    ","parent_name":"VGSFilePickerConfiguration"},"Classes/VGSFilePickerController.html#/delegate":{"name":"delegate","abstract":"

    VGSFilePickerControllerDelegate - handle user interaction on file picking.

    ","parent_name":"VGSFilePickerController"},"Classes/VGSFilePickerController.html#/init(configuration:)":{"name":"init(configuration:)","abstract":"

    Initialization

    ","parent_name":"VGSFilePickerController"},"Classes/VGSFilePickerController.html#/presentFilePicker(on:animated:completion:)":{"name":"presentFilePicker(on:animated:completion:)","abstract":"

    Present file picker view

    ","parent_name":"VGSFilePickerController"},"Classes/VGSFilePickerController.html#/dismissFilePicker(animated:completion:)":{"name":"dismissFilePicker(animated:completion:)","abstract":"

    Dismiss file picker view

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

    Controller responsible for importing files from device sources.

    "},"Classes/VGSFilePickerConfiguration.html":{"name":"VGSFilePickerConfiguration","abstract":"

    A class responsible for configuration VGSFilePickerController.

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

    Delegates produced by VGSFilePickerController.

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

    Available file source destinations that VGSFilePickerController can work with.

    "},"Classes/VGSFileInfo.html":{"name":"VGSFileInfo","abstract":"

    An object that holds optional files’ metadata on selecting file through VGSFilePickerController.

    "},"Enums/FieldType.html#/none":{"name":"none","abstract":"

    Field type that doesn’t require any input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/cardNumber":{"name":"cardNumber","abstract":"

    Field type that requires Credit Card Number input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/expDate":{"name":"expDate","abstract":"

    Field type that requires Expiration Date input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/cvc":{"name":"cvc","abstract":"

    Field type that requires Credit Card CVC input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/cardHolderName":{"name":"cardHolderName","abstract":"

    Field type that requires Cardholder Name input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/ssn":{"name":"ssn","abstract":"

    Field type that requires US Social Security Number input formatting and validation.

    ","parent_name":"FieldType"},"Classes/VGSExpDateConfiguration.html#/type":{"name":"type","abstract":"

    FieldType.expDate type of VGSTextField configuration.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSExpDateConfiguration.html#/inputSource":{"name":"inputSource","abstract":"

    Input Source type. Default is VGSTextFieldInputSource.datePicker.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSExpDateConfiguration.html#/inputDateFormat":{"name":"inputDateFormat","abstract":"

    Input date format to convert.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSExpDateConfiguration.html#/outputDateFormat":{"name":"outputDateFormat","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSExpDateConfiguration.html#/serializers":{"name":"serializers","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSConfiguration.html#/vgsCollector":{"name":"vgsCollector","abstract":"

    Collect form that will be assiciated with VGSTextField.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/type":{"name":"type","abstract":"

    Type of field congfiguration. Default is FieldType.none.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/fieldName":{"name":"fieldName","abstract":"

    Name that will be associated with VGSTextField and used as a JSON key on send request with textfield data to your organozation vault.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/isRequired":{"name":"isRequired","abstract":"

    Set if VGSTextField is required to be non-empty and non-nil on send request. Default is false.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/isRequiredValidOnly":{"name":"isRequiredValidOnly","abstract":"

    Set if VGSTextField is required to be valid only on send request. Default is false.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/formatPattern":{"name":"formatPattern","abstract":"

    Input data visual format pattern. If not applied, will be set by default depending on field type.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/divider":{"name":"divider","abstract":"

    String, used to replace not default VGSConfiguration.formatPattern characters in input text on send request.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/keyboardType":{"name":"keyboardType","abstract":"

    Preferred UIKeyboardType for VGSTextField. If not applied, will be set by default depending on field type parameter.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/returnKeyType":{"name":"returnKeyType","abstract":"

    Preferred UIReturnKeyType for VGSTextField.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/keyboardAppearance":{"name":"keyboardAppearance","abstract":"

    Preferred UIKeyboardAppearance for textfield. By default is UIKeyboardAppearance.default.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/validationRules":{"name":"validationRules","abstract":"

    Validation rules for field input. Defines State.isValide result.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/maxInputLength":{"name":"maxInputLength","abstract":"

    Max input length. IMPORTANT! Can conflict with .formatPattern attribute.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/init(collector:fieldName:)":{"name":"init(collector:fieldName:)","abstract":"

    Initialization

    ","parent_name":"VGSConfiguration"},"Protocols/VGSTextFieldDelegate.html#/vgsTextFieldDidBeginEditing(_:)":{"name":"vgsTextFieldDidBeginEditing(_:)","abstract":"

    VGSTextField did become first responder.

    ","parent_name":"VGSTextFieldDelegate"},"Protocols/VGSTextFieldDelegate.html#/vgsTextFieldDidEndEditing(_:)":{"name":"vgsTextFieldDidEndEditing(_:)","abstract":"

    VGSTextField did resign first responder.

    ","parent_name":"VGSTextFieldDelegate"},"Protocols/VGSTextFieldDelegate.html#/vgsTextFieldDidEndEditingOnReturn(_:)":{"name":"vgsTextFieldDidEndEditingOnReturn(_:)","abstract":"

    VGSTextField did resign first responder on Return button pressed.

    ","parent_name":"VGSTextFieldDelegate"},"Protocols/VGSTextFieldDelegate.html#/vgsTextFieldDidChange(_:)":{"name":"vgsTextFieldDidChange(_:)","abstract":"

    VGSTextField input changed.

    ","parent_name":"VGSTextFieldDelegate"},"Classes/VGSCVCTextField/CVCIconLocation.html#/left":{"name":"left","abstract":"

    CVC icon at left side of VGSCardTextField.

    ","parent_name":"CVCIconLocation"},"Classes/VGSCVCTextField/CVCIconLocation.html#/right":{"name":"right","abstract":"

    CVC icon at right side of VGSCardTextField.

    ","parent_name":"CVCIconLocation"},"Classes/VGSCVCTextField/CVCIconLocation.html":{"name":"CVCIconLocation","abstract":"

    Available CVC icon positions enum.

    ","parent_name":"VGSCVCTextField"},"Classes/VGSCVCTextField.html#/cvcIconLocation":{"name":"cvcIconLocation","abstract":"

    CVC icon position inside VGSCardTextField.

    ","parent_name":"VGSCVCTextField"},"Classes/VGSCVCTextField.html#/cvcIconSize":{"name":"cvcIconSize","abstract":"

    CVC icon size.

    ","parent_name":"VGSCVCTextField"},"Classes/VGSCVCTextField.html#/cvcIconSource":{"name":"cvcIconSource","abstract":"

    Asks custom image for specific VGSPaymentCards.CardBrand

    ","parent_name":"VGSCVCTextField"},"Classes/VGSExpDateTextField/YearFormat.html#/short":{"name":"short","abstract":"

    Two digits year format, e.g.: 21

    ","parent_name":"YearFormat"},"Classes/VGSExpDateTextField/YearFormat.html#/long":{"name":"long","abstract":"

    Four digits year format:, e.g.:2021

    ","parent_name":"YearFormat"},"Classes/VGSExpDateTextField/MonthFormat.html#/shortSymbols":{"name":"shortSymbols","abstract":"

    Short month name, e.g.: Jan

    ","parent_name":"MonthFormat"},"Classes/VGSExpDateTextField/MonthFormat.html#/longSymbols":{"name":"longSymbols","abstract":"

    Long month name, e.g.: January

    ","parent_name":"MonthFormat"},"Classes/VGSExpDateTextField/MonthFormat.html#/numbers":{"name":"numbers","abstract":"

    Month number: e.g.: 01

    ","parent_name":"MonthFormat"},"Classes/VGSExpDateTextField/MonthFormat.html":{"name":"MonthFormat","abstract":"

    Available Month Label formats in UIPickerView

    ","parent_name":"VGSExpDateTextField"},"Classes/VGSExpDateTextField/YearFormat.html":{"name":"YearFormat","abstract":"

    Available Year Label formats in UIPickerView

    ","parent_name":"VGSExpDateTextField"},"Classes/VGSExpDateTextField.html#/monthPickerFormat":{"name":"monthPickerFormat","abstract":"

    UIPickerView Month Label format

    ","parent_name":"VGSExpDateTextField"},"Classes/VGSExpDateTextField.html#/yearPickeFormat":{"name":"yearPickeFormat","abstract":"

    UIPickerView Year Label format

    ","parent_name":"VGSExpDateTextField"},"Classes/VGSCardTextField/CardIconLocation.html#/left":{"name":"left","abstract":"

    Card brand icon at left side of VGSCardTextField.

    ","parent_name":"CardIconLocation"},"Classes/VGSCardTextField/CardIconLocation.html#/right":{"name":"right","abstract":"

    Card brand icon at right side of VGSCardTextField.

    ","parent_name":"CardIconLocation"},"Classes/VGSCardTextField/CardIconLocation.html":{"name":"CardIconLocation","abstract":"

    Available Card brand icon positions enum.

    ","parent_name":"VGSCardTextField"},"Classes/VGSCardTextField.html#/cardIconLocation":{"name":"cardIconLocation","abstract":"

    Card brand icon position inside VGSCardTextField.

    ","parent_name":"VGSCardTextField"},"Classes/VGSCardTextField.html#/cardIconSize":{"name":"cardIconSize","abstract":"

    Card brand icon size.

    ","parent_name":"VGSCardTextField"},"Classes/VGSCardTextField.html#/cardsIconSource":{"name":"cardsIconSource","abstract":"

    Asks custom image for specific VGSPaymentCards.CardBrand

    ","parent_name":"VGSCardTextField"},"Classes/VGSTextField.html#/placeholder":{"name":"placeholder","abstract":"

    Textfield placeholder string.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/autocapitalizationType":{"name":"autocapitalizationType","abstract":"

    Textfield autocapitalization type. Default is .sentences.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/spellCheckingType":{"name":"spellCheckingType","abstract":"

    Textfield spell checking type. Default is UITextSpellCheckingType.default.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/attributedPlaceholder":{"name":"attributedPlaceholder","abstract":"

    Textfield attributedPlaceholder string.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/padding":{"name":"padding","abstract":"

    UIEdgeInsets for text and placeholder inside VGSTextField.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/textAlignment":{"name":"textAlignment","abstract":"

    The technique to use for aligning the text.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/clearButtonMode":{"name":"clearButtonMode","abstract":"

    Sets when the clear button shows up. Default is UITextField.ViewMode.never

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/isSecureTextEntry":{"name":"isSecureTextEntry","abstract":"

    Identifies whether the text object should disable text copying and in some cases hide the text being entered. Default is false.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/adjustsFontForContentSizeCategory":{"name":"adjustsFontForContentSizeCategory","abstract":"

    Indicates whether VGSTextField should automatically update its font when the device’s UIContentSizeCategory is changed.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/keyboardAccessoryView":{"name":"keyboardAccessoryView","abstract":"

    Input Accessory View

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/autocorrectionType":{"name":"autocorrectionType","abstract":"

    Determines whether autocorrection is enabled or disabled during typing.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/textFieldAccessibilityLabel":{"name":"textFieldAccessibilityLabel","abstract":"

    A succinct label in a localized string that identifies the accessibility text field.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/textFieldAccessibilityHint":{"name":"textFieldAccessibilityHint","abstract":"

    A localized string that contains a brief description of the result of performing an action on the accessibility text field.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/configuration":{"name":"configuration","abstract":"

    Specifies VGSTextField configuration parameters to work with VGSCollect.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/delegate":{"name":"delegate","abstract":"

    Delegates VGSTextField editing events. Default is nil.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/setDefaultText(_:)":{"name":"setDefaultText(_:)","abstract":"

    Set textfield default text.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/cleanText()":{"name":"cleanText()","abstract":"

    Removes input from field.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/isContentEqual(_:)":{"name":"isContentEqual(_:)","abstract":"

    Check if input text in two textfields is same. Returns Bool.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/font":{"name":"font","abstract":"

    VGSTextField text font

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/textColor":{"name":"textColor","abstract":"

    VGSTextField text color

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/cornerRadius":{"name":"cornerRadius","abstract":"

    VGSTextField layer corner radius

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/borderWidth":{"name":"borderWidth","abstract":"

    VGSTextField layer borderWidth

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/borderColor":{"name":"borderColor","abstract":"

    VGSTextField layer borderColor

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/becomeFirstResponder()":{"name":"becomeFirstResponder()","abstract":"

    Make VGSTextField focused.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/resignFirstResponder()":{"name":"resignFirstResponder()","abstract":"

    Remove focus from VGSTextField.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/isFirstResponder":{"name":"isFirstResponder","abstract":"

    Check if VGSTextField is focused.

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

    An object that displays an editable text area in user interface.

    "},"Classes/VGSCardTextField.html":{"name":"VGSCardTextField","abstract":"

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to detect and show credit card brand images.

    "},"Classes/VGSExpDateTextField.html":{"name":"VGSExpDateTextField","abstract":"

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to show picker view with Card Number Expiration Month and Year.

    "},"Classes/VGSCVCTextField.html":{"name":"VGSCVCTextField","abstract":"

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to show CVC/CVV images for credit card brands.

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

    Delegates produced by VGSTextField instance.

    "},"Classes/VGSConfiguration.html":{"name":"VGSConfiguration","abstract":"

    A class responsible for configuration VGSTextField.

    "},"Classes/VGSExpDateConfiguration.html":{"name":"VGSExpDateConfiguration","abstract":"

    A class responsible for configuration VGSTextField with fieldType = .expDate. Extends VGSConfiguration class.

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

    Type of VGSTextField configuration.

    "},"UI%20Elements.html":{"name":"UI Elements"},"File%20Picker.html":{"name":"File Picker"},"Observe%20State%20and%20Send%20Data.html":{"name":"Observe State and Send Data"},"Payment%20Cards.html":{"name":"Payment Cards"},"VGSTextField%20Serializers.html":{"name":"VGSTextField Serializers"},"Validation%20Rules.html":{"name":"Validation Rules"},"Errors.html":{"name":"Errors"},"Error%20Keys.html":{"name":"Error Keys"},"Debugging.html":{"name":"Debugging"},"Enumerations.html":{"name":"Enumerations"},"Other%20Classes.html":{"name":"Other Classes","abstract":"

    The following classes are available globally.

    "},"Other%20Enums.html":{"name":"Other Enumerations","abstract":"

    The following enumerations are available globally.

    "},"Other%20Extensions.html":{"name":"Other Extensions","abstract":"

    The following extensions are available globally.

    "},"Other%20Protocols.html":{"name":"Other Protocols","abstract":"

    The following protocols are available globally.

    "},"Other%20Structs.html":{"name":"Other Structures","abstract":"

    The following structures are available globally.

    "}} \ No newline at end of file +{"Enums/VGSCollectFieldNameMappingPolicy.html#/s:13VGSCollectSDK0A22FieldNameMappingPolicyO8flatJSONyA2CmF":{"name":"flatJSON","abstract":"

    Map fieldName to JSON without applying any transformations.","parent_name":"VGSCollectFieldNameMappingPolicy"},"Enums/VGSCollectFieldNameMappingPolicy.html#/s:13VGSCollectSDK0A22FieldNameMappingPolicyO10nestedJSONyA2CmF":{"name":"nestedJSON","abstract":"

    Map fieldName to nested JSON.","parent_name":"VGSCollectFieldNameMappingPolicy"},"Enums/VGSCollectFieldNameMappingPolicy.html#/s:13VGSCollectSDK0A22FieldNameMappingPolicyO24nestedJSONWithArrayMergeyA2CmF":{"name":"nestedJSONWithArrayMerge","abstract":"

    Map field name to nested JSON and array if array index is specified.","parent_name":"VGSCollectFieldNameMappingPolicy"},"Enums/VGSCollectFieldNameMappingPolicy.html#/s:13VGSCollectSDK0A22FieldNameMappingPolicyO28nestedJSONWithArrayOverwriteyA2CmF":{"name":"nestedJSONWithArrayOverwrite","abstract":"

    Map field name to nested JSON and array if array index is specified.","parent_name":"VGSCollectFieldNameMappingPolicy"},"Enums/VGSCardExpDateFormat.html#/s:13VGSCollectSDK20VGSCardExpDateFormatO9shortYearyA2CmF":{"name":"shortYear","abstract":"

    Exp.Date in format mm/yy: 01/22

    ","parent_name":"VGSCardExpDateFormat"},"Enums/VGSCardExpDateFormat.html#/s:13VGSCollectSDK20VGSCardExpDateFormatO8longYearyA2CmF":{"name":"longYear","abstract":"

    Exp.Date in format mm/yyyy: 01/2022

    ","parent_name":"VGSCardExpDateFormat"},"Enums/VGSCardExpDateFormat.html#/s:13VGSCollectSDK20VGSCardExpDateFormatO18shortYearThenMonthyA2CmF":{"name":"shortYearThenMonth","abstract":"

    Exp.Date in format yy/mm: 22/01

    ","parent_name":"VGSCardExpDateFormat"},"Enums/VGSCardExpDateFormat.html#/s:13VGSCollectSDK20VGSCardExpDateFormatO17longYearThenMonthyA2CmF":{"name":"longYearThenMonth","abstract":"

    Exp.Date in format yy/mm: 2022/01

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

    Payment Card Expiration Date Format

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

    Defines fieldName mapping to JSON.

    "},"Structs/VGSCollectLoggingConfiguration.html#/s:13VGSCollectSDK0A20LoggingConfigurationV5levelAA11VGSLogLevelOvp":{"name":"level","abstract":"

    Log level. Default is .none.

    ","parent_name":"VGSCollectLoggingConfiguration"},"Structs/VGSCollectLoggingConfiguration.html#/s:13VGSCollectSDK0A20LoggingConfigurationV21isNetworkDebugEnabledSbvp":{"name":"isNetworkDebugEnabled","abstract":"

    Bool flag. Specify true to record VGSCollectSDK network session with success/failed requests. Default is false.

    ","parent_name":"VGSCollectLoggingConfiguration"},"Structs/VGSCollectLoggingConfiguration.html#/s:13VGSCollectSDK0A20LoggingConfigurationV23isExtensiveDebugEnabledSbvp":{"name":"isExtensiveDebugEnabled","abstract":"

    Bool flag. Specify true to enable extensive debugging. Default is false.

    ","parent_name":"VGSCollectLoggingConfiguration"},"Enums/VGSLogLevel.html#/s:13VGSCollectSDK11VGSLogLevelO4infoyA2CmF":{"name":"info","abstract":"

    Log all events including errors and warnings.

    ","parent_name":"VGSLogLevel"},"Enums/VGSLogLevel.html#/s:13VGSCollectSDK11VGSLogLevelO7warningyA2CmF":{"name":"warning","abstract":"

    Log only events indicating warnings and errors.

    ","parent_name":"VGSLogLevel"},"Enums/VGSLogLevel.html#/s:13VGSCollectSDK11VGSLogLevelO4noneyA2CmF":{"name":"none","abstract":"

    Log no events.

    ","parent_name":"VGSLogLevel"},"Classes/VGSCollectLogger.html#/s:13VGSCollectSDK0A6LoggerC6sharedACvpZ":{"name":"shared","abstract":"

    Shared instance.

    ","parent_name":"VGSCollectLogger"},"Classes/VGSCollectLogger.html#/s:13VGSCollectSDK0A6LoggerC13configurationAA0A20LoggingConfigurationVvp":{"name":"configuration","abstract":"

    Logging configuration. Check VGSCollectLoggingConfiguration for logging options.

    ","parent_name":"VGSCollectLogger"},"Classes/VGSCollectLogger.html#/s:13VGSCollectSDK0A6LoggerC17disableAllLoggersyyF":{"name":"disableAllLoggers()","abstract":"

    Stop logging all activities.

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

    VGSCollectLogger encapsulates logging logic and debugging options for VGSCollectSDK. Use .configuration property to setup these options. VGSCollectLogger logging implies only printing logs to Xcode console. It doesn’t save logs to persistent store/local file, also it doesn’t send debugging logs to backend services."},"Enums/VGSLogLevel.html":{"name":"VGSLogLevel","abstract":"

    Defines levels of logging.

    "},"Structs/VGSCollectLoggingConfiguration.html":{"name":"VGSCollectLoggingConfiguration","abstract":"

    Holds configuration for VGSCollectSDK logging.

    "},"Error%20Keys.html#/s:13VGSCollectSDK30VGSSDKErrorInputDataIsNotValidSSvp":{"name":"VGSSDKErrorInputDataIsNotValid","abstract":"

    Error key, used for errors when input data is required to be not empty or to be valid only, but is not valid.

    "},"Error%20Keys.html#/s:13VGSCollectSDK28VGSSDKErrorInputDataRequiredSSvp":{"name":"VGSSDKErrorInputDataRequired","abstract":"

    Error key, used for errors when input data is required to be not empty but is empty or nil.

    "},"Error%20Keys.html#/s:13VGSCollectSDK33VGSSDKErrorInputDataRequiredValidSSvp":{"name":"VGSSDKErrorInputDataRequiredValid","abstract":"

    Error key, used for errors when input data is required to be valid is not valid.

    "},"Error%20Keys.html#/s:13VGSCollectSDK23VGSSDKErrorFileNotFoundSSvp":{"name":"VGSSDKErrorFileNotFound","abstract":"

    Error key, used for errors when SDK can’t find the file at file path. Can happened when file changes the path or doesn’t exist.

    "},"Error%20Keys.html#/s:13VGSCollectSDK31VGSSDKErrorFileTypeNotSupportedSSvp":{"name":"VGSSDKErrorFileTypeNotSupported","abstract":"

    Error key, used for errors when file type is not supported by SDK.

    "},"Error%20Keys.html#/s:13VGSCollectSDK34VGSSDKErrorFileSizeExceedsTheLimitSSvp":{"name":"VGSSDKErrorFileSizeExceedsTheLimit","abstract":"

    Error key, used for errors when file size exceeds maximum limit.

    "},"Error%20Keys.html#/s:13VGSCollectSDK29VGSSDKErrorSourceNotAvailableSSvp":{"name":"VGSSDKErrorSourceNotAvailable","abstract":"

    Error key, used for errors when SDK can’t get access to specific source.

    "},"Error%20Keys.html#/s:13VGSCollectSDK39VGSSDKErrorUnexpectedResponseDataFormatSSvp":{"name":"VGSSDKErrorUnexpectedResponseDataFormat","abstract":"

    Error key, used for errors when response for SDK API request is in format that not supported by SDK.

    "},"Enums/VGSValidationErrorType.html#/s:13VGSCollectSDK22VGSValidationErrorTypeO7patternyA2CmF":{"name":"pattern","abstract":"

    Default Validation error for VGSValidationRulePattern

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/s:13VGSCollectSDK22VGSValidationErrorTypeO6lengthyA2CmF":{"name":"length","abstract":"

    Default Validation error for VGSValidationRuleLength

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/s:13VGSCollectSDK22VGSValidationErrorTypeO12lengthMathesyA2CmF":{"name":"lengthMathes","abstract":"

    Default Validation error for VGSValidationRuleLength

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/s:13VGSCollectSDK22VGSValidationErrorTypeO7expDateyA2CmF":{"name":"expDate","abstract":"

    Default Validation error for VGSValidationRuleCardExpirationDate

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/s:13VGSCollectSDK22VGSValidationErrorTypeO4dateyA2CmF":{"name":"date","abstract":"

    Default Validation error for VGSValidationRuleDateRange

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/s:13VGSCollectSDK22VGSValidationErrorTypeO10cardNumberyA2CmF":{"name":"cardNumber","abstract":"

    Default Validation error for VGSValidationRulePaymentCard

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSValidationErrorType.html#/s:13VGSCollectSDK22VGSValidationErrorTypeO9luhnCheckyA2CmF":{"name":"luhnCheck","abstract":"

    Default Validation error for VGSValidationRuleLuhnCheck

    ","parent_name":"VGSValidationErrorType"},"Enums/VGSErrorType.html#/s:13VGSCollectSDK12VGSErrorTypeO19inputDataIsNotValidyA2CmF":{"name":"inputDataIsNotValid","abstract":"

    When input data is not valid, but required to be valid

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/s:13VGSCollectSDK12VGSErrorTypeO17inputFileNotFoundyA2CmF":{"name":"inputFileNotFound","abstract":"

    When can’t find file on device

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/s:13VGSCollectSDK12VGSErrorTypeO09inputFileD14IsNotSupportedyA2CmF":{"name":"inputFileTypeIsNotSupported","abstract":"

    When can’t find file on device

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/s:13VGSCollectSDK12VGSErrorTypeO28inputFileSizeExceedsTheLimityA2CmF":{"name":"inputFileSizeExceedsTheLimit","abstract":"

    When file size is larger then allowed limit

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/s:13VGSCollectSDK12VGSErrorTypeO18sourceNotAvailableyA2CmF":{"name":"sourceNotAvailable","abstract":"

    When can’t get access to file source

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/s:13VGSCollectSDK12VGSErrorTypeO018unexpectedResponseD0yA2CmF":{"name":"unexpectedResponseType","abstract":"

    When response type is not supported

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/s:13VGSCollectSDK12VGSErrorTypeO28unexpectedResponseDataFormatyA2CmF":{"name":"unexpectedResponseDataFormat","abstract":"

    When reponse data format is not supported

    ","parent_name":"VGSErrorType"},"Enums/VGSErrorType.html#/s:13VGSCollectSDK12VGSErrorTypeO23invalidConfigurationURLyA2CmF":{"name":"invalidConfigurationURL","abstract":"

    When VGS config URL is not valid.

    ","parent_name":"VGSErrorType"},"Classes/VGSError.html#/s:13VGSCollectSDK8VGSErrorC4typeAA0C4TypeOSgvp":{"name":"type","abstract":"

    VGSErrorType- required for each VGSError instance

    ","parent_name":"VGSError"},"Classes/VGSError.html#/c:@M@VGSCollectSDK@objc(cs)VGSError(py)code":{"name":"code","abstract":"

    Code assiciated with VGSErrorType

    ","parent_name":"VGSError"},"Classes/VGSError.html#/c:@M@VGSCollectSDK@objc(cs)VGSError(im)initWithCoder:":{"name":"init(coder:)","abstract":"

    : nodoc. Public required init.

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

    An error produced by VGSCollectSDK. Works similar to default NSError in iOS.

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

    Type of VGSError and it status code.

    "},"Errors.html#/s:13VGSCollectSDK0A14SDKErrorDomainSSvp":{"name":"VGSCollectSDKErrorDomain","abstract":"

    An error domain string used to produce VGSError from VGSCollectSDK - “vgscollect.sdk”

    "},"Errors.html#/s:13VGSCollectSDK18VGSValidationErrora":{"name":"VGSValidationError","abstract":"

    VGS Validation Error object type

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

    Default validation error types

    "},"Enums/CheckSumAlgorithmType.html#/s:13VGSCollectSDK21CheckSumAlgorithmTypeO4luhnyA2CmF":{"name":"luhn","abstract":"

    Luhn Algorithm

    ","parent_name":"CheckSumAlgorithmType"},"Enums/CheckSumAlgorithmType.html#/s:13VGSCollectSDK21CheckSumAlgorithmTypeO8validateySbSSF":{"name":"validate(_:)","abstract":"

    Validate input String with specified algorithm.

    ","parent_name":"CheckSumAlgorithmType"},"Structs/VGSValidationRuleDateRange.html#/s:13VGSCollectSDK26VGSValidationRuleDateRangeV10dateFormatAA07VGSDateH0Ovp":{"name":"dateFormat","abstract":"

    Date format used to validate the rule

    ","parent_name":"VGSValidationRuleDateRange"},"Structs/VGSValidationRuleDateRange.html#/s:13VGSCollectSDK26VGSValidationRuleDateRangeV5errorSSvp":{"name":"error","abstract":"

    Error used in case the validation is invalid

    ","parent_name":"VGSValidationRuleDateRange"},"Structs/VGSValidationRuleDateRange.html#/s:13VGSCollectSDK26VGSValidationRuleDateRangeV10dateFormat5error5start3endAcA07VGSDateH0O_SSAA0L0VSgALtcfc":{"name":"init(dateFormat:error:start:end:)","abstract":"

    Initialization

    ","parent_name":"VGSValidationRuleDateRange"},"Structs/VGSValidationRuleCardExpirationDate.html#/s:13VGSCollectSDK35VGSValidationRuleCardExpirationDateV10dateFormatAA010VGSCardExpgI0Ovp":{"name":"dateFormat","abstract":"

    Payment Card Expiration Date Format

    ","parent_name":"VGSValidationRuleCardExpirationDate"},"Structs/VGSValidationRuleCardExpirationDate.html#/s:13VGSCollectSDK35VGSValidationRuleCardExpirationDateV5errorSSvp":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRuleCardExpirationDate"},"Structs/VGSValidationRuleCardExpirationDate.html#/s:13VGSCollectSDK35VGSValidationRuleCardExpirationDateV10dateFormat5errorAcA010VGSCardExpgI0O_SStcfc":{"name":"init(dateFormat:error:)","abstract":"

    Initialization

    ","parent_name":"VGSValidationRuleCardExpirationDate"},"Structs/VGSValidationRuleLuhnCheck.html#/s:13VGSCollectSDK26VGSValidationRuleLuhnCheckV5errorSSvp":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRuleLuhnCheck"},"Structs/VGSValidationRuleLuhnCheck.html#/s:13VGSCollectSDK26VGSValidationRuleLuhnCheckV5errorACSS_tcfc":{"name":"init(error:)","abstract":"

    Initialization

    ","parent_name":"VGSValidationRuleLuhnCheck"},"Structs/VGSValidationRulePaymentCard.html#/s:13VGSCollectSDK28VGSValidationRulePaymentCardV5errorSSvp":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRulePaymentCard"},"Structs/VGSValidationRulePaymentCard.html#/s:13VGSCollectSDK28VGSValidationRulePaymentCardV015validateUnknownF5BrandSbvp":{"name":"validateUnknownCardBrand","abstract":"

    Turn on/off validation of cards that are not defined in SDK - CardBrand.unknown

    ","parent_name":"VGSValidationRulePaymentCard"},"Structs/VGSValidationRulePaymentCard.html#/s:13VGSCollectSDK28VGSValidationRulePaymentCardV5errorACSS_tcfc":{"name":"init(error:)","abstract":"

    Initialization

    ","parent_name":"VGSValidationRulePaymentCard"},"Structs/VGSValidationRulePaymentCard.html#/s:13VGSCollectSDK28VGSValidationRulePaymentCardV5error015validateUnknownF5BrandACSS_Sbtcfc":{"name":"init(error:validateUnknownCardBrand:)","abstract":"

    Initialization

    ","parent_name":"VGSValidationRulePaymentCard"},"Structs/VGSValidationRulePattern.html#/s:13VGSCollectSDK24VGSValidationRulePatternV7patternSSvp":{"name":"pattern","abstract":"

    Regex pattern

    ","parent_name":"VGSValidationRulePattern"},"Structs/VGSValidationRulePattern.html#/s:13VGSCollectSDK24VGSValidationRulePatternV5errorSSvp":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRulePattern"},"Structs/VGSValidationRulePattern.html#/s:13VGSCollectSDK24VGSValidationRulePatternV7pattern5errorACSS_SStcfc":{"name":"init(pattern:error:)","abstract":"

    Initialization

    ","parent_name":"VGSValidationRulePattern"},"Structs/VGSValidationRuleLengthMatch.html#/s:13VGSCollectSDK28VGSValidationRuleLengthMatchV7lengthsSaySiGvp":{"name":"lengths","abstract":"

    Array of valid length ranges

    ","parent_name":"VGSValidationRuleLengthMatch"},"Structs/VGSValidationRuleLengthMatch.html#/s:13VGSCollectSDK28VGSValidationRuleLengthMatchV5errorSSvp":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRuleLengthMatch"},"Structs/VGSValidationRuleLengthMatch.html#/s:13VGSCollectSDK28VGSValidationRuleLengthMatchV7lengths5errorACSaySiG_SStcfc":{"name":"init(lengths:error:)","abstract":"

    Initialization

    ","parent_name":"VGSValidationRuleLengthMatch"},"Structs/VGSValidationRuleLength.html#/s:13VGSCollectSDK23VGSValidationRuleLengthV3minSivp":{"name":"min","abstract":"

    Min input length required

    ","parent_name":"VGSValidationRuleLength"},"Structs/VGSValidationRuleLength.html#/s:13VGSCollectSDK23VGSValidationRuleLengthV3maxSivp":{"name":"max","abstract":"

    Max input length required

    ","parent_name":"VGSValidationRuleLength"},"Structs/VGSValidationRuleLength.html#/s:13VGSCollectSDK23VGSValidationRuleLengthV5errorSSvp":{"name":"error","abstract":"

    Validation Error

    ","parent_name":"VGSValidationRuleLength"},"Structs/VGSValidationRuleLength.html#/s:13VGSCollectSDK23VGSValidationRuleLengthV3min3max5errorACSi_SiSStcfc":{"name":"init(min:max:error:)","abstract":"

    Initialization

    ","parent_name":"VGSValidationRuleLength"},"Structs/VGSValidationRuleSet.html#/s:13VGSCollectSDK20VGSValidationRuleSetVACycfc":{"name":"init()","abstract":"

    Initialization

    ","parent_name":"VGSValidationRuleSet"},"Structs/VGSValidationRuleSet.html#/s:13VGSCollectSDK20VGSValidationRuleSetV5rulesACSayAA0cD8Protocol_pG_tcfc":{"name":"init(rules:)","abstract":"

    Initialization

    ","parent_name":"VGSValidationRuleSet"},"Structs/VGSValidationRuleSet.html#/s:13VGSCollectSDK20VGSValidationRuleSetV3add4ruleyAA0cD8Protocol_p_tF":{"name":"add(rule:)","abstract":"

    Add validation rule

    ","parent_name":"VGSValidationRuleSet"},"Structs/VGSValidationRuleSet.html":{"name":"VGSValidationRuleSet","abstract":"

    Set of validation rules

    "},"Structs/VGSValidationRuleLength.html":{"name":"VGSValidationRuleLength","abstract":"

    Validate input in scope of length.

    "},"Structs/VGSValidationRuleLengthMatch.html":{"name":"VGSValidationRuleLengthMatch","abstract":"

    Validate input in scope of multiple lengths, e.x.: [16, 19].

    "},"Structs/VGSValidationRulePattern.html":{"name":"VGSValidationRulePattern","abstract":"

    Validate input in scope of matching the pattern(regex).

    "},"Structs/VGSValidationRulePaymentCard.html":{"name":"VGSValidationRulePaymentCard","abstract":"

    Validate input in scope of matching supported card brands, available lengths and checkSum algorithms."},"Structs/VGSValidationRuleLuhnCheck.html":{"name":"VGSValidationRuleLuhnCheck","abstract":"

    Validate input in scope of matching Luhn algorithm.

    "},"Structs/VGSValidationRuleCardExpirationDate.html":{"name":"VGSValidationRuleCardExpirationDate","abstract":"

    Validate input in scope of matching card expiration date format and time range.

    "},"Structs/VGSValidationRuleDateRange.html":{"name":"VGSValidationRuleDateRange","abstract":"

    Validation rule used to validate the date input in objects"},"Enums/CheckSumAlgorithmType.html":{"name":"CheckSumAlgorithmType","abstract":"

    Check Sum Algorithm Types

    "},"Structs/VGSExpDateSeparateSerializer.html#/s:13VGSCollectSDK28VGSExpDateSeparateSerializerV14monthFieldNameSSvp":{"name":"monthFieldName","abstract":"

    Field Name that will be used as a JSON key with month value from expDate string on send request.

    ","parent_name":"VGSExpDateSeparateSerializer"},"Structs/VGSExpDateSeparateSerializer.html#/s:13VGSCollectSDK28VGSExpDateSeparateSerializerV13yearFieldNameSSvp":{"name":"yearFieldName","abstract":"

    Field Name that will be used as a JSON key with year value from expDate string on send request.

    ","parent_name":"VGSExpDateSeparateSerializer"},"Structs/VGSExpDateSeparateSerializer.html#/s:13VGSCollectSDK28VGSExpDateSeparateSerializerV14monthFieldName04yearhI0ACSS_SStcfc":{"name":"init(monthFieldName:yearFieldName:)","abstract":"

    Initialization

    ","parent_name":"VGSExpDateSeparateSerializer"},"VGSTextField%20Serializers.html#/s:13VGSCollectSDK27VGSFormatSerializerProtocolP":{"name":"VGSFormatSerializerProtocol","abstract":"

    Base protocol describing Content Serialization attributes

    "},"Structs/VGSExpDateSeparateSerializer.html":{"name":"VGSExpDateSeparateSerializer","abstract":"

    Expiration Date Separate serializer, split date string to components with separate fieldNames

    "},"Structs/VGSUnknownPaymentCardModel.html#/s:13VGSCollectSDK26VGSUnknownPaymentCardModelV5regexSSvp":{"name":"regex","abstract":"

    Regex validating that input contains digits only.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/s:13VGSCollectSDK26VGSUnknownPaymentCardModelV17cardNumberLengthsSaySiGvp":{"name":"cardNumberLengths","abstract":"

    Valid Unknown Card Numbers Lengths

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/s:13VGSCollectSDK26VGSUnknownPaymentCardModelV10cvcLengthsSaySiGvp":{"name":"cvcLengths","abstract":"

    Valid Unknown Card CVC/CVV Lengths. For most brands valid cvc lengths is [3], while for Amex is [4]. For unknown brands can be set as [3, 4]

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/s:13VGSCollectSDK26VGSUnknownPaymentCardModelV17checkSumAlgorithmAA05CheckhI4TypeOSgvp":{"name":"checkSumAlgorithm","abstract":"

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/s:13VGSCollectSDK26VGSUnknownPaymentCardModelV13formatPatternSSvp":{"name":"formatPattern","abstract":"

    Unknown Payment Card Numbers visual format pattern. NOTE: format pattern length limits input length.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/s:13VGSCollectSDK26VGSUnknownPaymentCardModelV9brandIconSo7UIImageCSgvp":{"name":"brandIcon","abstract":"

    Image, associated with Unknown Payment Card Brands.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSUnknownPaymentCardModel.html#/s:13VGSCollectSDK26VGSUnknownPaymentCardModelV7cvcIconSo7UIImageCSgvp":{"name":"cvcIcon","abstract":"

    Image, associated with CVC for Unknown Payment Card Brands.

    ","parent_name":"VGSUnknownPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV5brandAA15VGSPaymentCardsC0E5BrandOvp":{"name":"brand","abstract":"

    Payment Card Brand

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV4nameSSvp":{"name":"name","abstract":"

    Payment Card Name

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV5regexSSvp":{"name":"regex","abstract":"

    Regex Pattern required to detect Payment Card Brand

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV17cardNumberLengthsSaySiGvp":{"name":"cardNumberLengths","abstract":"

    Valid Card Number Lengths

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV10cvcLengthsSaySiGvp":{"name":"cvcLengths","abstract":"

    Valid Card CVC/CVV Lengths. For most brands valid cvc lengths is [3], while for Amex is [4]. For unknown brands can be set as [3, 4]

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV17checkSumAlgorithmAA05CheckhI4TypeOSgvp":{"name":"checkSumAlgorithm","abstract":"

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV13formatPatternSSvp":{"name":"formatPattern","abstract":"

    Payment Card Number visual format pattern.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV9brandIconSo7UIImageCSgvp":{"name":"brandIcon","abstract":"

    Image, associated with Payment Card Brand.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV7cvcIconSo7UIImageCSgvp":{"name":"cvcIcon","abstract":"

    Image, associated with CVC for Payment Card Brand.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSCustomPaymentCardModel.html#/s:13VGSCollectSDK25VGSCustomPaymentCardModelV4name5regex13formatPattern17cardNumberLengths03cvcM017checkSumAlgorithm9brandIconACSS_S2SSaySiGAkA05CheckpQ4TypeOSgSo7UIImageCSgtcfc":{"name":"init(name:regex:formatPattern:cardNumberLengths:cvcLengths:checkSumAlgorithm:brandIcon:)","abstract":"

    Initializer.

    ","parent_name":"VGSCustomPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/s:13VGSCollectSDK19VGSPaymentCardModelV5brandAA0C5CardsC0D5BrandOvp":{"name":"brand","abstract":"

    Payment Card Brand

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/s:13VGSCollectSDK19VGSPaymentCardModelV4nameSSvp":{"name":"name","abstract":"

    Payment Card Name

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/s:13VGSCollectSDK19VGSPaymentCardModelV5regexSSvp":{"name":"regex","abstract":"

    Regex Pattern required to detect Payment Card Brand

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/s:13VGSCollectSDK19VGSPaymentCardModelV17cardNumberLengthsSaySiGvp":{"name":"cardNumberLengths","abstract":"

    Valid Card Number Lengths

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/s:13VGSCollectSDK19VGSPaymentCardModelV10cvcLengthsSaySiGvp":{"name":"cvcLengths","abstract":"

    Valid Card CVC/CVV Lengths. For most brands valid cvc lengths is [3], while for Amex is [4]. For unknown brands can be set as [3, 4]

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/s:13VGSCollectSDK19VGSPaymentCardModelV17checkSumAlgorithmAA05CheckgH4TypeOSgvp":{"name":"checkSumAlgorithm","abstract":"

    Check sum validation algorithm. For most brands card number can be validated by CheckSumAlgorithmType.luhn algorithm. If none - result of Checksum Algorithm validation will be true.

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/s:13VGSCollectSDK19VGSPaymentCardModelV13formatPatternSSvp":{"name":"formatPattern","abstract":"

    Payment Card Number visual format pattern.

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/s:13VGSCollectSDK19VGSPaymentCardModelV9brandIconSo7UIImageCSgvp":{"name":"brandIcon","abstract":"

    Image, associated with Payment Card Brand.

    ","parent_name":"VGSPaymentCardModel"},"Structs/VGSPaymentCardModel.html#/s:13VGSCollectSDK19VGSPaymentCardModelV7cvcIconSo7UIImageCSgvp":{"name":"cvcIcon","abstract":"

    Image, associated with CVC for Payment Card Brand.

    ","parent_name":"VGSPaymentCardModel"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO3eloyA2EmF":{"name":"elo","abstract":"

    ELO

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO12visaElectronyA2EmF":{"name":"visaElectron","abstract":"

    Visa Electron

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO7maestroyA2EmF":{"name":"maestro","abstract":"

    Maestro

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO18forbrugsforeningenyA2EmF":{"name":"forbrugsforeningen","abstract":"

    Forbrugsforeningen

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO7dankortyA2EmF":{"name":"dankort","abstract":"

    Dankort

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO4visayA2EmF":{"name":"visa","abstract":"

    Visa

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO10mastercardyA2EmF":{"name":"mastercard","abstract":"

    Mastercard

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO4amexyA2EmF":{"name":"amex","abstract":"

    American Express

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO9hipercardyA2EmF":{"name":"hipercard","abstract":"

    Hipercard

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO10dinersClubyA2EmF":{"name":"dinersClub","abstract":"

    Diners Club

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO8discoveryA2EmF":{"name":"discover","abstract":"

    Discover

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO8unionpayyA2EmF":{"name":"unionpay","abstract":"

    UnionPay

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO3jcbyA2EmF":{"name":"jcb","abstract":"

    JCB

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO7unknownyA2EmF":{"name":"unknown","abstract":"

    Not supported card brand - “unknown”

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO6customyAESS_tcAEmF":{"name":"custom(brandName:)","abstract":"

    Custom Payment Card Brand. Should have unique brandName.

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO16cvcFormatPatternSSvp":{"name":"cvcFormatPattern","abstract":"

    no:doc

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO9brandIconSo7UIImageCSgvp":{"name":"brandIcon","abstract":"

    no:doc

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO7cvcIconSo7UIImageCSgvp":{"name":"cvcIcon","abstract":"

    no:doc

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO11stringValueSSvp":{"name":"stringValue","abstract":"

    String representation of VGSPaymentCards.CardBrand enum values.

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html#/s:13VGSCollectSDK15VGSPaymentCardsC9CardBrandO11cardLengthsSaySiGvp":{"name":"cardLengths","abstract":"

    Returns array with valid card number lengths for specific VGSPaymentCards.CardBrand

    ","parent_name":"CardBrand"},"Classes/VGSPaymentCards/CardBrand.html":{"name":"CardBrand","abstract":"

    Supported card brands

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC3eloAA0C9CardModelVvpZ":{"name":"elo","abstract":"

    Elo Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC12visaElectronAA0C9CardModelVvpZ":{"name":"visaElectron","abstract":"

    Visa Electron Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC7maestroAA0C9CardModelVvpZ":{"name":"maestro","abstract":"

    Maestro Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC18forbrugsforeningenAA0C9CardModelVvpZ":{"name":"forbrugsforeningen","abstract":"

    Forbrugsforeningen Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC7dankortAA0C9CardModelVvpZ":{"name":"dankort","abstract":"

    Dankort Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC4visaAA0C9CardModelVvpZ":{"name":"visa","abstract":"

    Elo Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC10masterCardAA0cF5ModelVvpZ":{"name":"masterCard","abstract":"

    Master Card Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC4amexAA0C9CardModelVvpZ":{"name":"amex","abstract":"

    Amex Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC9hipercardAA0C9CardModelVvpZ":{"name":"hipercard","abstract":"

    Hipercard Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC10dinersClubAA0C9CardModelVvpZ":{"name":"dinersClub","abstract":"

    DinersClub Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC8discoverAA0C9CardModelVvpZ":{"name":"discover","abstract":"

    Discover Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC8unionpayAA0C9CardModelVvpZ":{"name":"unionpay","abstract":"

    UnionPay Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC3jcbAA0C9CardModelVvpZ":{"name":"jcb","abstract":"

    JCB Payment Card Model

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC7unknownAA26VGSUnknownPaymentCardModelVvpZ":{"name":"unknown","abstract":"

    Unknown Brand Payment Card Model. Can be used for specifing cards details when VGSValidationRulePaymentCard requires validating CardBrand.unknown cards.

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC22cutomPaymentCardModelsSayAA09VGSCustomfG5ModelVGvpZ":{"name":"cutomPaymentCardModels","abstract":"

    Array of Custom Payment Card Models.

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC15validCardBrandsSayAA0cF13ModelProtocol_pGSgvpZ":{"name":"validCardBrands","abstract":"

    An array of valid Card Brands, could include custom and default brands. If not set, will use availableCardBrands array instead.

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC31getCardModelFromAvailableModels5brandAA0cfG8Protocol_pSgAC0F5BrandO_tFZ":{"name":"getCardModelFromAvailableModels(brand:)","abstract":"

    no:doc

    ","parent_name":"VGSPaymentCards"},"Classes/VGSPaymentCards.html#/s:13VGSCollectSDK15VGSPaymentCardsC028detectCardBrandFromAvailableD05inputAC0fG0OSS_tFZ":{"name":"detectCardBrandFromAvailableCards(input:)","abstract":"

    no:doc

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

    Class responsible for storing and managing Payment Cards in SDK.

    "},"Structs/VGSPaymentCardModel.html":{"name":"VGSPaymentCardModel","abstract":"

    An object representing Payment Card

    "},"Structs/VGSCustomPaymentCardModel.html":{"name":"VGSCustomPaymentCardModel","abstract":"

    Holds information for custom payment model.

    "},"Structs/VGSUnknownPaymentCardModel.html":{"name":"VGSUnknownPaymentCardModel","abstract":"

    An object representing Unknown Payment Cards - cards not defined in the SDK. Object is used when validation forCardBrand.unknown is set as true. Check VGSValidationRulePaymentCard for more details. Validation attributes can be edited through `VGSPaymentCards.unknown model.

    "},"Enums/VGSCollectHTTPMethod.html#/s:13VGSCollectSDK0A10HTTPMethodO3getyA2CmF":{"name":"get","abstract":"

    GET method.

    ","parent_name":"VGSCollectHTTPMethod"},"Enums/VGSCollectHTTPMethod.html#/s:13VGSCollectSDK0A10HTTPMethodO4postyA2CmF":{"name":"post","abstract":"

    POST method.

    ","parent_name":"VGSCollectHTTPMethod"},"Enums/VGSCollectHTTPMethod.html#/s:13VGSCollectSDK0A10HTTPMethodO3putyA2CmF":{"name":"put","abstract":"

    PUT method.

    ","parent_name":"VGSCollectHTTPMethod"},"Enums/VGSCollectHTTPMethod.html#/s:13VGSCollectSDK0A10HTTPMethodO5patchyA2CmF":{"name":"patch","abstract":"

    PATCH method.

    ","parent_name":"VGSCollectHTTPMethod"},"Enums/VGSCollectHTTPMethod.html#/s:13VGSCollectSDK0A10HTTPMethodO6deleteyA2CmF":{"name":"delete","abstract":"

    DELETE method.

    ","parent_name":"VGSCollectHTTPMethod"},"Structs/VGSCollectRequestOptions.html#/s:13VGSCollectSDK0A14RequestOptionsV22fieldNameMappingPolicyAA0a5FieldfgH0Ovp":{"name":"fieldNameMappingPolicy","abstract":"

    Defines how to map fieldNames to JSON. Default is .nestedJSON.

    ","parent_name":"VGSCollectRequestOptions"},"Structs/VGSCollectRequestOptions.html#/s:13VGSCollectSDK0A14RequestOptionsVACycfc":{"name":"init()","abstract":"

    Initializer.

    ","parent_name":"VGSCollectRequestOptions"},"Enums/VGSTokenizationResponse.html#/s:13VGSCollectSDK23VGSTokenizationResponseO7successyACSi_SDySSypGSgSo13NSURLResponseCSgtcACmF":{"name":"success(_:_:_:)","abstract":"

    Success response case

    ","parent_name":"VGSTokenizationResponse"},"Enums/VGSTokenizationResponse.html#/s:13VGSCollectSDK23VGSTokenizationResponseO7failureyACSi_10Foundation4DataVSgSo13NSURLResponseCSgs5Error_pSgtcACmF":{"name":"failure(_:_:_:_:)","abstract":"

    Failed response case

    ","parent_name":"VGSTokenizationResponse"},"Enums/VGSResponse.html#/s:13VGSCollectSDK11VGSResponseO7successyACSi_10Foundation4DataVSgSo13NSURLResponseCSgtcACmF":{"name":"success(_:_:_:)","abstract":"

    Success response case

    ","parent_name":"VGSResponse"},"Enums/VGSResponse.html#/s:13VGSCollectSDK11VGSResponseO7failureyACSi_10Foundation4DataVSgSo13NSURLResponseCSgs5Error_pSgtcACmF":{"name":"failure(_:_:_:_:)","abstract":"

    Failed response case

    ","parent_name":"VGSResponse"},"Structs/VGSTextFieldStatePublisher.html#/s:7Combine9PublisherP6OutputQa":{"name":"Output","parent_name":"VGSTextFieldStatePublisher"},"Structs/VGSTextFieldStatePublisher.html#/s:7Combine9PublisherP7FailureQa":{"name":"Failure","parent_name":"VGSTextFieldStatePublisher"},"Structs/VGSTextFieldStatePublisher.html#/s:13VGSCollectSDK26VGSTextFieldStatePublisherV7receive10subscriberyx_t7Combine10SubscriberRzs5NeverO7FailureRtzAA0E0C5InputRtzlF":{"name":"receive(subscriber:)","abstract":"

    Attaches a subscriber to the publisher to receive updates on the VGSTextField State.

    ","parent_name":"VGSTextFieldStatePublisher"},"Classes/CardState.html#/s:13VGSCollectSDK9CardStateC5last4SSvp":{"name":"last4","abstract":"

    Last 4 digits of the valid card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    ","parent_name":"CardState"},"Classes/CardState.html#/s:13VGSCollectSDK9CardStateC3binSSvp":{"name":"bin","abstract":"

    Bin digits of the valid card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    ","parent_name":"CardState"},"Classes/CardState.html#/s:13VGSCollectSDK9CardStateC9cardBrandAA15VGSPaymentCardsC0cF0Ovp":{"name":"cardBrand","abstract":"

    Credit Card Brand of the card number from associated VGSTextField with field configuration type FieldType.cardNumber.

    ","parent_name":"CardState"},"Classes/CardState.html#/s:13VGSCollectSDK9CardStateC11descriptionSSvp":{"name":"description","abstract":"

    Message that contains CardState attributes and their values.

    ","parent_name":"CardState"},"Classes/SSNState.html#/s:13VGSCollectSDK8SSNStateC5last4SSvp":{"name":"last4","abstract":"

    Last 4 digits of the valid ssn from associated VGSTextField with field configuration type FieldType.ssn.

    ","parent_name":"SSNState"},"Classes/SSNState.html#/s:13VGSCollectSDK8SSNStateC11descriptionSSvp":{"name":"description","abstract":"

    Message that contains SSNState attributes and their values.

    ","parent_name":"SSNState"},"Classes/State.html#/s:13VGSCollectSDK5StateC9fieldNameSSSgvp":{"name":"fieldName","abstract":"

    VGSConfiguration.fieldName associated with VGSTextField

    ","parent_name":"State"},"Classes/State.html#/s:13VGSCollectSDK5StateC10isRequiredSbvp":{"name":"isRequired","abstract":"

    VGSConfiguration.isRequired attribute defined for VGSTextField

    ","parent_name":"State"},"Classes/State.html#/s:13VGSCollectSDK5StateC19isRequiredValidOnlySbvp":{"name":"isRequiredValidOnly","abstract":"

    VGSConfiguration.isRequiredValidOnly attribute defined for VGSTextField

    ","parent_name":"State"},"Classes/State.html#/s:13VGSCollectSDK5StateC7isValidSbvp":{"name":"isValid","abstract":"

    Contains current validation state for VGSTextField

    ","parent_name":"State"},"Classes/State.html#/s:13VGSCollectSDK5StateC7isEmptySbvp":{"name":"isEmpty","abstract":"

    Show if VGSTextField input is empty

    ","parent_name":"State"},"Classes/State.html#/s:13VGSCollectSDK5StateC7isDirtySbvp":{"name":"isDirty","abstract":"

    Show if VGSTextField was edited

    ","parent_name":"State"},"Classes/State.html#/s:13VGSCollectSDK5StateC11inputLengthSivp":{"name":"inputLength","abstract":"

    Input data length in VGSTextField

    ","parent_name":"State"},"Classes/State.html#/s:13VGSCollectSDK5StateC16validationErrorsSaySSGvp":{"name":"validationErrors","abstract":"

    Array of VGSValidationError. Should be empty when textfield input is valid.

    ","parent_name":"State"},"Classes/State.html#/s:13VGSCollectSDK5StateC11descriptionSSvp":{"name":"description","abstract":"

    Message that contains State attributes and their values

    ","parent_name":"State"},"Enums/Environment.html#/s:13VGSCollectSDK11EnvironmentO7sandboxyA2CmF":{"name":"sandbox","abstract":"

    Should be used for development and testing purpose.

    ","parent_name":"Environment"},"Enums/Environment.html#/s:13VGSCollectSDK11EnvironmentO4liveyA2CmF":{"name":"live","abstract":"

    Should be used for production.

    ","parent_name":"Environment"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C13customHeadersSDyS2SGSgvp":{"name":"customHeaders","abstract":"

    Set your custom HTTP headers.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C17observeFieldStateyAA07VGSTextD0CcSgvp":{"name":"observeFieldState","abstract":"

    Observe only focused VGSTextField on editing events.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C13observeStatesySayAA12VGSTextFieldCGcSgvp":{"name":"observeStates","abstract":"

    Observe all VGSTextField on editing events.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C10textFieldsSayAA12VGSTextFieldCGvp":{"name":"textFields","abstract":"

    Returns array of VGSTextFields associated with VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C2id11environment8hostname13satellitePortACSS_S2SSgSiSgtcfc":{"name":"init(id:environment:hostname:satellitePort:)","abstract":"

    Initialization.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C2id11environment10dataRegion8hostname13satellitePortACSS_AA11EnvironmentOSSSgAKSiSgtcfc":{"name":"init(id:environment:dataRegion:hostname:satellitePort:)","abstract":"

    Initialization.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C12getTextField9fieldNameAA07VGSTextE0CSgSS_tF":{"name":"getTextField(fieldName:)","abstract":"

    Returns VGSTextField with VGSConfiguration.fieldName associated with VGCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C20unsubscribeTextFieldyyAA07VGSTextE0CF":{"name":"unsubscribeTextField(_:)","abstract":"

    Unasubscribe VGSTextField from VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C21unsubscribeTextFieldsyySayAA12VGSTextFieldCGF":{"name":"unsubscribeTextFields(_:)","abstract":"

    Unasubscribe VGSTextFields from VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C24unsubscribeAllTextFieldsyyF":{"name":"unsubscribeAllTextFields()","abstract":"

    Unasubscribe all VGSTextFields from VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C10cleanFilesyyF":{"name":"cleanFiles()","abstract":"

    Detach files for associated VGSCollect instance.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C8sendData4path6method7routeId05extraD014requestOptions10completionySS_AA0A10HTTPMethodOSSSgSDySSypGSgAA0a7RequestK0VyAA11VGSResponseOctF":{"name":"sendData(path:method:routeId:extraData:requestOptions:completion:)","abstract":"

    Send data from VGSTextFields to your organization vault.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C8sendFile4path6method7routeId9extraData14requestOptions10completionySS_AA0A10HTTPMethodOSSSgSDySSypGSgAA0a7RequestL0VyAA11VGSResponseOctF":{"name":"sendFile(path:method:routeId:extraData:requestOptions:completion:)","abstract":"

    Send file to your organization vault. Only send one file at a time.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C12tokenizeData7routeId10completionySSSg_yAA23VGSTokenizationResponseOctF":{"name":"tokenizeData(routeId:completion:)","abstract":"

    Send tokenization request with data from VGSTextFields.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C8sendData4path6method7routeId05extraD014requestOptionsAA11VGSResponseOSS_AA0A10HTTPMethodOSSSgSDySSypGSgAA0a7RequestK0VtYaF":{"name":"sendData(path:method:routeId:extraData:requestOptions:)","abstract":"

    Asynchronously send data from VGSTextFields to your organization vault.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C8sendFile4path6method7routeId9extraDataAA11VGSResponseOSS_AA0A10HTTPMethodOSSSgSDySSypGSgtYaF":{"name":"sendFile(path:method:routeId:extraData:)","abstract":"

    Asynchronously send file to your organization vault. Only send one file at a time.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C12tokenizeData7routeIdAA23VGSTokenizationResponseOSSSg_tYaF":{"name":"tokenizeData(routeId:)","abstract":"

    Asynchronously send tokenization request with data from VGSTextFields.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C17sendDataPublisher4path6method7routeId05extraD014requestOptions7Combine6FutureCyAA11VGSResponseOs5NeverOGSS_AA0A10HTTPMethodOSSSgSDySSypGSgAA0a7RequestL0VtF":{"name":"sendDataPublisher(path:method:routeId:extraData:requestOptions:)","abstract":"

    Send data from VGSTextFields to your organization vault using the Combine framework.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C17sendFilePublisher4path6method7routeId9extraData14requestOptions7Combine6FutureCyAA11VGSResponseOs5NeverOGSS_AA0A10HTTPMethodOSSSgSDySSypGSgAA0a7RequestM0VtF":{"name":"sendFilePublisher(path:method:routeId:extraData:requestOptions:)","abstract":"

    Send file to your organization vault using the Combine framework.

    ","parent_name":"VGSCollect"},"Classes/VGSCollect.html#/s:13VGSCollectSDK0A0C21tokenizeDataPublisher7routeId7Combine6FutureCyAA23VGSTokenizationResponseOs5NeverOGSSSg_tF":{"name":"tokenizeDataPublisher(routeId:)","abstract":"

    Send tokenization request with data from VGSTextFields to your organization vault using the Combine framework.

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

    An object you use for observing VGSTextField State and send data to your organization vault.

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

    Organization vault environment.

    "},"Classes/State.html":{"name":"State","abstract":"

    An object that describes VGSTextField state. State attributes are read-only.

    "},"Classes/SSNState.html":{"name":"SSNState","abstract":"

    An object that describes VGSTextField state with configuration FieldType.ssn . State attributes are read-only.

    "},"Classes/CardState.html":{"name":"CardState","abstract":"

    An object that describes VGSTextField state with configuration FieldType.cardNumber . State attributes are read-only.

    "},"Structs/VGSTextFieldStatePublisher.html":{"name":"VGSTextFieldStatePublisher","abstract":"

    A custom publisher that emits State of a given VGSTextField.

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

    Response enum cases for SDK requests.

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

    Tokenization response enum cases for SDK requests.

    "},"Structs/VGSCollectRequestOptions.html":{"name":"VGSCollectRequestOptions","abstract":"

    Request options.

    "},"Observe%20State%20and%20Send%20Data.html#/s:13VGSCollectSDK8JsonDataa":{"name":"JsonData","abstract":"

    Key-value data type, usually used for response format.

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

    HTTP request methods

    "},"Observe%20State%20and%20Send%20Data.html#/s:13VGSCollectSDK11HTTPHeadersa":{"name":"HTTPHeaders","abstract":"

    Key-value data type, used in http request headers.

    "},"Classes/VGSFileInfo.html#/c:@M@VGSCollectSDK@objc(cs)VGSFileInfo(py)fileExtension":{"name":"fileExtension","abstract":"

    File extension, like “jpeg”, “png”, etc.

    ","parent_name":"VGSFileInfo"},"Classes/VGSFileInfo.html#/c:@M@VGSCollectSDK@objc(cs)VGSFileInfo(py)size":{"name":"size","abstract":"

    File size.

    ","parent_name":"VGSFileInfo"},"Classes/VGSFileInfo.html#/c:@M@VGSCollectSDK@objc(cs)VGSFileInfo(py)sizeUnits":{"name":"sizeUnits","abstract":"

    File size units.

    ","parent_name":"VGSFileInfo"},"Enums/VGSFileSource.html#/s:13VGSCollectSDK13VGSFileSourceO12photoLibraryyA2CmF":{"name":"photoLibrary","abstract":"

    Device photo library.

    ","parent_name":"VGSFileSource"},"Enums/VGSFileSource.html#/s:13VGSCollectSDK13VGSFileSourceO6camerayA2CmF":{"name":"camera","abstract":"

    Device camera.

    ","parent_name":"VGSFileSource"},"Enums/VGSFileSource.html#/s:13VGSCollectSDK13VGSFileSourceO18documentsDirectoryyA2CmF":{"name":"documentsDirectory","abstract":"

    Device documents directory.

    ","parent_name":"VGSFileSource"},"Protocols/VGSFilePickerControllerDelegate.html#/c:@M@VGSCollectSDK@objc(pl)VGSFilePickerControllerDelegate(im)userDidPickFileWithInfo:":{"name":"userDidPickFileWithInfo(_:)","abstract":"

    On user select a file

    ","parent_name":"VGSFilePickerControllerDelegate"},"Protocols/VGSFilePickerControllerDelegate.html#/c:@M@VGSCollectSDK@objc(pl)VGSFilePickerControllerDelegate(im)userDidSCancelFilePicking":{"name":"userDidSCancelFilePicking()","abstract":"

    On user canceling file picking

    ","parent_name":"VGSFilePickerControllerDelegate"},"Protocols/VGSFilePickerControllerDelegate.html#/c:@M@VGSCollectSDK@objc(pl)VGSFilePickerControllerDelegate(im)filePickingFailedWithError:":{"name":"filePickingFailedWithError(_:)","abstract":"

    On error occured when user pick a file.

    ","parent_name":"VGSFilePickerControllerDelegate"},"Classes/VGSFilePickerConfiguration.html#/s:13VGSCollectSDK26VGSFilePickerConfigurationC9fieldNameSSvp":{"name":"fieldName","abstract":"

    Name that will be associated with selected file by user. Used as a JSON key on send request with file data to your organozation vault.

    ","parent_name":"VGSFilePickerConfiguration"},"Classes/VGSFilePickerConfiguration.html#/s:13VGSCollectSDK26VGSFilePickerConfigurationC9collector9fieldName10fileSourceAcA0A0C_SSAA0cJ0Otcfc":{"name":"init(collector:fieldName:fileSource:)","abstract":"

    Initialization

    ","parent_name":"VGSFilePickerConfiguration"},"Classes/VGSFilePickerController.html#/s:13VGSCollectSDK23VGSFilePickerControllerC8delegateAA0cdE8Delegate_pSgvp":{"name":"delegate","abstract":"

    VGSFilePickerControllerDelegate - handle user interaction on file picking.

    ","parent_name":"VGSFilePickerController"},"Classes/VGSFilePickerController.html#/s:13VGSCollectSDK23VGSFilePickerControllerC13configurationAcA0cD13ConfigurationC_tcfc":{"name":"init(configuration:)","abstract":"

    Initialization

    ","parent_name":"VGSFilePickerController"},"Classes/VGSFilePickerController.html#/s:13VGSCollectSDK23VGSFilePickerControllerC011presentFileD02on8animated10completionySo06UIViewE0C_SbyycSgtF":{"name":"presentFilePicker(on:animated:completion:)","abstract":"

    Present file picker view

    ","parent_name":"VGSFilePickerController"},"Classes/VGSFilePickerController.html#/s:13VGSCollectSDK23VGSFilePickerControllerC011dismissFileD08animated10completionySb_yycSgtF":{"name":"dismissFilePicker(animated:completion:)","abstract":"

    Dismiss file picker view

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

    Controller responsible for importing files from device sources.

    "},"Classes/VGSFilePickerConfiguration.html":{"name":"VGSFilePickerConfiguration","abstract":"

    A class responsible for configuration VGSFilePickerController.

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

    Delegates produced by VGSFilePickerController.

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

    Available file source destinations that VGSFilePickerController can work with.

    "},"Classes/VGSFileInfo.html":{"name":"VGSFileInfo","abstract":"

    An object that holds optional files’ metadata on selecting file through VGSFilePickerController.

    "},"Enums/VGSVaultStorageType.html#/s:13VGSCollectSDK19VGSVaultStorageTypeO10PERSISTENTyA2CmF":{"name":"PERSISTENT","abstract":"

    PERSISTENT data storage.

    ","parent_name":"VGSVaultStorageType"},"Enums/VGSVaultStorageType.html#/s:13VGSCollectSDK19VGSVaultStorageTypeO8VOLATILEyA2CmF":{"name":"VOLATILE","abstract":"

    VOLATILE data storage.

    ","parent_name":"VGSVaultStorageType"},"Enums/VGSVaultAliasFormat.html#/s:13VGSCollectSDK19VGSVaultAliasFormatO18FPE_ACC_NUM_T_FOURyA2CmF":{"name":"FPE_ACC_NUM_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/s:13VGSCollectSDK19VGSVaultAliasFormatO31FPE_ALPHANUMERIC_ACC_NUM_T_FOURyA2CmF":{"name":"FPE_ALPHANUMERIC_ACC_NUM_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/s:13VGSCollectSDK19VGSVaultAliasFormatO14FPE_SIX_T_FOURyA2CmF":{"name":"FPE_SIX_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/s:13VGSCollectSDK19VGSVaultAliasFormatO14FPE_SSN_T_FOURyA2CmF":{"name":"FPE_SSN_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/s:13VGSCollectSDK19VGSVaultAliasFormatO10FPE_T_FOURyA2CmF":{"name":"FPE_T_FOUR","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/s:13VGSCollectSDK19VGSVaultAliasFormatO21NUM_LENGTH_PRESERVINGyA2CmF":{"name":"NUM_LENGTH_PRESERVING","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/s:13VGSCollectSDK19VGSVaultAliasFormatO4PFPTyA2CmF":{"name":"PFPT","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/s:13VGSCollectSDK19VGSVaultAliasFormatO8RAW_UUIDyA2CmF":{"name":"RAW_UUID","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Enums/VGSVaultAliasFormat.html#/s:13VGSCollectSDK19VGSVaultAliasFormatO4UUIDyA2CmF":{"name":"UUID","abstract":"

    no:doc

    ","parent_name":"VGSVaultAliasFormat"},"Structs/VGSTokenizationParameters.html#/s:13VGSCollectSDK25VGSTokenizationParametersV7storageSSvp":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSTokenizationParameters"},"Structs/VGSTokenizationParameters.html#/s:13VGSCollectSDK25VGSTokenizationParametersV6formatSSvp":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSTokenizationParameters"},"Structs/VGSSSNTokenizationParameters.html#/s:13VGSCollectSDK28VGSSSNTokenizationParametersV7storageSSvp":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSSSNTokenizationParameters"},"Structs/VGSSSNTokenizationParameters.html#/s:13VGSCollectSDK28VGSSSNTokenizationParametersV6formatSSvp":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSSSNTokenizationParameters"},"Structs/VGSExpDateTokenizationParameters.html#/s:13VGSCollectSDK32VGSExpDateTokenizationParametersV7storageSSvp":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSExpDateTokenizationParameters"},"Structs/VGSExpDateTokenizationParameters.html#/s:13VGSCollectSDK32VGSExpDateTokenizationParametersV6formatSSvp":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSExpDateTokenizationParameters"},"Structs/VGSDateTokenizationParameters.html#/s:13VGSCollectSDK29VGSDateTokenizationParametersV7storageSSvp":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSDateTokenizationParameters"},"Structs/VGSDateTokenizationParameters.html#/s:13VGSCollectSDK29VGSDateTokenizationParametersV6formatSSvp":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSDateTokenizationParameters"},"Structs/VGSCardNumberTokenizationParameters.html#/s:13VGSCollectSDK35VGSCardNumberTokenizationParametersV7storageSSvp":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSCardNumberTokenizationParameters"},"Structs/VGSCardNumberTokenizationParameters.html#/s:13VGSCollectSDK35VGSCardNumberTokenizationParametersV6formatSSvp":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSCardNumberTokenizationParameters"},"Structs/VGSCardHolderNameTokenizationParameters.html#/s:13VGSCollectSDK39VGSCardHolderNameTokenizationParametersV7storageSSvp":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSCardHolderNameTokenizationParameters"},"Structs/VGSCardHolderNameTokenizationParameters.html#/s:13VGSCollectSDK39VGSCardHolderNameTokenizationParametersV6formatSSvp":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSCardHolderNameTokenizationParameters"},"Structs/VGSCVCTokenizationParameters.html#/s:13VGSCollectSDK28VGSCVCTokenizationParametersV7storageSSvp":{"name":"storage","abstract":"

    Vault storage type.

    ","parent_name":"VGSCVCTokenizationParameters"},"Structs/VGSCVCTokenizationParameters.html#/s:13VGSCollectSDK28VGSCVCTokenizationParametersV6formatSSvp":{"name":"format","abstract":"

    Data alies format.

    ","parent_name":"VGSCVCTokenizationParameters"},"Protocols/VGSTokenizationParametersProtocol.html#/s:13VGSCollectSDK33VGSTokenizationParametersProtocolP6formatSSvp":{"name":"format","abstract":"

    Tokenization format.

    ","parent_name":"VGSTokenizationParametersProtocol"},"Protocols/VGSTokenizationParametersProtocol.html#/s:13VGSCollectSDK33VGSTokenizationParametersProtocolP7storageSSvp":{"name":"storage","abstract":"

    Storage type.

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

    Parameters describing textfield input tokenization.

    "},"Structs/VGSCVCTokenizationParameters.html":{"name":"VGSCVCTokenizationParameters","abstract":"

    VGSCVCTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSCardHolderNameTokenizationParameters.html":{"name":"VGSCardHolderNameTokenizationParameters","abstract":"

    VGSCardHolderNameTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSCardNumberTokenizationParameters.html":{"name":"VGSCardNumberTokenizationParameters","abstract":"

    VGSCardTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSDateTokenizationParameters.html":{"name":"VGSDateTokenizationParameters","abstract":"

    VGSDateTokenizationParameters - parameters required for tokenization API

    "},"Structs/VGSExpDateTokenizationParameters.html":{"name":"VGSExpDateTokenizationParameters","abstract":"

    VGSExpDateTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSSSNTokenizationParameters.html":{"name":"VGSSSNTokenizationParameters","abstract":"

    VGSSSNTokenizationParameters - parameters required for tokenization api.

    "},"Structs/VGSTokenizationParameters.html":{"name":"VGSTokenizationParameters","abstract":"

    VGSTokenizationParameters - parameters required for tokenization api.

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

    Type of Alias format. Read more about avaliable formats: https://www.verygoodsecurity.com/docs/terminology/nomenclature#alias-formats .

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

    Type of VGS Vault storage.

    "},"Enums/VGSTextFieldInputSource.html#/s:13VGSCollectSDK23VGSTextFieldInputSourceO8keyboardyA2CmF":{"name":"keyboard","abstract":"

    UIKeyboard input type.

    ","parent_name":"VGSTextFieldInputSource"},"Enums/VGSTextFieldInputSource.html#/s:13VGSCollectSDK23VGSTextFieldInputSourceO10datePickeryA2CmF":{"name":"datePicker","abstract":"

    UIDatePicker input type.

    ","parent_name":"VGSTextFieldInputSource"},"Structs/VGSDate.html#/s:13VGSCollectSDK7VGSDateV12dayFormattedSSvp":{"name":"dayFormatted","abstract":"

    Get the day formatted value, for example if the day is 1 it is returned as 01

    ","parent_name":"VGSDate"},"Structs/VGSDate.html#/s:13VGSCollectSDK7VGSDateV14monthFormattedSSvp":{"name":"monthFormatted","abstract":"

    Get the month formatted value, for example if the month is 3 it is returned as 03

    ","parent_name":"VGSDate"},"Structs/VGSDate.html#/s:13VGSCollectSDK7VGSDateV3day5month4yearACSgSi_S2itcfc":{"name":"init(day:month:year:)","abstract":"

    Create a new instance of a VGSDate object, if the date is not valid, it returns nil

    ","parent_name":"VGSDate"},"Enums/VGSDateFormat.html#/s:13VGSCollectSDK13VGSDateFormatO07displayD0SSvp":{"name":"displayFormat","abstract":"

    Date format used for display in UI

    ","parent_name":"VGSDateFormat"},"Enums/VGSDateFormat.html#/s:13VGSCollectSDK13VGSDateFormatO7defaultACvpZ":{"name":"default","abstract":"

    Default format

    ","parent_name":"VGSDateFormat"},"Enums/FieldType.html#/s:13VGSCollectSDK9FieldTypeO4noneyA2CmF":{"name":"none","abstract":"

    Field type that doesn’t require any input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/s:13VGSCollectSDK9FieldTypeO10cardNumberyA2CmF":{"name":"cardNumber","abstract":"

    Field type that requires Credit Card Number input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/s:13VGSCollectSDK9FieldTypeO7expDateyA2CmF":{"name":"expDate","abstract":"

    Field type that requires Expiration Date input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/s:13VGSCollectSDK9FieldTypeO4dateyA2CmF":{"name":"date","abstract":"

    Field type that requires Date input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/s:13VGSCollectSDK9FieldTypeO3cvcyA2CmF":{"name":"cvc","abstract":"

    Field type that requires Credit Card CVC input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/s:13VGSCollectSDK9FieldTypeO14cardHolderNameyA2CmF":{"name":"cardHolderName","abstract":"

    Field type that requires Cardholder Name input formatting and validation.

    ","parent_name":"FieldType"},"Enums/FieldType.html#/s:13VGSCollectSDK9FieldTypeO3ssnyA2CmF":{"name":"ssn","abstract":"

    Field type that requires US Social Security Number input formatting and validation.

    ","parent_name":"FieldType"},"Protocols/VGSExpDateConfigurationProtocol.html#/s:13VGSCollectSDK31VGSExpDateConfigurationProtocolP11inputSourceAA017VGSTextFieldInputH0Ovp":{"name":"inputSource","abstract":"

    Input Source type.

    ","parent_name":"VGSExpDateConfigurationProtocol"},"Protocols/VGSExpDateConfigurationProtocol.html#/s:13VGSCollectSDK31VGSExpDateConfigurationProtocolP05inputD6FormatAA010VGSCardExpdH0OSgvp":{"name":"inputDateFormat","abstract":"

    Input date format to convert.

    ","parent_name":"VGSExpDateConfigurationProtocol"},"Protocols/VGSExpDateConfigurationProtocol.html#/s:13VGSCollectSDK31VGSExpDateConfigurationProtocolP06outputD6FormatAA010VGSCardExpdH0OSgvp":{"name":"outputDateFormat","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateConfigurationProtocol"},"Protocols/VGSDateConfigurationProtocol.html#/s:13VGSCollectSDK28VGSDateConfigurationProtocolP11inputSourceAA017VGSTextFieldInputG0Ovp":{"name":"inputSource","abstract":"

    Input source type.

    ","parent_name":"VGSDateConfigurationProtocol"},"Protocols/VGSDateConfigurationProtocol.html#/s:13VGSCollectSDK28VGSDateConfigurationProtocolP15inputDateFormatAA0cH0OSgvp":{"name":"inputDateFormat","abstract":"

    Input date format to convert.

    ","parent_name":"VGSDateConfigurationProtocol"},"Protocols/VGSDateConfigurationProtocol.html#/s:13VGSCollectSDK28VGSDateConfigurationProtocolP16outputDateFormatAA0cH0OSgvp":{"name":"outputDateFormat","abstract":"

    Output date format to convert.

    ","parent_name":"VGSDateConfigurationProtocol"},"Classes/VGSTokenizationConfiguration.html#/s:13VGSCollectSDK28VGSTokenizationConfigurationC22tokenizationParametersAA0cF0Vvp":{"name":"tokenizationParameters","abstract":"

    VGSTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSTokenizationConfiguration"},"Classes/VGSSSNTokenizationConfiguration.html#/s:13VGSCollectSDK31VGSSSNTokenizationConfigurationC22tokenizationParametersAA0cF0Vvp":{"name":"tokenizationParameters","abstract":"

    VGSSSNTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSSSNTokenizationConfiguration"},"Classes/VGSSSNTokenizationConfiguration.html#/s:13VGSCollectSDK31VGSSSNTokenizationConfigurationC4typeAA9FieldTypeOvp":{"name":"type","abstract":"

    FieldType.ssn type of VGSTextFieldtokenization configuration.

    ","parent_name":"VGSSSNTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/s:13VGSCollectSDK35VGSExpDateTokenizationConfigurationC4typeAA9FieldTypeOvp":{"name":"type","abstract":"

    FieldType.expDate type of VGSTextFieldtokenization configuration.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/s:13VGSCollectSDK35VGSExpDateTokenizationConfigurationC11inputSourceAA017VGSTextFieldInputH0Ovp":{"name":"inputSource","abstract":"

    Input Source type. Default is VGSTextFieldInputSource.datePicker.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/s:13VGSCollectSDK35VGSExpDateTokenizationConfigurationC05inputD6FormatAA010VGSCardExpdH0OSgvp":{"name":"inputDateFormat","abstract":"

    Input date format to convert.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/s:13VGSCollectSDK35VGSExpDateTokenizationConfigurationC06outputD6FormatAA010VGSCardExpdH0OSgvp":{"name":"outputDateFormat","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/s:13VGSCollectSDK35VGSExpDateTokenizationConfigurationC22tokenizationParametersAA0cdeH0Vvp":{"name":"tokenizationParameters","abstract":"

    VGSExpDateTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSExpDateTokenizationConfiguration.html#/s:13VGSCollectSDK35VGSExpDateTokenizationConfigurationC11serializersSayAA27VGSFormatSerializerProtocol_pGvp":{"name":"serializers","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateTokenizationConfiguration"},"Classes/VGSDateTokenizationConfiguration.html#/s:13VGSCollectSDK32VGSDateTokenizationConfigurationC9collector9fieldName19datePickerStartDate0ij3EndL0AcA0A0C_SSAA0C0VSgALtcfc":{"name":"init(collector:fieldName:datePickerStartDate:datePickerEndDate:)","abstract":"

    Initialization","parent_name":"VGSDateTokenizationConfiguration"},"Classes/VGSDateTokenizationConfiguration.html#/s:13VGSCollectSDK32VGSDateTokenizationConfigurationC4typeAA9FieldTypeOvp":{"name":"type","abstract":"

    Super initializer

    ","parent_name":"VGSDateTokenizationConfiguration"},"Classes/VGSDateTokenizationConfiguration.html#/s:13VGSCollectSDK28VGSDateConfigurationProtocolP11inputSourceAA017VGSTextFieldInputG0Ovp":{"name":"inputSource","parent_name":"VGSDateTokenizationConfiguration"},"Classes/VGSDateTokenizationConfiguration.html#/s:13VGSCollectSDK28VGSDateConfigurationProtocolP15inputDateFormatAA0cH0OSgvp":{"name":"inputDateFormat","parent_name":"VGSDateTokenizationConfiguration"},"Classes/VGSDateTokenizationConfiguration.html#/s:13VGSCollectSDK28VGSDateConfigurationProtocolP16outputDateFormatAA0cH0OSgvp":{"name":"outputDateFormat","parent_name":"VGSDateTokenizationConfiguration"},"Classes/VGSCVCTokenizationConfiguration.html#/s:13VGSCollectSDK31VGSCVCTokenizationConfigurationC22tokenizationParametersAA0cF0Vvp":{"name":"tokenizationParameters","abstract":"

    VGSCVCTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSCVCTokenizationConfiguration"},"Classes/VGSCVCTokenizationConfiguration.html#/s:13VGSCollectSDK31VGSCVCTokenizationConfigurationC4typeAA9FieldTypeOvp":{"name":"type","abstract":"

    FieldType.cvc type of VGSTextFieldtokenization configuration.

    ","parent_name":"VGSCVCTokenizationConfiguration"},"Classes/VGSCardNumberTokenizationConfiguration.html#/s:13VGSCollectSDK38VGSCardNumberTokenizationConfigurationC22tokenizationParametersAA0cdeH0Vvp":{"name":"tokenizationParameters","abstract":"

    VGSCardTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSCardNumberTokenizationConfiguration"},"Classes/VGSCardNumberTokenizationConfiguration.html#/s:13VGSCollectSDK38VGSCardNumberTokenizationConfigurationC4typeAA9FieldTypeOvp":{"name":"type","abstract":"

    FieldType.cardNumber type of VGSTextFieldtokenization configuration.

    ","parent_name":"VGSCardNumberTokenizationConfiguration"},"Classes/VGSCardHolderNameTokenizationConfiguration.html#/s:13VGSCollectSDK42VGSCardHolderNameTokenizationConfigurationC22tokenizationParametersAA0cdefI0Vvp":{"name":"tokenizationParameters","abstract":"

    VGSCardHolderNameTokenizationParameters - tokenization configuration parameters.

    ","parent_name":"VGSCardHolderNameTokenizationConfiguration"},"Classes/VGSCardHolderNameTokenizationConfiguration.html#/s:13VGSCollectSDK42VGSCardHolderNameTokenizationConfigurationC4typeAA9FieldTypeOvp":{"name":"type","abstract":"

    FieldType.cardHolderName type of VGSTextFieldtokenization configuration.

    ","parent_name":"VGSCardHolderNameTokenizationConfiguration"},"Classes/VGSDateConfiguration.html#/s:13VGSCollectSDK20VGSDateConfigurationC9collector9fieldName19datePickerStartDate0hi3EndK0AcA0A0C_SSAA0C0VSgALtcfc":{"name":"init(collector:fieldName:datePickerStartDate:datePickerEndDate:)","abstract":"

    Initialization","parent_name":"VGSDateConfiguration"},"Classes/VGSDateConfiguration.html#/s:13VGSCollectSDK20VGSDateConfigurationC4typeAA9FieldTypeOvp":{"name":"type","abstract":"

    Super initializer

    ","parent_name":"VGSDateConfiguration"},"Classes/VGSDateConfiguration.html#/s:13VGSCollectSDK28VGSDateConfigurationProtocolP11inputSourceAA017VGSTextFieldInputG0Ovp":{"name":"inputSource","parent_name":"VGSDateConfiguration"},"Classes/VGSDateConfiguration.html#/s:13VGSCollectSDK28VGSDateConfigurationProtocolP15inputDateFormatAA0cH0OSgvp":{"name":"inputDateFormat","parent_name":"VGSDateConfiguration"},"Classes/VGSDateConfiguration.html#/s:13VGSCollectSDK28VGSDateConfigurationProtocolP16outputDateFormatAA0cH0OSgvp":{"name":"outputDateFormat","parent_name":"VGSDateConfiguration"},"Classes/VGSDateConfiguration.html#/s:13VGSCollectSDK20VGSDateConfigurationC15validYearsCountSivpZ":{"name":"validYearsCount","abstract":"

    Amount of years used to calculate the minimun and maximun date picker default dates

    ","parent_name":"VGSDateConfiguration"},"Classes/VGSDateConfiguration.html#/s:13VGSCollectSDK20VGSDateConfigurationC23minValidPickerStartDateAA0C0VvpZ":{"name":"minValidPickerStartDate","abstract":"

    Minimun date picker start date, current year minus validYearsCount

    ","parent_name":"VGSDateConfiguration"},"Classes/VGSDateConfiguration.html#/s:13VGSCollectSDK20VGSDateConfigurationC21maxValidPickerEndDateAA0C0VvpZ":{"name":"maxValidPickerEndDate","abstract":"

    Maximun date picker valid end date, current year plus validYearsCount

    ","parent_name":"VGSDateConfiguration"},"Classes/VGSExpDateConfiguration.html#/s:13VGSCollectSDK23VGSExpDateConfigurationC4typeAA9FieldTypeOvp":{"name":"type","abstract":"

    FieldType.expDate type of VGSTextField configuration.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSExpDateConfiguration.html#/s:13VGSCollectSDK23VGSExpDateConfigurationC11inputSourceAA017VGSTextFieldInputG0Ovp":{"name":"inputSource","abstract":"

    Input Source type. Default is VGSTextFieldInputSource.datePicker.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSExpDateConfiguration.html#/s:13VGSCollectSDK23VGSExpDateConfigurationC05inputD6FormatAA010VGSCardExpdG0OSgvp":{"name":"inputDateFormat","abstract":"

    Input date format to convert.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSExpDateConfiguration.html#/s:13VGSCollectSDK23VGSExpDateConfigurationC06outputD6FormatAA010VGSCardExpdG0OSgvp":{"name":"outputDateFormat","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSExpDateConfiguration.html#/s:13VGSCollectSDK23VGSExpDateConfigurationC11serializersSayAA27VGSFormatSerializerProtocol_pGvp":{"name":"serializers","abstract":"

    Output date format.

    ","parent_name":"VGSExpDateConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC12vgsCollectorAA0A0CSgvp":{"name":"vgsCollector","abstract":"

    Collect form that will be assiciated with VGSTextField.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC4typeAA9FieldTypeOvp":{"name":"type","abstract":"

    Type of field congfiguration. Default is FieldType.none.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC9fieldNameSSvp":{"name":"fieldName","abstract":"

    Name that will be associated with VGSTextField and used as a JSON key on send request with textfield data to your organozation vault.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC10isRequiredSbvp":{"name":"isRequired","abstract":"

    Set if VGSTextField is required to be non-empty and non-nil on send request. Default is false.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC19isRequiredValidOnlySbvp":{"name":"isRequiredValidOnly","abstract":"

    Set if VGSTextField is required to be valid only on send request. Default is false.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC13formatPatternSSSgvp":{"name":"formatPattern","abstract":"

    Input data visual format pattern. If not applied, will be set by default depending on field type.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC7dividerSSSgvp":{"name":"divider","abstract":"

    String, used to replace not default VGSConfiguration.formatPattern characters in input text on send request.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC12keyboardTypeSo010UIKeyboardE0VSgvp":{"name":"keyboardType","abstract":"

    Preferred UIKeyboardType for VGSTextField. If not applied, will be set by default depending on field type parameter.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC13returnKeyTypeSo08UIReturneF0VSgvp":{"name":"returnKeyType","abstract":"

    Preferred UIReturnKeyType for VGSTextField.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC18keyboardAppearanceSo010UIKeyboardE0VSgvp":{"name":"keyboardAppearance","abstract":"

    Preferred UIKeyboardAppearance for textfield. By default is UIKeyboardAppearance.default.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC15validationRulesAA20VGSValidationRuleSetVSgvp":{"name":"validationRules","abstract":"

    Validation rules for field input. Defines State.isValide result.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC14maxInputLengthSiSgvp":{"name":"maxInputLength","abstract":"

    Max input length. IMPORTANT! Can conflict with .formatPattern attribute.

    ","parent_name":"VGSConfiguration"},"Classes/VGSConfiguration.html#/s:13VGSCollectSDK16VGSConfigurationC9collector9fieldNameAcA0A0C_SStcfc":{"name":"init(collector:fieldName:)","abstract":"

    Initialization

    ","parent_name":"VGSConfiguration"},"Protocols/VGSTextFieldDelegate.html#/c:@M@VGSCollectSDK@objc(pl)VGSTextFieldDelegate(im)vgsTextFieldDidBeginEditing:":{"name":"vgsTextFieldDidBeginEditing(_:)","abstract":"

    VGSTextField did become first responder.

    ","parent_name":"VGSTextFieldDelegate"},"Protocols/VGSTextFieldDelegate.html#/c:@M@VGSCollectSDK@objc(pl)VGSTextFieldDelegate(im)vgsTextFieldDidEndEditing:":{"name":"vgsTextFieldDidEndEditing(_:)","abstract":"

    VGSTextField did resign first responder.

    ","parent_name":"VGSTextFieldDelegate"},"Protocols/VGSTextFieldDelegate.html#/c:@M@VGSCollectSDK@objc(pl)VGSTextFieldDelegate(im)vgsTextFieldDidEndEditingOnReturn:":{"name":"vgsTextFieldDidEndEditingOnReturn(_:)","abstract":"

    VGSTextField did resign first responder on Return button pressed.

    ","parent_name":"VGSTextFieldDelegate"},"Protocols/VGSTextFieldDelegate.html#/c:@M@VGSCollectSDK@objc(pl)VGSTextFieldDelegate(im)vgsTextFieldDidChange:":{"name":"vgsTextFieldDidChange(_:)","abstract":"

    VGSTextField input changed.

    ","parent_name":"VGSTextFieldDelegate"},"Classes/VGSCVCTextField/CVCIconLocation.html#/s:13VGSCollectSDK15VGSCVCTextFieldC15CVCIconLocationO4leftyA2EmF":{"name":"left","abstract":"

    CVC icon at left side of VGSCardTextField.

    ","parent_name":"CVCIconLocation"},"Classes/VGSCVCTextField/CVCIconLocation.html#/s:13VGSCollectSDK15VGSCVCTextFieldC15CVCIconLocationO5rightyA2EmF":{"name":"right","abstract":"

    CVC icon at right side of VGSCardTextField.

    ","parent_name":"CVCIconLocation"},"Classes/VGSCVCTextField/CVCIconLocation.html":{"name":"CVCIconLocation","abstract":"

    Available CVC icon positions enum.

    ","parent_name":"VGSCVCTextField"},"Classes/VGSCVCTextField.html#/s:13VGSCollectSDK15VGSCVCTextFieldC15cvcIconLocationAC07CVCIconG0Ovp":{"name":"cvcIconLocation","abstract":"

    CVC icon position inside VGSCardTextField.

    ","parent_name":"VGSCVCTextField"},"Classes/VGSCVCTextField.html#/s:13VGSCollectSDK15VGSCVCTextFieldC11cvcIconSizeSo6CGSizeVvp":{"name":"cvcIconSize","abstract":"

    CVC icon size.

    ","parent_name":"VGSCVCTextField"},"Classes/VGSCVCTextField.html#/s:13VGSCollectSDK15VGSCVCTextFieldC13cvcIconSourceSo7UIImageCSgAA15VGSPaymentCardsC9CardBrandOcSgvp":{"name":"cvcIconSource","abstract":"

    Asks custom image for specific VGSPaymentCards.CardBrand

    ","parent_name":"VGSCVCTextField"},"Classes/VGSDateTextField/MonthFormat.html#/s:13VGSCollectSDK16VGSDateTextFieldC11MonthFormatO12shortSymbolsyA2EmF":{"name":"shortSymbols","abstract":"

    Short month name, e.g.: Jan

    ","parent_name":"MonthFormat"},"Classes/VGSDateTextField/MonthFormat.html#/s:13VGSCollectSDK16VGSDateTextFieldC11MonthFormatO11longSymbolsyA2EmF":{"name":"longSymbols","abstract":"

    Long month name, e.g.: January

    ","parent_name":"MonthFormat"},"Classes/VGSDateTextField/MonthFormat.html#/s:13VGSCollectSDK16VGSDateTextFieldC11MonthFormatO7numbersyA2EmF":{"name":"numbers","abstract":"

    Month number: e.g.: 01

    ","parent_name":"MonthFormat"},"Classes/VGSDateTextField/MonthFormat.html":{"name":"MonthFormat","abstract":"

    Available month Label formats in UIPickerView

    ","parent_name":"VGSDateTextField"},"Classes/VGSDateTextField.html#/s:13VGSCollectSDK16VGSDateTextFieldC17monthPickerFormatAC05MonthH0Ovp":{"name":"monthPickerFormat","abstract":"

    UIPickerView month label format

    ","parent_name":"VGSDateTextField"},"Classes/VGSDateTextField.html#/s:13VGSCollectSDK16VGSDateTextFieldC13configurationAA16VGSConfigurationCSgvp":{"name":"configuration","parent_name":"VGSDateTextField"},"Classes/VGSExpDateTextField/YearFormat.html#/s:13VGSCollectSDK19VGSExpDateTextFieldC10YearFormatO5shortyA2EmF":{"name":"short","abstract":"

    Two digits year format, e.g.: 21

    ","parent_name":"YearFormat"},"Classes/VGSExpDateTextField/YearFormat.html#/s:13VGSCollectSDK19VGSExpDateTextFieldC10YearFormatO4longyA2EmF":{"name":"long","abstract":"

    Four digits year format:, e.g.:2021

    ","parent_name":"YearFormat"},"Classes/VGSExpDateTextField/MonthFormat.html#/s:13VGSCollectSDK19VGSExpDateTextFieldC11MonthFormatO12shortSymbolsyA2EmF":{"name":"shortSymbols","abstract":"

    Short month name, e.g.: Jan

    ","parent_name":"MonthFormat"},"Classes/VGSExpDateTextField/MonthFormat.html#/s:13VGSCollectSDK19VGSExpDateTextFieldC11MonthFormatO11longSymbolsyA2EmF":{"name":"longSymbols","abstract":"

    Long month name, e.g.: January

    ","parent_name":"MonthFormat"},"Classes/VGSExpDateTextField/MonthFormat.html#/s:13VGSCollectSDK19VGSExpDateTextFieldC11MonthFormatO7numbersyA2EmF":{"name":"numbers","abstract":"

    Month number: e.g.: 01

    ","parent_name":"MonthFormat"},"Classes/VGSExpDateTextField/MonthFormat.html":{"name":"MonthFormat","abstract":"

    Available Month Label formats in UIPickerView

    ","parent_name":"VGSExpDateTextField"},"Classes/VGSExpDateTextField/YearFormat.html":{"name":"YearFormat","abstract":"

    Available Year Label formats in UIPickerView

    ","parent_name":"VGSExpDateTextField"},"Classes/VGSExpDateTextField.html#/s:13VGSCollectSDK19VGSExpDateTextFieldC17monthPickerFormatAC05MonthI0Ovp":{"name":"monthPickerFormat","abstract":"

    UIPickerView Month Label format

    ","parent_name":"VGSExpDateTextField"},"Classes/VGSExpDateTextField.html#/s:13VGSCollectSDK19VGSExpDateTextFieldC15yearPickeFormatAC04YearI0Ovp":{"name":"yearPickeFormat","abstract":"

    UIPickerView Year Label format

    ","parent_name":"VGSExpDateTextField"},"Classes/VGSCardTextField/CardIconLocation.html#/s:13VGSCollectSDK16VGSCardTextFieldC16CardIconLocationO4leftyA2EmF":{"name":"left","abstract":"

    Card brand icon at left side of VGSCardTextField.

    ","parent_name":"CardIconLocation"},"Classes/VGSCardTextField/CardIconLocation.html#/s:13VGSCollectSDK16VGSCardTextFieldC16CardIconLocationO5rightyA2EmF":{"name":"right","abstract":"

    Card brand icon at right side of VGSCardTextField.

    ","parent_name":"CardIconLocation"},"Classes/VGSCardTextField/CardIconLocation.html":{"name":"CardIconLocation","abstract":"

    Available Card brand icon positions enum.

    ","parent_name":"VGSCardTextField"},"Classes/VGSCardTextField.html#/s:13VGSCollectSDK16VGSCardTextFieldC16cardIconLocationAC04CardgH0Ovp":{"name":"cardIconLocation","abstract":"

    Card brand icon position inside VGSCardTextField.

    ","parent_name":"VGSCardTextField"},"Classes/VGSCardTextField.html#/s:13VGSCollectSDK16VGSCardTextFieldC12cardIconSizeSo6CGSizeVvp":{"name":"cardIconSize","abstract":"

    Card brand icon size.

    ","parent_name":"VGSCardTextField"},"Classes/VGSCardTextField.html#/s:13VGSCollectSDK16VGSCardTextFieldC15cardsIconSourceSo7UIImageCSgAA15VGSPaymentCardsC9CardBrandOcSgvp":{"name":"cardsIconSource","abstract":"

    Asks custom image for specific VGSPaymentCards.CardBrand

    ","parent_name":"VGSCardTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC11placeholderSSSgvp":{"name":"placeholder","abstract":"

    Textfield placeholder string.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC22autocapitalizationTypeSo024UITextAutocapitalizationF0Vvp":{"name":"autocapitalizationType","abstract":"

    Textfield autocapitalization type. Default is .sentences.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC17spellCheckingTypeSo011UITextSpellfG0Vvp":{"name":"spellCheckingType","abstract":"

    Textfield spell checking type. Default is UITextSpellCheckingType.default.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC21attributedPlaceholderSo18NSAttributedStringCSgvp":{"name":"attributedPlaceholder","abstract":"

    Textfield attributedPlaceholder string.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC7paddingSo12UIEdgeInsetsVvp":{"name":"padding","abstract":"

    UIEdgeInsets for text and placeholder inside VGSTextField.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC13textAlignmentSo06NSTextF0Vvp":{"name":"textAlignment","abstract":"

    The technique to use for aligning the text.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC15clearButtonModeSo06UITextd4ViewG0Vvp":{"name":"clearButtonMode","abstract":"

    Sets when the clear button shows up. Default is UITextField.ViewMode.never

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC17isSecureTextEntrySbvp":{"name":"isSecureTextEntry","abstract":"

    Identifies whether the text object should disable text copying and in some cases hide the text being entered. Default is false.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC33adjustsFontForContentSizeCategorySbvp":{"name":"adjustsFontForContentSizeCategory","abstract":"

    Indicates whether VGSTextField should automatically update its font when the device’s UIContentSizeCategory is changed.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC21keyboardAccessoryViewSo6UIViewCSgvp":{"name":"keyboardAccessoryView","abstract":"

    Input Accessory View

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC18autocorrectionTypeSo020UITextAutocorrectionF0Vvp":{"name":"autocorrectionType","abstract":"

    Determines whether autocorrection is enabled or disabled during typing.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC04textD18AccessibilityLabelSSSgvp":{"name":"textFieldAccessibilityLabel","abstract":"

    A succinct label in a localized string that identifies the accessibility text field.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC04textD17AccessibilityHintSSSgvp":{"name":"textFieldAccessibilityHint","abstract":"

    A localized string that contains a brief description of the result of performing an action on the accessibility text field.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC13configurationAA16VGSConfigurationCSgvp":{"name":"configuration","abstract":"

    Specifies VGSTextField configuration parameters to work with VGSCollect.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC8delegateAA0cD8Delegate_pSgvp":{"name":"delegate","abstract":"

    Delegates VGSTextField editing events. Default is nil.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC14setDefaultTextyySSSgF":{"name":"setDefaultText(_:)","abstract":"

    Set textfield default text.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC9cleanTextyyF":{"name":"cleanText()","abstract":"

    Removes input from field.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC14isContentEqualySbACF":{"name":"isContentEqual(_:)","abstract":"

    Check if input text in two textfields is same. Returns Bool.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC4fontSo6UIFontCSgvp":{"name":"font","abstract":"

    VGSTextField text font

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/c:@CM@VGSCollectSDK@objc(cs)VGSTextField(py)textColor":{"name":"textColor","abstract":"

    VGSTextField text color

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/c:@CM@VGSCollectSDK@objc(cs)VGSTextField(py)cornerRadius":{"name":"cornerRadius","abstract":"

    VGSTextField layer corner radius

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/c:@CM@VGSCollectSDK@objc(cs)VGSTextField(py)borderWidth":{"name":"borderWidth","abstract":"

    VGSTextField layer borderWidth

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/c:@CM@VGSCollectSDK@objc(cs)VGSTextField(py)borderColor":{"name":"borderColor","abstract":"

    VGSTextField layer borderColor

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/s:13VGSCollectSDK12VGSTextFieldC14statePublisherAA0cd5StateF0Vvp":{"name":"statePublisher","abstract":"

    VGSTextFieldStatePublisher publisher that emits the State of a given VGSTextField.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/c:@CM@VGSCollectSDK@objc(cs)VGSTextField(im)becomeFirstResponder":{"name":"becomeFirstResponder()","abstract":"

    Make VGSTextField focused.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/c:@CM@VGSCollectSDK@objc(cs)VGSTextField(im)resignFirstResponder":{"name":"resignFirstResponder()","abstract":"

    Remove focus from VGSTextField.

    ","parent_name":"VGSTextField"},"Classes/VGSTextField.html#/c:@CM@VGSCollectSDK@objc(cs)VGSTextField(py)isFirstResponder":{"name":"isFirstResponder","abstract":"

    Check if VGSTextField is focused.

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

    An object that displays an editable text area in user interface.

    "},"Classes/VGSCardTextField.html":{"name":"VGSCardTextField","abstract":"

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to detect and show credit card brand images.

    "},"Classes/VGSExpDateTextField.html":{"name":"VGSExpDateTextField","abstract":"

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to show picker view with Card Number Expiration Month and Year.

    "},"Classes/VGSDateTextField.html":{"name":"VGSDateTextField","abstract":"

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to show picker view with a Date. It support to define a range of valid dates to select from.

    "},"Classes/VGSCVCTextField.html":{"name":"VGSCVCTextField","abstract":"

    An object that displays an editable text area. Can be use instead of a VGSTextField when need to show CVC/CVV images for credit card brands.

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

    Delegates produced by VGSTextField instance.

    "},"Classes/VGSConfiguration.html":{"name":"VGSConfiguration","abstract":"

    A class responsible for configuration VGSTextField.

    "},"Classes/VGSExpDateConfiguration.html":{"name":"VGSExpDateConfiguration","abstract":"

    A class responsible for configuration VGSTextField with fieldType = .expDate. Extends VGSConfiguration class.

    "},"Classes/VGSDateConfiguration.html":{"name":"VGSDateConfiguration","abstract":"

    Class responsible for configuration VGSDateTextField or VGSTextField with fieldType = .date. Extends VGSConfiguration

    "},"Classes/VGSCardHolderNameTokenizationConfiguration.html":{"name":"VGSCardHolderNameTokenizationConfiguration","abstract":"

    VGSCardHolderNameTokenizationConfiguration - textfield configuration for textfield with type .cardHolderName, required for work with tokenization api.

    "},"Classes/VGSCardNumberTokenizationConfiguration.html":{"name":"VGSCardNumberTokenizationConfiguration","abstract":"

    VGSCardTokenizationConfiguration - textfield configuration for textfield with type .cardNumber, required for work with tokenization api.

    "},"Classes/VGSCVCTokenizationConfiguration.html":{"name":"VGSCVCTokenizationConfiguration","abstract":"

    VGSCVCTokenizationConfiguration - textfield configuration for textfield with type .cvc, required for work with tokenization api.

    "},"Classes/VGSDateTokenizationConfiguration.html":{"name":"VGSDateTokenizationConfiguration","abstract":"

    Class responsible for configuration VGSDateTextField or VGSTextField with fieldType = .date."},"Classes/VGSExpDateTokenizationConfiguration.html":{"name":"VGSExpDateTokenizationConfiguration","abstract":"

    VGSExpDateTokenizationConfiguration - textfield configuration for textfield with type .expDate, required for work with tokenization api.

    "},"Classes/VGSSSNTokenizationConfiguration.html":{"name":"VGSSSNTokenizationConfiguration","abstract":"

    VGSSSNTokenizationConfiguration - textfield configuration for textfield with type .ssn, required for work with tokenization api.

    "},"Classes/VGSTokenizationConfiguration.html":{"name":"VGSTokenizationConfiguration","abstract":"

    VGSTokenizationConfiguration - textfield configuration for textfield with any type of data, required for work with tokenization api.

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

    Define the methods and properties the date configuration must have

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

    Attributes required to configure date format and input source for field with type .expDate.

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

    Type of VGSTextField configuration.

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

    Format used to validate a VGS date text input

    "},"Structs/VGSDate.html":{"name":"VGSDate","abstract":"

    Struct that represents a date including year, month and day. It doesn’t include hours, minutes or seconds.

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

    Type of VGSTextField input source.

    "},"UI%20Elements.html":{"name":"UI Elements"},"Tokenization%20Parameters.html":{"name":"Tokenization Parameters"},"File%20Picker.html":{"name":"File Picker"},"Observe%20State%20and%20Send%20Data.html":{"name":"Observe State and Send Data"},"Payment%20Cards.html":{"name":"Payment Cards"},"VGSTextField%20Serializers.html":{"name":"VGSTextField Serializers"},"Validation%20Rules.html":{"name":"Validation Rules"},"Errors.html":{"name":"Errors"},"Error%20Keys.html":{"name":"Error Keys"},"Debugging.html":{"name":"Debugging"},"Enumerations.html":{"name":"Enumerations"}} \ No newline at end of file diff --git a/docs/undocumented.json b/docs/undocumented.json index c421daec..5e821bd8 100644 --- a/docs/undocumented.json +++ b/docs/undocumented.json @@ -1,6 +1,75 @@ { "warnings": [ - + { + "file": "/Users/donald.rodriguez/Documents/Projects/VGS/repos/vgs-collect-ios/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSDateTokenizationConfiguration.swift", + "line": 76, + "symbol": "VGSDateTokenizationConfiguration.serializers", + "symbol_kind": "source.lang.swift.decl.var.instance", + "warning": "undocumented" + }, + { + "file": "/Users/donald.rodriguez/Documents/Projects/VGS/repos/vgs-collect-ios/Sources/VGSCollectSDK/Core/TokenizationConfiguration/VGSDateTokenizationConfiguration.swift", + "line": 85, + "symbol": "VGSDateTokenizationConfiguration.tokenizationParameters", + "symbol_kind": "source.lang.swift.decl.var.instance", + "warning": "undocumented" + }, + { + "file": "/Users/donald.rodriguez/Documents/Projects/VGS/repos/vgs-collect-ios/Sources/VGSCollectSDK/Core/VGSDate.swift", + "line": 12, + "symbol": "VGSDate.day", + "symbol_kind": "source.lang.swift.decl.var.instance", + "warning": "undocumented" + }, + { + "file": "/Users/donald.rodriguez/Documents/Projects/VGS/repos/vgs-collect-ios/Sources/VGSCollectSDK/Core/VGSDate.swift", + "line": 13, + "symbol": "VGSDate.month", + "symbol_kind": "source.lang.swift.decl.var.instance", + "warning": "undocumented" + }, + { + "file": "/Users/donald.rodriguez/Documents/Projects/VGS/repos/vgs-collect-ios/Sources/VGSCollectSDK/Core/VGSDate.swift", + "line": 14, + "symbol": "VGSDate.year", + "symbol_kind": "source.lang.swift.decl.var.instance", + "warning": "undocumented" + }, + { + "file": "/Users/donald.rodriguez/Documents/Projects/VGS/repos/vgs-collect-ios/Sources/VGSCollectSDK/Core/VGSDateConfiguration.swift", + "line": 78, + "symbol": "VGSDateConfiguration.serializers", + "symbol_kind": "source.lang.swift.decl.var.instance", + "warning": "undocumented" + }, + { + "file": "/Users/donald.rodriguez/Documents/Projects/VGS/repos/vgs-collect-ios/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSDateFormat.swift", + "line": 8, + "symbol": "VGSDateFormat.mmddyyyy", + "symbol_kind": "source.lang.swift.decl.enumelement", + "warning": "undocumented" + }, + { + "file": "/Users/donald.rodriguez/Documents/Projects/VGS/repos/vgs-collect-ios/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSDateFormat.swift", + "line": 9, + "symbol": "VGSDateFormat.ddmmyyyy", + "symbol_kind": "source.lang.swift.decl.enumelement", + "warning": "undocumented" + }, + { + "file": "/Users/donald.rodriguez/Documents/Projects/VGS/repos/vgs-collect-ios/Sources/VGSCollectSDK/UIElements/Text Field/Validation/Date/VGSDateFormat.swift", + "line": 10, + "symbol": "VGSDateFormat.yyyymmdd", + "symbol_kind": "source.lang.swift.decl.enumelement", + "warning": "undocumented" + }, + { + "file": "/Users/donald.rodriguez/Documents/Projects/VGS/repos/vgs-collect-ios/Sources/VGSCollectSDK/Utils/Helpers/Serializers/VGSDateSeparateSerializer.swift", + "line": 8, + "symbol": "VGSDateSeparateSerializer", + "symbol_kind": "source.lang.swift.decl.struct", + "warning": "undocumented" + } ], - "source_directory": "/Users/eugene/vgs-collect-ios" + "source_directory": "/Users/donald.rodriguez/Documents/Projects/VGS/repos/vgs-collect-ios" } \ No newline at end of file From f9edf780a558173d42f98df8bf6ca7f46c3c3965 Mon Sep 17 00:00:00 2001 From: Dmytro Khludkov Date: Mon, 12 Jun 2023 17:33:04 +0300 Subject: [PATCH 7/9] Readme updates. --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 833e5662..ec546277 100644 --- a/README.md +++ b/README.md @@ -434,7 +434,6 @@ Use vgsCollect.cleanFiles() to unassign file from associated VGSCollect instance ## Demo Application Demo application for collecting card data on iOS is here. -Also you can check our [payment optimization demo](./demoapp/demoapp/UseCases/PayOptIntegration/) with Payment Orchestration integration. ### Documentation - SDK Documentation: https://www.verygoodsecurity.com/docs/vgs-collect/ios-sdk @@ -451,7 +450,7 @@ VGSAnalyticsClient.shared.shouldCollectAnalytics = false ``` ## Dependencies -- iOS 10+ +- iOS 12+ - Swift 5 - Optional 3rd party libraries: - [CardIO](https://github.com/card-io/card.io-iOS-SDK) From aaa31de621a81d4c829e2e6376f7456079d8b303 Mon Sep 17 00:00:00 2001 From: Dmytro Khludkov Date: Mon, 12 Jun 2023 18:59:46 +0300 Subject: [PATCH 8/9] Fix typo in yearPickerFormat. --- .../UIElements/Text Field/VGSExpDateTextField.swift | 4 ++-- .../Satellite Tests/Text Fields Tests/ExpDateTextField.swift | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift b/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift index a91b8084..229adbb3 100644 --- a/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift +++ b/Sources/VGSCollectSDK/UIElements/Text Field/VGSExpDateTextField.swift @@ -38,7 +38,7 @@ public final class VGSExpDateTextField: VGSTextField { } /// UIPickerView Year Label format - public var yearPickeFormat: YearFormat = .long { + public var yearPickerFormat: YearFormat = .long { didSet { updateYearsDataSource() } @@ -171,7 +171,7 @@ private extension VGSExpDateTextField { } func updateYearsDataSource() { - let suffixLength = yearPickeFormat == .short ? 2 : 4 + let suffixLength = yearPickerFormat == .short ? 2 : 4 yearsDataSource = years.map { String(String($0).suffix(suffixLength))} } diff --git a/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/ExpDateTextField.swift b/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/ExpDateTextField.swift index 61c0a477..12674c8c 100644 --- a/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/ExpDateTextField.swift +++ b/Tests/FrameworkTests/Satellite Tests/Text Fields Tests/ExpDateTextField.swift @@ -44,9 +44,9 @@ class ExpDateTextField: VGSCollectBaseTestCase { } func testYearFormat() { - textField.yearPickeFormat = .long + textField.yearPickerFormat = .long XCTAssertTrue(textField.yearsDataSource.first == String(Calendar.currentYear)) - textField.yearPickeFormat = .short + textField.yearPickerFormat = .short XCTAssertTrue(textField.yearsDataSource.first == String(Calendar.currentYear - 2000)) } From 7cfe8466020ab667a5ca0fa416d32ca79f2425ca Mon Sep 17 00:00:00 2001 From: Dmytro Khludkov Date: Mon, 12 Jun 2023 19:22:27 +0300 Subject: [PATCH 9/9] Bump SDK version. --- Sources/VGSCollectSDK/Utils/Extensions/Utils.swift | 2 +- VGSCollectSDK.podspec | 6 +++--- VGSCollectSDK.xcodeproj/project.pbxproj | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Sources/VGSCollectSDK/Utils/Extensions/Utils.swift b/Sources/VGSCollectSDK/Utils/Extensions/Utils.swift index 9cc3dacb..f6903331 100644 --- a/Sources/VGSCollectSDK/Utils/Extensions/Utils.swift +++ b/Sources/VGSCollectSDK/Utils/Extensions/Utils.swift @@ -46,7 +46,7 @@ internal class Utils { /// VGS Collect SDK Version. /// Necessary since SPM doesn't track info plist correctly: https://forums.swift.org/t/add-info-plist-on-spm-bundle/40274/5 - static let vgsCollectVersion: String = "1.12.0" + static let vgsCollectVersion: String = "1.13.0" } extension Dictionary { diff --git a/VGSCollectSDK.podspec b/VGSCollectSDK.podspec index e49d5900..e6653582 100644 --- a/VGSCollectSDK.podspec +++ b/VGSCollectSDK.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'VGSCollectSDK' - spec.version = '1.12.0' + spec.version = '1.13.0' spec.summary = 'VGS Collect - is a product suite that allows customers to collect information securely without possession of it.' spec.swift_version = '5.0' spec.description = <<-DESC @@ -13,8 +13,8 @@ Pod::Spec.new do |spec| "Very Good Security" => "support@verygoodsecurity.com" } spec.social_media_url = "https://twitter.com/getvgs" - spec.platform = :ios, "10.0" - spec.ios.deployment_target = "10.0" + spec.platform = :ios, "12.0" + spec.ios.deployment_target = "12.0" spec.source = { :git => "https://github.com/verygoodsecurity/vgs-collect-ios.git", :tag => "#{spec.version}" } spec.requires_arc = true diff --git a/VGSCollectSDK.xcodeproj/project.pbxproj b/VGSCollectSDK.xcodeproj/project.pbxproj index 3fc33ff6..606762b3 100644 --- a/VGSCollectSDK.xcodeproj/project.pbxproj +++ b/VGSCollectSDK.xcodeproj/project.pbxproj @@ -1830,7 +1830,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.12.0; + MARKETING_VERSION = 1.13.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -1892,7 +1892,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.12.0; + MARKETING_VERSION = 1.13.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos;

    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