From 4cde93575023baaf1c2f35b2987409a59b8f33fe Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Thu, 10 Oct 2019 08:44:53 +0300 Subject: [PATCH 01/32] Add podspec & package json --- ios/libs/Sqlite/CHANGELOG.md | 0 ios/libs/Sqlite/CONTRIBUTING.md | 0 ios/libs/Sqlite/Documentation/Index.md | 0 ios/libs/Sqlite/Documentation/Planning.md | 0 .../Documentation/Resources/installation@2x.png | Bin .../Documentation/Resources/playground@2x.png | Bin ios/libs/Sqlite/LICENSE.txt | 0 ios/libs/Sqlite/Makefile | 0 ios/libs/Sqlite/Package.swift | 0 ios/libs/Sqlite/README.md | 0 ios/libs/Sqlite/SQLite.playground/Contents.swift | 0 .../Sqlite/SQLite.playground/contents.xcplayground | 0 ios/libs/Sqlite/SQLite.swift.podspec | 0 ios/libs/Sqlite/SQLite.xcodeproj/project.pbxproj | 0 .../xcshareddata/xcschemes/SQLite Mac.xcscheme | 0 .../xcshareddata/xcschemes/SQLite iOS.xcscheme | 0 .../xcshareddata/xcschemes/SQLite tvOS.xcscheme | 0 .../xcshareddata/xcschemes/SQLite watchOS.xcscheme | 0 ios/libs/Sqlite/Sources/SQLite/Core/Blob.swift | 0 .../Sqlite/Sources/SQLite/Core/Connection.swift | 0 ios/libs/Sqlite/Sources/SQLite/Core/Errors.swift | 0 ios/libs/Sqlite/Sources/SQLite/Core/Statement.swift | 0 ios/libs/Sqlite/Sources/SQLite/Core/Value.swift | 0 .../Sqlite/Sources/SQLite/Extensions/Cipher.swift | 0 .../Sqlite/Sources/SQLite/Extensions/FTS4.swift | 0 .../Sqlite/Sources/SQLite/Extensions/FTS5.swift | 0 .../Sqlite/Sources/SQLite/Extensions/RTree.swift | 0 ios/libs/Sqlite/Sources/SQLite/Foundation.swift | 0 ios/libs/Sqlite/Sources/SQLite/Helpers.swift | 0 ios/libs/Sqlite/Sources/SQLite/Info.plist | 0 ios/libs/Sqlite/Sources/SQLite/SQLite.h | 0 .../Sources/SQLite/Typed/AggregateFunctions.swift | 0 ios/libs/Sqlite/Sources/SQLite/Typed/Coding.swift | 0 .../Sqlite/Sources/SQLite/Typed/Collation.swift | 0 .../Sqlite/Sources/SQLite/Typed/CoreFunctions.swift | 0 .../Sources/SQLite/Typed/CustomFunctions.swift | 0 .../Sources/SQLite/Typed/DateAndTimeFunctions.swift | 0 .../Sqlite/Sources/SQLite/Typed/Expression.swift | 0 .../Sqlite/Sources/SQLite/Typed/Operators.swift | 0 ios/libs/Sqlite/Sources/SQLite/Typed/Query.swift | 0 ios/libs/Sqlite/Sources/SQLite/Typed/Schema.swift | 0 ios/libs/Sqlite/Sources/SQLite/Typed/Setter.swift | 0 .../Sqlite/Sources/SQLiteObjc/SQLite-Bridging.m | 0 ios/libs/Sqlite/Sources/SQLiteObjc/fts3_tokenizer.h | 0 .../Sources/SQLiteObjc/include/SQLite-Bridging.h | 0 ios/libs/Sqlite/Tests/Carthage/.gitignore | 0 ios/libs/Sqlite/Tests/Carthage/Makefile | 0 ios/libs/Sqlite/Tests/CocoaPods/.gitignore | 0 ios/libs/Sqlite/Tests/CocoaPods/Gemfile | 0 ios/libs/Sqlite/Tests/CocoaPods/Gemfile.lock | 0 ios/libs/Sqlite/Tests/CocoaPods/Makefile | 0 ios/libs/Sqlite/Tests/CocoaPods/integration_test.rb | 0 ios/libs/Sqlite/Tests/LinuxMain.swift | 0 .../Tests/SQLiteTests/AggregateFunctionsTests.swift | 0 ios/libs/Sqlite/Tests/SQLiteTests/BlobTests.swift | 0 ios/libs/Sqlite/Tests/SQLiteTests/CipherTests.swift | 0 .../Sqlite/Tests/SQLiteTests/ConnectionTests.swift | 0 .../Tests/SQLiteTests/CoreFunctionsTests.swift | 0 .../Tests/SQLiteTests/CustomFunctionsTests.swift | 0 .../SQLiteTests/DateAndTimeFunctionTests.swift | 0 .../Sqlite/Tests/SQLiteTests/ExpressionTests.swift | 0 ios/libs/Sqlite/Tests/SQLiteTests/FTS4Tests.swift | 0 ios/libs/Sqlite/Tests/SQLiteTests/FTS5Tests.swift | 0 ios/libs/Sqlite/Tests/SQLiteTests/Fixtures.swift | 0 .../Sqlite/Tests/SQLiteTests/FoundationTests.swift | 0 ios/libs/Sqlite/Tests/SQLiteTests/Info.plist | 0 .../Sqlite/Tests/SQLiteTests/OperatorsTests.swift | 0 ios/libs/Sqlite/Tests/SQLiteTests/QueryTests.swift | 0 ios/libs/Sqlite/Tests/SQLiteTests/RTreeTests.swift | 0 ios/libs/Sqlite/Tests/SQLiteTests/RowTests.swift | 0 ios/libs/Sqlite/Tests/SQLiteTests/SchemaTests.swift | 0 ios/libs/Sqlite/Tests/SQLiteTests/SetterTests.swift | 0 .../Sqlite/Tests/SQLiteTests/StatementTests.swift | 0 ios/libs/Sqlite/Tests/SQLiteTests/TestHelpers.swift | 0 ios/libs/Sqlite/Tests/SQLiteTests/ValueTests.swift | 0 ios/libs/Sqlite/run-tests.sh | 0 ios/libs/Webim/Cartfile | 0 ios/libs/Webim/Cartfile.resolved | 0 ios/libs/Webim/Documentation/Images/Logo.png | Bin .../Images/Screenshots/ChatScreenClassic.png | Bin .../Images/Screenshots/ChatScreenDark.png | Bin .../Images/Screenshots/ImageScreenClassic.png | Bin .../Images/Screenshots/ImageScreenDark.png | Bin .../Images/Screenshots/RatingScreenClassic.png | Bin .../Images/Screenshots/RatingScreenDark.png | Bin .../Images/Screenshots/SettingsScreenClassic.png | Bin .../Images/Screenshots/SettingsScreenDark.png | Bin .../Images/Screenshots/StartScreenClassic.png | Bin .../Images/Screenshots/StartScreenDark.png | Bin ios/libs/Webim/Documentation/Index.md | 0 ios/libs/Webim/Example/Podfile | 0 ios/libs/Webim/Example/Podfile.lock | 0 .../Example/Tests/AbstractRequestLoopTests.swift | 0 .../Webim/Example/Tests/AccessCheckerTests.swift | 0 .../Example/Tests/ActionRequestLoopTests.swift | 0 .../Example/Tests/AuthorizationDataTests.swift | 0 ios/libs/Webim/Example/Tests/ChatItemTests.swift | 0 .../Webim/Example/Tests/ClientSideIDTests.swift | 0 ios/libs/Webim/Example/Tests/DeltaItemTests.swift | 0 .../Webim/Example/Tests/DeltaRequestLoopTests.swift | 0 .../Webim/Example/Tests/DeltaResponseTests.swift | 0 .../Example/Tests/DepartmentFactoryTests.swift | 0 .../Webim/Example/Tests/DepartmentItemTests.swift | 0 .../ExampleTests/ChatViewControllerTests.swift | 0 .../DecodePercentEscapedLinksIfPresentTests.swift | 0 .../Example/Tests/ExampleTests/MimeTypeTests.swift | 0 .../ExecIfNotDestroyedHandlerExecutorTests.swift | 0 .../Example/Tests/FileParametersItemTests.swift | 0 ios/libs/Webim/Example/Tests/FullUpdateTests.swift | 0 ios/libs/Webim/Example/Tests/HMACsha256Tests.swift | 0 .../Example/Tests/HistoryBeforeResponseTests.swift | 0 ios/libs/Webim/Example/Tests/HistoryIDTests.swift | 0 .../Example/Tests/HistorySinceResponseTests.swift | 0 ios/libs/Webim/Example/Tests/Info.plist | 0 .../Webim/Example/Tests/InternalUtilsTests.swift | 0 .../Example/Tests/LocationSettingsHolderTests.swift | 0 .../Example/Tests/LocationSettingsImplTests.swift | 0 .../MemoryHistoryMetaInformationStorageTests.swift | 0 .../Example/Tests/MemoryHistoryStorageTests.swift | 0 .../Webim/Example/Tests/MessageFactoriesTests.swift | 0 .../Webim/Example/Tests/MessageHolderTests.swift | 0 ios/libs/Webim/Example/Tests/MessageImplTests.swift | 0 ios/libs/Webim/Example/Tests/MessageItemTests.swift | 0 .../Example/Tests/MessageStreamImplTests.swift | 0 .../Example/Tests/Mocks/ActionRequestLoopMock.swift | 0 .../Tests/Mocks/InternalErrorListenerMock.swift | 0 .../Webim/Example/Tests/OperatorFactoryTests.swift | 0 .../Webim/Example/Tests/OperatorImplTests.swift | 0 .../Webim/Example/Tests/OperatorItemTests.swift | 0 .../Example/Tests/ProvidedVisitorFieldsTests.swift | 0 ios/libs/Webim/Example/Tests/RatingItemTests.swift | 0 .../Example/Tests/SQLiteHistoryStorageTests.swift | 0 .../Webim/Example/Tests/SessionBuilderTests.swift | 0 .../Webim/Example/Tests/SessionDestroyerTests.swift | 0 .../Tests/StringFromHTTPParametersTests.swift | 0 .../Webim/Example/Tests/UIColorHexStringTests.swift | 0 ios/libs/Webim/Example/Tests/VisitorItemTests.swift | 0 .../Webim/Example/Tests/WebimActionsTests.swift | 0 ios/libs/Webim/Example/Tests/WebimClientTests.swift | 0 .../Webim/Example/Tests/WebimErrorImplTests.swift | 0 .../Example/Tests/WebimInternalLoggerTests.swift | 0 .../Tests/WebimRemoteNotificationImplTests.swift | 0 ios/libs/Webim/Example/Tests/WebimTests.swift | 0 .../WebimClientLibrary.xcodeproj/project.pbxproj | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/WorkspaceSettings.xcsettings | 0 .../Example/WebimClientLibrary/AppDelegate.swift | 0 .../AppearanceSettings/ButtonConstants.swift | 0 .../AppearanceSettings/ColorConstants.swift | 0 .../AppearanceSettings/StringConstants.swift | 0 .../WebimClientLibrary/Base.lproj/LaunchScreen.xib | 0 .../Base.lproj/Localizable.strings | 0 .../WebimClientLibrary/Base.lproj/Main.storyboard | 0 .../Base.lproj/RatingViewController.xib | 0 .../WebimClientLibrary/ChatViewController.swift | 0 .../AppIcon.appiconset/AppIcon-1.png | Bin .../AppIcon.appiconset/AppIcon-2.png | Bin .../AppIcon.appiconset/AppIcon-3.png | Bin .../AppIcon.appiconset/AppIcon-4.png | Bin .../AppIcon.appiconset/AppIcon-5.png | Bin .../AppIcon.appiconset/AppIcon-6.png | Bin .../AppIcon.appiconset/AppIcon-7.png | Bin .../AppIcon.appiconset/AppIcon-8.png | Bin .../Images.xcassets/AppIcon.appiconset/AppIcon.png | Bin .../AppIcon.appiconset/Contents.json | 0 .../Images.xcassets/AppIcon.appiconset/Icon-152.png | Bin .../Images.xcassets/AppIcon.appiconset/Icon-167.png | Bin .../Images.xcassets/AppIcon.appiconset/Icon-20.png | Bin .../Images.xcassets/AppIcon.appiconset/Icon-29.png | Bin .../Images.xcassets/AppIcon.appiconset/Icon-40.png | Bin .../Images.xcassets/AppIcon.appiconset/Icon-41.png | Bin .../Images.xcassets/AppIcon.appiconset/Icon-58.png | Bin .../Images.xcassets/AppIcon.appiconset/Icon-76.png | Bin .../Images.xcassets/AppIcon.appiconset/Icon-80.png | Bin .../Images.xcassets/Check.imageset/Contents.json | 0 .../Check.imageset/check_Icon-32.png | Bin .../Images.xcassets/Contents.json | 0 .../DefaultAvatar.imageset/Contents.json | 0 .../HardcodedVisitorAvatar.imageset/Contents.json | 0 .../VisitorAvatar.png | Bin .../Icons/Back/Back.imageset/Contents.json | 0 .../Icons/Back/Back.imageset/back_Icon-32.png | Bin .../Icons/Back/Back_dark.imageset/Contents.json | 0 .../Icons/Back/Back_dark.imageset/back_Icon-32.png | Bin .../Images.xcassets/Icons/Back/Contents.json | 0 .../Icons/Clip/Clip.imageset/Contents.json | 0 .../Icons/Clip/Clip_dark.imageset/Contents.json | 0 .../Images.xcassets/Icons/Clip/Contents.json | 0 .../Icons/Close/Close.imageset/Contents.json | 0 .../Icons/Close/Close.imageset/close_Icon-32.png | Bin .../Icons/Close/Close_dark.imageset/Contents.json | 0 .../Close/Close_dark.imageset/close_Icon-32.png | Bin .../Images.xcassets/Icons/Close/Contents.json | 0 .../Images.xcassets/Icons/Contents.json | 0 .../Icons/Empty.imageset/Contents.json | 0 .../Images.xcassets/Icons/SendMessage/Contents.json | 0 .../SendMessage/SendMessage.imageset/Contents.json | 0 .../SendMessage_dark.imageset/Contents.json | 0 .../Images.xcassets/Logo/Contents.json | 0 .../Logo/LogoWebim.imageset/Contents.json | 0 .../Logo/NavigationBar/Contents.json | 0 .../LogoWebimNavigationBar.imageset/Contents.json | 0 .../Contents.json | 0 .../logo_white.png | Bin .../Images.xcassets/ScrollToBottom/Contents.json | 0 .../ScrollToBottom.imageset/Contents.json | 0 .../ScrollToBottom_dark.imageset/Contents.json | 0 .../Webim/Example/WebimClientLibrary/Info.plist | 0 .../WebimClientLibrary/MessageTableViewCell.swift | 0 .../WebimClientLibrary/Models/ColorScheme.swift | 0 .../WebimClientLibrary/Models/Settings.swift | 0 .../WebimClientLibrary/RatingViewController.swift | 0 .../SettingsTableViewController.swift | 0 .../WebimClientLibrary/SettingsViewController.swift | 0 .../WebimClientLibrary/StartViewController.swift | 0 .../Utilities/Extensions/String.swift | 0 .../Utilities/Extensions/UIImage.swift | 0 .../Utilities/Extensions/UIImageView.swift | 0 .../Utilities/Extensions/UITableView.swift | 0 .../Utilities/Extensions/UIViewController.swift | 0 .../WebimClientLibrary/Utilities/MimeType.swift | 0 .../Utilities/PopupDialogHandler.swift | 0 .../WebimClientLibrary/Utilities/WebimService.swift | 0 .../ru-RU.lproj/Localizable.strings | 0 .../WebimClientLibrary/ru-RU.lproj/Main.strings | 0 .../ru-RU.lproj/RatingViewController.strings | 0 .../Example/WebimClientLibrary_Example.entitlements | 0 ios/libs/Webim/Info.plist | 0 ios/libs/Webim/LICENSE | 0 ios/libs/Webim/README.md | 0 ios/libs/Webim/WebimClientLibrary.podspec | 0 .../WebimClientLibrary.xcodeproj/project.pbxproj | 0 .../xcschemes/WebimClientLibrary.xcscheme | 0 .../Backend/AbstractRequestLoop.swift | 0 .../WebimClientLibrary/Backend/AccessChecker.swift | 0 .../Backend/ActionRequestLoop.swift | 0 .../Backend/AuthorizationData.swift | 0 .../WebimClientLibrary/Backend/ClientSideID.swift | 0 .../WebimClientLibrary/Backend/DeltaCallback.swift | 0 .../Backend/DeltaRequestLoop.swift | 0 .../ExecIfNotDestroyedFAQHandlerExecutor.swift | 0 .../Backend/ExecIfNotDestroyedHandlerExecutor.swift | 0 .../Backend/FAQAccessChecker.swift | 0 .../WebimClientLibrary/Backend/FAQActions.swift | 0 .../WebimClientLibrary/Backend/FAQClient.swift | 0 .../WebimClientLibrary/Backend/FAQDestroyer.swift | 0 .../WebimClientLibrary/Backend/FAQRequestLoop.swift | 0 .../WebimClientLibrary/Backend/HistoryID.swift | 0 .../Backend/HistoryMetaInformationStorage.swift | 0 .../WebimClientLibrary/Backend/HistoryStorage.swift | 0 .../Backend/InternalErrorListener.swift | 0 .../WebimClientLibrary/Backend/Items/ChatItem.swift | 0 .../Backend/Items/Deltas/DeltaItem.swift | 0 .../Backend/Items/Deltas/FullUpdate.swift | 0 .../Backend/Items/DepartmentItem.swift | 0 .../Backend/Items/FAQCategoryInfoItem.swift | 0 .../Backend/Items/FAQCategoryItem.swift | 0 .../Backend/Items/FAQItemItem.swift | 0 .../Backend/Items/FAQStructureItem.swift | 0 .../Backend/Items/FileParametersItem.swift | 0 .../Backend/Items/HistoryRevisionItem.swift | 0 .../Backend/Items/MessageItem.swift | 0 .../Backend/Items/OnlineStatusItem.swift | 0 .../Backend/Items/OperatorItem.swift | 0 .../Backend/Items/RatingItem.swift | 0 .../Backend/Items/Responses/DeltaResponse.swift | 0 .../Items/Responses/HistoryBeforeResponse.swift | 0 .../Items/Responses/HistorySinceResponse.swift | 0 .../Backend/Items/VisitSessionStateItem.swift | 0 .../Backend/Items/VisitorItem.swift | 0 .../Backend/LocationSettingsHolder.swift | 0 .../MemoryHistoryMetaInformationStorage.swift | 0 .../Backend/MemoryHistoryStorage.swift | 0 .../Backend/MessageComposingHandler.swift | 0 .../WebimClientLibrary/Backend/MessageHolder.swift | 0 .../WebimClientLibrary/Backend/MessageToSend.swift | 0 .../Backend/ProvidedVisitorFields.swift | 0 .../Backend/RemoteHistoryProvider.swift | 0 .../Backend/SQLiteHistoryStorage.swift | 0 .../Backend/SessionDestroyer.swift | 0 .../Backend/SessionParametersListener.swift | 0 .../Utilities/CompletionHandlerWrappers.swift | 0 .../Backend/Utilities/DepartmentFactory.swift | 0 .../Backend/Utilities/Extensions/Array.swift | 0 .../Backend/Utilities/Extensions/Collection.swift | 0 .../Backend/Utilities/Extensions/Dictionary.swift | 0 .../Backend/Utilities/Extensions/Int.swift | 0 .../Backend/Utilities/Extensions/String.swift | 0 .../Backend/Utilities/Extensions/UIColor.swift | 0 .../Backend/Utilities/Extensions/UInt32.swift | 0 .../Backend/Utilities/InternalUtils.swift | 0 .../Backend/Utilities/MessageFactories.swift | 0 .../Backend/Utilities/OperatorFactory.swift | 0 .../WebimClientLibrary/Backend/WebimActions.swift | 0 .../WebimClientLibrary/Backend/WebimClient.swift | 0 .../Backend/WebimInternalError.swift | 0 .../Backend/WebimInternalLogger.swift | 0 .../WebimClientLibrary/Backend/WebimRequest.swift | 0 ios/libs/Webim/WebimClientLibrary/Department.swift | 0 ios/libs/Webim/WebimClientLibrary/FAQ.swift | 0 ios/libs/Webim/WebimClientLibrary/FAQCategory.swift | 0 .../Webim/WebimClientLibrary/FAQCategoryInfo.swift | 0 ios/libs/Webim/WebimClientLibrary/FAQItem.swift | 0 .../Webim/WebimClientLibrary/FAQStructure.swift | 0 .../WebimClientLibrary/FatalErrorHandler.swift | 0 .../Implementation/DepartmentImpl.swift | 0 .../WebimClientLibrary/Implementation/FAQImpl.swift | 0 .../Implementation/LocationSettingsImpl.swift | 0 .../Implementation/MessageImpl.swift | 0 .../Implementation/MessageStreamImpl.swift | 0 .../Implementation/MessageTrackerImpl.swift | 0 .../Implementation/OperatorImpl.swift | 0 .../Implementation/WebimErrorImpl.swift | 0 .../WebimRemoteNotificationImpl.swift | 0 .../Implementation/WebimSessionImpl.swift | 0 ios/libs/Webim/WebimClientLibrary/Message.swift | 0 .../Webim/WebimClientLibrary/MessageListener.swift | 0 .../Webim/WebimClientLibrary/MessageStream.swift | 0 .../Webim/WebimClientLibrary/MessageTracker.swift | 0 ios/libs/Webim/WebimClientLibrary/Operator.swift | 0 .../ProvidedAuthorizationTokenStateListener.swift | 0 ios/libs/Webim/WebimClientLibrary/Webim.swift | 0 .../Webim/WebimClientLibrary/WebimClientLibrary.h | 0 ios/libs/Webim/WebimClientLibrary/WebimError.swift | 0 ios/libs/Webim/WebimClientLibrary/WebimLogger.swift | 0 .../WebimRemoteNotification.swift | 0 .../Webim/WebimClientLibrary/WebimSession.swift | 0 328 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 ios/libs/Sqlite/CHANGELOG.md mode change 100755 => 100644 ios/libs/Sqlite/CONTRIBUTING.md mode change 100755 => 100644 ios/libs/Sqlite/Documentation/Index.md mode change 100755 => 100644 ios/libs/Sqlite/Documentation/Planning.md mode change 100755 => 100644 ios/libs/Sqlite/Documentation/Resources/installation@2x.png mode change 100755 => 100644 ios/libs/Sqlite/Documentation/Resources/playground@2x.png mode change 100755 => 100644 ios/libs/Sqlite/LICENSE.txt mode change 100755 => 100644 ios/libs/Sqlite/Makefile mode change 100755 => 100644 ios/libs/Sqlite/Package.swift mode change 100755 => 100644 ios/libs/Sqlite/README.md mode change 100755 => 100644 ios/libs/Sqlite/SQLite.playground/Contents.swift mode change 100755 => 100644 ios/libs/Sqlite/SQLite.playground/contents.xcplayground mode change 100755 => 100644 ios/libs/Sqlite/SQLite.swift.podspec mode change 100755 => 100644 ios/libs/Sqlite/SQLite.xcodeproj/project.pbxproj mode change 100755 => 100644 ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite Mac.xcscheme mode change 100755 => 100644 ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite iOS.xcscheme mode change 100755 => 100644 ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite tvOS.xcscheme mode change 100755 => 100644 ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite watchOS.xcscheme mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Core/Blob.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Core/Connection.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Core/Errors.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Core/Statement.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Core/Value.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Extensions/Cipher.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Extensions/FTS4.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Extensions/FTS5.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Extensions/RTree.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Foundation.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Helpers.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Info.plist mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/SQLite.h mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Typed/AggregateFunctions.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Typed/Coding.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Typed/Collation.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Typed/CoreFunctions.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Typed/CustomFunctions.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Typed/DateAndTimeFunctions.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Typed/Expression.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Typed/Operators.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Typed/Query.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Typed/Schema.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLite/Typed/Setter.swift mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLiteObjc/SQLite-Bridging.m mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLiteObjc/fts3_tokenizer.h mode change 100755 => 100644 ios/libs/Sqlite/Sources/SQLiteObjc/include/SQLite-Bridging.h mode change 100755 => 100644 ios/libs/Sqlite/Tests/Carthage/.gitignore mode change 100755 => 100644 ios/libs/Sqlite/Tests/Carthage/Makefile mode change 100755 => 100644 ios/libs/Sqlite/Tests/CocoaPods/.gitignore mode change 100755 => 100644 ios/libs/Sqlite/Tests/CocoaPods/Gemfile mode change 100755 => 100644 ios/libs/Sqlite/Tests/CocoaPods/Gemfile.lock mode change 100755 => 100644 ios/libs/Sqlite/Tests/CocoaPods/Makefile mode change 100755 => 100644 ios/libs/Sqlite/Tests/CocoaPods/integration_test.rb mode change 100755 => 100644 ios/libs/Sqlite/Tests/LinuxMain.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/AggregateFunctionsTests.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/BlobTests.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/CipherTests.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/ConnectionTests.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/CoreFunctionsTests.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/CustomFunctionsTests.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/DateAndTimeFunctionTests.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/ExpressionTests.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/FTS4Tests.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/FTS5Tests.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/Fixtures.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/FoundationTests.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/Info.plist mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/OperatorsTests.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/QueryTests.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/RTreeTests.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/RowTests.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/SchemaTests.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/SetterTests.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/StatementTests.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/TestHelpers.swift mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/ValueTests.swift mode change 100755 => 100644 ios/libs/Sqlite/run-tests.sh mode change 100755 => 100644 ios/libs/Webim/Cartfile mode change 100755 => 100644 ios/libs/Webim/Cartfile.resolved mode change 100755 => 100644 ios/libs/Webim/Documentation/Images/Logo.png mode change 100755 => 100644 ios/libs/Webim/Documentation/Images/Screenshots/ChatScreenClassic.png mode change 100755 => 100644 ios/libs/Webim/Documentation/Images/Screenshots/ChatScreenDark.png mode change 100755 => 100644 ios/libs/Webim/Documentation/Images/Screenshots/ImageScreenClassic.png mode change 100755 => 100644 ios/libs/Webim/Documentation/Images/Screenshots/ImageScreenDark.png mode change 100755 => 100644 ios/libs/Webim/Documentation/Images/Screenshots/RatingScreenClassic.png mode change 100755 => 100644 ios/libs/Webim/Documentation/Images/Screenshots/RatingScreenDark.png mode change 100755 => 100644 ios/libs/Webim/Documentation/Images/Screenshots/SettingsScreenClassic.png mode change 100755 => 100644 ios/libs/Webim/Documentation/Images/Screenshots/SettingsScreenDark.png mode change 100755 => 100644 ios/libs/Webim/Documentation/Images/Screenshots/StartScreenClassic.png mode change 100755 => 100644 ios/libs/Webim/Documentation/Images/Screenshots/StartScreenDark.png mode change 100755 => 100644 ios/libs/Webim/Documentation/Index.md mode change 100755 => 100644 ios/libs/Webim/Example/Podfile mode change 100755 => 100644 ios/libs/Webim/Example/Podfile.lock mode change 100755 => 100644 ios/libs/Webim/Example/Tests/AbstractRequestLoopTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/AccessCheckerTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/ActionRequestLoopTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/AuthorizationDataTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/ChatItemTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/ClientSideIDTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/DeltaItemTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/DeltaRequestLoopTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/DeltaResponseTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/DepartmentFactoryTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/DepartmentItemTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/ExampleTests/ChatViewControllerTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/ExampleTests/DecodePercentEscapedLinksIfPresentTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/ExampleTests/MimeTypeTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/ExecIfNotDestroyedHandlerExecutorTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/FileParametersItemTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/FullUpdateTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/HMACsha256Tests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/HistoryBeforeResponseTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/HistoryIDTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/HistorySinceResponseTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/Info.plist mode change 100755 => 100644 ios/libs/Webim/Example/Tests/InternalUtilsTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/LocationSettingsHolderTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/LocationSettingsImplTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/MemoryHistoryMetaInformationStorageTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/MemoryHistoryStorageTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/MessageFactoriesTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/MessageHolderTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/MessageImplTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/MessageItemTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/MessageStreamImplTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/Mocks/ActionRequestLoopMock.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/Mocks/InternalErrorListenerMock.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/OperatorFactoryTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/OperatorImplTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/OperatorItemTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/ProvidedVisitorFieldsTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/RatingItemTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/SQLiteHistoryStorageTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/SessionBuilderTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/SessionDestroyerTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/StringFromHTTPParametersTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/UIColorHexStringTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/VisitorItemTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/WebimActionsTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/WebimClientTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/WebimErrorImplTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/WebimInternalLoggerTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/WebimRemoteNotificationImplTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/Tests/WebimTests.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary.xcodeproj/project.pbxproj mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary.xcworkspace/contents.xcworkspacedata mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/AppDelegate.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/ButtonConstants.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/ColorConstants.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/StringConstants.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/LaunchScreen.xib mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/Localizable.strings mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/Main.storyboard mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/RatingViewController.xib mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/ChatViewController.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-1.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-2.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-3.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-4.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-5.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-6.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-7.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-8.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-152.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-167.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-20.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-29.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-40.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-41.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-58.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-76.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-80.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Check.imageset/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Check.imageset/check_Icon-32.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/DefaultAvatar.imageset/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/HardcodedVisitorAvatar.imageset/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/HardcodedVisitorAvatar.imageset/VisitorAvatar.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back.imageset/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back.imageset/back_Icon-32.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back_dark.imageset/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back_dark.imageset/back_Icon-32.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip.imageset/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip_dark.imageset/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close.imageset/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close.imageset/close_Icon-32.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close_dark.imageset/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close_dark.imageset/close_Icon-32.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Empty.imageset/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/SendMessage/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/SendMessage/SendMessage.imageset/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/SendMessage/SendMessage_dark.imageset/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/LogoWebim.imageset/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/LogoWebimNavigationBar.imageset/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/LogoWebimNavigationBar_dark.imageset/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/LogoWebimNavigationBar_dark.imageset/logo_white.png mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/ScrollToBottom/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/ScrollToBottom/ScrollToBottom.imageset/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/ScrollToBottom/ScrollToBottom_dark.imageset/Contents.json mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Info.plist mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/MessageTableViewCell.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Models/ColorScheme.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Models/Settings.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/RatingViewController.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/SettingsTableViewController.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/SettingsViewController.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/StartViewController.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/String.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIImage.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIImageView.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UITableView.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIViewController.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Utilities/MimeType.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Utilities/PopupDialogHandler.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Utilities/WebimService.swift mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/Localizable.strings mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/Main.strings mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/RatingViewController.strings mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary_Example.entitlements mode change 100755 => 100644 ios/libs/Webim/Info.plist mode change 100755 => 100644 ios/libs/Webim/LICENSE mode change 100755 => 100644 ios/libs/Webim/README.md mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary.podspec mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary.xcodeproj/project.pbxproj mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary.xcodeproj/xcshareddata/xcschemes/WebimClientLibrary.xcscheme mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/AbstractRequestLoop.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/AccessChecker.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/ActionRequestLoop.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/AuthorizationData.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/ClientSideID.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/DeltaCallback.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/DeltaRequestLoop.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/ExecIfNotDestroyedFAQHandlerExecutor.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/ExecIfNotDestroyedHandlerExecutor.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/FAQAccessChecker.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/FAQActions.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/FAQClient.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/FAQDestroyer.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/FAQRequestLoop.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/HistoryID.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/HistoryMetaInformationStorage.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/HistoryStorage.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/InternalErrorListener.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/ChatItem.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/Deltas/DeltaItem.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/Deltas/FullUpdate.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/DepartmentItem.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQCategoryInfoItem.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQCategoryItem.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQItemItem.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQStructureItem.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/FileParametersItem.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/HistoryRevisionItem.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/MessageItem.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/OnlineStatusItem.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/OperatorItem.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/RatingItem.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/DeltaResponse.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/HistoryBeforeResponse.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/HistorySinceResponse.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/VisitSessionStateItem.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/VisitorItem.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/LocationSettingsHolder.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/MemoryHistoryMetaInformationStorage.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/MemoryHistoryStorage.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/MessageComposingHandler.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/MessageHolder.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/MessageToSend.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/ProvidedVisitorFields.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/RemoteHistoryProvider.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/SQLiteHistoryStorage.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/SessionDestroyer.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/SessionParametersListener.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/CompletionHandlerWrappers.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/DepartmentFactory.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Array.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Collection.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Dictionary.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Int.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/String.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/UIColor.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/UInt32.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/InternalUtils.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/MessageFactories.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/OperatorFactory.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/WebimActions.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/WebimClient.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/WebimInternalError.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/WebimInternalLogger.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Backend/WebimRequest.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Department.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/FAQ.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/FAQCategory.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/FAQCategoryInfo.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/FAQItem.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/FAQStructure.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/FatalErrorHandler.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Implementation/DepartmentImpl.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Implementation/FAQImpl.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Implementation/LocationSettingsImpl.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Implementation/MessageImpl.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Implementation/MessageStreamImpl.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Implementation/MessageTrackerImpl.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Implementation/OperatorImpl.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Implementation/WebimErrorImpl.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Implementation/WebimRemoteNotificationImpl.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Implementation/WebimSessionImpl.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Message.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/MessageListener.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/MessageStream.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/MessageTracker.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Operator.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/ProvidedAuthorizationTokenStateListener.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/Webim.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/WebimClientLibrary.h mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/WebimError.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/WebimLogger.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/WebimRemoteNotification.swift mode change 100755 => 100644 ios/libs/Webim/WebimClientLibrary/WebimSession.swift diff --git a/ios/libs/Sqlite/CHANGELOG.md b/ios/libs/Sqlite/CHANGELOG.md old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/CONTRIBUTING.md b/ios/libs/Sqlite/CONTRIBUTING.md old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Documentation/Index.md b/ios/libs/Sqlite/Documentation/Index.md old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Documentation/Planning.md b/ios/libs/Sqlite/Documentation/Planning.md old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Documentation/Resources/installation@2x.png b/ios/libs/Sqlite/Documentation/Resources/installation@2x.png old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Documentation/Resources/playground@2x.png b/ios/libs/Sqlite/Documentation/Resources/playground@2x.png old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/LICENSE.txt b/ios/libs/Sqlite/LICENSE.txt old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Makefile b/ios/libs/Sqlite/Makefile old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Package.swift b/ios/libs/Sqlite/Package.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/README.md b/ios/libs/Sqlite/README.md old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/SQLite.playground/Contents.swift b/ios/libs/Sqlite/SQLite.playground/Contents.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/SQLite.playground/contents.xcplayground b/ios/libs/Sqlite/SQLite.playground/contents.xcplayground old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/SQLite.swift.podspec b/ios/libs/Sqlite/SQLite.swift.podspec old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/SQLite.xcodeproj/project.pbxproj b/ios/libs/Sqlite/SQLite.xcodeproj/project.pbxproj old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite Mac.xcscheme b/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite Mac.xcscheme old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite iOS.xcscheme b/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite iOS.xcscheme old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite tvOS.xcscheme b/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite tvOS.xcscheme old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite watchOS.xcscheme b/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite watchOS.xcscheme old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Core/Blob.swift b/ios/libs/Sqlite/Sources/SQLite/Core/Blob.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Core/Connection.swift b/ios/libs/Sqlite/Sources/SQLite/Core/Connection.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Core/Errors.swift b/ios/libs/Sqlite/Sources/SQLite/Core/Errors.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Core/Statement.swift b/ios/libs/Sqlite/Sources/SQLite/Core/Statement.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Core/Value.swift b/ios/libs/Sqlite/Sources/SQLite/Core/Value.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Extensions/Cipher.swift b/ios/libs/Sqlite/Sources/SQLite/Extensions/Cipher.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Extensions/FTS4.swift b/ios/libs/Sqlite/Sources/SQLite/Extensions/FTS4.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Extensions/FTS5.swift b/ios/libs/Sqlite/Sources/SQLite/Extensions/FTS5.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Extensions/RTree.swift b/ios/libs/Sqlite/Sources/SQLite/Extensions/RTree.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Foundation.swift b/ios/libs/Sqlite/Sources/SQLite/Foundation.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Helpers.swift b/ios/libs/Sqlite/Sources/SQLite/Helpers.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Info.plist b/ios/libs/Sqlite/Sources/SQLite/Info.plist old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/SQLite.h b/ios/libs/Sqlite/Sources/SQLite/SQLite.h old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/AggregateFunctions.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/AggregateFunctions.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/Coding.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/Coding.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/Collation.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/Collation.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/CoreFunctions.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/CoreFunctions.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/CustomFunctions.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/CustomFunctions.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/DateAndTimeFunctions.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/DateAndTimeFunctions.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/Expression.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/Expression.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/Operators.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/Operators.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/Query.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/Query.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/Schema.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/Schema.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/Setter.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/Setter.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLiteObjc/SQLite-Bridging.m b/ios/libs/Sqlite/Sources/SQLiteObjc/SQLite-Bridging.m old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLiteObjc/fts3_tokenizer.h b/ios/libs/Sqlite/Sources/SQLiteObjc/fts3_tokenizer.h old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Sources/SQLiteObjc/include/SQLite-Bridging.h b/ios/libs/Sqlite/Sources/SQLiteObjc/include/SQLite-Bridging.h old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/Carthage/.gitignore b/ios/libs/Sqlite/Tests/Carthage/.gitignore old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/Carthage/Makefile b/ios/libs/Sqlite/Tests/Carthage/Makefile old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/CocoaPods/.gitignore b/ios/libs/Sqlite/Tests/CocoaPods/.gitignore old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/CocoaPods/Gemfile b/ios/libs/Sqlite/Tests/CocoaPods/Gemfile old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/CocoaPods/Gemfile.lock b/ios/libs/Sqlite/Tests/CocoaPods/Gemfile.lock old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/CocoaPods/Makefile b/ios/libs/Sqlite/Tests/CocoaPods/Makefile old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/CocoaPods/integration_test.rb b/ios/libs/Sqlite/Tests/CocoaPods/integration_test.rb old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/LinuxMain.swift b/ios/libs/Sqlite/Tests/LinuxMain.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/AggregateFunctionsTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/AggregateFunctionsTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/BlobTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/BlobTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/CipherTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/CipherTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/ConnectionTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/ConnectionTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/CoreFunctionsTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/CoreFunctionsTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/CustomFunctionsTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/CustomFunctionsTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/DateAndTimeFunctionTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/DateAndTimeFunctionTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/ExpressionTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/ExpressionTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/FTS4Tests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/FTS4Tests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/FTS5Tests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/FTS5Tests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/Fixtures.swift b/ios/libs/Sqlite/Tests/SQLiteTests/Fixtures.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/FoundationTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/FoundationTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/Info.plist b/ios/libs/Sqlite/Tests/SQLiteTests/Info.plist old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/OperatorsTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/OperatorsTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/QueryTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/QueryTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/RTreeTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/RTreeTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/RowTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/RowTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/SchemaTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/SchemaTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/SetterTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/SetterTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/StatementTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/StatementTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/TestHelpers.swift b/ios/libs/Sqlite/Tests/SQLiteTests/TestHelpers.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/ValueTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/ValueTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Sqlite/run-tests.sh b/ios/libs/Sqlite/run-tests.sh old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Cartfile b/ios/libs/Webim/Cartfile old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Cartfile.resolved b/ios/libs/Webim/Cartfile.resolved old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Documentation/Images/Logo.png b/ios/libs/Webim/Documentation/Images/Logo.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Documentation/Images/Screenshots/ChatScreenClassic.png b/ios/libs/Webim/Documentation/Images/Screenshots/ChatScreenClassic.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Documentation/Images/Screenshots/ChatScreenDark.png b/ios/libs/Webim/Documentation/Images/Screenshots/ChatScreenDark.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Documentation/Images/Screenshots/ImageScreenClassic.png b/ios/libs/Webim/Documentation/Images/Screenshots/ImageScreenClassic.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Documentation/Images/Screenshots/ImageScreenDark.png b/ios/libs/Webim/Documentation/Images/Screenshots/ImageScreenDark.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Documentation/Images/Screenshots/RatingScreenClassic.png b/ios/libs/Webim/Documentation/Images/Screenshots/RatingScreenClassic.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Documentation/Images/Screenshots/RatingScreenDark.png b/ios/libs/Webim/Documentation/Images/Screenshots/RatingScreenDark.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Documentation/Images/Screenshots/SettingsScreenClassic.png b/ios/libs/Webim/Documentation/Images/Screenshots/SettingsScreenClassic.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Documentation/Images/Screenshots/SettingsScreenDark.png b/ios/libs/Webim/Documentation/Images/Screenshots/SettingsScreenDark.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Documentation/Images/Screenshots/StartScreenClassic.png b/ios/libs/Webim/Documentation/Images/Screenshots/StartScreenClassic.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Documentation/Images/Screenshots/StartScreenDark.png b/ios/libs/Webim/Documentation/Images/Screenshots/StartScreenDark.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Documentation/Index.md b/ios/libs/Webim/Documentation/Index.md old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Podfile b/ios/libs/Webim/Example/Podfile old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Podfile.lock b/ios/libs/Webim/Example/Podfile.lock old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/AbstractRequestLoopTests.swift b/ios/libs/Webim/Example/Tests/AbstractRequestLoopTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/AccessCheckerTests.swift b/ios/libs/Webim/Example/Tests/AccessCheckerTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/ActionRequestLoopTests.swift b/ios/libs/Webim/Example/Tests/ActionRequestLoopTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/AuthorizationDataTests.swift b/ios/libs/Webim/Example/Tests/AuthorizationDataTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/ChatItemTests.swift b/ios/libs/Webim/Example/Tests/ChatItemTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/ClientSideIDTests.swift b/ios/libs/Webim/Example/Tests/ClientSideIDTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/DeltaItemTests.swift b/ios/libs/Webim/Example/Tests/DeltaItemTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/DeltaRequestLoopTests.swift b/ios/libs/Webim/Example/Tests/DeltaRequestLoopTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/DeltaResponseTests.swift b/ios/libs/Webim/Example/Tests/DeltaResponseTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/DepartmentFactoryTests.swift b/ios/libs/Webim/Example/Tests/DepartmentFactoryTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/DepartmentItemTests.swift b/ios/libs/Webim/Example/Tests/DepartmentItemTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/ExampleTests/ChatViewControllerTests.swift b/ios/libs/Webim/Example/Tests/ExampleTests/ChatViewControllerTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/ExampleTests/DecodePercentEscapedLinksIfPresentTests.swift b/ios/libs/Webim/Example/Tests/ExampleTests/DecodePercentEscapedLinksIfPresentTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/ExampleTests/MimeTypeTests.swift b/ios/libs/Webim/Example/Tests/ExampleTests/MimeTypeTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/ExecIfNotDestroyedHandlerExecutorTests.swift b/ios/libs/Webim/Example/Tests/ExecIfNotDestroyedHandlerExecutorTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/FileParametersItemTests.swift b/ios/libs/Webim/Example/Tests/FileParametersItemTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/FullUpdateTests.swift b/ios/libs/Webim/Example/Tests/FullUpdateTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/HMACsha256Tests.swift b/ios/libs/Webim/Example/Tests/HMACsha256Tests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/HistoryBeforeResponseTests.swift b/ios/libs/Webim/Example/Tests/HistoryBeforeResponseTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/HistoryIDTests.swift b/ios/libs/Webim/Example/Tests/HistoryIDTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/HistorySinceResponseTests.swift b/ios/libs/Webim/Example/Tests/HistorySinceResponseTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/Info.plist b/ios/libs/Webim/Example/Tests/Info.plist old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/InternalUtilsTests.swift b/ios/libs/Webim/Example/Tests/InternalUtilsTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/LocationSettingsHolderTests.swift b/ios/libs/Webim/Example/Tests/LocationSettingsHolderTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/LocationSettingsImplTests.swift b/ios/libs/Webim/Example/Tests/LocationSettingsImplTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/MemoryHistoryMetaInformationStorageTests.swift b/ios/libs/Webim/Example/Tests/MemoryHistoryMetaInformationStorageTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/MemoryHistoryStorageTests.swift b/ios/libs/Webim/Example/Tests/MemoryHistoryStorageTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/MessageFactoriesTests.swift b/ios/libs/Webim/Example/Tests/MessageFactoriesTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/MessageHolderTests.swift b/ios/libs/Webim/Example/Tests/MessageHolderTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/MessageImplTests.swift b/ios/libs/Webim/Example/Tests/MessageImplTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/MessageItemTests.swift b/ios/libs/Webim/Example/Tests/MessageItemTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/MessageStreamImplTests.swift b/ios/libs/Webim/Example/Tests/MessageStreamImplTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/Mocks/ActionRequestLoopMock.swift b/ios/libs/Webim/Example/Tests/Mocks/ActionRequestLoopMock.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/Mocks/InternalErrorListenerMock.swift b/ios/libs/Webim/Example/Tests/Mocks/InternalErrorListenerMock.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/OperatorFactoryTests.swift b/ios/libs/Webim/Example/Tests/OperatorFactoryTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/OperatorImplTests.swift b/ios/libs/Webim/Example/Tests/OperatorImplTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/OperatorItemTests.swift b/ios/libs/Webim/Example/Tests/OperatorItemTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/ProvidedVisitorFieldsTests.swift b/ios/libs/Webim/Example/Tests/ProvidedVisitorFieldsTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/RatingItemTests.swift b/ios/libs/Webim/Example/Tests/RatingItemTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/SQLiteHistoryStorageTests.swift b/ios/libs/Webim/Example/Tests/SQLiteHistoryStorageTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/SessionBuilderTests.swift b/ios/libs/Webim/Example/Tests/SessionBuilderTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/SessionDestroyerTests.swift b/ios/libs/Webim/Example/Tests/SessionDestroyerTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/StringFromHTTPParametersTests.swift b/ios/libs/Webim/Example/Tests/StringFromHTTPParametersTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/UIColorHexStringTests.swift b/ios/libs/Webim/Example/Tests/UIColorHexStringTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/VisitorItemTests.swift b/ios/libs/Webim/Example/Tests/VisitorItemTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/WebimActionsTests.swift b/ios/libs/Webim/Example/Tests/WebimActionsTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/WebimClientTests.swift b/ios/libs/Webim/Example/Tests/WebimClientTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/WebimErrorImplTests.swift b/ios/libs/Webim/Example/Tests/WebimErrorImplTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/WebimInternalLoggerTests.swift b/ios/libs/Webim/Example/Tests/WebimInternalLoggerTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/WebimRemoteNotificationImplTests.swift b/ios/libs/Webim/Example/Tests/WebimRemoteNotificationImplTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/Tests/WebimTests.swift b/ios/libs/Webim/Example/Tests/WebimTests.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary.xcodeproj/project.pbxproj b/ios/libs/Webim/Example/WebimClientLibrary.xcodeproj/project.pbxproj old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary.xcworkspace/contents.xcworkspacedata b/ios/libs/Webim/Example/WebimClientLibrary.xcworkspace/contents.xcworkspacedata old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/libs/Webim/Example/WebimClientLibrary.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/libs/Webim/Example/WebimClientLibrary.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/AppDelegate.swift b/ios/libs/Webim/Example/WebimClientLibrary/AppDelegate.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/ButtonConstants.swift b/ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/ButtonConstants.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/ColorConstants.swift b/ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/ColorConstants.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/StringConstants.swift b/ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/StringConstants.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/LaunchScreen.xib b/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/LaunchScreen.xib old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/Localizable.strings b/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/Localizable.strings old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/Main.storyboard b/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/Main.storyboard old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/RatingViewController.xib b/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/RatingViewController.xib old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/ChatViewController.swift b/ios/libs/Webim/Example/WebimClientLibrary/ChatViewController.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-1.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-1.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-2.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-2.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-3.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-3.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-4.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-4.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-5.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-5.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-6.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-6.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-7.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-7.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-8.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-8.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-152.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-152.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-167.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-167.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-20.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-20.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-29.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-29.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-40.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-40.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-41.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-41.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-58.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-58.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-76.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-76.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-80.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-80.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Check.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Check.imageset/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Check.imageset/check_Icon-32.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Check.imageset/check_Icon-32.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/DefaultAvatar.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/DefaultAvatar.imageset/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/HardcodedVisitorAvatar.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/HardcodedVisitorAvatar.imageset/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/HardcodedVisitorAvatar.imageset/VisitorAvatar.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/HardcodedVisitorAvatar.imageset/VisitorAvatar.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back.imageset/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back.imageset/back_Icon-32.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back.imageset/back_Icon-32.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back_dark.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back_dark.imageset/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back_dark.imageset/back_Icon-32.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back_dark.imageset/back_Icon-32.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip.imageset/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip_dark.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip_dark.imageset/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close.imageset/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close.imageset/close_Icon-32.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close.imageset/close_Icon-32.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close_dark.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close_dark.imageset/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close_dark.imageset/close_Icon-32.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close_dark.imageset/close_Icon-32.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Empty.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Empty.imageset/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/SendMessage/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/SendMessage/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/SendMessage/SendMessage.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/SendMessage/SendMessage.imageset/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/SendMessage/SendMessage_dark.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/SendMessage/SendMessage_dark.imageset/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/LogoWebim.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/LogoWebim.imageset/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/LogoWebimNavigationBar.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/LogoWebimNavigationBar.imageset/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/LogoWebimNavigationBar_dark.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/LogoWebimNavigationBar_dark.imageset/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/LogoWebimNavigationBar_dark.imageset/logo_white.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/LogoWebimNavigationBar_dark.imageset/logo_white.png old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/ScrollToBottom/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/ScrollToBottom/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/ScrollToBottom/ScrollToBottom.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/ScrollToBottom/ScrollToBottom.imageset/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/ScrollToBottom/ScrollToBottom_dark.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/ScrollToBottom/ScrollToBottom_dark.imageset/Contents.json old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Info.plist b/ios/libs/Webim/Example/WebimClientLibrary/Info.plist old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/MessageTableViewCell.swift b/ios/libs/Webim/Example/WebimClientLibrary/MessageTableViewCell.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Models/ColorScheme.swift b/ios/libs/Webim/Example/WebimClientLibrary/Models/ColorScheme.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Models/Settings.swift b/ios/libs/Webim/Example/WebimClientLibrary/Models/Settings.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/RatingViewController.swift b/ios/libs/Webim/Example/WebimClientLibrary/RatingViewController.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/SettingsTableViewController.swift b/ios/libs/Webim/Example/WebimClientLibrary/SettingsTableViewController.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/SettingsViewController.swift b/ios/libs/Webim/Example/WebimClientLibrary/SettingsViewController.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/StartViewController.swift b/ios/libs/Webim/Example/WebimClientLibrary/StartViewController.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/String.swift b/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/String.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIImage.swift b/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIImage.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIImageView.swift b/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIImageView.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UITableView.swift b/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UITableView.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIViewController.swift b/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIViewController.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/MimeType.swift b/ios/libs/Webim/Example/WebimClientLibrary/Utilities/MimeType.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/PopupDialogHandler.swift b/ios/libs/Webim/Example/WebimClientLibrary/Utilities/PopupDialogHandler.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/WebimService.swift b/ios/libs/Webim/Example/WebimClientLibrary/Utilities/WebimService.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/Localizable.strings b/ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/Localizable.strings old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/Main.strings b/ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/Main.strings old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/RatingViewController.strings b/ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/RatingViewController.strings old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Example/WebimClientLibrary_Example.entitlements b/ios/libs/Webim/Example/WebimClientLibrary_Example.entitlements old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/Info.plist b/ios/libs/Webim/Info.plist old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/LICENSE b/ios/libs/Webim/LICENSE old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/README.md b/ios/libs/Webim/README.md old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary.podspec b/ios/libs/Webim/WebimClientLibrary.podspec old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary.xcodeproj/project.pbxproj b/ios/libs/Webim/WebimClientLibrary.xcodeproj/project.pbxproj old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary.xcodeproj/xcshareddata/xcschemes/WebimClientLibrary.xcscheme b/ios/libs/Webim/WebimClientLibrary.xcodeproj/xcshareddata/xcschemes/WebimClientLibrary.xcscheme old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/AbstractRequestLoop.swift b/ios/libs/Webim/WebimClientLibrary/Backend/AbstractRequestLoop.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/AccessChecker.swift b/ios/libs/Webim/WebimClientLibrary/Backend/AccessChecker.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/ActionRequestLoop.swift b/ios/libs/Webim/WebimClientLibrary/Backend/ActionRequestLoop.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/AuthorizationData.swift b/ios/libs/Webim/WebimClientLibrary/Backend/AuthorizationData.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/ClientSideID.swift b/ios/libs/Webim/WebimClientLibrary/Backend/ClientSideID.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/DeltaCallback.swift b/ios/libs/Webim/WebimClientLibrary/Backend/DeltaCallback.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/DeltaRequestLoop.swift b/ios/libs/Webim/WebimClientLibrary/Backend/DeltaRequestLoop.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/ExecIfNotDestroyedFAQHandlerExecutor.swift b/ios/libs/Webim/WebimClientLibrary/Backend/ExecIfNotDestroyedFAQHandlerExecutor.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/ExecIfNotDestroyedHandlerExecutor.swift b/ios/libs/Webim/WebimClientLibrary/Backend/ExecIfNotDestroyedHandlerExecutor.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/FAQAccessChecker.swift b/ios/libs/Webim/WebimClientLibrary/Backend/FAQAccessChecker.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/FAQActions.swift b/ios/libs/Webim/WebimClientLibrary/Backend/FAQActions.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/FAQClient.swift b/ios/libs/Webim/WebimClientLibrary/Backend/FAQClient.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/FAQDestroyer.swift b/ios/libs/Webim/WebimClientLibrary/Backend/FAQDestroyer.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/FAQRequestLoop.swift b/ios/libs/Webim/WebimClientLibrary/Backend/FAQRequestLoop.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/HistoryID.swift b/ios/libs/Webim/WebimClientLibrary/Backend/HistoryID.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/HistoryMetaInformationStorage.swift b/ios/libs/Webim/WebimClientLibrary/Backend/HistoryMetaInformationStorage.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/HistoryStorage.swift b/ios/libs/Webim/WebimClientLibrary/Backend/HistoryStorage.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/InternalErrorListener.swift b/ios/libs/Webim/WebimClientLibrary/Backend/InternalErrorListener.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/ChatItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/ChatItem.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/Deltas/DeltaItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/Deltas/DeltaItem.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/Deltas/FullUpdate.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/Deltas/FullUpdate.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/DepartmentItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/DepartmentItem.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQCategoryInfoItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQCategoryInfoItem.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQCategoryItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQCategoryItem.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQItemItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQItemItem.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQStructureItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQStructureItem.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/FileParametersItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/FileParametersItem.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/HistoryRevisionItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/HistoryRevisionItem.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/MessageItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/MessageItem.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/OnlineStatusItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/OnlineStatusItem.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/OperatorItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/OperatorItem.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/RatingItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/RatingItem.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/DeltaResponse.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/DeltaResponse.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/HistoryBeforeResponse.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/HistoryBeforeResponse.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/HistorySinceResponse.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/HistorySinceResponse.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/VisitSessionStateItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/VisitSessionStateItem.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/VisitorItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/VisitorItem.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/LocationSettingsHolder.swift b/ios/libs/Webim/WebimClientLibrary/Backend/LocationSettingsHolder.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/MemoryHistoryMetaInformationStorage.swift b/ios/libs/Webim/WebimClientLibrary/Backend/MemoryHistoryMetaInformationStorage.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/MemoryHistoryStorage.swift b/ios/libs/Webim/WebimClientLibrary/Backend/MemoryHistoryStorage.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/MessageComposingHandler.swift b/ios/libs/Webim/WebimClientLibrary/Backend/MessageComposingHandler.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/MessageHolder.swift b/ios/libs/Webim/WebimClientLibrary/Backend/MessageHolder.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/MessageToSend.swift b/ios/libs/Webim/WebimClientLibrary/Backend/MessageToSend.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/ProvidedVisitorFields.swift b/ios/libs/Webim/WebimClientLibrary/Backend/ProvidedVisitorFields.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/RemoteHistoryProvider.swift b/ios/libs/Webim/WebimClientLibrary/Backend/RemoteHistoryProvider.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/SQLiteHistoryStorage.swift b/ios/libs/Webim/WebimClientLibrary/Backend/SQLiteHistoryStorage.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/SessionDestroyer.swift b/ios/libs/Webim/WebimClientLibrary/Backend/SessionDestroyer.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/SessionParametersListener.swift b/ios/libs/Webim/WebimClientLibrary/Backend/SessionParametersListener.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/CompletionHandlerWrappers.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/CompletionHandlerWrappers.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/DepartmentFactory.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/DepartmentFactory.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Array.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Array.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Collection.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Collection.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Dictionary.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Dictionary.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Int.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Int.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/String.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/String.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/UIColor.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/UIColor.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/UInt32.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/UInt32.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/InternalUtils.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/InternalUtils.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/MessageFactories.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/MessageFactories.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/OperatorFactory.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/OperatorFactory.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/WebimActions.swift b/ios/libs/Webim/WebimClientLibrary/Backend/WebimActions.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/WebimClient.swift b/ios/libs/Webim/WebimClientLibrary/Backend/WebimClient.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/WebimInternalError.swift b/ios/libs/Webim/WebimClientLibrary/Backend/WebimInternalError.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/WebimInternalLogger.swift b/ios/libs/Webim/WebimClientLibrary/Backend/WebimInternalLogger.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/WebimRequest.swift b/ios/libs/Webim/WebimClientLibrary/Backend/WebimRequest.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Department.swift b/ios/libs/Webim/WebimClientLibrary/Department.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/FAQ.swift b/ios/libs/Webim/WebimClientLibrary/FAQ.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/FAQCategory.swift b/ios/libs/Webim/WebimClientLibrary/FAQCategory.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/FAQCategoryInfo.swift b/ios/libs/Webim/WebimClientLibrary/FAQCategoryInfo.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/FAQItem.swift b/ios/libs/Webim/WebimClientLibrary/FAQItem.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/FAQStructure.swift b/ios/libs/Webim/WebimClientLibrary/FAQStructure.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/FatalErrorHandler.swift b/ios/libs/Webim/WebimClientLibrary/FatalErrorHandler.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/DepartmentImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/DepartmentImpl.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/FAQImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/FAQImpl.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/LocationSettingsImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/LocationSettingsImpl.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/MessageImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/MessageImpl.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/MessageStreamImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/MessageStreamImpl.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/MessageTrackerImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/MessageTrackerImpl.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/OperatorImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/OperatorImpl.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/WebimErrorImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/WebimErrorImpl.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/WebimRemoteNotificationImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/WebimRemoteNotificationImpl.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/WebimSessionImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/WebimSessionImpl.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Message.swift b/ios/libs/Webim/WebimClientLibrary/Message.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/MessageListener.swift b/ios/libs/Webim/WebimClientLibrary/MessageListener.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/MessageStream.swift b/ios/libs/Webim/WebimClientLibrary/MessageStream.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/MessageTracker.swift b/ios/libs/Webim/WebimClientLibrary/MessageTracker.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Operator.swift b/ios/libs/Webim/WebimClientLibrary/Operator.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/ProvidedAuthorizationTokenStateListener.swift b/ios/libs/Webim/WebimClientLibrary/ProvidedAuthorizationTokenStateListener.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/Webim.swift b/ios/libs/Webim/WebimClientLibrary/Webim.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/WebimClientLibrary.h b/ios/libs/Webim/WebimClientLibrary/WebimClientLibrary.h old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/WebimError.swift b/ios/libs/Webim/WebimClientLibrary/WebimError.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/WebimLogger.swift b/ios/libs/Webim/WebimClientLibrary/WebimLogger.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/WebimRemoteNotification.swift b/ios/libs/Webim/WebimClientLibrary/WebimRemoteNotification.swift old mode 100755 new mode 100644 diff --git a/ios/libs/Webim/WebimClientLibrary/WebimSession.swift b/ios/libs/Webim/WebimClientLibrary/WebimSession.swift old mode 100755 new mode 100644 From 970e3b17cb806e50148d970c51e8f9df7c2acdf8 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Thu, 10 Oct 2019 08:47:41 +0300 Subject: [PATCH 02/32] Add --- ios/RNWebim.podspec | 26 ++++++++++++++++++ .../SQLiteTests/fixtures/encrypted-3.x.sqlite | Bin 2048 -> 0 bytes .../SQLiteTests/fixtures/encrypted-4.x.sqlite | Bin 8192 -> 0 bytes .../DefaultAvatar.imageset/DefaultAvatar.pdf | Bin 56741 -> 0 bytes .../Icons/Clip/Clip.imageset/ClipIcon.pdf | Bin 52123 -> 0 bytes .../Clip/Clip_dark.imageset/Clip_dark.pdf | Bin 46261 -> 0 bytes .../Icons/Empty.imageset/Empty.pdf | Bin 44798 -> 0 bytes .../SendMessage.imageset/SendMessageIcon.pdf | Bin 53136 -> 0 bytes .../SendMessage_dark.pdf | Bin 46316 -> 0 bytes .../Logo/LogoWebim.imageset/LogoWebim.pdf | Bin 57476 -> 0 bytes .../LogoWebimNavigationBar.pdf | Bin 57347 -> 0 bytes .../ScrollToBottom.pdf | Bin 58455 -> 0 bytes .../ScrollToBottom_dark.pdf | Bin 74796 -> 0 bytes package.json | 24 ++++++++-------- react-native.config.js | 15 ++++++++++ 15 files changed, 54 insertions(+), 11 deletions(-) create mode 100644 ios/RNWebim.podspec mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/fixtures/encrypted-3.x.sqlite mode change 100755 => 100644 ios/libs/Sqlite/Tests/SQLiteTests/fixtures/encrypted-4.x.sqlite mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/DefaultAvatar.imageset/DefaultAvatar.pdf mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip.imageset/ClipIcon.pdf mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip_dark.imageset/Clip_dark.pdf mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Empty.imageset/Empty.pdf mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/SendMessage/SendMessage.imageset/SendMessageIcon.pdf mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/SendMessage/SendMessage_dark.imageset/SendMessage_dark.pdf mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/LogoWebim.imageset/LogoWebim.pdf mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/LogoWebimNavigationBar.imageset/LogoWebimNavigationBar.pdf mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/ScrollToBottom/ScrollToBottom.imageset/ScrollToBottom.pdf mode change 100755 => 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/ScrollToBottom/ScrollToBottom_dark.imageset/ScrollToBottom_dark.pdf create mode 100644 react-native.config.js diff --git a/ios/RNWebim.podspec b/ios/RNWebim.podspec new file mode 100644 index 0000000..14bbe54 --- /dev/null +++ b/ios/RNWebim.podspec @@ -0,0 +1,26 @@ +require 'json' + +package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) + +Pod::Spec.new do |s| + s.name = 'RNWebim' + s.version = package['version'] + s.summary = package['description'] + s.license = package['license'] + s.author = package['author'] + s.source = { :git => "https://github.com/AlfClausen/react-native-webim.git", :tag => "v#{s.version}" } + + s.homepage = package['repository']['url'] + + s.requires_arc = true + s.platform = :ios, '9.0' + + s.preserve_paths = 'LICENSE', 'README.md', 'package.json', 'index.js' + s.source_files = "ios/**/*.{h,m,swift}" + + s.dependency 'React' + s.frameworks = 'Foundation' + s.dependency 'SQLite.swift', '0.12.2' + s.dependency 'WebimClientLibrary', '3.14.2' + +end diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/fixtures/encrypted-3.x.sqlite b/ios/libs/Sqlite/Tests/SQLiteTests/fixtures/encrypted-3.x.sqlite old mode 100755 new mode 100644 index 4b3c4d0ec06c7224bbe23ca0e8bf3c5538a66ae9..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 HcmV?d00001 literal 2048 zcmV+b2>3)08a>;W-J5(;;@D*~Bq9FW90iNe-OU^w&-Fcb$F#j?3aO_f4=8pqB zwUCPy(GDu&{$YUF5!X#`@>&eL5Em+_AEBZn8MZu@THAj{8Bv!*evFKqdG{YKs^8#T zCpmB+qU86jKR*e(Y>tA*FEg$$J|-8+pg&N&8o;RU8`DsWc#tGE$f5ywo9kBc@QhiHX%2s8Quttn2V zuGP*8u0`77#)W$on++;OqGNNqzogAI?GX)H;H_#6^&_K^!wl`xO)Ih9&ymiuN4PcU zt&VfsB*ds2Vnzrm!$C#3&;=p#{3 zrr8mr`4MBBojX@#pxxmE%B{n8MdtZy-h_#mQ2k%uyFPR1{JfQ)0kAC{P-Ebs2tDq( zjPnghm6-cX?zC=zlxrpaU;H@eW4x~N=Oiwu29xA|y+f4@TDvQOM&;U7tN(l#eDucI zDa#1T?{pn)V=;L{nNvz7?GND8N`9Srs{URN;Jj{j{#nl}qrVi}5+wb#ncUl&RiVOQQ95zzU@4a#jWNnrZo5HlLAWh0 z_sW}l4KZD#Uyzy4xJ2G2WIpg5N*q$x`drk|^-<;W5$_PMhXz3{o+>X_OsN!Ei;d7d z$Wm=XO};b66?p);>yJa|$VMDf^2gn-!SqbLPm9G}XB?%<@Dm2SF^CnJubCMU!+62& z<6JqBo`kMu?=AVrJ9hSBuroR3ZAO^n82#F)IREa{RNaq8xtWqCL5rRO4rn1++A;T- zH|wXI{~2a3e_c{8?;lGUo#GaDY(ZT$7PzhbC~erD8UeZ>kbz;z#d#6wacoA|n|_cX zSRnz&3qql~%jFQ`->|)Z2u}zajj{Peubri}rg+)kAO==0#2J zt>7uOLj4yB^C;y}%`U+c{PM%I_Rr>nUr=Mbtw2ky-gayM)7tgQ(J$KJ%yNbw>C_P2 z@PxB}H>HPB-kS)kB)x|u_}grUH|bSTzi70Ifz^+Wo&Ok$phkHBS_M|*YGz>kH<^+% zx-ZFmvoy+=5@Qt898FL49?%td>4!+=>!ueg^$68NXD8gaNTCesCKyzD?22s(Dw0wO z131^t6@R1LR4IXd!cK|y9s{Y9(L7!VIO*oMa0i6M{Q_5-s~!tV#J$){OZ|vu#$c0k z<8lcG?@1BFroP|He3B|;P%W1^!JtSl+cdI|a@obN`_0ywi1IzfP)a6MtPdA7K4A#8 zB6cuIWSff|DQzNO*tyB#JhA8?I8{HJY+Fv?9>my=c@g?Gi4R#?5Ja27&diEbN}GeX zWgDS*ti#>3*OLoeHgn_|n_SW`rsh4luOh#lZ6eXmKMiU7qOhP1sZ_`}B>Fu4HAwl$ z&&+LFFHOBz2!Vw-sJei$;m@otCD5wYf!Gt3Rji(lK&1$#LTfAFZjBcR(ifwCZA+_q z%QA?z-s3I&?J5;rtYpsIp0UegCO^+prph0M*w9{@xHuo|ENOFE^a~&!y&!?@Qzy1(qN2noyyx? zqXw(T+H|8K@GXJ)|!Q%`oU#ql2yWN7hR(=l(1NRDA%uC7vS!T=Z0H zUv93_!4dz2nUOF^xy~i%Ui+`x`oHAOE$LrK5F4>0t%l~Ux=K3QJTYl7jYG&vDWUXh e@S*KLmc9i7F)WxTL6K?@Y7};KXset%z6Wp5kNblF diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/fixtures/encrypted-4.x.sqlite b/ios/libs/Sqlite/Tests/SQLiteTests/fixtures/encrypted-4.x.sqlite old mode 100755 new mode 100644 index 36890365583fc0fa1383f4377d7c9b844059872c..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 HcmV?d00001 literal 8192 zcmV+bAphU50pp8hy(yqK&QH?T=pj>XQ#YZ$vEL0D1VwzN+29B&{r~vU4y>H|8AqoW z{*8r8;(f@lGt@4B_LE(PFQy0U)mKADn*2FfTp)@TKrkyr;d268(^B`MTGF;I{~9M8 z={X| zZMb3wOK)gC40IPXuAl@g4Tq=HjOHgf3w`#1u$k2CJ5JtzK~Xn@NvcIS7?^1yi*#XTgUG^#R9l%5t)eHjCM)WoVt2TGR%D zj@Qgn6qMyz2#hdA-p9%`ssCozLrq^b)R4ip|FK zV})XFFON|d?<|eZi4bQ%mXB?rXQtj@K{I>#N$vlgOT1hk<~Pf5E8;$P`!U85n?1mF ztp(ooX%X zbJ2=>UG733Qy?jpQKubErRHfA43!i7AHEbr!N6E43cP^yhrv&PtcYwL`Xx=O}O9*|MmolJ+`h6w@x@GH~4!rxI-F;`v~KsE_ zdf^s@P6}fv5p&yb?5d!sUZGug-1JqdSLB>?a<8m~OHtv~vD0SEl)*(%WmG@o^8VWs8=#vVLEQ;@AoQeD;ke zdYp!6J|mNH6e^lFt|ZVmzI=nz_@XQ6m=y<==p4M5WU^Sq8YhSsahJP2ZVx4cuS6pT z=zhzBDD2zVjlfS7B3>1Z8d%Lb4cB^b|4Q*8$2)YBywK!;g5-~&^E&1BlF$|fO`8qO zK3c^bKiwbLyo(9X=;J^$>|boEz#QMO7?29YiaH-YbyxmG6FCc7D3tk)XR5mDUT#i! zTf;%gMx7YlBM%J9V^T*Y~E%&;iWLbC{f;E1vl^+z&j2cAL3 zC4vvV%t^4?MKhw1Xr%~TQNmvf^XX>kY4QngA9(t_L@wfWo8FI{^%#4Sps=uDc)`4ED^*#{7dv-z6glvtOMsiyOMu?SE z%6T?QJ;p0I39*Wer|6=;Izd=+a5&N0C$6yhE}C7;T~e~U9hIf|b&l06$G<2eK0B$l z9pnj~q=&}lV@FpNm@9#bv)FdFtkJ%D>EMlLT6t3FDsF=Y>ez8DSc2bB+Uqjk$$}lA z;%yjBE1Acd_kut)- zEsDu9=6yD>RFNVnBjqNTk8qm@Bmz{tUEWEv9`@`Z*P@DPu{z)r3hwu`-#(9`fMre1 zn7x?LLd*Mtw5RS>$LtdpikcATx)^$;YET{LYQ$hKWkiIxfpu+rO%8z0Jg0uu?E|fP zps;C6=3X?9M)Q^)Mb3Vk!7^S<`fE&&WN8vz+W){n>htZ6h9+S%80q%gJ9&6Nw;mlc z*c+pFkqI~>lrqy0OC^XAA})eD&A5r@9uFcJT7FwatT--I*Vm*ML_Kkd#U?Rf=}dn2_&s zbP?CKJSOTU4J}6>EMfI;TU!*qo(pg*buWVhST1Ju^bDB=UB^^s$qT_}_z5t(DbAge z+H3bw&eHxrvg6jQf~GtZ*_zwCWVAK1}wjw)ACrWEeH*~!6^71Gzr>N>~LVqmRmu=g0f zf4Sk2qDN8M##(!Q?N28=nGzXOvc}9$23FwYizPxP8@^H)V1ywCqvrU>phB!`OafC< z-W{EgWjNh}RPVWC$-eO2$VlxaQ8HRAP4Tv&9t`1gg~nbha)E}$6^n#K8@ZKh^$6`i1Bj)`}@U?!gTY>Rm4^u&%oCMS@U#j4VNb4Bxh)_V6$eWT!?n2n8bZWlMJ_CGFT8&%I7mGMHpvjImD#_@d4p^2W%!rJ z4;LVmaD2e2nqBHBuVNMm8P&cCu#5+{PigBk*}E1a`dP=L1YeX{fn2_p?Wt*M^J~i2 zGpaZmeT36Lv8}F~cVI?dZF476ZR#JsyyZd#mw$9Qd4sL1nkY+cj0;Hyi5C)2ugHTp zRsjaMZhlFC{blfg`$&;QP04%zRUc4QnP<0ns$JbF2+zS;Sf-ymJYZNbFM;jULUOjA^6pw)`ZWu4Gka=<`>T5E8m+1fG8=3MD4m zHup4y?wFq4orqK5Zy#b?`G7<^)l|RH{++V$r#vvgJvT3AtnN(&=|Sw6c^E&MFJj{y zQWA2XMrn5jmAbxG;A&IR3$0e=0`toI3N96gXV2`cb$SU7i!30b4nxF$z_FBc196H1 zH`-D(I#$AbcQm0@DlHUfl4@$FNwNliJ8rLSTy%e$$wz&Bz?DS zDOv%XL*_dQ1!NsI#Mk|7DSdGgKRynxEy1?aUy6(f158_9Bn-aii>A(BZ0SKny$%)1 zN)XEYKL~N9r{MZfedFQ?P*877#x{?AnykKW25 z2;B#|FCl7xbo=!Ct-ir%7{HbF4u=GY&#sbG=PQrRywtg*09&=Cgf!>yCQ^ft?)81Q z7@Oj+4X;VU`8w5)@ zo~g@sV;up~00Q{KZ?u}dJ;Hwbl=F8w>wb6=aB9+}iG;iZzv{k-y#4~o7P=K3bMn&X z&#?hh!;#(tq+?q;&r2GR(I*%_2w=x*0RjRU?|n3=j3L6&BP;8mo^~&4v+<=jtONPq zE>kQ`t2CGlbH~**wPueHwYPB*kE4=u$BfNMp7>TwQ)tXAr~c4W0P3n#K?e={$t~uQ z^dzA0KD+Jg)E^d}kMsYzbs_Ed^mwb>E=@~-mDR8mrYoRFaWG^T3DeCUii!4c+=0O= zBDZDOiOHni0exRfL%DEY&`yDZG;ee9v6&!a+^)~13&|Kw$6@HC>qwUv6rs=A1A^o2jCz-d`Y0}{VNJWEX^7BX4ozfjdHq+d==fabkZa6VihU5V{NH1v8p^%$y!XJm z>1oAHXVmdSH!-uQj^kJy%3BShWXahXekpn99-#L8qMJZxNAQ<9xdkhw4+Y5%FHA>? ztpJvl1Erb*4S5O?c2rT7BGVet2dc!C47gIR6Nf+N&&dClUtz5lvnc;!yxO9#4lcGM zt779cK)SkvM>A|Ms|hX0=*{u}=^h=|$UG~q-&{Hja8x{`Wi%!mFp)Z%0G#zX`o^L_ z-@d%NoC(KSbF4tQtzX*7NYXN2!`bPU(CmjtXRw?kzHHk46wKcqIf;k{kgqL^sZBoK z72QW8>6D{tde#_HXI04Y7ICXd%R}Nbzz=@D)5F%(nDTJSdgg3GqT4;lI=3Z0w3?=Qh&iXddM1Mf_wsikcNgDH=HZo3QTooiKIW**l_{XO z-&@fVd0x9q-er)$*&E(bcXT7)8u&9#hDFAWS$1BiVwb>ito`Kl>y~=M04lYg^2s>* zCIE(403LoNkhiS&siZg2Slum>3|36cr>YwrV6arzXawR_e7A1?v8~x7bH$HRCBkz@ zTd6ey6Di|H@9at1(LX;i&@REzso% zK^!rvR}Vc_hSP%atdEfm(fi(u@Z{p-xT=WP#?z4t{4SdJhI>S`Nv-?^)mWJt$Oy1u zCPmYBShRMp(}gJym`Tn@W-_TUUJRUgr~s3+&wykw)L6SEGg#{fg_!fozBf^XFt+iC zDzT8udDS(b<0V~VGIHbuHX56I~1a-zNpAEK}Nw(hvxR03t8FMcJzP?x0$nh zumoo%v0E;`q2o#Yg)d173vt337vLM%L#n5po_Ra9x=(z?RFv|bhlW#NJ4uZBG)VV1!(6$$$#wccU?C$HLFI zFRD=r(6L{JgLjGZ1~-Zmb1(PWFZ4trww66duC$_okg~uw*~0a;11uwYp`xq65=k$o z7XNspcE(tV!|1bi<*%mly$xsSIdGQjc*s zCu%E@{1q_{#xzSLi;6!I=c6U8vkSqTERb9(!y;Uf=_C`deu_L+@wPQobKOk4YBhk% z?RSZAfzL#Jy^DHHshp@>J@8)_+$ITk#}Njwrw+YbG^J0gD; z{Jcgl-vq%lw@0jGeApXyZXu3~f!;r-SUk-^(=PK#+-gA48cR_w?3t_pze_rycj6ii zML7lqaTf$*l5cWdY{hnHhrdpfrU{-a9U*JOQiT`ADE4u_yIGJP?XhU7<=>X1L$g_1 z7pY;`_zzJz2|Uv3{alqsgVr87;V++ExMmS_=b zoagsh`BS`oC*z1?=t}r*K5T->$W0h~Dt3=uo1@KA;q(q)cd_bnN}>Yr?h*Qc6uA1$ z!{IG}y4vw+0NRS(&}b*D&PB|-eJP){d_uZ0ROYfv^0%S%TD{>I@q3GBo9U-bIaFu( za5=+L#$rKQZi6+ttF3#+NmOEW)esnq!LR?@A>NMs*j~sf6ycRWkV$JEo0@c)4iKtH zGm{YNPn@Y*+1`je1^vv`Xt4gnBC^OZpuM)r4=z@`&3CE9N^C0QzM_&{3NADx;swFl zBRq(uo>^MaP<4v0WkHc5VX;eKbQbMBt-16ZvmB`+IX-b2=(dKf;!^Ka@l2?W)04lW zBsoId{O@x^-PhZ|Hq?N(>)Qxl3gLpGfr=;kdmYC7EvnL)+;Yy{VLcpxNj~YKwZTJC zr9ab*fHM+ax8c12SQsH8Z35|z2k4AkXC-`>HN=Ef&8(bXuGIF*#Y$d}$DHB#vVjzqn$;^k@$?E?KkhWQF_M(B@%94mHH?pbQ$PzuBzj`W4CU zN$&w7=Z^vri~g!&$|;(?_y_)Y=sonZ5)xpH1yE0AlDsi3x?c_NR~$Jg%DE7NawFNg6>vz(Xl zq6TXNnI(i|D3X#nhCr+C_vKuW^8~`Dh+wPkrHLXp@?%lAC`8Fp{VK(VuD?o>Kgl`) z%k1^;r=0oY4v=>sC4iPtlG5}g45fC#phBjS+zH0QR3g_&i{*u_ll*=6<1C&bl9T@M zYx?B)8Co7EM@7+X^M)xX7v93+G!j`_yfy*l0Ta*B$)nZQ+ccf3uR{cx&ri$-2uPz! z;Y~c{s4s}ad`xDz1`b&eN%vW&Vk_CLWh1-@&4e(P@Q!m}Wdw%mxmDBe7 zU=C<&HEyMf(8h9#L>3DZG6_-u81D6bZ~BpZ-#=b|vgW4;8~PZwl3)zuz$Lt&M$#!Q z83EY%=-(b$JUQP%zNObfmnu-o7J{})p;)We&7K{5yCz(XG_U8Hu$b(HtBpeA?!-&f{wmDH4T5JC6zXwl`Gpfzz>8H)%_QC)feLNbJp~ z>{jd_`9d@~ElMdq#kwO}_Q~9N@0-&#i2YhU;km#=IVbO0M~alZf30TK_05t z9DRziuYMVcoLH*ea&%riJ>64YNiF~@;m48cu2Y|Fu_p=J)yS*$Dd9e&r22Uzo6Xli zT6REL7a;Beq7vHc_{ZH1F`%M6vC)7JCn~IY6NDcHt1U90)r<*)*HL=KJZB9%K+IM1 z5na#aEeCfs=U8>Rof}6WI8$_;Dzd{rvW0^n!DW?Hm}|^1+n0r4mHen?VezonwS!M6 zzmY_S8yzd$DEN)XnTk6^lHI0v1%tx8V%G*refWde4#Xes3#?oS1BC}n!Mh)NS678Z z3}O`XL+?q%M7fRV>6ft_6w7g++}+jlX^-a@-1BR?TRAi3n?ahN%RF0g*AhkprHWQ} z_HFF9Y$CkPZiTVQzBPpQxbzmL z!nZQ^TsjA|109XbjvcJTl>h{p%(bnG&I%+S9`mwi9w_52i;-E}rQL=M`t&Y?e30Ax z9h)hDZdXFrS8Wij9{sW77Ox6l@N}Wchig}o`Z16XBZH!rz#(T1`MeUOW^mh4A^r?U z^N1LRcr=5)IU0x&e85B_Bt2jbEZqConzzz-0AsAU1497zx{~?k90!g8Ag>I&=6+S} zfg;lWz#;=G%@_H^^3Z_sv@cshqh9f4NMZ^TJno_+&SgV#rf?ql+qvQK{w9?I0A4~dBIw7BVe|2B0d!GuTQTw8Z;`<;+ zML7qP$OrYGqYarP2@pcZ&Lss^x<>ul|8xl@9%U7CZ+^vi9G)yVR9(p-jA;cQy^I7$ z~}86 z<}O7|#h&LBLJ&y|je|9sD;B{9tw}!YV6n*oO4Gqc!j~b!-5jBO{%`~RY}`0whr4o_ zv{e8TGLCM`I+_L;a{+Z*DZDSf6Cv(8nFPIMt#j8GrSuUch?6EVc5@kNJvc}?+^&36 zGI@ZP7;`C;38(&F$*3ezia@%-I(nUIa)25YzN)2?LiepnH{o-F$+nFq{OI{H?_V)k zev_pJG{WGy`)0JVw-Z%#41vm0n!r204pGs6+n8w;YiOMEq;@OiLK=)rz4C^4I1Bfc z81sv;S6W6Cd)yz;=Y!&tmjh39$_(=mdQ7x?8K#QGlQX@b^Yw0=>?6tsM2zH@X%J^) zf#s)4V>o3OSeLEk$vla#iHp3pg(+yU1wu!}p{JoNIkTt%r<-Ks{)Wo5LkGvK>}caM zWXKVR`g>u+NibNJpN0_8u`EEW4TQixAAp=w2zVaTEs7-CT3z8O4c0u8!v>V`yc?lO zsC}-mB~`-fLAB0s*w`-w4)zT8J~5nQLvaVb7`fC)5<`#2VDH&_^p6^ zG#KX+*0^V6fXLl9KQ_#x7vzDr?`$>~O~$ku{q&yh4|%&NV`z7U>u~Xuj~h7pmbO9> z%6^c)>g6&mhcvlKG8uZ!MKNT(=(pf5{5P%dyK7mJWATi_u$TcHdV5!)X0+?63Bx_RdPo+^4a;8_23J*sf+9xg|9HXGgVx$zqJ*RWL1D!l8( z50nY+{EkxNN4DNGxmMNbyPe=Z8lOtt&}v)@env$2+Bu&Dg@+mO zC11xDFqet(!I)i6TGq_=E%fY#vk7(vRO}XdqTuN_Jo2ivg`Df zpg&g*3fl_&`{z--N|UxQZD3!I97&=T9-fdx)?X$no=J-nKz#d=zUi4`@?@tyancy% zlVS~AxKnu9R6a$SBO-8nHS){e9{6!A+Eg8QM|SM>+&65~oT~R1A;7AcyS<l&~e$OP{dDTIcp9~=hdLJ6~+z-7R)fP9K>s1rWm5ZIV{FTgd-$A zYxf8StO!pQNy1r9k0G2KMTykmiG*+}Jqk~z6KJHa;RGC>g2j=rczPtB7!Cd>;lhJk zL~IRk7UR(yqh)MvP#w7H9%1(RT+vvp-|vs|6Qi6S6JV#)u{Z*jK!^ksk=}sAr^$+R zc-x{vLUPy!ug+s}`7BOHIFzf=Ix~FTBO;)pye;UL-Ib@v;f+FkjM6#n*es0;i;u!# zOJU*(?56KCny?nTsWf(lZua9l9e_yi~Nd-V=aCiX(0G*N@=Y3yH$@=xW zJT6y;$A*MOufrN_2B6O81(@MWb6Or zAoYDtkHYD+#iGe6u-P&|i-4u!EEY^hauhMVlSrepIDAg8xpNG*C}Tcm`7#Y`jn5DZ zxM`6%d?cQxz*C~}v}h6ugCj=ca0P^*ltpBSoO+8fP!<^lD2vJn_CIBkQjoTY9ECZ< zu61ZEHZRit@|p$G5E(XK;Zle!Y)Li?(x6-#kJkXRtb2sa;B{trbcTXK$QK4cg)Jr8 zZ_)eAu>>*&fv7-HzE#DU%m$0e>?_O_Ec+gt(dn^ke6d0ahnKG{Sol3YiyidCu~>RK zmc(F4veGQU()?Au-riu2oAA+88_qQp_-7wG08MG)Xy3hLXcHDY;CO zmB*B-ge<>_$26JZ*$ihK%kPXs1hSb75u4$MKPj6*l5iNb1U6Ho;4-BOPL^NG%kt{@ zSu|tb&(GmA{W>w5fl~nuDxO&>!Jt8oVupmW&Mjh!U1qDRo#W3E5(^Ua96Q*tiUVKkECkTG<+wzj zI5Cdt36QW74k8erpunk)yT(V zjKlJ1q$&;zB!m`XYv!<-ERI~HoJzKkRn zv$%;ui!PIsEo95sCbLGa3?x}p)OZ$?D3OZ|LXIg*ueAD2h|9usHJ4}6TlHKek>*aw z_6JNZL?8|$$uNgZHAyaymWR*K5`N@9A`rv2 z36qj+WQ*GF%FsE~6r67I z>B1z??rcUqa?Q@f*|bGHJi293p$>e?y#q0{A9k5fT4o+Z?bV^8izpa;~xV#zzFo2?Y8C`@d+f@aJFMrLzxSr&V`E!k@JkkT_m9)Zh? z_BKAFNnSKT^MajUVfMJ`NqkZwCQjj}vdQE)kyaJ3$&=)AiGV1~RyyLPJS$?MO=~X2 zs(f=jPBK4TYc)G%CV`SGq9)Okw4@{q56I?|)roOpF;1Oi(OD3If$!rd)l&@^M^b_a z%O^_AR#KKq4(zg8LBB-S;1dc%gb4IlWkfMY={0JZ8k{Fyl`O-mU9^CR&*LRClEtcI zDOT;FSwsd=yq_!6^QAbw+(oB}y_zIa;b5BNh(NYduS->U_70oH;f0j7(XwC6i7fDhT{^t24`&jtGoP6e{I%jl*NhE*hNlc)35`B#HNC zstx1-$0Z{96o*^X` z?te5|st}VD=i=I>Bx9rlsnbVOs1kLBduAKK6~J4QM0ze) zLCdyT8F)n;E0AR>7&;U)s>$eJAp+A408%nJB?1+&>LR|E_$5fvjOV3M`*ezD!; z(5ubT;`aG*1f$CDKrzH8V-gax`H5bW!IBX0c?*eT;^T}eX}Slm#qg4({6vr4U`Zyc z@I^ueE{#kf1rewVNJxAmSx;l~0#ZGW8USjOHUCdrEkEZi=G>Rm(zF@ejYC31C6i8zxl%pWI|5~JPb#%4;5pv%$` zL>Re}tiz$EA_5EdxuC)?WV#bF;+*byrP@l+lCr3DWLV;<>`G~d%kQAdy=*!&AYmjW z^Y~)7PJjt`I9RF3fZnHgvdruNC0#^vX8PF#3f5>fGeioJQ)#v0C52jQk-3AC;AJP_ z6$G~=D_}Q@Gt2?>E}#HTEQ$@ADZzTd(4ix6F!IFWqedtSB}Jyx{!lCyV~Gx|pJ~;( z9obry&YEcDX@l(zIBle6W2pjl0$*&FSZ#(RpCZ&25e)NEBtKcoaHdcwj5LM;{0Opu z+bH${hm)j;z`SvYO(c0VnN+2OM2_Q&(}D7Y0zFfnUL8ZOVe3e4PZl9DfTi*|hIlQQ zud@ZRH~}J1A(j=u1nAIn$r^#aReei*-Ffo(7{-$q%o2$Sw0yi3nRpOOeBlL z#71eQC_N@s{zP6A&c*P|AuE3iV~u1QVLRtfYJak|-(&gCfC zL@G#0mR4<2X8MK2!sHIfd2v#uUTQRE(ilcF)5YWl@0Ya-xtNrmjAgJCSOzzsauB_2 zc7{|T2#69@9FAV9v*UfLLX!@+-XHHb%ZyA}avVEbn-xeVaS#{~myt7_~Tui)CYRC$Zcm%7(CSip-G!Ht^3$RMNOv0gJ z<1^nIOpy z*kxWHP9{yH<;A$rm{Bk!ZnHsZNn&P_Z5W}^8Bi)@ssPsJ08OICtWNPyRRofMLc2Of&a6BUYpLK4tn1$wj1&lStWZUfq=PzxyuVi%tkpP?`b zmCOW{%4SJt#S;kdcK@^CrV8aV3RCrl~TpTjjT2fXcWhN>iK$m;1DvTsU!WU*) z{WcyB5$F>L#B6*3@6KLlc@-9F(#YGq-7^#?0i#l7MCT*WPlEs zmm#2W2?42vC$uLrpwDh2UnmN-MqoEO72()T6q4JXXj2;;a=FyVC-BWSrAzEp;nGE> z?0maRI+Nn@>Uc3tj%5o;^mH2HGR?+I6scvtc%gupuC3SvT{l|W#WIArE$YLPRyO|0<;u$p8eMy2Jmgy<7afk>+4$Gfa1V!BEs zVNm%(i#ACmNRqQO5~_w{z-p;9JBue|CaIK#26`i(37!I(Sw^Fej$v4Zj5zf6)`AO2 zsR0p}ZxUx)*Iq1!a4~=tRLJG(vWLCCS7a9#$nJ0L13l?CRi*#oM0uB zt)v8zi^Onym@EfDsWi|gTeSTS~7Uq-uvol0so}d4Ww?sBXpc{)-=f5>U zUx^fbX%d4)Uj-F@MTC|XeshGr5G(Oj6MU%#-hxJpk+g+sO&Y^W$-K78YbmYRzbnu|b>5@t9ozF3J9c;XF7M2hl-=D}3J>H?xd zNK0(sHK$l(HX(EvH}`M$=Lzj31*E5zy;ph|By~)u-TmclF880 z!lvXoSEBhL-{gJ`7~Rmd7=`^n>?F#h)y%SvRI6EBF>^igc>^Q`uf>QD$iE4qU<|~3P zWMk2n&_O1oq$tzBK(rLlV)VM`;EPoac%o?0Y2cCzEO;*;gUzqX*AMA^7N5;f0`P@9 zj>5o$r5e#TjRP#1$coe(jG7FaFCvzWo-i`OVj0i(d@3v%v8<>O5JZtES_YQeSfC3m zo5t&nb$OglV>IGTiS-2>L+ja2T?SkQAz;U5WLWgkIE{`%AyH_NG&-IbN!OC7kyo+L^4T_r-kGe;4L5*I28>RF6lFL22XH_1X%JEZnJ1T8c!e`td4-I846JaxlyDG ztgu01iI#%(J7DP$HgD}v;V|c=?0@(q->v_!;DX}*tE3JPldg*%629*cq(-)>|~C2$aCv zQD1Nsx5Q!qvo(j&36_HwTzX1}%D{^6(4tAWWSo=b#Ch6|kY@xz zDOiS_B@ocaL6{3bo{Hro%Ur`LA@E5AY!X~98&1iO0j*oI%jS;7nhD09@eyi5w4K>I zAwGc_*O^08r?m0)vh--vE{TykpoHdySORTM!3rFDLzY30Wg9XrI)jYI3@4Du;dtcJ zgH-4(BttF>rO0>952g%>Kr3W!YCE$-RAW5_4YA4HMKX%K zho!g5#2|K0jpDPDxlyuqHbH#P2$vAUk#uU0tD#M$XwvQA@pzXu-8&{o)dp#ARhO>a zQ+u$Yn3!Hln~APBv%5rCSSj7QbSL(4O7JOdyz!Sxdb;{IKwynJ=UeznAhdx&1 zs6lBjB{)?^v5ecU9VS5>gGrSsg?1KB5R-0;k8&nkyy|Xpl`;iOZ5z{pNcHG!(m1z4 zXlUD2$)(CnT6~Q}aS}Jq80%oGNeK!sPTt0=;l=WJaY~!Ci?j!c9L*ARAPGCB5z=D} zKB0h>PBl;+5|Orh0tLLFOW?=UkR(t&y#!JGj1C5zz5^#Fs$*v(N9MuWFkO zchOkLF&P>0$x&1jHnv@IoJXf};T)J`Tbe`JC81LdTS_~M*nv@}iQTwVFV*Z#?US60 zcc^I{=p;?Ak`e~?Gr{-^kX|wzPeOVc_#~s#x4$d3sno4fY$bZR@N)RhX!i_0Xu&GI z;K2^Kb%dn({SCs3W?!Pk;0LMawU`|F$yPvFaM^ya-wa-LD!zc9fQtfpL*KrD{@?HP zSYf}Im%*?L4SK*3$it2B5h0c-!iwS2a2uAz2#23`BuIia2@(+)bL5P0pC`kBm5Vf9 zD z2o&&96CknZ(lk09oLQvlETEMd(zG`4NmLq%=E{olW||-^q6OdpKdXoautwp)hb%M@ zAMkw#tkyU(!6PB?kQY=^h%_Q7V?sp0iVHCIMgvUYtONWHD)<&KzL#1Xde8%gcb&oO zMTQJ-bU1u;8XkN!8je2t3)U8BpjF|!97|d%diB1-9L2`+;};e_2@bU1icM+*m!=73H-i9!yi zk}2T?*!qDLbP@%`5S}8Jh*^LPRzc%{KJX0F;Bf$eLpo7M|8ojB4t-j%WgGMbm5>oH zpbsGos33jdbUeXh0U$(!SmI$UL6d;F#`9S8`KbmXObbVL2-HykQ@G*rbOMe}0DV;1 zO2B7-V53s-WE!3XCRS0jAC;i^zkcv)+RPYS$Ar*@SsaPy1i3K*ehcsL+tmSek6v)lx!g?+j`UO|uG9!i3C zha^Lf;5qag9w8O<3F?GYsD02gcn&3@esRGDErM7=y0G@}h$4+*iDHFv!W!rY+@rRm zwxQag7q(1^hrNCo{1MHoc|<%Ryia(D&3L*ozksO7K( zUO_78AKar+gjoRn3u#7kB$NZta%c@Kh5m&sgJP2yb=s@YP2I_))h&eo>)dZmK>wgEunhVavJ0NUb5t*i8?+o+fqD-0!5?ZDJVL6Fbd(>h zho#Uv$c?s4=pPzS)N8m$X`qK_{zAV(Xh6wf?I9QR4f+K4upY$;l?F>;MnD?qQ7Ajm zh`}pVC!~TAgL_B?J%W1_Yt$l0laD0SosUMyR!9lAkY0F>#)!qj<6#?vV+kCm(K9@< z5eP^HF8@eCHaKU1TmF%RY+>!mWV9y#NJcg)6)n#{Qjv`o9LL}h)lCa-3z5yrK|8ej(n*okn`gZhdcQQeTL zG>T9;mrVw~71mU$?ozESAOW;v#5y*a6f8whDTqN(cOkR@Epm-;msk^`C~%|$>j^v*!oJ8gy=4@1|SJ-0nQfpw-n1uri9s2EK{J=B7T?5jdG%PKyUIQo9B04$&X?W z>|g>3h_|TjA8{0^rv>pq=ZeL$AcV?yk8C{X9RS6@;|Bf%Zt%Hg$d90fB}OnrQ}CFF z8t?_r4%L)ZNkkpns-0o4so&x$Or^&2x9XOvL&AbSW`d_$d*#`u&AaY*TAo^ z_INlBmFgMfD7_wLY90lO(RZi|&>~U`afkG<5qrvzKhW%vGCt}8@aB6lH*U_W0XI%RAn zp=`|WsgWE*xbw3O!J+`N-@iu2F%+-w=1j0Jfw&f=Lv$A^3HIG(>YV^;Xq*a52`6zk}lnl=u%ZFJePbH)>34FYcwV8pgT5E$L}vqq%Zf<<4tEhs7%dPF zh+tmc1uZX70?{Z)@x5zQcQBXB%oUOz7bO&(;5<-~#$8rte z4lPIStAjDf(^1-WUc7%uiAeb0#2m#k^pxU<8C)b{WoTDO^A>m=#N{6z0ctW#wl*G!{_8?@O_PgVk&{|dFdxB%`FWR@k?kncaF8}$#` zQ9^4dDaRpQFk=6Jqo5?{_rGh~|3WvMHNgl5k^cV$=6TkHtSZZ~)OZK|%WqF5wI&#` z?^ArQ9&-Pvg_d6bAJAPWhGju3)QU<)txP>5;Qqg8p{RGjqW{lYNs;yl{Vr_HKe>kS zF4ms}eavr(r6K!&gn5ba|JS+^@1WlhwSU*nLfoadqkQQhE%`^t{UgrO>&v3M^pOy7 z|L?Vu(0ry84gW#i=z`$lGj?PpD7-==fdT!8?G`a~Zj_2;ueJW2hAZB;Z>aXld|nE>!bRkHB)Yheq}0 z_h@B8;XC)CYy!lylnh79%XmkXe+OG2SN`dnT=1+E+5&%wr>O3r?}g+-s_&Kqd&+2e z@f-s8%LFjf1UkxuZ%K53JBUc3$d$2=hTKHtt^B{`F8sW%Bnu&eMan@7BZ7Z7sYq#2 zs*i=h_3H)gd_(2M*S((IzXN0Cy-uGfOSQYD}0T3TOw*jF%Q1QERG`7T?kh;F>mcaLBtBtpa|#t zUD&Fkx)FpBsrfmJ&=j*g_@=)&LWS@FchW>4Dac(~Hs+Os-aE8=|SCvv$X(nL2EW&yfVbhC*;&k9C2D;VvBABGHFPm-K_!!HDI{f+c0RhItEZ zLudD8MyV(^d8qv>2_>M$CL;Y%(1X(Q2q{Oo%R&jPE+#1twPH1eB(h1N?|Ta6#DCoH zynd&YUI+aK0*P#%bM^&m7ISHGEO?amy=_vfq1lt@9}A(RBTh zaXWTbn{;n`Zlwz3h4wWoa&V2W9$TCFWl`z^bJ~KQ>zxy#o^IZo`L@=Z=IIC0pcSFifr+BTuzySIs^O=lZ--=2Q4mLl-Z+;(BRx@V(hi_F8{lEe{o zg?(-K^NY14>CZpq#=joH#n-@=g()IDA@SiL*d=(p2o|D;kPNhew*IW0#bocBN;fvZ=Zndi(zi+_Fz2xU@pRduS zjS|oz+$VYqa;%>ljUn&T&i`eZ$h~b`txu*euUc0+ojm(6amnlmepOPudSW$m3um>c zg;_1_V+12U{N9;g?a#0Wy?QCi?Kz*Tom1gLdBIPc+r2tmo3i8Nl-J(|L_d~>m+!l| z#pdnDuDorsdJyAtO6|V6bIXtMnI{eEv2IGcwYze=c3Y52lDr>%lscI@+1c^$xxG>c zcHcIuUyskH?>~JYG{)9DP=4g8ds}`I9BtFG7G1LJ%&g3ljHT^ce_k73b3v!E%JbB- zD<91KeZ$^y7IT0R))Jq+e%uERpImcnrzhqQ_UpKJ^0;fAmz{k(q5bWtorgc2HLUyD zWi8$HJwZH8cVO0)%$E1*QH0b#IJuc^h8?~@?iKUf z`(`mY(rT3+S#N%cOeG2&rW=DczfVjM=lZmpsU*S@x5 za=AZ;HTiw#XoK?j?@aKohORW6za^}2{(R0u&ZBaR%@}RYM%C4%dV8+l?L1<0+ljUP z`|C?rJZmz4$<7(au_s4hUsr&Su zS*~$?`{x&Xw=T-)TE~`fc~xCXubI!9{nSvp_!pdf*TY+*P0n-m&5}d!8ZXtPr!7vH zC;jxGPxbw$%I)1^-RJz2mAScYOc-y<=$u}uvr~8W8$Edfn?LrJ`~B%YgfmZ7s;thygn~wEN8g+<7o4@baxw^AjVDI1?ocn3v0WSTC{AJ@VQ`n;$Uo+f^tcZ=D({{p{ z-0PB5>gfnWpQlR8V2_gz;7*ciNDRg zabZB0A%9nW{h~svI@yDN%aYi-p1Pi~YR<;dze(rSTe+0n#olFYA4RnMPS+(3nsnZ~ zoHnoXszAkc8*Z-3UVUScUd-JyNO4wT6oxeyY-S8{xKPFSajz6us2i zt;zAawhJwrWZX_y`tS2|*EAnyza+Z;aqRZ_Gh-c!H_hAc9CPPE(yM!MO}6*E(zEa5 z(bKCuJ@CrCW8s{~Nte`>)-CGTaATDty*?#=`gvW2ugn@LLk}2+bs75W&F;DioA;ET zwWsoiwQKgw>m^v(F{$S!cJ^N@330tGm8T|ppZ0rk?@Oft(+?fpX})z=DEic<>F}_~ zb7R@FKC39ThB<1T!p-}1Bcv&;DH*3aGA<@D3JdN+0nny&I!{PmAP%eU7Z zscE}#agO*cX2PBY*GEJU20S9Q-qA`neiNnr&h~rjG~r&%JZACzgwObr-AmnP@*$S^ zaNl;(mj^$+@7(+F!+m>ubhx$e^sTgk8DC99b7svO-u0*co!Sn{ z9<_4A)_46@Paihex$*so$oflPEfamtF3NHo)NR#gS6KPt z;7=dsg-cu47``~B^Ul7Ly06+c>@I;-`*Zf!Zoi)&SmF7qqYVd7zdU*1@tkKprk?xK zA@lbtW0szMex_Z^g^^Kx-PKYzHat6{!*ZAAk1VIZ_0m1WLAS3y7&JV*cjbz8pDn3A z);auZ#o1e{erf;f?J=(huzx#9{O#cJC2uB<8QzqBF>RRJ&tCYc`l~thdnLB4JMZCk zPt3fW#?zSdFtOk6UwyK#N)5^DdiTqXoG>c-k48krrQOTgea&gYs(Z?_ZOr)5x95DA zzHgfKru@^(5v@*h_9%Kaed698e-}IE{xZemXN#7^rLK&1HHyn(H0!8+wQlb70}t+G z$KPkDTbUMQbe%n}_0Fih)5rflwKZ$%;f{@4zjpk!*YK0KQNO3Vva((CDsSjm&#d3^ zuHDhKKaF10ukWb?nfkVSrk|)l?_K5Mr$xiv+Z5GfNn`%Xq&7d&)UeESeB+xH508v{ zJox?O-wfppqgwCluy%V2Z?UxJ?1->0b#@;=(EHt)s9I*`pRUK-R<(ZL?a$YvcUL=C zK5Y8RiId*k^CulPE)8#QO~4M15Z-UPwC)ktsLykZV^7ceFu&2*yKO3C+HP;Tet>_7 z=cZ<@WAlpH=_$QNJidLu-O`zuQ}N18{#t^)lWgwmue*2C{V_LlOWRq$J^RExd1hdT z%sByT%&z#Q2WPAqX^L!euF%J!5FSC3?j>398bHaBh^Zer(wR%6FDgt)29n+DSc z@4?5F8|>>ax_-SXaf74-rdCKl&0EK*aIIPbJ#}&9lbt!X6W*K!H#1rspSese=`p#= zl8=dRntp!0X8n*b-+oQooHk=8@avyqj=I~f-lNZJWaP2U)-+u*&vWz2RU!TKmjiWI zSH+iq;<;2mduD^j5B0YjT<^L8)l@B83RZdo>fKjB?`Wf$=44-gpQgVkCHwVrdvu~$r z)i_PpyBkG6cgvE_YdvwoAyc`Xiajge?fUcXx%t`NPQ#Xbo;Q5#-)DQw#mUEC zw;x#kFJ5<(J7vP&3YjT=_3|6e)APQ37C%aSWAfKYm(;YidA3Kk^p#mP`_kC1Ta0N= z&ae^J!nv`Nk3J;bj@r=-&wI78XQtEsNPK0-#p~_*&YrN@uH3utl{9zjtNo)I_U*PK z_gp7){YH^%yF}Uhd+rOSp4>Mp>i(zRJzL;w_RHk7o6USAv~JrmvHNd6j;tZ!^Rt>+ z$$Y}n0eI1e%@i+jNAn$he{GSr)qeGDhOp|S&KNbwAawdBJm^aw7o5!r6?N57g z_{^pY=P+G7fyrKQBW8`8S8rTDame`B?Llv9t{f#=kRoZ= z?@O%Q6nOgh%!K+?#*G-&$?llqXu;Ez`>fleyWp9wUpb*}%|(N5Eb7zN1->5dKiqb8Zk|}}=*+Eu z{rYIlrSl_tulq8wb@rJ<1k3S5yCTM%U$D@!dgZKuqviJT?+#0UzYv}6&dPeXtm29B z{ktgXr&ldFqFVLmR8e}JoMn@${5;XE+#6Ym+2Uh=;|2eu2Flac7UO8o-sav9I5X!T z^X`zU<+pp>sBGGz44*mr|F4f5CVbj7 zp#3)i>t^JB9o)OK+yy}DguCix9)vDNiooF+yIXwRtZ#CHaQ+f>E z*RVq4)3;Oh#-4qAumLXNfMes7j`Js!@1Z|7+e52(a{j_gulKxOa^mqp)5wc`2GHw` zv|QVFYo`0++1)?CoxWnt?bIeGo~?UB+iy_mRvwc|j!f(=N&h9xlD%PjwnCF|<-+p% z&EHhJcH@z4O!wb@t=)6+><6`TtaU!INl6OX->rH$hZ*H3`K?;mZ{M!itX;)Zx?@c^ znNJ95t^uYbjV^{P@;zt<;Owtx2g zz>Q7m#y`s^FMa9eGW%dGpPFUkmh0;^+p*;xuIrBDM!wS1;9-*%%ld6=f9ve(V{6j; zi(gz>`8JENZ^X}cadV@7iE(zjfb(4KGi2F-#?m2OHji&LWiibZIn1lZSA5a4<$)o_ ztE)FXn@g_z3E%tJ7uDJ%`3B|0rY9C0cz&8RO*?tLd|^ji5e+TXfGagzme&D9@8&)px9 zJGQ%hTiZ=nuCA81xLl#b#JD-Vt3L6jTx!zi+yK|j_qC{=WZtyd`-eY>TOYsiMB;+D zR;0Do155sB&Zujj?cV!-(6YzX`mwhV9gU+0^y<8n@v_g`slj1qgJu<)R<^ZPnZf^48;;yr z@%e$Ome#TOFRoK7@q6!|a!twH@_u;r;Ww#t-)DQJq#pCCUvRcIMXk<~R_t15*06Th zS}wa`)_WHHozQMl)s$foc(U>ZX<062;_?f7cC;8`m~X%EXU?B1D#=^Ff6q#|Tx;s( z`&9kcpQ|OzXuJ6MjcXm=n(!~oQn`Zn-l z!&RiDoLlazL%9Q*w7alqYW>&hQIG6L7VWOTl}P&#ur8^vWs|FFhwAq|nTxul4(_>h z-Jh51PToCloTk%>QAfvajXNE7`rMj~RgE%?C*BF~jtH+aGUdqWnTm?I6PcYxXI7Ur z8lU2eU#HUzOdb7q-M=S!o&^5lPJZMc{phu|-rtK=@2xZLct5?19bm0f``9C+yq9vH z>W#7c^0PBXcFLirFIw0BijZJdjOcav=8#@XcUty0KA(E_QisD4ch{t!O*nY)ZS(DE z=lmD0)HIRIx#i>TByYMlz2$0oxBX{lvzAw=tKK=}_c`qtvop_8c3oe^j@#09an<9P zP1yKqbM}6UuKxyGJ$*-&B~52`UKP>!-Kz8B$e(2=IL$VXRZsCOKTS}L-CA?U*kjfI z8pB9hA{^}Ax}iP3&wfJxwd?ELy?=he)jFL|E$oY%JJ;W2nQs2oKk*9{S$}M4-lo~S zcP|&>uHE=~N}XLe?2=ij@vNNpZJk{{E=)hPZ!`B^i<#u7>T30B)k$VljIYq+{HjTt zq9*Zv!QP)CG>p_~%D>xtc$>V!@L>Y*&n>D=)-%N9eoEEYMz^(kUq(mG_)xY>B~5J$Gz*?#kGK4Sk0ns+TKQ zF$HIYpQKV&?jOzW`=bUwJ%j&w5f3|y&!|Ol3%WsR4%5!cfZy!~q zQ`|xF-my=shm}(_c>HdA%v88SSvhQXazpIi+o!7ZNVMY?#P`OTGW$C;4J%8Any%hW=E>_1 zP)p^aiU)gvzcrp+zxTG>sY7|ATGlYN9w<66VD{?wRdb`7Mx?g?`aFXEZjQF+i<)<= zHz+?pJ6r2L1)7WW)KJW+jd?9=qv90}-9rwZX<-Y!CTdw?MRBpv+ z=AVRZz8d|F4`iR0L~SFs=>JN7^w&ntCE}LdclNE+_TIbbK5+wno-C)-Trh8%tZwZW zCk~(Jp3~*TnEXjGoc!{}zTsQzOUJFvAOGdUA}d7L?6;j;a)9}eP2ubR?XG%e7)^YMP!^WL|9I`zx&q5F@-tynf_ zUF)HJIRRRq8WkB&t39#(+5Y~?!-Nv7!scP5%c5`d|8F#e!Q|}6Pv$Dmv z#CCs8<_vwc(|)u1Y5d13qPI;%HNT|9<8C-of1h<{d!+nLE_Xk*PB!VBEZJ*yti7;l z&$~LSYDgB9EB94&;?Eiid8u>|<$DwTZsNkO_%Ofr?v5Ijr(1jPWZwC8r=0s{IW@_9 z(_2#{j>tVUKfGS_(ry`DNsap1&3UMzNzLw?Ws%C>(IDgK6F_4b@_+>i+>G!*!iubC(GK;O>m6k@*gi>-#KML7tWD2OMYkW z?K#|ST)gwV+1$VX6-qsK?do%)+CoLyDDQ8n} zp2jr16h1qnJ8W7%rQFz?ix^(na$D5U0jei&Dh;io=(O%o^3-GRu3q}xQgrh{4kpvTZ>@`lIglRsA_UZ{@w+qQd1^5OJVb5dWN{+!Zg^?T|D@k5_^L(_Fz zFYithcT@LGIn_aW+*h}AM(Vx(Z@O&ZFEN_09}pzDK1Am%&VEpJ$(Gyu`-N$5zj+`? z-QN3f*K_6=68+h)w!4W>9EO+I`Kx0-B#UdWKSz6J7rj1r(H5V&q|tazOVuTE*1iF$ z@Bbil?H%phc{6A6$|DQM4f|^7y}w^e>^9+wH46o4E5;9f@O;h7KODctu|6zTMz7uI zH;r#|f7jrbF@}i63HM|8x0f7X68cZQnPn4>(}|y7es=F(&d{ljY}=ZVlb*J^?x-|i z%$H^}uJ0V(XGufKiI3~gP0!t#dZ_OS&emfrY@+(arH65=H|{q+Z?p5rhDy)gwZo_J zgz@-4x?i8;yQNyZTP#2N_*}nm!>*}IPAT3QrJnbvvggixOB*xESmk5bq6Vvt!%pH7 z`o47y%bEA~@`DpwXH}p4d&gBx`}zjAyMDj=_DK`=KHTwQFR$FU4nKWkV(PR`Sa6~J z99Of;(;2_+f4ozL@voV^VeXQ1<2T+6V=i9LdR4o2@7Ko?Q!@9a8@Gz~sr&JMCT|!x znA~)Aw?Us~ZGY8b-F` z!Nvs{)oL1sUe0b_`Qpo(wi(z?;NKe23>|h|T#?lK^ro;gzZ`$CmD%t}`c=Za{-^Ht z`F3Di|5(-`fBg$>H932CSsGQoxXhj5-+JYkszojTaD0_6V_!|XR=K_H=@(`38#ILkio}{n5#D`RgRK@xFL`YKK!<@3Gzg>~rN#~wa3;6Snl=j0}4-+b~uqN=Tx@uJfa_2R;=Uv64bJ*}qz%cKWDJV#Ilp|8eURnJkPpW`m-`@l=h=60L(kr=BHtRzpThS_eU)8a z#$L4Tyzt>_&&RrdJsW)d#?ihX#!=ord+=#tkHsqg(#r`E*8E=cT>fF=n6EoPGyl z--BEJYkm5DjUGI1bpPI~`@3HKp}ki%`vJ9WwR>B(=pRo%b#DCN^N0S>v~fBj`(<45 zPx?A;_q(rYrfIalKHYe^`DNc$W4J^1?4&>3QD@GfhgC)%ON&0;Uec)bn3snSjqZ!T_G$EhKXSfAZ9I@G97(w))LrG? zI>sBde?|wD<3amoJ@8|Xzl+{KlON5g z`sm(-2g~2ad^maF#K%*8ufH)>czUUP%76hcjUT=}InR$~esla@r}gRWk$a<74C2?4 zG|fF!)zJzk2SLyVG52alKg|Bi$2-upm3+UN1_uhxBdk!F~-Vy-#kdE?=N`B;39w^tf_ zb5F-mCjLG1$e4zIU}G|I9j=i&-0Hf9cT+udOzQKF=iN^_uIf`$e#G;&;p^N(Rr+Jb zH~rFM$JA}#hQGDi-_6{!ByeQ*+{P1c9v#|h<*oO%h0U8Eeb{ctv*|bQ{B7E$-f=E* z;bZLY<8RlkP_K9OO}`}C0yUSsmv(B<@cpO<`;|lY{=J77I2CUs)Zah7>-4zObB^5n z@?5voI&;O*dCL~09EeJ5KpVL?sb`nF9b0vqSgzr^hY{!M-$)r2chJ)~HTI8@$8pE6 z%o@1k&~)wqVb4Q54w<)TGKNesmj8X^^4z8gff)ztP-oX1@u^YR=-UHwdPsW9`&OOP zXUr4L^1J1qlwX^4t1CACUK{>|+f(X2oIj)Xw0Tq3mAmoB{o9+mwrx_g(V)?|3Oz4X z?KUiN`A}!{t_L&Z3tlv?u&FC{&(2P##$I&({AbU|oz*G+C70%&tsAkJz9){8lh&`? z*P36=C*RaYPeW8mCW^ z%1J*vDz!&@)?KU=HE7j)-{5nxPt*B+wO#dFp-z_BVv@-Ey`) zK~RzV)N*2M4=Hs3+3?5k`=EV_zFmxO6@~1fw$+V1^v-Gb^Zz@ZOH^i^bk7S2u! z^?-B9jKrIH`5DBaiD-L6llP)5x_gi;HO0s2krPw8LEFu7Y;k2 zMgQTLu6_Ywq{}U~?1Ub2>PZI=r2ZDcNl|^NM*{qqEfg)>aW1cg=&>(#B7rSF5dDSV z?^2~Z-SahIL$)C` zMzf`c=XpA_=cn7QS-7AhsnIQ321JjyFq75mrHZGeyDx7LDB_+drPTTM*E(1jf{XcV ztW>eb4>v;hPsVN)L1f2J(7nuf`;Mg@;SMTdNZh9t(*ls9;>>VA- zrlBd0pdWtI@DxYFH*d7iX2@R3pO*b=vhdIz9SFUB>%sMvUfBNII~$BH=zZ<<&ALoF zCQcposzx&cS*d2efaO6o0aHL?L9OvSAd0XN7F(|^_|Y2&ic+iTknx*(gwFN`8#n3j zgRes*X(l*jG*DtnLE*XakXllC=zO)A)^scn*NK8ymTErV z9VsR&MjzT4w?U!(U11eg{;mX;2P|fK_xq51bpMH@0O}NcD&w*R?8QNUeYa1~yfE&! z`k<86Dfz@Ia{kv|e88cYuTlS41+#aIT^EeT>SQUGaO31F$>0U?jbh2D8=DsA`48)-yDzGpM)G9jhLF z?~Bw!&E|vWHioyS5)^2&!*AD5(p;e1Zf}QOslF1^zItRki3iu;_}PN+e!OYl`5#?I zJYE@+(A!^`^SD%Uzb-M_X5n1cgKLwBck}x1hr`f!^NOXc?>}BBOF+3kqE@uKBne{t z-(|Z5aeSqUkhcoN_32(@g5(=on2^Xqzbq@Ee7R)+?D^ zzRNc`nh|2;Zda0rHic8ZO@(~XQ(}PBKFzsg$sQkvfj?(y>U?MOw@}v#bBxfvgPPIv zdyB$XmpV7-Y|9?Q9y?#-c)}(3r|&5*ZUXNSyfdBS39nHEaD1mi%iy{OWT13A5dw?vlmR-J z?dPtNF<(#mJ$sr-_g2$B(5qOHHlY}Yz%8J9H}-a8(i1~qmj_v8o%%`_-1H0C|w5-!B@UD)eEvcyv=3B5!y}a7B|DEtWJqi5O3E9Urc$1+j;q;Ig@I&RA-~| zz1J!!4HbWbpr*13^z;R*s4f2X98w23tT}&B4kdn$EYX0t{~*L<*nrL;NbIp$W~gZe zXPs=TVuaNdyX8f=FR<}sM_D`=aeu8#;h!eql@^1bg5iUFtsQkLqg*KC9|j?9k`%aQ z=cI9dUxX%Pw9H@lQSo{vSmHjNTjy`!cVcQZ8MQ2ao?9PnTr6_OcUuffL4Cd2d*$c! z?Jov!jkM_S*HW&RU`qSkFvz5lgk|4eEatW*d@WpDV6f@Me<{(lY1H)qu@_5b@9|}# z7?cD(<8`%)*C~Ej#=>!^_d_On-nIflIr-KZt${p0&esaY+o0v{t~9Gy+hG!6+>V%+ zC(>Y5IV``?u5S(;UeQaR8e@|*R}OlVrt(!en@cdtGkhQ z;xfmg_pM}IYf7eT>zV zU8u`OSQ0jK8;x$A7JRLNRvn8+>**pym%cOB^W~`3f*o93IYai+RPoV5jRyF;p#YJD zNkk?llEo*IM3IOTIF%)5(}E>Z;g`$N$9yTv8+=KuR~QYF*^QK|bc`1x?=^>UGv`Fr zuUuEi^sB?uJ;NoIX>ovkN>2py{z(czmVKa8VGOGwuY6A)HD^GN6M-u=d3C}S&%-;P z(&@ zD94E2PI5UuQQ{pvvL}UN6?G)TwXaAwc>^cNdC^9Ad4`S2KKb!ptAofs>9atS1P_v7 zqDD(NHXFA74{g!)djIE-+dI;SC7_fjVg||A9UBuxb!Mz~riB~g4Zgp8e7H7JnIx1b zMfSTnZacxYR7{*{ zR3g3q=H=Np94vKJm_qJd%!>ED{g)T(H6}&&vZav0P_!8k;q9HIYdghQ5{I?IhOO|Z zi{eDb!yJe3qmSaw7cyL_?|?;3H+#S^hu2AdNa^3$2td#t%kpe**>hv3)+{Ix0yf~0 zi%{JBopFW$#De3&Ts$7ZSvos3$xQ(ZiNyH^ok(37%d%W6tll7y39a5Nw|>hdET-_(n+_<$g!EJzv#)<;M|Xo~Sb z`Rv>;Pu)-sMy7g%7B@h7!6C|;KM;{)$5tNLm6E{oFbCKZr9hk-CACBi&EF(pRgw_4 z5^$mTdVHd@DEvibZk!ewo2APU^&2k^=?)%<(7nj@GD@#J_$7(%@0*yDh9U$b0G?e(>ebjeM={)zs5p?W2xoNzV6DMaohvM&k?D9zf#b7!Ya3HR{9K zzuAz5^q05eOBZiKH`BX#R|1OFhjDib7gfEwbaKG(>(|@ z@hiC?Y0WYf4ILHd6i{>^Sn#f1@WD!C@b}^IYsCp4xh?aXmS-_w<8j zSiQXTxpiv9ERmeCxOqKp|D&aAtQ!B?N}_YPozGuZ!DDwZf3a}GtaZ|figL)Nj5CAp z(Q#Ooyl(NZGK=p@xzlrwlJ;pc=2>@9f?OloYa9K9#w@VD8@%08TX^2uW&;UaFpza zS4En@iKedy9|f zcB%!7fN-mw_&#m!RvVECZ70_^r1GTYO7(QfOb6waj$Y_h`HI%AeH5uena84Obw(K> z;D2LmrG>J7^+V4HN)lbvaTJdfL>54fS9V^o8|#}tvRGrrtWqm|zk-aLxDFEtg8_qP z^>9B5p~sdS+^wrUkko(WoxJ}G1`agbhXY0zMi1CFtbG-Xpz3+eNnDG8Hy(OK1OPiT ztMf+{fUE^{@3NR2Asx}PtVpU9;E96+z)cwSvsu%fmRslNioEs9eAWcrbwBE%$j^r| z(n>rzv#D~(1U+r%N~lPdqDVd6Tgc&O`$GBKksNIb_Yni|`^G76#fF0)ZX)S}DeDkv z;cx&EspG42c{~Ylj!+^}OTKDgtJ}q0Z{;|2HffydZ=$B&dSrOC+6e)_+g{JHKmOq? zC%wpP*~IFqrqRMjj7Ia93T zU`PIt`pJPC>(Gu=X@jdE?it~Niz5)SjDAV5+0&-s`FAYv<$^-mEs!nTH591dm-qp6 z*RfOB7xx<`nBv@uy0-=&fF*ain8VZl6lZqp1z1-_B$Dk%FsY93VpCZr$s3vrKOx)z zgp=t>sBOl5ND*E&_{mzvoh>>jm2VfN;)9}6< zcF9rHeuBA3>^fL`^!6zla#{nmx}>JKBSmm?O5qvdds%ufhkJ9^(;e@e_Bc}^19$|) zt$V&US!Kp3Ez+8MQJ|&$%m_&o6Qp(3IS)P_=nzq~p=4FPtH0fqA0QaO7}6x}|BD0t zpZMhe0yO`BHw*nkdHx?jbn%EPwM)$nNfe(zo?roSf&>!(mIWYMgdhS`c?x&RG&vsC zjXD-mWHU10H#0se=j+Q2uj>?@#awh)L_UkRr<9Aw5_?DG*{4X?og0djq>%(sV+l`O+~`7n%m_wQ(2;>Cr9?Z#?2{&yXNMZkP%Z}L z({U-4Z=u!5RY`RQ`84rys+Fyps^ihDKFOZ9X0-|G=9F(4J!`Pc7j6y3=H27=EJ>r( zHFdy)jrSw&M1`&kwVBNFw7v-hbxtNs$ZYFINs;R+Z854tqjhMWq1I-yYD(seecL0itS~E6O0HW`80oSk`sZ* z$^N;qg^f${qf(bUoK8PjX--;Qf!^wLf0v5#j=0n2`?w7wfGYznE9SnyQDEwtGGA0h zy^S*y(SzWeYkOHhRYme;nt25ehjfbewhN~Nb8D0UbTR%RY(GsP z9N<9vMubWp03UGW8|R~&ksyjCI1=(mi`U~LLFWq0#!=IV*dZY(t8?c#eq ziW@1R#AvVznEtkm-fqOCfC}Fm3uy3Uz1=6wf7&+smISY zT{W4?M4z2_Hw!R$WlH#-nc>f#FVdf5VsFbuuZP|{1lTP}?Z6QWXO3Q{B+(zY{CX5F z;Vqvo6~I_EyJQQ_uXB$O3**k6ktAxLD8Em1(bR0I3+i)u%#JR$@f+q1PXcUN9QYIPkqk$s&}4D+^Z#7Udf6ZG9n1&xty-i`gmqu|pfSZh%iCCYPo z1hzTk_E2|BeI9cvJhK0-NIOxkl6q!Ol&VR|ByWi~__2`L@!oEd=@uxHOsg{RS4!L5 zen|f2V~3oq-M?~?>&Htky#!e#bsM-lvIwDn{^Irl=z<(JE&}}*Xxh{D<7UtQEttc;hoGnG0e(|6>niay2B+Q0 zKV__q>6Ti#hBTXV_CLl0Imw3%t)bSs}`JhcBXB4`c zS|S=F&$41oSC_Y{Bth%=H5>npUvQnNHogs!Z%#m)pkez!Ch5sQbnP5Sf&-pjS!GBU1RHABYf;gSWPI$} zctBB5Vl<>9JfP|bZc(wCr9d=m1n5z@gZ9^+EG?U|&4K45AC)$5iZupwOAA*dI-30uh^yKNw}=zvtgFPHTcj6WmmB1!VPE+H_%UP}f^hLr zR;f~`t83T&D4V9w*UYrYjrQK)?n~{eHnA~pOI0{%xzFAsWD4AHzYQD_(+?LsVh;I@*+F1Sa_hhW3 zy^tiggTe>W5|1Oy6%K+jx~Nr@-TiC#A&)AzObT+y(z;bbCYs$cUX$m){y(**= z@Oz*cInh_ddcY8AIgoZ8dIdZ7HsaM!4M^Um!Z;plANd;eazJAAP_#N^p()#72kucY z8-Vn(PnUg+UjSYdi$^*6eG`ZG+9O=BYT|eIES0&mdBIu9ODV!?!E%5(j^tL0kx3gD z$N&786u89@+D#S8-HfLc6`kY`gs625WjT?8Xy7AHLcG&Ad2*zW?B?kzd_WLq#>zfi zeni!sX?W49xVARA#O-WbB@=Jb=9?8Ya&;I={Xx*xk!Ebu=uxum)25&? zxiDM@6iZ1#VbU^@%&}Em+3*LlN1Zdei?^j@5Y}5W;Z=9oOWw->$b%py|(gK&P>fkmT(x=QBe4!ENQEFfvf_E+GAZSG6*SM-7q1c@J^IBV7 za|9AV(){;WARAEfC@ostzme!XTy{$Z--HVM{P=!A*_kF$;6B^cWyqp&_J@}Tz~7XcrlWZOqvhN))j=iJ*7G2h8oQL+P1@c+dRT#lF4$g(SQ_Z*nl@pii3; zPEHREJe<+p5xBI5a_^wP!0&kg`+V!mKUeKrA5J|>p7=P*n2p|rSo+6YfjNQ}aEz?@ ztkj*!28fJ8>)^HpJ>5!yO)B}*2o-xFtIJm{dqZ%u``)1(wTW^Ui%O4nvlM3bDTSlgXKB`s#E$aS{$ccpY1fj=Ew0RBc;36BG{-6ju(wTUf4#px6Cuf&Xpfk$#R@WP1(w!wr|zv{)G={(L96Ma33w#QJAS3u(hbDehPEG-)FA5 zwlLfFCKhN6^@LS$mq{{Um1|b0LHJCa|K3N5X~?jW^^S77B~&!u-2{|H|I8mKhq_}= zTWpjUMQE}+D>S5kXULdLNNH4I4wm!8Ey(4sRk~>R85C4Ld2h&h4!&GLu8T{$>G`1@ zRUuWuCx&)KJ>R;V5PeBUvp3&a=}FMxpD4U86Puye!o|>A$HF7*JT{;-?AiHqi=cN3 zldPPamO%91qaxh9UGa6V_7(eH9Qd^FH0;K^qb5KwMfl466BPBvLnp9i|A~U?e9*{t zQHTs+X_k%A#wbK&W6W@@I-Maq%(_H)oW{MqX8&@ooC$f zLS=`*E5^Dn?Opg81Y7DRw%zv|J}uPjY-^7(-iLGvsMs|}4BT;Ot%f?s_=0B(w{@zl!2D%T#&Mij>sf$2K!vMa zC*qz5EXuZA1wVu-qr@|qe!GL9jSyT&eHvj!G}r>V*X;yvw4(d8ZCcJ*g$c}FW}Jqc zP&vAfKtNa-ha)uJ(($EZ5^3mki}I}M*dqw7M|nU@%#!U$jjYS^N|JBa(E@0E#~X2~ z_*TAEY{$y7N@?|Nw@hat6dS@-%&-uJPf&bL&j;I|m|?5_uJ0&cxsO(FrEWH)y@{ea z;wBpg^=qaDSi&EOV}WAqv2rub1UeJ$?NNChB$XRxvpBfej|~EGuJyN2Pdg@ZGAjyR znoPo8o+G1Ifvby6W+Rokyh-ysYzuVu(v!LSlboFtvPx&hL%ERV5}gcPes!gnBLK^E zr{j@y)*{f2H(V!&a=A~M-H3giF2+sJ`ZI9}%vXGeCy-Zt^q)_$IXyBy<`;lVF5Qi_ zOK@`gi|cb_#)?4mqX9AQOi+W7_@lUu=C>Be2HH~t@F{SN1Tz`RP^)L`!hY@Mrkm$M zY*+-OQ0dvRp0bE*tpXH2r-Se#9Vi8OTQ;fTWea5SC51Ay+}e>zlm0Sk>TC~+Q`&&a z!j-1*WEFVNkN#!3=J$*OBUQWFxa;7q=_k{F=W@{&nlCu5m%$+WRK3Asytx)u^kRQ8+k zocnFdN=9%I&k~o~8o9<_py6me(gm|5!=B0NH0^GbG(>~ZF#{ZkRu?$ngp@bv@Ega^ zQIIBT()Jo21ggyPydqUKKtgiH!r2sOdg)^t$B6Cr`o|^ak+mx+(;|)P8q13gY3{3jo>;_8z+i-`d9FYG9xG63bTRf-aV+aR%7$x-=x}ZabqV#(C`K)aTGqoDiS#M zTlATqA{J;`^hffUpURfFwtOani!e`$HUF{k{+zXSz?=$ot(0H{u237&zeyD--KT`Y z5>W{JF4-y(X(6}`3HuZEoAVx~`hY7(i*=KiW5EP;WNoJ27oV%{(zPz(chdNm>McGQ z-=~keWxcAYXoWW;R&k{E?s*pC(aXi=h}HQs>gaZSPP`QILs1a^uqk^JqN#+a|dq}t%=&WjxLFO;Si`{K?+NV#`P z*|(7sy-lhHbj24uBxp$%|v3vjW0CuGYlW%sW(jc)Mf)At5Xgz;j3u!6J(8 zAlRY_&E4ADjoBS;)Z{Km`x$)IvA!j<+>Cy7>^gjBp)f}LMwpI=uaMm(| z1p;-?)+SkDtyQrYq38@Sn&{75;iAVK^o$ApB;Oc1(bO1AYLIM0GrCx`7IOb1W{m9% z3a33)G_fcVzD%1s%Js=tlalo3<^B-_P?z?xAN?6exUcN*{);zNJ4S98E59<%yWWtU ztlFlI?I zFmgSu{62BqYuUIIZtB2wG2Pq= z(v|CT>`RI|#pxH%nw2~a`r0L2n!ES9%Qx~kix&nCGBn?_}yi9?(E`*0lZ z6M3(-P6hw1GNN{E`GV5lEJWad0F|2hUXj6zyjBHGPQzs1df%aJ=RcfxlQ=ae;ck0m zVV66iK5z&7-u0pHPBh$ie#gli4De(RAz9z8m#|FHx=#E$`)m7|{8s`dSYwDFj1Tpw zf#hO9zC{e0V>}ajkY-u^XNH9!y?p0sP;Gj2?v-~p=WZY0CEUE`_H|l#7Wb?Rz*q#$ljCUxhQ+BFOp$^FB@KrLJBCT8V zcjJ@8*lTt+u+?8VYO?U`K?A%Fk?Sz40hfSEZutEl5j>`NbXOBnORGHE&QUt~JtzBI zca#6gjisiQ)q1$>e>+BeWU8SXTmd~dH^t@X=snuwwpD+Os16lL4EG!+dlM9O=d!Rn zv@Uw$MN?~`IbphC#HS||;i4Yt0==i)$2G=-PZP3k2?=~=)v-rM+6v#AbFyoraZ+if zkX^{IyJE@|T%O(()YSS4b+A2LN{HOntoG|Ds4y_tqYq&y*JJZm!zyhpBi+Cv=DVpk zy%)=FTsJ0)_=JCCjX+PKs+&6h+mn4W+3JF-q5&%IDKZ0@okCE~4y{hzD&Sje%hAF@ z`euC_6I6;>-i2MmJJGq0O6uHN2teA+;^=RHckw(PcMe^+13SP2go>4(E4DQ) z2m}^=+_#7XDNeMLiw(f(Fdw{-mq1@9CXCJ9ru8viQ{Y1Ucq(>whKj=SiljvH)WK3m zN*(Z4Q#4JsY<+o{g~3UUYmfQS*oU1fIP9=Tm7HFjS&s`AW9Ufrz1bo)%(CtuXtj+^ z{3be}C?hyvCJyKu28+{{3Bq4V4*0>mm;~UJr@ghlvn zCvitQ0a8F>fI)xlqU2urQg4mIoGL66z(egPCzRd0OLZof0I!MUsB?1hxDEv8eZRq8 zDs4RFrj$u3f#BN32zjV@j{&#E)H?19ZD&FowY`fnhVfZ2;6Kt^@g@VP%_X4&nElzJ zBA%0enom6SDVRl{8M&{L%0&)COrQeV>s(wOsa$y8j2hbVY(WKZ%WxXJ?-XiUH4x<$ zzp?o-rDERJ6erpAj0#CiCwFc;5I&Iyg>u5KW-xRt!AF3%Xm6ox(2Ny~m?DPaul~}- zpS**AI^>pj?5;4XGTgqC9YcuTXHfK$2ogJUf=EEn5|55^-!|)NI(~@J2&JSrx~AYS5S`(1kNvt1WrS};9#UX5mF*I1 z6wMRLILW7;IhL+ZlU|Ty-UNcR}BE$hV^S7D6 zWf#w&!qkN2ohCw3WoFdBHOe5d5hV_n-J1%neHAO`Ss`lPz=a;U`TIt1)Tp&3=;4PXLq zYSQMaQ8;vpxclnY84ipW%sI32pSCb*&6ss{0Fd6g0B@ma-0=Gx%t^Hl2zn^zuB_C9 z#NG)G#dy8LBf)o4D5+kKJ`TjF@oIKWYE}75_hJz_-(nN|nBYo4-%<(>g4^~-+Y|jO z^i-E(wQO>;_!#$SEKMm|)N}fsO379Q2!i$_ESpBgR5=zrCLtfG=;jF<(!%ZOWt(m) z-N5<4-Nc%KstHK?;NP{MIVa`et)yldX|p@x2zhzDy1NT=iL>;t)_>Ex&SfEjJp!y% z7%h0T!UVi+1Sh}xPP;m>#|X&Wk}|N2b5YI1`<%n8dFTgqaMDorq8`lz zJvN%X%2+`oa9&c#_h|uCK#W1ZRe>z68P5h#J|2O{e_MMi0iwrefgA2?J{FN+eqe}_ zPrn1Q2S$t{3;XSIL5Sy(O>_~PMF zoyGrxeB9~yR$yH>P{8C#xxWzW`P7JW=kr7i!e6`bks9%>PO3f31e{t5^hh8wOKVp_v*7?%k8R0oQ~1%y@H(Px z&r@NkvK(NQZ9;!WCVfY)786cju;ad9h9n8}3dsI_<%HCiM(DPQGy+!8bcGrd+?^jL zbx$)jEU+#w=ubW>zF~s~!9;_|&GUz+(|*Tb6DAmQ5}2b1ax0R02LK8g-7D$Gk;jNc zwI3^r(LOl`0^R)Sr*38VMl%`y>?C#T)3w)0FFjFySbBT=}`|9Ds*KrI{s z=YVF@LsUHklO7vFnn&Hz=7^u2&@`>+J0pZ^9xFd`>JJ1{3#sZ`0Y96l%%^z&O+QS9 z-}!1see1(-X~>deFP{X|PU++KCQ|0e$mlTlrK z|FRLtj!jFVeB*TXvoD;_QR@d+K_TGt&djgkg~a+&Jg}nRp43tM`{zEzYJ{bnK+a(y zEy_@L1-1;j(6Es^+S@vW;o}=P9IO^b^m;%gnvP9)Y7!Ncp(ZPMh5R>Ow^*y3S?USW z9fDX%d~A&8PdZ8lk3RweprA5B{Qj-aixw{l3(fN(&abhHV$Q_{mg}`;;H>L1vF~|% zI38q10X*|QKI-Z|xK2jH*$WG^e5D*IxrT#M=d|+QPUWI(_xMOF<~d4h@RCIKsBTrp z3>m&ZJE3Y%D8asM-*UV@hY%^^9R)LIbOT4K^4qLoQB@kTb#6`(=TuY0j-51VnPEiQ zBcpC@Pmhj$#fv7nlV=aWX>iMu+HBlX`KwfEY}w!|}UT1eRwH-=#3nb8XBn8;!-@Tp0DV6^mQYcmOp{yTOgAOwE`(1QV) z;>(xZf+K8Io^>>6%I;nkEq`L%uw_6)++-5j{La`%6H)hJ3I?0`DT-(rPY^8pTkMxf z`I)yS4xI}gbveMwp&|JD+Elz9^$IQzqv>1XaDOiSbz1WzBIlUHhfq-0nK+Ub6`^Nk z{LFfrsGc_%Qb5#Z$6;11#>_PP!^yD=b<$LjuT}24ii;$doOwEBR!!CN?j&f=c!yCg(ZQ>Ol7Ib9Q5|{D~6u$0> zP%rCRT=iV=_}@NYyba`5|4;TmP3V5G;BwRy|a>uGP-|+Yi)7`r1td5}RMOcM0(p<&WRU;fY?N*3vUL75f zE04aIxpoR|dGZ75NTZ#xwW{*kLuy39Q{06YnZF(mj^2X0Jd){{ zeIryCTC*R!cY?iYzuDG4m>?WXMB#x@aQ6on1VIDxE*$v2sTJHP5Q<$YpZSD77UgM>4ehKf+E8h0ay?YJu#@79D!2LUXr9tK>4*?PDNRjm>QUxPf{OdHIxj0 z$|U_-z5|dU@*FJIH)I@FWeX!x#FL^((;uo?P7y$UxkFDzpK?}S2tnmBDWj|@qJUw^ zUL};<#HeX(20*5iJGw+{+q1(56k>DituHDm5EdW%t+R>86mo5jL3W|1sY%Eh+5R#} zh0{7{$AsjY&XJ&L2v-|@p3)_>!d^5rX!qvT+zFhmmqZrz4i3Fi$eTL590A6x!=EMfV)PW1mceh1v4E*Uiq0TwuaVlR@w?~ z9s%B90vV+|#?ZHUy8JR@8oENTuy{a4bT1%aSaR~%>gYByP-p)PPkuRjp z4oK_@uXQWn4`MdraX7(`cI{uzfIopd^KNCj!4;!DbCvXud)R-9+6P`3BrV-1`ha$_ zZh&F;fJhO_kS@~`>KYCl+l0b&6Cglbeb^0!)WV-Z-{_EZl)O@}v5>Qs<+K&zj^Chg zJU;_;-YFbzZSIofga0`Eu&uPPP8RO=*C06?Uj%>M#9apiUIzc^wdF4GN)%8Da1ivX zl%qi(QXT;f<-`S=E|rb{BA11*^K%8lxo~2l6UWZ88UZb%ih!Og;1~@@HW&ZdgfxFj z7%%W_>&d5^gS%+;@V^Xk2=tb|x>?qwLm;i(IB+=+Pfy_3Pa(;bPb8Cr&*_CL!j zS%{;0t5w#{2k1yI9(awTvIZS!efB?e6co8Tu(R&F3Vi*2!CII#ft~-IwHoVf7BrZD z*iDq|76=%8PJ&A4ZR+SPw@D~Md0y)+f8!kpKVYY#iwPYoN*;W!j!d%3u8gM(56!jk z>{bV?_;%>NE1I6zc9vF-s9NW7G;UEr-y-pR^iHp&A+ITX)+!)jq!m z+gAIUlYNCmKVFk-O{5piF^bKpy!&lXHYO9qsqw3Df4@Znc};Udov^EQh~-j^{T^m* z>TTVp88!ayt*pioSA`8ITPq3thyc2lTI$E^Ttd!#i(|v#Zg|-&S}3w(4!j=Y7x~i} zyoD2R3DaUPwld>zs<>lFW^y7*ia4 z>j-N`3JbglAL`?N@z_p_cBLA^ic&Kmkl3{bh417_AbVd|%m z@uWq-1f+P2eBdZE?tA4$wrZL+0d)#kDQprgASyDfSku)M<=rLKt-{0)5!C{gsr|`Q z{zy^l&kX>2%&P(x7X;QD9fcw|o9&k>6wX*MBsA($fa1 z<+C&N158fUy=+8j!R7WIMjvG;R%zJF1rndgtjLqNH`|e3^s0RQjs0A&6~F|cUU#Hbye4A{|bVN zPZlr;kIvS@S-&Kt~Sg>*THRV8AK(}P8uEddyLR9jf3{dRIp6!L23W2}Oq4RtKC-iv?ro}G3T8Om%Wcq;CJ z>GxoxnJL1VJ-*sG#cJ&VBbdtE6PGT#pyPA;n2v{@uW&3GC!1+%ZYDl%h8W0If2L`ruQ2`)t_rX|kqGb14F#>*W< zZxdmiLUL==&dwZ9P2Es0RZQxSg+~L&4ogpLp9dUxzVGGG(i+JdT6|#ma%9 z*M&ce|G9`Rc#L)xl#VIzU*`1$Qi#WmBJ~z?V;Ud+p?!m4;HOnCM`~{%pPON&=px}fMKi+}VbNs-?1r2hL6ev-Y zvq!}Qj$BqsmqB2P18^>*w_;alZZlq;{KB|D_4J2X z3#ozDC2`?9>ROC@uK%*5V7u|PcEn6=nJBLo?R{S1reo|I(QsWK;|_BIIi^Vd)hKHD z_teyV>zTp1sU?Van7<*Xb(tlPzH(j7x#?WynN~?<^|8eA0f?GK=OoLtXUf@$wHFzL z3jW|Mrj$O49|#7Z&}@$T{|zu^BVZu-PkgZ!>%S94o&Oa0PnL=CzvMhT^nV;p44f_O zZ2$2LOelo8m>3v27#JBj7}*#(SXihTn8_I!$SMC*9 z3I6;c_*aLOj+sE4LdL+z!q(Z&$y}R~l3vE{Ka7O`k4||i|A-5Ylze>ueHZSICZ@0q1WZh@4F5Y3u(7f- zvl5uXLjAXh@!vD}Pa?4W-!euPmj6q}$jHXb@ITtRmK6kI82API5Bmo;P10>a7WP%} zBE(B zXRUfp=yX0@ z3)pabx*zbBi_JJrCE6`Fi`C^gmQSnV-S3v#xy~AcHGag>_N{lM8Y?x%Q#C}Yml00v n48=wpD`ZUT`e6vZjXZSNE9>h$+;fAArl)rl1a{u$v5v(9aBfdR diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip.imageset/ClipIcon.pdf b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip.imageset/ClipIcon.pdf old mode 100755 new mode 100644 index 6fafcae780bf809ce4bff9c9f34dbaa0db1ed5f8..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 HcmV?d00001 literal 52123 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 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Empty.imageset/Empty.pdf b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Empty.imageset/Empty.pdf old mode 100755 new mode 100644 index f1716049dc44e50615b9fcc2fc5fcee43e8c79f5..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 HcmV?d00001 literal 44798 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 ytXR-)Nrae*L_+mos=mm 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

^EFU?sqkt zaC`mDRb)!GS;9MpH@@eygNBlqQLomT&``A32OqUn$@Vw94TLH8>PPktNM^w*ga42U z%Gp6E5&+qpKLkIJbcygqY_^wwe@JibBF=OcRMjLrj>|Q<*pur>V&0jHG`Gg1nVWl#NW+CdG9DWH3ecQcSEPRCF8$e0!aqB z(2Hcsdy4sM8ozqVOau@!z_R-v1y;pJKiiXjrQ(_w^V-Lzz_s7@`s=>MnZG|DA$oE( z)@sgBbmPpCZVN8QF57);hN3Z`$yWhvZ_PY;|78^N+@6vIu$Ug? zx2t7bL!0eIvZZUD_{h#k(9-aDiA9eW$C%t}-(|@fIU=7NzA{SZlw7Vc7n1(+Fgf79 z-XDoNHE)Aj>@~j(luuV%&fF#y9$`K?Dw=96oII0##A)*pck?%nb?C|~_l(?_Owu)P z!TCi`bO+S_`{KpY8~t^6Pg;Axh~JDtz9_yw7n}KEkJ*Nyl+YpjKRxl3{yK@~OVio8 ztV|45i0un%u?EwkmuiB&-2Ay0B*csUM*zvf+*c~`WDAbfB zH~EO5Z~eQC`p1u+2^0({rs0!`|9y*lPi4gUTjG11imyVPR-gLju~(n=ami>-#Gi4$ zBDcZ!_S7{@7xoFOL!J;nA5xH8=~K4&xdU0#Sr6Y*d7Dtqc!W ze=mEHs$e0Zr};e+^6=ofCl9`n0)5O}c&dA!alEk;x&2pJwqy3VtC%mZJJGGycUF6y99s%!f&a6~>D?RA>yj!%j#(S>mn1L@ z=e(z41f$foufJJ_kruSuCxCOi*B#E3jZ?DN??-QWa&n;kriz-^LU;nA-w}tOrFaLE5Es#I6q1_680w3`$hPq zvWU80dW2Hoe7G3jmBC{0P6{1U|Sh5sz0`kTf)^tYhfx+ce^>>b_jqHxf>E5|V zxVFQYopw_A1#&HpdExmp30@gYt4@!4J$X*NFJ}g;CF+CjF&jRhuHo@Moj6IXf&VMltfJUGD^;G=K~Wd3ibueXr2JJ#C9CqVea%5&}{Ic7j>7ETXO!~_~TLK&V16;-2>QD8C9kAwT#s2 z*tevJ3HWN9wmr~$lc+hp_`4syNu(S1hGBOUsha5CKL>_c1z1Tk@7%ObNMzbelPD&(s;U<=YN5*{7 zQF-O|EuTVPcli)(Gvs9Gs`);-3Z2oI$H6EkV0hZ-*@1 zQXB7zOEoiUkoB|Md}7g8RL)a&(@`;Fs;AaR(F#%F@`afgcaKvFN}UN!I-BSZq7=Mr zC^}G<-1-tcOV1(QGVAH60~%|mc=S?!ZLCFtA>ggPS_cF$!8>jlY(2uD|G~Aj)iHE3 zkwKwRf$RIp%Gl#D2%wSxg`%NIK!_Ql3V|y@AWAAftY~y)J;0v~HumuF^qDb z!GHlDgc=-7P&OlyC{zZ`$Bm$(qHadpk_7laoECJNi!X`%lhguh0QR7qrxWRy!2llw zqM~k1VR(?0t$oR!J*-3GzMw_#UM3sI4BOOqm9;w00{+@R{*UH4HOKi2dJyV m5rA|MTwfCqM#1Pf0@dTgAkrCs)eZuN&;W#o6mjMTg8v49y#hu6 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/SendMessage/SendMessage_dark.imageset/SendMessage_dark.pdf b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/SendMessage/SendMessage_dark.imageset/SendMessage_dark.pdf old mode 100755 new mode 100644 index 4e8ba63b1add5f3fcbc68818b97f33e68f0605e2..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 HcmV?d00001 literal 46316 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

~YW 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 z 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 B#sdHV diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/LogoWebimNavigationBar.imageset/LogoWebimNavigationBar.pdf b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/LogoWebimNavigationBar.imageset/LogoWebimNavigationBar.pdf old mode 100755 new mode 100644 index 0fc82ebcb45ec5b923c6c2a13e06ede8da26d39e..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 HcmV?d00001 literal 57347 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 V diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/ScrollToBottom/ScrollToBottom.imageset/ScrollToBottom.pdf b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/ScrollToBottom/ScrollToBottom.imageset/ScrollToBottom.pdf old mode 100755 new mode 100644 index 357d8d1869f8d192febd872e9d5501ee5ee379e5..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 HcmV?d00001 literal 58455 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 Date: Thu, 10 Oct 2019 08:49:13 +0300 Subject: [PATCH 03/32] Move podspec --- ios/RNWebim.podspec => RNWebim.podspec | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ios/RNWebim.podspec => RNWebim.podspec (100%) diff --git a/ios/RNWebim.podspec b/RNWebim.podspec similarity index 100% rename from ios/RNWebim.podspec rename to RNWebim.podspec From 83bb5e32a79f28cd7376a1659aa28c71e812a4c1 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Thu, 10 Oct 2019 10:02:15 +0300 Subject: [PATCH 04/32] Remove libs --- RNWebim.podspec | 4 - ios/RNWebim.xcodeproj/project.pbxproj | 166 -- .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../UserInterfaceState.xcuserstate | Bin 0 -> 19492 bytes .../xcschemes/xcschememanagement.plist | 4 +- ios/libs/Sqlite/CHANGELOG.md | 97 - ios/libs/Sqlite/CONTRIBUTING.md | 108 - ios/libs/Sqlite/Documentation/Index.md | 1901 ----------------- ios/libs/Sqlite/Documentation/Planning.md | 38 - .../Resources/installation@2x.png | Bin 312530 -> 0 bytes .../Documentation/Resources/playground@2x.png | Bin 124729 -> 0 bytes ios/libs/Sqlite/LICENSE.txt | 21 - ios/libs/Sqlite/Makefile | 60 - ios/libs/Sqlite/Package.swift | 24 - ios/libs/Sqlite/README.md | 293 --- .../Sqlite/SQLite.playground/Contents.swift | 43 - .../SQLite.playground/contents.xcplayground | 4 - ios/libs/Sqlite/SQLite.swift.podspec | 69 - .../Sqlite/SQLite.xcodeproj/project.pbxproj | 1461 ------------- .../xcschemes/SQLite Mac.xcscheme | 99 - .../xcschemes/SQLite iOS.xcscheme | 99 - .../xcschemes/SQLite tvOS.xcscheme | 99 - .../xcschemes/SQLite watchOS.xcscheme | 80 - .../xcschemes/xcschememanagement.plist | 29 - .../Sqlite/Sources/SQLite/Core/Blob.swift | 60 - .../Sources/SQLite/Core/Connection.swift | 750 ------- .../Sqlite/Sources/SQLite/Core/Errors.swift | 21 - .../Sources/SQLite/Core/Statement.swift | 317 --- .../Sqlite/Sources/SQLite/Core/Value.swift | 132 -- .../Sources/SQLite/Extensions/Cipher.swift | 66 - .../Sources/SQLite/Extensions/FTS4.swift | 352 --- .../Sources/SQLite/Extensions/FTS5.swift | 97 - .../Sources/SQLite/Extensions/RTree.swift | 37 - .../Sqlite/Sources/SQLite/Foundation.swift | 70 - ios/libs/Sqlite/Sources/SQLite/Helpers.swift | 120 -- ios/libs/Sqlite/Sources/SQLite/Info.plist | 26 - ios/libs/Sqlite/Sources/SQLite/SQLite.h | 6 - .../SQLite/Typed/AggregateFunctions.swift | 264 --- .../Sqlite/Sources/SQLite/Typed/Coding.swift | 340 --- .../Sources/SQLite/Typed/Collation.swift | 69 - .../Sources/SQLite/Typed/CoreFunctions.swift | 796 ------- .../SQLite/Typed/CustomFunctions.swift | 136 -- .../SQLite/Typed/DateAndTimeFunctions.swift | 106 - .../Sources/SQLite/Typed/Expression.swift | 147 -- .../Sources/SQLite/Typed/Operators.swift | 605 ------ .../Sqlite/Sources/SQLite/Typed/Query.swift | 1175 ---------- .../Sqlite/Sources/SQLite/Typed/Schema.swift | 517 ----- .../Sqlite/Sources/SQLite/Typed/Setter.swift | 277 --- .../Sources/SQLiteObjc/SQLite-Bridging.m | 138 -- .../Sources/SQLiteObjc/fts3_tokenizer.h | 161 -- .../SQLiteObjc/include/SQLite-Bridging.h | 32 - ios/libs/Sqlite/Tests/Carthage/.gitignore | 3 - ios/libs/Sqlite/Tests/Carthage/Makefile | 16 - ios/libs/Sqlite/Tests/CocoaPods/.gitignore | 1 - ios/libs/Sqlite/Tests/CocoaPods/Gemfile | 4 - ios/libs/Sqlite/Tests/CocoaPods/Gemfile.lock | 77 - ios/libs/Sqlite/Tests/CocoaPods/Makefile | 15 - .../Tests/CocoaPods/integration_test.rb | 70 - ios/libs/Sqlite/Tests/LinuxMain.swift | 6 - .../SQLiteTests/AggregateFunctionsTests.swift | 68 - .../Sqlite/Tests/SQLiteTests/BlobTests.swift | 23 - .../Tests/SQLiteTests/CipherTests.swift | 104 - .../Tests/SQLiteTests/ConnectionTests.swift | 451 ---- .../SQLiteTests/CoreFunctionsTests.swift | 145 -- .../SQLiteTests/CustomFunctionsTests.swift | 137 -- .../DateAndTimeFunctionTests.swift | 66 - .../Tests/SQLiteTests/ExpressionTests.swift | 6 - .../Sqlite/Tests/SQLiteTests/FTS4Tests.swift | 208 -- .../Sqlite/Tests/SQLiteTests/FTS5Tests.swift | 124 -- .../Sqlite/Tests/SQLiteTests/Fixtures.swift | 8 - .../Tests/SQLiteTests/FoundationTests.swift | 16 - ios/libs/Sqlite/Tests/SQLiteTests/Info.plist | 24 - .../Tests/SQLiteTests/OperatorsTests.swift | 342 --- .../Sqlite/Tests/SQLiteTests/QueryTests.swift | 542 ----- .../Sqlite/Tests/SQLiteTests/RTreeTests.swift | 17 - .../Sqlite/Tests/SQLiteTests/RowTests.swift | 88 - .../Tests/SQLiteTests/SchemaTests.swift | 788 ------- .../Tests/SQLiteTests/SetterTests.swift | 137 -- .../Tests/SQLiteTests/StatementTests.swift | 26 - .../Tests/SQLiteTests/TestHelpers.swift | 126 -- .../Sqlite/Tests/SQLiteTests/ValueTests.swift | 6 - .../SQLiteTests/fixtures/encrypted-3.x.sqlite | 0 .../SQLiteTests/fixtures/encrypted-4.x.sqlite | 0 ios/libs/Sqlite/run-tests.sh | 15 - ios/libs/Webim/Cartfile | 1 - ios/libs/Webim/Cartfile.resolved | 1 - ios/libs/Webim/Documentation/Images/Logo.png | Bin 7933 -> 0 bytes .../Images/Screenshots/ChatScreenClassic.png | Bin 30563 -> 0 bytes .../Images/Screenshots/ChatScreenDark.png | Bin 30034 -> 0 bytes .../Images/Screenshots/ImageScreenClassic.png | Bin 21057 -> 0 bytes .../Images/Screenshots/ImageScreenDark.png | Bin 20412 -> 0 bytes .../Screenshots/RatingScreenClassic.png | Bin 23643 -> 0 bytes .../Images/Screenshots/RatingScreenDark.png | Bin 22825 -> 0 bytes .../Screenshots/SettingsScreenClassic.png | Bin 21088 -> 0 bytes .../Images/Screenshots/SettingsScreenDark.png | Bin 18850 -> 0 bytes .../Images/Screenshots/StartScreenClassic.png | Bin 28392 -> 0 bytes .../Images/Screenshots/StartScreenDark.png | Bin 23135 -> 0 bytes ios/libs/Webim/Documentation/Index.md | 1736 --------------- ios/libs/Webim/Example/Podfile | 49 - ios/libs/Webim/Example/Podfile.lock | 51 - .../Tests/AbstractRequestLoopTests.swift | 63 - .../Example/Tests/AccessCheckerTests.swift | 58 - .../Tests/ActionRequestLoopTests.swift | 69 - .../Tests/AuthorizationDataTests.swift | 142 -- .../Webim/Example/Tests/ChatItemTests.swift | 230 -- .../Example/Tests/ClientSideIDTests.swift | 55 - .../Webim/Example/Tests/DeltaItemTests.swift | 91 - .../Example/Tests/DeltaRequestLoopTests.swift | 147 -- .../Example/Tests/DeltaResponseTests.swift | 85 - .../Tests/DepartmentFactoryTests.swift | 60 - .../Example/Tests/DepartmentItemTests.swift | 107 - .../ChatViewControllerTests.swift | 87 - ...odePercentEscapedLinksIfPresentTests.swift | 99 - .../Tests/ExampleTests/MimeTypeTests.swift | 63 - ...ecIfNotDestroyedHandlerExecutorTests.swift | 48 - .../Tests/FileParametersItemTests.swift | 73 - .../Webim/Example/Tests/FullUpdateTests.swift | 195 -- .../Webim/Example/Tests/HMACsha256Tests.swift | 44 - .../Tests/HistoryBeforeResponseTests.swift | 82 - .../Webim/Example/Tests/HistoryIDTests.swift | 76 - .../Tests/HistorySinceResponseTests.swift | 85 - ios/libs/Webim/Example/Tests/Info.plist | 24 - .../Example/Tests/InternalUtilsTests.swift | 52 - .../Tests/LocationSettingsHolderTests.swift | 67 - .../Tests/LocationSettingsImplTests.swift | 70 - ...ryHistoryMetaInformationStorageTests.swift | 43 - .../Tests/MemoryHistoryStorageTests.swift | 81 - .../Example/Tests/MessageFactoriesTests.swift | 143 -- .../Example/Tests/MessageHolderTests.swift | 1713 --------------- .../Example/Tests/MessageImplTests.swift | 350 --- .../Example/Tests/MessageItemTests.swift | 149 -- .../Tests/MessageStreamImplTests.swift | 202 -- .../Tests/Mocks/ActionRequestLoopMock.swift | 40 - .../Mocks/InternalErrorListenerMock.swift | 36 - .../Example/Tests/OperatorFactoryTests.swift | 57 - .../Example/Tests/OperatorImplTests.swift | 87 - .../Example/Tests/OperatorItemTests.swift | 68 - .../Tests/ProvidedVisitorFieldsTests.swift | 73 - .../Webim/Example/Tests/RatingItemTests.swift | 64 - .../Tests/SQLiteHistoryStorageTests.swift | 196 -- .../Example/Tests/SessionBuilderTests.swift | 129 -- .../Example/Tests/SessionDestroyerTests.swift | 66 - .../Tests/StringFromHTTPParametersTests.swift | 43 - .../Example/Tests/UIColorHexStringTests.swift | 58 - .../Example/Tests/VisitorItemTests.swift | 151 -- .../Example/Tests/WebimActionsTests.swift | 445 ---- .../Example/Tests/WebimClientTests.swift | 99 - .../Example/Tests/WebimErrorImplTests.swift | 52 - .../Tests/WebimInternalLoggerTests.swift | 112 - .../WebimRemoteNotificationImplTests.swift | 150 -- ios/libs/Webim/Example/Tests/WebimTests.swift | 94 - .../project.pbxproj | 1054 --------- .../contents.xcworkspacedata | 10 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - .../WebimClientLibrary/AppDelegate.swift | 104 - .../AppearanceSettings/ButtonConstants.swift | 48 - .../AppearanceSettings/ColorConstants.swift | 153 -- .../AppearanceSettings/StringConstants.swift | 139 -- .../Base.lproj/LaunchScreen.xib | 53 - .../Base.lproj/Localizable.strings | 109 - .../Base.lproj/Main.storyboard | 422 ---- .../Base.lproj/RatingViewController.xib | 94 - .../ChatViewController.swift | 637 ------ .../AppIcon.appiconset/AppIcon-1.png | Bin 11731 -> 0 bytes .../AppIcon.appiconset/AppIcon-2.png | Bin 8195 -> 0 bytes .../AppIcon.appiconset/AppIcon-3.png | Bin 8195 -> 0 bytes .../AppIcon.appiconset/AppIcon-4.png | Bin 6264 -> 0 bytes .../AppIcon.appiconset/AppIcon-5.png | Bin 5919 -> 0 bytes .../AppIcon.appiconset/AppIcon-6.png | Bin 4446 -> 0 bytes .../AppIcon.appiconset/AppIcon-7.png | Bin 4595 -> 0 bytes .../AppIcon.appiconset/AppIcon-8.png | Bin 3456 -> 0 bytes .../AppIcon.appiconset/AppIcon.png | Bin 49253 -> 0 bytes .../AppIcon.appiconset/Contents.json | 116 - .../AppIcon.appiconset/Icon-152.png | Bin 8903 -> 0 bytes .../AppIcon.appiconset/Icon-167.png | Bin 10000 -> 0 bytes .../AppIcon.appiconset/Icon-20.png | Bin 644 -> 0 bytes .../AppIcon.appiconset/Icon-29.png | Bin 1001 -> 0 bytes .../AppIcon.appiconset/Icon-40.png | Bin 1541 -> 0 bytes .../AppIcon.appiconset/Icon-41.png | Bin 1541 -> 0 bytes .../AppIcon.appiconset/Icon-58.png | Bin 2667 -> 0 bytes .../AppIcon.appiconset/Icon-76.png | Bin 3753 -> 0 bytes .../AppIcon.appiconset/Icon-80.png | Bin 3999 -> 0 bytes .../Check.imageset/Contents.json | 15 - .../Check.imageset/check_Icon-32.png | Bin 500 -> 0 bytes .../Images.xcassets/Contents.json | 6 - .../DefaultAvatar.imageset/Contents.json | 15 - .../DefaultAvatar.imageset/DefaultAvatar.pdf | Bin .../Contents.json | 12 - .../VisitorAvatar.png | Bin 28809 -> 0 bytes .../Icons/Back/Back.imageset/Contents.json | 15 - .../Icons/Back/Back.imageset/back_Icon-32.png | Bin 710 -> 0 bytes .../Back/Back_dark.imageset/Contents.json | 15 - .../Back/Back_dark.imageset/back_Icon-32.png | Bin 710 -> 0 bytes .../Images.xcassets/Icons/Back/Contents.json | 6 - .../Icons/Clip/Clip.imageset/ClipIcon.pdf | Bin .../Icons/Clip/Clip.imageset/Contents.json | 15 - .../Clip/Clip_dark.imageset/Clip_dark.pdf | Bin .../Clip/Clip_dark.imageset/Contents.json | 15 - .../Images.xcassets/Icons/Clip/Contents.json | 6 - .../Icons/Close/Close.imageset/Contents.json | 15 - .../Close/Close.imageset/close_Icon-32.png | Bin 549 -> 0 bytes .../Close/Close_dark.imageset/Contents.json | 15 - .../Close_dark.imageset/close_Icon-32.png | Bin 549 -> 0 bytes .../Images.xcassets/Icons/Close/Contents.json | 6 - .../Images.xcassets/Icons/Contents.json | 6 - .../Icons/Empty.imageset/Contents.json | 15 - .../Icons/Empty.imageset/Empty.pdf | Bin .../Icons/SendMessage/Contents.json | 6 - .../SendMessage.imageset/Contents.json | 15 - .../SendMessage.imageset/SendMessageIcon.pdf | Bin .../SendMessage_dark.imageset/Contents.json | 15 - .../SendMessage_dark.pdf | Bin .../Images.xcassets/Logo/Contents.json | 6 - .../Logo/LogoWebim.imageset/Contents.json | 15 - .../Logo/LogoWebim.imageset/LogoWebim.pdf | Bin .../Logo/NavigationBar/Contents.json | 6 - .../Contents.json | 15 - .../LogoWebimNavigationBar.pdf | Bin .../Contents.json | 15 - .../logo_white.png | Bin 24261 -> 0 bytes .../ScrollToBottom/Contents.json | 6 - .../ScrollToBottom.imageset/Contents.json | 15 - .../ScrollToBottom.pdf | Bin .../Contents.json | 15 - .../ScrollToBottom_dark.pdf | Bin .../Example/WebimClientLibrary/Info.plist | 70 - .../MessageTableViewCell.swift | 315 --- .../Models/ColorScheme.swift | 134 -- .../WebimClientLibrary/Models/Settings.swift | 77 - .../RatingViewController.swift | 46 - .../SettingsTableViewController.swift | 199 -- .../SettingsViewController.swift | 170 -- .../StartViewController.swift | 102 - .../Utilities/Extensions/String.swift | 93 - .../Utilities/Extensions/UIImage.swift | 65 - .../Utilities/Extensions/UIImageView.swift | 63 - .../Utilities/Extensions/UITableView.swift | 47 - .../Extensions/UIViewController.swift | 47 - .../Utilities/MimeType.swift | 159 -- .../Utilities/PopupDialogHandler.swift | 230 -- .../Utilities/WebimService.swift | 510 ----- .../ru-RU.lproj/Localizable.strings | 109 - .../ru-RU.lproj/Main.strings | 88 - .../ru-RU.lproj/RatingViewController.strings | 9 - .../WebimClientLibrary_Example.entitlements | 8 - ios/libs/Webim/Info.plist | 24 - ios/libs/Webim/LICENSE | 19 - ios/libs/Webim/README.md | 181 -- ios/libs/Webim/WebimClientLibrary.podspec | 19 - .../project.pbxproj | 778 ------- .../xcschemes/WebimClientLibrary.xcscheme | 99 - .../Backend/AbstractRequestLoop.swift | 278 --- .../Backend/AccessChecker.swift | 60 - .../Backend/ActionRequestLoop.swift | 407 ---- .../Backend/AuthorizationData.swift | 77 - .../Backend/ClientSideID.swift | 68 - .../Backend/DeltaCallback.swift | 395 ---- .../Backend/DeltaRequestLoop.swift | 388 ---- ...ExecIfNotDestroyedFAQHandlerExecutor.swift | 60 - .../ExecIfNotDestroyedHandlerExecutor.swift | 60 - .../Backend/FAQAccessChecker.swift | 60 - .../Backend/FAQActions.swift | 96 - .../Backend/FAQClient.swift | 106 - .../Backend/FAQDestroyer.swift | 62 - .../Backend/FAQRequestLoop.swift | 148 -- .../Backend/HistoryID.swift | 71 - .../HistoryMetaInformationStorage.swift | 43 - .../Backend/HistoryStorage.swift | 61 - .../Backend/InternalErrorListener.swift | 39 - .../Backend/Items/ChatItem.swift | 318 --- .../Backend/Items/Deltas/DeltaItem.swift | 117 - .../Backend/Items/Deltas/FullUpdate.swift | 162 -- .../Backend/Items/DepartmentItem.swift | 115 - .../Backend/Items/FAQCategoryInfoItem.swift | 85 - .../Backend/Items/FAQCategoryItem.swift | 152 -- .../Backend/Items/FAQItemItem.swift | 137 -- .../Backend/Items/FAQStructureItem.swift | 133 -- .../Backend/Items/FileParametersItem.swift | 162 -- .../Backend/Items/HistoryRevisionItem.swift | 59 - .../Backend/Items/MessageItem.swift | 262 --- .../Backend/Items/OnlineStatusItem.swift | 47 - .../Backend/Items/OperatorItem.swift | 85 - .../Backend/Items/RatingItem.swift | 70 - .../Items/Responses/DeltaResponse.swift | 86 - .../Responses/HistoryBeforeResponse.swift | 100 - .../Responses/HistorySinceResponse.swift | 107 - .../Backend/Items/VisitSessionStateItem.swift | 50 - .../Backend/Items/VisitorItem.swift | 181 -- .../Backend/LocationSettingsHolder.swift | 63 - .../MemoryHistoryMetaInformationStorage.swift | 55 - .../Backend/MemoryHistoryStorage.swift | 226 -- .../Backend/MessageComposingHandler.swift | 115 - .../Backend/MessageHolder.swift | 564 ----- .../Backend/MessageToSend.swift | 63 - .../Backend/ProvidedVisitorFields.swift | 106 - .../Backend/RemoteHistoryProvider.swift | 81 - .../Backend/SQLiteHistoryStorage.swift | 677 ------ .../Backend/SessionDestroyer.swift | 71 - .../Backend/SessionParametersListener.swift | 42 - .../Utilities/CompletionHandlerWrappers.swift | 53 - .../Backend/Utilities/DepartmentFactory.swift | 78 - .../Backend/Utilities/Extensions/Array.swift | 50 - .../Utilities/Extensions/Collection.swift | 112 - .../Utilities/Extensions/Dictionary.swift | 56 - .../Backend/Utilities/Extensions/Int.swift | 59 - .../Backend/Utilities/Extensions/String.swift | 407 ---- .../Utilities/Extensions/UIColor.swift | 62 - .../Backend/Utilities/Extensions/UInt32.swift | 58 - .../Backend/Utilities/InternalUtils.swift | 103 - .../Backend/Utilities/MessageFactories.swift | 222 -- .../Backend/Utilities/OperatorFactory.swift | 53 - .../Backend/WebimActions.swift | 348 --- .../Backend/WebimClient.swift | 283 --- .../Backend/WebimInternalError.swift | 84 - .../Backend/WebimInternalLogger.swift | 134 -- .../Backend/WebimRequest.swift | 172 -- .../Webim/WebimClientLibrary/Department.swift | 162 -- ios/libs/Webim/WebimClientLibrary/FAQ.swift | 169 -- .../WebimClientLibrary/FAQCategory.swift | 81 - .../WebimClientLibrary/FAQCategoryInfo.swift | 59 - .../Webim/WebimClientLibrary/FAQItem.swift | 111 - .../WebimClientLibrary/FAQStructure.swift | 118 - .../FatalErrorHandler.swift | 55 - .../Implementation/DepartmentImpl.swift | 81 - .../Implementation/FAQImpl.swift | 175 -- .../Implementation/LocationSettingsImpl.swift | 96 - .../Implementation/MessageImpl.swift | 537 ----- .../Implementation/MessageStreamImpl.swift | 700 ------ .../Implementation/MessageTrackerImpl.swift | 644 ------ .../Implementation/OperatorImpl.swift | 84 - .../Implementation/WebimErrorImpl.swift | 60 - .../WebimRemoteNotificationImpl.swift | 125 -- .../Implementation/WebimSessionImpl.swift | 765 ------- .../Webim/WebimClientLibrary/Message.swift | 446 ---- .../WebimClientLibrary/MessageListener.swift | 98 - .../WebimClientLibrary/MessageStream.swift | 1633 -------------- .../WebimClientLibrary/MessageTracker.swift | 151 -- .../Webim/WebimClientLibrary/Operator.swift | 73 - ...videdAuthorizationTokenStateListener.swift | 57 - ios/libs/Webim/WebimClientLibrary/Webim.swift | 759 ------- .../WebimClientLibrary/WebimClientLibrary.h | 37 - .../Webim/WebimClientLibrary/WebimError.swift | 144 -- .../WebimClientLibrary/WebimLogger.swift | 50 - .../WebimRemoteNotification.swift | 176 -- .../WebimClientLibrary/WebimSession.swift | 160 -- 346 files changed, 9 insertions(+), 47908 deletions(-) create mode 100644 ios/RNWebim.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename ios/{libs/Webim/Example/WebimClientLibrary.xcworkspace => RNWebim.xcodeproj/project.xcworkspace}/xcshareddata/IDEWorkspaceChecks.plist (100%) create mode 100644 ios/RNWebim.xcodeproj/project.xcworkspace/xcuserdata/alfclausen.xcuserdatad/UserInterfaceState.xcuserstate rename ios/{libs/Webim/WebimClientLibrary.xcodeproj/xcuserdata/nikitasirotkin.xcuserdatad => RNWebim.xcodeproj/xcuserdata/alfclausen.xcuserdatad}/xcschemes/xcschememanagement.plist (78%) delete mode 100644 ios/libs/Sqlite/CHANGELOG.md delete mode 100644 ios/libs/Sqlite/CONTRIBUTING.md delete mode 100644 ios/libs/Sqlite/Documentation/Index.md delete mode 100644 ios/libs/Sqlite/Documentation/Planning.md delete mode 100644 ios/libs/Sqlite/Documentation/Resources/installation@2x.png delete mode 100644 ios/libs/Sqlite/Documentation/Resources/playground@2x.png delete mode 100644 ios/libs/Sqlite/LICENSE.txt delete mode 100644 ios/libs/Sqlite/Makefile delete mode 100644 ios/libs/Sqlite/Package.swift delete mode 100644 ios/libs/Sqlite/README.md delete mode 100644 ios/libs/Sqlite/SQLite.playground/Contents.swift delete mode 100644 ios/libs/Sqlite/SQLite.playground/contents.xcplayground delete mode 100644 ios/libs/Sqlite/SQLite.swift.podspec delete mode 100644 ios/libs/Sqlite/SQLite.xcodeproj/project.pbxproj delete mode 100644 ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite Mac.xcscheme delete mode 100644 ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite iOS.xcscheme delete mode 100644 ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite tvOS.xcscheme delete mode 100644 ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite watchOS.xcscheme delete mode 100644 ios/libs/Sqlite/SQLite.xcodeproj/xcuserdata/nikitasirotkin.xcuserdatad/xcschemes/xcschememanagement.plist delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Core/Blob.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Core/Connection.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Core/Errors.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Core/Statement.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Core/Value.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Extensions/Cipher.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Extensions/FTS4.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Extensions/FTS5.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Extensions/RTree.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Foundation.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Helpers.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Info.plist delete mode 100644 ios/libs/Sqlite/Sources/SQLite/SQLite.h delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Typed/AggregateFunctions.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Typed/Coding.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Typed/Collation.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Typed/CoreFunctions.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Typed/CustomFunctions.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Typed/DateAndTimeFunctions.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Typed/Expression.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Typed/Operators.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Typed/Query.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Typed/Schema.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLite/Typed/Setter.swift delete mode 100644 ios/libs/Sqlite/Sources/SQLiteObjc/SQLite-Bridging.m delete mode 100644 ios/libs/Sqlite/Sources/SQLiteObjc/fts3_tokenizer.h delete mode 100644 ios/libs/Sqlite/Sources/SQLiteObjc/include/SQLite-Bridging.h delete mode 100644 ios/libs/Sqlite/Tests/Carthage/.gitignore delete mode 100644 ios/libs/Sqlite/Tests/Carthage/Makefile delete mode 100644 ios/libs/Sqlite/Tests/CocoaPods/.gitignore delete mode 100644 ios/libs/Sqlite/Tests/CocoaPods/Gemfile delete mode 100644 ios/libs/Sqlite/Tests/CocoaPods/Gemfile.lock delete mode 100644 ios/libs/Sqlite/Tests/CocoaPods/Makefile delete mode 100644 ios/libs/Sqlite/Tests/CocoaPods/integration_test.rb delete mode 100644 ios/libs/Sqlite/Tests/LinuxMain.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/AggregateFunctionsTests.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/BlobTests.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/CipherTests.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/ConnectionTests.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/CoreFunctionsTests.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/CustomFunctionsTests.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/DateAndTimeFunctionTests.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/ExpressionTests.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/FTS4Tests.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/FTS5Tests.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/Fixtures.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/FoundationTests.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/Info.plist delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/OperatorsTests.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/QueryTests.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/RTreeTests.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/RowTests.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/SchemaTests.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/SetterTests.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/StatementTests.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/TestHelpers.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/ValueTests.swift delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/fixtures/encrypted-3.x.sqlite delete mode 100644 ios/libs/Sqlite/Tests/SQLiteTests/fixtures/encrypted-4.x.sqlite delete mode 100644 ios/libs/Sqlite/run-tests.sh delete mode 100644 ios/libs/Webim/Cartfile delete mode 100644 ios/libs/Webim/Cartfile.resolved delete mode 100644 ios/libs/Webim/Documentation/Images/Logo.png delete mode 100644 ios/libs/Webim/Documentation/Images/Screenshots/ChatScreenClassic.png delete mode 100644 ios/libs/Webim/Documentation/Images/Screenshots/ChatScreenDark.png delete mode 100644 ios/libs/Webim/Documentation/Images/Screenshots/ImageScreenClassic.png delete mode 100644 ios/libs/Webim/Documentation/Images/Screenshots/ImageScreenDark.png delete mode 100644 ios/libs/Webim/Documentation/Images/Screenshots/RatingScreenClassic.png delete mode 100644 ios/libs/Webim/Documentation/Images/Screenshots/RatingScreenDark.png delete mode 100644 ios/libs/Webim/Documentation/Images/Screenshots/SettingsScreenClassic.png delete mode 100644 ios/libs/Webim/Documentation/Images/Screenshots/SettingsScreenDark.png delete mode 100644 ios/libs/Webim/Documentation/Images/Screenshots/StartScreenClassic.png delete mode 100644 ios/libs/Webim/Documentation/Images/Screenshots/StartScreenDark.png delete mode 100644 ios/libs/Webim/Documentation/Index.md delete mode 100644 ios/libs/Webim/Example/Podfile delete mode 100644 ios/libs/Webim/Example/Podfile.lock delete mode 100644 ios/libs/Webim/Example/Tests/AbstractRequestLoopTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/AccessCheckerTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/ActionRequestLoopTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/AuthorizationDataTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/ChatItemTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/ClientSideIDTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/DeltaItemTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/DeltaRequestLoopTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/DeltaResponseTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/DepartmentFactoryTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/DepartmentItemTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/ExampleTests/ChatViewControllerTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/ExampleTests/DecodePercentEscapedLinksIfPresentTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/ExampleTests/MimeTypeTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/ExecIfNotDestroyedHandlerExecutorTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/FileParametersItemTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/FullUpdateTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/HMACsha256Tests.swift delete mode 100644 ios/libs/Webim/Example/Tests/HistoryBeforeResponseTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/HistoryIDTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/HistorySinceResponseTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/Info.plist delete mode 100644 ios/libs/Webim/Example/Tests/InternalUtilsTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/LocationSettingsHolderTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/LocationSettingsImplTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/MemoryHistoryMetaInformationStorageTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/MemoryHistoryStorageTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/MessageFactoriesTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/MessageHolderTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/MessageImplTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/MessageItemTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/MessageStreamImplTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/Mocks/ActionRequestLoopMock.swift delete mode 100644 ios/libs/Webim/Example/Tests/Mocks/InternalErrorListenerMock.swift delete mode 100644 ios/libs/Webim/Example/Tests/OperatorFactoryTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/OperatorImplTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/OperatorItemTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/ProvidedVisitorFieldsTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/RatingItemTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/SQLiteHistoryStorageTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/SessionBuilderTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/SessionDestroyerTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/StringFromHTTPParametersTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/UIColorHexStringTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/VisitorItemTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/WebimActionsTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/WebimClientTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/WebimErrorImplTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/WebimInternalLoggerTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/WebimRemoteNotificationImplTests.swift delete mode 100644 ios/libs/Webim/Example/Tests/WebimTests.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary.xcodeproj/project.pbxproj delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary.xcworkspace/contents.xcworkspacedata delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/AppDelegate.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/ButtonConstants.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/ColorConstants.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/StringConstants.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/LaunchScreen.xib delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/Localizable.strings delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/Main.storyboard delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/RatingViewController.xib delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/ChatViewController.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-1.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-2.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-3.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-4.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-5.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-6.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-7.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-8.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-152.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-167.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-20.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-29.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-40.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-41.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-58.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-76.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-80.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Check.imageset/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Check.imageset/check_Icon-32.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/DefaultAvatar.imageset/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/DefaultAvatar.imageset/DefaultAvatar.pdf delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/HardcodedVisitorAvatar.imageset/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/HardcodedVisitorAvatar.imageset/VisitorAvatar.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back.imageset/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back.imageset/back_Icon-32.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back_dark.imageset/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back_dark.imageset/back_Icon-32.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip.imageset/ClipIcon.pdf delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip.imageset/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip_dark.imageset/Clip_dark.pdf delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip_dark.imageset/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close.imageset/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close.imageset/close_Icon-32.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close_dark.imageset/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close_dark.imageset/close_Icon-32.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Empty.imageset/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Empty.imageset/Empty.pdf delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/SendMessage/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/SendMessage/SendMessage.imageset/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/SendMessage/SendMessage.imageset/SendMessageIcon.pdf delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/SendMessage/SendMessage_dark.imageset/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/SendMessage/SendMessage_dark.imageset/SendMessage_dark.pdf delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/LogoWebim.imageset/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/LogoWebim.imageset/LogoWebim.pdf delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/LogoWebimNavigationBar.imageset/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/LogoWebimNavigationBar.imageset/LogoWebimNavigationBar.pdf delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/LogoWebimNavigationBar_dark.imageset/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Logo/NavigationBar/LogoWebimNavigationBar_dark.imageset/logo_white.png delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/ScrollToBottom/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/ScrollToBottom/ScrollToBottom.imageset/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/ScrollToBottom/ScrollToBottom.imageset/ScrollToBottom.pdf delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/ScrollToBottom/ScrollToBottom_dark.imageset/Contents.json delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/ScrollToBottom/ScrollToBottom_dark.imageset/ScrollToBottom_dark.pdf delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Info.plist delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/MessageTableViewCell.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Models/ColorScheme.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Models/Settings.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/RatingViewController.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/SettingsTableViewController.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/SettingsViewController.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/StartViewController.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/String.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIImage.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIImageView.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UITableView.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIViewController.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Utilities/MimeType.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Utilities/PopupDialogHandler.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/Utilities/WebimService.swift delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/Localizable.strings delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/Main.strings delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/RatingViewController.strings delete mode 100644 ios/libs/Webim/Example/WebimClientLibrary_Example.entitlements delete mode 100644 ios/libs/Webim/Info.plist delete mode 100644 ios/libs/Webim/LICENSE delete mode 100644 ios/libs/Webim/README.md delete mode 100644 ios/libs/Webim/WebimClientLibrary.podspec delete mode 100644 ios/libs/Webim/WebimClientLibrary.xcodeproj/project.pbxproj delete mode 100644 ios/libs/Webim/WebimClientLibrary.xcodeproj/xcshareddata/xcschemes/WebimClientLibrary.xcscheme delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/AbstractRequestLoop.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/AccessChecker.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/ActionRequestLoop.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/AuthorizationData.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/ClientSideID.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/DeltaCallback.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/DeltaRequestLoop.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/ExecIfNotDestroyedFAQHandlerExecutor.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/ExecIfNotDestroyedHandlerExecutor.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/FAQAccessChecker.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/FAQActions.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/FAQClient.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/FAQDestroyer.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/FAQRequestLoop.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/HistoryID.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/HistoryMetaInformationStorage.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/HistoryStorage.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/InternalErrorListener.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/ChatItem.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/Deltas/DeltaItem.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/Deltas/FullUpdate.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/DepartmentItem.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQCategoryInfoItem.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQCategoryItem.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQItemItem.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQStructureItem.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/FileParametersItem.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/HistoryRevisionItem.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/MessageItem.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/OnlineStatusItem.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/OperatorItem.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/RatingItem.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/DeltaResponse.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/HistoryBeforeResponse.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/HistorySinceResponse.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/VisitSessionStateItem.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Items/VisitorItem.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/LocationSettingsHolder.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/MemoryHistoryMetaInformationStorage.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/MemoryHistoryStorage.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/MessageComposingHandler.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/MessageHolder.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/MessageToSend.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/ProvidedVisitorFields.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/RemoteHistoryProvider.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/SQLiteHistoryStorage.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/SessionDestroyer.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/SessionParametersListener.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/CompletionHandlerWrappers.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/DepartmentFactory.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Array.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Collection.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Dictionary.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Int.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/String.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/UIColor.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/UInt32.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/InternalUtils.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/MessageFactories.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/Utilities/OperatorFactory.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/WebimActions.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/WebimClient.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/WebimInternalError.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/WebimInternalLogger.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Backend/WebimRequest.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Department.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/FAQ.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/FAQCategory.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/FAQCategoryInfo.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/FAQItem.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/FAQStructure.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/FatalErrorHandler.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Implementation/DepartmentImpl.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Implementation/FAQImpl.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Implementation/LocationSettingsImpl.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Implementation/MessageImpl.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Implementation/MessageStreamImpl.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Implementation/MessageTrackerImpl.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Implementation/OperatorImpl.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Implementation/WebimErrorImpl.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Implementation/WebimRemoteNotificationImpl.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Implementation/WebimSessionImpl.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Message.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/MessageListener.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/MessageStream.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/MessageTracker.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Operator.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/ProvidedAuthorizationTokenStateListener.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/Webim.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/WebimClientLibrary.h delete mode 100644 ios/libs/Webim/WebimClientLibrary/WebimError.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/WebimLogger.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/WebimRemoteNotification.swift delete mode 100644 ios/libs/Webim/WebimClientLibrary/WebimSession.swift diff --git a/RNWebim.podspec b/RNWebim.podspec index 14bbe54..5220ef1 100644 --- a/RNWebim.podspec +++ b/RNWebim.podspec @@ -19,8 +19,4 @@ Pod::Spec.new do |s| s.source_files = "ios/**/*.{h,m,swift}" s.dependency 'React' - s.frameworks = 'Foundation' - s.dependency 'SQLite.swift', '0.12.2' - s.dependency 'WebimClientLibrary', '3.14.2' - end diff --git a/ios/RNWebim.xcodeproj/project.pbxproj b/ios/RNWebim.xcodeproj/project.pbxproj index 0dcd142..35c2eae 100644 --- a/ios/RNWebim.xcodeproj/project.pbxproj +++ b/ios/RNWebim.xcodeproj/project.pbxproj @@ -21,69 +21,8 @@ D65659CF22A156A200B76477 /* ProvidedAuthorizationTokenStateListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65659C222A156A100B76477 /* ProvidedAuthorizationTokenStateListener.swift */; }; D65659D022A156A200B76477 /* MessageStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65659C322A156A200B76477 /* MessageStream.swift */; }; D65659D122A156A200B76477 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65659C422A156A200B76477 /* Message.swift */; }; - D6565A0C22A16A2800B76477 /* WebimClientLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6565A0B22A16A1100B76477 /* WebimClientLibrary.framework */; }; - D6A45F8922A1393300B5BB27 /* SQLite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6A45F3622A137AF00B5BB27 /* SQLite.framework */; }; /* End PBXBuildFile section */ -/* Begin PBXContainerItemProxy section */ - D6565A0A22A16A1100B76477 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = D6565A0622A16A1100B76477 /* WebimClientLibrary.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 8FD2427A200CDB18007EB9CB; - remoteInfo = WebimClientLibrary; - }; - D6A45F3522A137AF00B5BB27 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = D6A45F2B22A137AE00B5BB27 /* SQLite.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = EE247AD31C3F04ED00AE3E12; - remoteInfo = "SQLite iOS"; - }; - D6A45F3722A137AF00B5BB27 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = D6A45F2B22A137AE00B5BB27 /* SQLite.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = EE247ADD1C3F04ED00AE3E12; - remoteInfo = "SQLiteTests iOS"; - }; - D6A45F3922A137AF00B5BB27 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = D6A45F2B22A137AE00B5BB27 /* SQLite.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = EE247B3C1C3F3ED000AE3E12; - remoteInfo = "SQLite Mac"; - }; - D6A45F3B22A137AF00B5BB27 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = D6A45F2B22A137AE00B5BB27 /* SQLite.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = EE247B451C3F3ED000AE3E12; - remoteInfo = "SQLiteTests Mac"; - }; - D6A45F3D22A137AF00B5BB27 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = D6A45F2B22A137AE00B5BB27 /* SQLite.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 03A65E5A1C6BB0F50062603F; - remoteInfo = "SQLite tvOS"; - }; - D6A45F3F22A137AF00B5BB27 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = D6A45F2B22A137AE00B5BB27 /* SQLite.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 03A65E631C6BB0F60062603F; - remoteInfo = "SQLiteTests tvOS"; - }; - D6A45F4122A137AF00B5BB27 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = D6A45F2B22A137AE00B5BB27 /* SQLite.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = A121AC451CA35C79005A31D1; - remoteInfo = "SQLite watchOS"; - }; -/* End PBXContainerItemProxy section */ - /* Begin PBXCopyFilesBuildPhase section */ 58B511D91A9E6C8500147676 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; @@ -115,8 +54,6 @@ D65659C322A156A200B76477 /* MessageStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MessageStream.swift; path = swift_bridging/MessageStream.swift; sourceTree = ""; }; D65659C422A156A200B76477 /* Message.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Message.swift; path = swift_bridging/Message.swift; sourceTree = ""; }; D65659D222A158C400B76477 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - D6565A0622A16A1100B76477 /* WebimClientLibrary.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = WebimClientLibrary.xcodeproj; path = libs/Webim/WebimClientLibrary.xcodeproj; sourceTree = ""; }; - D6A45F2B22A137AE00B5BB27 /* SQLite.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SQLite.xcodeproj; path = libs/Sqlite/SQLite.xcodeproj; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -124,8 +61,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D6A45F8922A1393300B5BB27 /* SQLite.framework in Frameworks */, - D6565A0C22A16A2800B76477 /* WebimClientLibrary.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -143,7 +78,6 @@ 58B511D21A9E6C8500147676 = { isa = PBXGroup; children = ( - D6A45F2422A1379100B5BB27 /* Libraries */, B3E7B5881CC2AC0600A0062D /* RNWebim.h */, B3E7B5891CC2AC0600A0062D /* RNWebim.m */, D65659B822A156A000B76477 /* Department.swift */, @@ -165,37 +99,6 @@ ); sourceTree = ""; }; - D6565A0722A16A1100B76477 /* Products */ = { - isa = PBXGroup; - children = ( - D6565A0B22A16A1100B76477 /* WebimClientLibrary.framework */, - ); - name = Products; - sourceTree = ""; - }; - D6A45F2422A1379100B5BB27 /* Libraries */ = { - isa = PBXGroup; - children = ( - D6565A0622A16A1100B76477 /* WebimClientLibrary.xcodeproj */, - D6A45F2B22A137AE00B5BB27 /* SQLite.xcodeproj */, - ); - name = Libraries; - sourceTree = ""; - }; - D6A45F2C22A137AE00B5BB27 /* Products */ = { - isa = PBXGroup; - children = ( - D6A45F3622A137AF00B5BB27 /* SQLite.framework */, - D6A45F3822A137AF00B5BB27 /* SQLiteTests iOS.xctest */, - D6A45F3A22A137AF00B5BB27 /* SQLite.framework */, - D6A45F3C22A137AF00B5BB27 /* SQLiteTests Mac.xctest */, - D6A45F3E22A137AF00B5BB27 /* SQLite.framework */, - D6A45F4022A137AF00B5BB27 /* SQLiteTests tvOS.xctest */, - D6A45F4222A137AF00B5BB27 /* SQLite.framework */, - ); - name = Products; - sourceTree = ""; - }; D6A45F7F22A1392900B5BB27 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -250,16 +153,6 @@ mainGroup = 58B511D21A9E6C8500147676; productRefGroup = 58B511D21A9E6C8500147676; projectDirPath = ""; - projectReferences = ( - { - ProductGroup = D6A45F2C22A137AE00B5BB27 /* Products */; - ProjectRef = D6A45F2B22A137AE00B5BB27 /* SQLite.xcodeproj */; - }, - { - ProductGroup = D6565A0722A16A1100B76477 /* Products */; - ProjectRef = D6565A0622A16A1100B76477 /* WebimClientLibrary.xcodeproj */; - }, - ); projectRoot = ""; targets = ( 58B511DA1A9E6C8500147676 /* RNWebim */, @@ -267,65 +160,6 @@ }; /* End PBXProject section */ -/* Begin PBXReferenceProxy section */ - D6565A0B22A16A1100B76477 /* WebimClientLibrary.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = WebimClientLibrary.framework; - remoteRef = D6565A0A22A16A1100B76477 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - D6A45F3622A137AF00B5BB27 /* SQLite.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = SQLite.framework; - remoteRef = D6A45F3522A137AF00B5BB27 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - D6A45F3822A137AF00B5BB27 /* SQLiteTests iOS.xctest */ = { - isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = "SQLiteTests iOS.xctest"; - remoteRef = D6A45F3722A137AF00B5BB27 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - D6A45F3A22A137AF00B5BB27 /* SQLite.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = SQLite.framework; - remoteRef = D6A45F3922A137AF00B5BB27 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - D6A45F3C22A137AF00B5BB27 /* SQLiteTests Mac.xctest */ = { - isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = "SQLiteTests Mac.xctest"; - remoteRef = D6A45F3B22A137AF00B5BB27 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - D6A45F3E22A137AF00B5BB27 /* SQLite.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = SQLite.framework; - remoteRef = D6A45F3D22A137AF00B5BB27 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - D6A45F4022A137AF00B5BB27 /* SQLiteTests tvOS.xctest */ = { - isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = "SQLiteTests tvOS.xctest"; - remoteRef = D6A45F3F22A137AF00B5BB27 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - D6A45F4222A137AF00B5BB27 /* SQLite.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = SQLite.framework; - remoteRef = D6A45F4122A137AF00B5BB27 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; -/* End PBXReferenceProxy section */ - /* Begin PBXSourcesBuildPhase section */ 58B511D71A9E6C8500147676 /* Sources */ = { isa = PBXSourcesBuildPhase; diff --git a/ios/RNWebim.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/RNWebim.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/ios/RNWebim.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ios/libs/Webim/Example/WebimClientLibrary.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/RNWebim.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from ios/libs/Webim/Example/WebimClientLibrary.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to ios/RNWebim.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/ios/RNWebim.xcodeproj/project.xcworkspace/xcuserdata/alfclausen.xcuserdatad/UserInterfaceState.xcuserstate b/ios/RNWebim.xcodeproj/project.xcworkspace/xcuserdata/alfclausen.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..08dfdf3f61d47c3cebc3d6fad9120e0e5958d201 GIT binary patch literal 19492 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 literal 0 HcmV?d00001 diff --git a/ios/libs/Webim/WebimClientLibrary.xcodeproj/xcuserdata/nikitasirotkin.xcuserdatad/xcschemes/xcschememanagement.plist b/ios/RNWebim.xcodeproj/xcuserdata/alfclausen.xcuserdatad/xcschemes/xcschememanagement.plist similarity index 78% rename from ios/libs/Webim/WebimClientLibrary.xcodeproj/xcuserdata/nikitasirotkin.xcuserdatad/xcschemes/xcschememanagement.plist rename to ios/RNWebim.xcodeproj/xcuserdata/alfclausen.xcuserdatad/xcschemes/xcschememanagement.plist index 18e0bff..7493a26 100644 --- a/ios/libs/Webim/WebimClientLibrary.xcodeproj/xcuserdata/nikitasirotkin.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/ios/RNWebim.xcodeproj/xcuserdata/alfclausen.xcuserdatad/xcschemes/xcschememanagement.plist @@ -4,10 +4,10 @@ SchemeUserState - WebimClientLibrary.xcscheme_^#shared#^_ + RNWebim.xcscheme_^#shared#^_ orderHint - 7 + 0 diff --git a/ios/libs/Sqlite/CHANGELOG.md b/ios/libs/Sqlite/CHANGELOG.md deleted file mode 100644 index 027611e..0000000 --- a/ios/libs/Sqlite/CHANGELOG.md +++ /dev/null @@ -1,97 +0,0 @@ -0.11.6 (xxx), [diff][diff-0.11.6] -======================================== - -* Swift 4.2, SQLCipher 4.x ([#866][]) - -0.11.5 (04-14-2018), [diff][diff-0.11.5] -======================================== - -* Swift 4.1 ([#797][]) - -0.11.4 (30-09-2017), [diff][diff-0.11.4] -======================================== - -* Collate `.nocase` strictly enforces `NOT NULL` even when using Optional ([#697][]) -* Fix transactions not being rolled back when committing fails ([#426][]) -* Add possibility to have expression on right hand side of like ([#591][]) -* Added Date and Time functions ([#142][]) -* Add Swift4 Coding support ([#733][]) -* Preliminary Linux support ([#315][], [#681][]) -* Add `RowIterator` for more safety ([#647][], [#726][]) -* Make `Row.get` throw instead of crash ([#649][]) -* Fix create/drop index functions ([#666][]) -* Revert deployment target to 8.0 ([#625][], [#671][], [#717][]) -* Added support for the union query clause ([#723][]) -* Add support for `ORDER` and `LIMIT` on `UPDATE` and `DELETE` ([#657][], [#722][]) -* Swift 4 support ([#668][]) - -0.11.3 (30-03-2017), [diff][diff-0.11.3] -======================================== - -* Fix compilation problems when using Carthage ([#615][]) -* Add `WITHOUT ROWID` table option ([#541][]) -* Argument count fixed for binary custom functions ([#481][]) -* Documentation updates -* Tested with Xcode 8.3 / iOS 10.3 - -0.11.2 (25-12-2016), [diff][diff-0.11.2] -======================================== - -* Fixed SQLCipher integration with read-only databases ([#559][]) -* Preliminary Swift Package Manager support ([#548][], [#560][]) -* Fixed null pointer when fetching an empty BLOB ([#561][]) -* Allow `where` as alias for `filter` ([#571][]) - -0.11.1 (06-12-2016), [diff][diff-0.11.1] -======================================== - -* Integrate SQLCipher via CocoaPods ([#546][], [#553][]) -* Made lastInsertRowid consistent with other SQLite wrappers ([#532][]) -* Fix for `~=` operator used with Double ranges -* Various documentation updates - -0.11.0 (19-10-2016) -=================== - -* Swift3 migration ([diff][diff-0.11.0]) - - -[diff-0.11.0]: https://github.com/stephencelis/SQLite.swift/compare/0.10.1...0.11.0 -[diff-0.11.1]: https://github.com/stephencelis/SQLite.swift/compare/0.11.0...0.11.1 -[diff-0.11.2]: https://github.com/stephencelis/SQLite.swift/compare/0.11.1...0.11.2 -[diff-0.11.3]: https://github.com/stephencelis/SQLite.swift/compare/0.11.2...0.11.3 -[diff-0.11.4]: https://github.com/stephencelis/SQLite.swift/compare/0.11.3...0.11.4 -[diff-0.11.5]: https://github.com/stephencelis/SQLite.swift/compare/0.11.4...0.11.5 -[diff-0.11.6]: https://github.com/stephencelis/SQLite.swift/compare/0.11.5...0.11.6 - -[#142]: https://github.com/stephencelis/SQLite.swift/issues/142 -[#315]: https://github.com/stephencelis/SQLite.swift/issues/315 -[#426]: https://github.com/stephencelis/SQLite.swift/pull/426 -[#481]: https://github.com/stephencelis/SQLite.swift/pull/481 -[#532]: https://github.com/stephencelis/SQLite.swift/issues/532 -[#541]: https://github.com/stephencelis/SQLite.swift/issues/541 -[#546]: https://github.com/stephencelis/SQLite.swift/issues/546 -[#548]: https://github.com/stephencelis/SQLite.swift/pull/548 -[#553]: https://github.com/stephencelis/SQLite.swift/pull/553 -[#559]: https://github.com/stephencelis/SQLite.swift/pull/559 -[#560]: https://github.com/stephencelis/SQLite.swift/pull/560 -[#561]: https://github.com/stephencelis/SQLite.swift/issues/561 -[#571]: https://github.com/stephencelis/SQLite.swift/issues/571 -[#591]: https://github.com/stephencelis/SQLite.swift/pull/591 -[#615]: https://github.com/stephencelis/SQLite.swift/pull/615 -[#625]: https://github.com/stephencelis/SQLite.swift/issues/625 -[#647]: https://github.com/stephencelis/SQLite.swift/pull/647 -[#649]: https://github.com/stephencelis/SQLite.swift/pull/649 -[#657]: https://github.com/stephencelis/SQLite.swift/issues/657 -[#666]: https://github.com/stephencelis/SQLite.swift/pull/666 -[#668]: https://github.com/stephencelis/SQLite.swift/pull/668 -[#671]: https://github.com/stephencelis/SQLite.swift/issues/671 -[#681]: https://github.com/stephencelis/SQLite.swift/issues/681 -[#697]: https://github.com/stephencelis/SQLite.swift/issues/697 -[#717]: https://github.com/stephencelis/SQLite.swift/issues/717 -[#722]: https://github.com/stephencelis/SQLite.swift/pull/722 -[#723]: https://github.com/stephencelis/SQLite.swift/pull/723 -[#733]: https://github.com/stephencelis/SQLite.swift/pull/733 -[#726]: https://github.com/stephencelis/SQLite.swift/pull/726 -[#797]: https://github.com/stephencelis/SQLite.swift/pull/797 -[#866]: https://github.com/stephencelis/SQLite.swift/pull/866 diff --git a/ios/libs/Sqlite/CONTRIBUTING.md b/ios/libs/Sqlite/CONTRIBUTING.md deleted file mode 100644 index 6c367b9..0000000 --- a/ios/libs/Sqlite/CONTRIBUTING.md +++ /dev/null @@ -1,108 +0,0 @@ -# Contributing - -The where and when to open an [issue](#issues) or [pull -request](#pull-requests). - - -## Issues - -Issues are used to track **bugs** and **feature requests**. Need **help** or -have a **general question**? [Ask on Stack Overflow][] (tag `sqlite.swift`). - -Before reporting a bug or requesting a feature, [run a few searches][Search] to -see if a similar issue has already been opened and ensure you’re not submitting -a duplicate. - -If you find a similar issue, read the existing conversation and see if it -addresses everything. If it doesn’t, continue the conversation there. - -If your searches return empty, see the [bug](#bugs) or [feature -request](#feature-requests) guidelines below. - -[Ask on Stack Overflow]: http://stackoverflow.com/questions/tagged/sqlite.swift -[Search]: https://github.com/stephencelis/SQLite.swift/search?type=Issues - - -### Bugs - -Think you’ve discovered a new **bug**? Let’s try troubleshooting a few things -first. - - - **Is it an installation issue?** - - If this is your first time building SQLite.swift in your project, you may - encounter a build error, _e.g._: - - No such module 'SQLite' - - Please carefully re-read the [installation instructions][] to make sure - everything is in order. - - - **Have you read the documentation?** - - If you can’t seem to get something working, check - [the documentation][See Documentation] to see if the solution is there. - - - **Are you up-to-date?** - - If you’re perusing [the documentation][See Documentation] online and find - that an example is just not working, please upgrade to the latest version - of SQLite.swift and try again before continuing. - - - **Is it an unhelpful build error?** - - While Swift error messaging is improving with each release, complex - expressions still lend themselves to misleading errors. If you encounter an - error on a complex line, breaking it down into smaller pieces generally - yields a more understandable error. - - - **Is it an _even more_ unhelpful build error?** - - Have you updated Xcode recently? Did your project stop building out of the - blue? - - Hold down the **option** key and select **Clean Build Folder…** from the - **Product** menu (⌥⇧⌘K). - -Made it through everything above and still having trouble? Sorry! -[Open an issue][]! And _please_: - - - Be as descriptive as possible. - - Provide as much information needed to _reliably reproduce_ the issue. - - Attach screenshots if possible. - - Better yet: attach GIFs or link to video. - - Even better: link to a sample project exhibiting the issue. - - Include the SQLite.swift commit or branch experiencing the issue. - - Include devices and operating systems affected. - - Include build information: the Xcode and macOS versions affected. - -[installation instructions]: Documentation/Index.md#installation -[See Documentation]: Documentation/Index.md#sqliteswift-documentation -[Open an issue]: https://github.com/stephencelis/SQLite.swift/issues/new - - -### Feature Requests - -Have an innovative **feature request**? [Open an issue][]! Be thorough! Provide -context and examples. Be open to discussion. - - -## Pull Requests - -Interested in contributing but don’t know where to start? Try the [`help -wanted`][help wanted] label. - -Ready to submit a fix or a feature? [Submit a pull request][]! And _please_: - - - If code changes, run the tests and make sure everything still works. - - Write new tests for new functionality. - - Update documentation comments where applicable. - - Maintain the existing style. - - Don’t forget to have fun. - -While we cannot guarantee a merge to every pull request, we do read each one -and love your input. - - -[help wanted]: https://github.com/stephencelis/SQLite.swift/labels/help%20wanted -[Submit a pull request]: https://github.com/stephencelis/SQLite.swift/fork diff --git a/ios/libs/Sqlite/Documentation/Index.md b/ios/libs/Sqlite/Documentation/Index.md deleted file mode 100644 index 70d67c2..0000000 --- a/ios/libs/Sqlite/Documentation/Index.md +++ /dev/null @@ -1,1901 +0,0 @@ -# SQLite.swift Documentation - - - [Installation](#installation) - - [Carthage](#carthage) - - [CocoaPods](#cocoapods) - - [Swift Package Manager](#swift-package-manager) - - [Manual](#manual) - - [Getting Started](#getting-started) - - [Connecting to a Database](#connecting-to-a-database) - - [Read-Write Databases](#read-write-databases) - - [Read-Only Databases](#read-only-databases) - - [In-Memory Databases](#in-memory-databases) - - [Thread-Safety](#thread-safety) - - [Building Type-Safe SQL](#building-type-safe-sql) - - [Expressions](#expressions) - - [Compound Expressions](#compound-expressions) - - [Queries](#queries) - - [Creating a Table](#creating-a-table) - - [Create Table Options](#create-table-options) - - [Column Constraints](#column-constraints) - - [Table Constraints](#table-constraints) - - [Inserting Rows](#inserting-rows) - - [Handling SQLite errors](#handling-sqlite-errors) - - [Setters](#setters) - - [Selecting Rows](#selecting-rows) - - [Iterating and Accessing Values](#iterating-and-accessing-values) - - [Plucking Rows](#plucking-rows) - - [Building Complex Queries](#building-complex-queries) - - [Selecting Columns](#selecting-columns) - - [Joining Other Tables](#joining-other-tables) - - [Column Namespacing](#column-namespacing) - - [Table Aliasing](#table-aliasing) - - [Filtering Rows](#filtering-rows) - - [Filter Operators and Functions](#filter-operators-and-functions) - - [Sorting Rows](#sorting-rows) - - [Limiting and Paging Results](#limiting-and-paging-results) - - [Aggregation](#aggregation) - - [Updating Rows](#updating-rows) - - [Deleting Rows](#deleting-rows) - - [Transactions and Savepoints](#transactions-and-savepoints) - - [Altering the Schema](#altering-the-schema) - - [Renaming Tables](#renaming-tables) - - [Adding Columns](#adding-columns) - - [Added Column Constraints](#added-column-constraints) - - [Indexes](#indexes) - - [Creating Indexes](#creating-indexes) - - [Dropping Indexes](#dropping-indexes) - - [Dropping Tables](#dropping-tables) - - [Migrations and Schema Versioning](#migrations-and-schema-versioning) - - [Custom Types](#custom-types) - - [Date-Time Values](#date-time-values) - - [Binary Data](#binary-data) - - [Codable Types](#codable-types) - - [Other Operators](#other-operators) - - [Core SQLite Functions](#core-sqlite-functions) - - [Aggregate SQLite Functions](#aggregate-sqlite-functions) - - [Date and Time Functions](#date-and-time-functions) - - [Custom SQL Functions](#custom-sql-functions) - - [Custom Collations](#custom-collations) - - [Full-text Search](#full-text-search) - - [Executing Arbitrary SQL](#executing-arbitrary-sql) - - [Logging](#logging) - - -[↩]: #sqliteswift-documentation - - -## Installation - -> _Note:_ SQLite.swift requires Swift 5 (and -> [Xcode 10.2](https://developer.apple.com/xcode/downloads/)) or greater. - - -### Carthage - -[Carthage][] is a simple, decentralized dependency manager for Cocoa. To -install SQLite.swift with Carthage: - 1. Make sure Carthage is [installed][Carthage Installation]. - - 2. Update your Cartfile to include the following: - - ```ruby - github "stephencelis/SQLite.swift" ~> 0.12.0 - ``` - - 3. Run `carthage update` and [add the appropriate framework][Carthage Usage]. - - -[Carthage]: https://github.com/Carthage/Carthage -[Carthage Installation]: https://github.com/Carthage/Carthage#installing-carthage -[Carthage Usage]: https://github.com/Carthage/Carthage#adding-frameworks-to-an-application - - -### CocoaPods - -[CocoaPods][] is a dependency manager for Cocoa projects. To install SQLite.swift with CocoaPods: - - 1. Make sure CocoaPods is [installed][CocoaPods Installation] (SQLite.swift - requires version 1.6.1 or greater). - - ```sh - # Using the default Ruby install will require you to use sudo when - # installing and updating gems. - [sudo] gem install cocoapods - ``` - - 2. Update your Podfile to include the following: - - ```ruby - use_frameworks! - - target 'YourAppTargetName' do - pod 'SQLite.swift', '~> 0.12.0' - end - ``` - - 3. Run `pod install --repo-update`. - - -#### Requiring a specific version of SQLite - -If you want to use a more recent version of SQLite than what is provided -with the OS you can require the `standalone` subspec: - -```ruby -target 'YourAppTargetName' do - pod 'SQLite.swift/standalone', '~> 0.12.0' -end -``` - -By default this will use the most recent version of SQLite without any -extras. If you want you can further customize this by adding another -dependency to sqlite3 or one of its subspecs: - -```ruby -target 'YourAppTargetName' do - pod 'SQLite.swift/standalone', '~> 0.12.0' - pod 'sqlite3/fts5', '= 3.15.0' # SQLite 3.15.0 with FTS5 enabled -end -``` - -See the [sqlite3 podspec][sqlite3pod] for more details. - -#### Using SQLite.swift with SQLCipher - -If you want to use [SQLCipher][] with SQLite.swift you can require the -`SQLCipher` subspec in your Podfile: - -```ruby -target 'YourAppTargetName' do - pod 'SQLite.swift/SQLCipher', '~> 0.12.0' -end -``` - -This will automatically add a dependency to the SQLCipher pod as well as -extend `Connection` with methods to change the database key: - -```swift -import SQLite - -let db = try Connection("path/to/db.sqlite3") -try db.key("secret") -try db.rekey("another secret") -``` - -[CocoaPods]: https://cocoapods.org -[CocoaPods Installation]: https://guides.cocoapods.org/using/getting-started.html#getting-started -[sqlite3pod]: https://github.com/clemensg/sqlite3pod -[SQLCipher]: https://www.zetetic.net/sqlcipher/ - -### Swift Package Manager - -The [Swift Package Manager][] is a tool for managing the distribution of -Swift code. It’s integrated with the Swift build system to automate the -process of downloading, compiling, and linking dependencies. - -It is the recommended approach for using SQLite.swift in OSX CLI -applications. - - 1. Add the following to your `Package.swift` file: - - ```swift - dependencies: [ - .package(url: "https://github.com/stephencelis/SQLite.swift.git", from: "0.12.0") - ] - ``` - - 2. Build your project: - - ```sh - $ swift build - ``` - -[Swift Package Manager]: https://swift.org/package-manager - -### Manual - -To install SQLite.swift as an Xcode sub-project: - - 1. Drag the **SQLite.xcodeproj** file into your own project. - ([Submodule](http://git-scm.com/book/en/Git-Tools-Submodules), clone, or - [download](https://github.com/stephencelis/SQLite.swift/archive/master.zip) - the project first.) - - ![Installation Screen Shot](Resources/installation@2x.png) - - 2. In your target’s **General** tab, click the **+** button under **Linked - Frameworks and Libraries**. - - 3. Select the appropriate **SQLite.framework** for your platform. - - 4. **Add**. - -You should now be able to `import SQLite` from any of your target’s source -files and begin using SQLite.swift. - -Some additional steps are required to install the application on an actual -device: - - 5. In the **General** tab, click the **+** button under **Embedded - Binaries**. - - 6. Select the appropriate **SQLite.framework** for your platform. - - 7. **Add**. - -## Getting Started - -To use SQLite.swift classes or structures in your target’s source file, first -import the `SQLite` module. - -```swift -import SQLite -``` - - -### Connecting to a Database - -Database connections are established using the `Connection` class. A -connection is initialized with a path to a database. SQLite will attempt to -create the database file if it does not already exist. - -```swift -let db = try Connection("path/to/db.sqlite3") -``` - - -#### Read-Write Databases - -On iOS, you can create a writable database in your app’s **Documents** -directory. - -```swift -let path = NSSearchPathForDirectoriesInDomains( - .documentDirectory, .userDomainMask, true -).first! - -let db = try Connection("\(path)/db.sqlite3") -``` - -On macOS, you can use your app’s **Application Support** directory: - -```swift -var path = NSSearchPathForDirectoriesInDomains( - .applicationSupportDirectory, .userDomainMask, true -).first! + "/" + Bundle.main.bundleIdentifier! - -// create parent directory iff it doesn’t exist -try FileManager.default.createDirectoryAtPath( - path, withIntermediateDirectories: true, attributes: nil -) - -let db = try Connection("\(path)/db.sqlite3") -``` - - -#### Read-Only Databases - -If you bundle a database with your app (_i.e._, you’ve copied a database file -into your Xcode project and added it to your application target), you can -establish a _read-only_ connection to it. - -```swift -let path = Bundle.main.pathForResource("db", ofType: "sqlite3")! - -let db = try Connection(path, readonly: true) -``` - -> _Note:_ Signed applications cannot modify their bundle resources. If you -> bundle a database file with your app for the purpose of bootstrapping, copy -> it to a writable location _before_ establishing a connection (see -> [Read-Write Databases](#read-write-databases), above, for typical, writable -> locations). -> -> See these two Stack Overflow questions for more information about iOS apps -> with SQLite databases: [1](https://stackoverflow.com/questions/34609746/what-different-between-store-database-in-different-locations-in-ios), -> [2](https://stackoverflow.com/questions/34614968/ios-how-to-copy-pre-seeded-database-at-the-first-running-app-with-sqlite-swift). -> We welcome sample code to show how to successfully copy and use a bundled "seed" -> database for writing in an app. - -#### In-Memory Databases - -If you omit the path, SQLite.swift will provision an [in-memory -database](https://www.sqlite.org/inmemorydb.html). - -```swift -let db = try Connection() // equivalent to `Connection(.inMemory)` -``` - -To create a temporary, disk-backed database, pass an empty file name. - -```swift -let db = try Connection(.temporary) -``` - -In-memory databases are automatically deleted when the database connection is -closed. - - -#### Thread-Safety - -Every Connection comes equipped with its own serial queue for statement -execution and can be safely accessed across threads. Threads that open -transactions and savepoints will block other threads from executing -statements while the transaction is open. - -If you maintain multiple connections for a single database, consider setting a timeout (in seconds) and/or a busy handler: - -```swift -db.busyTimeout = 5 - -db.busyHandler({ tries in - if tries >= 3 { - return false - } - return true -}) -``` - -> _Note:_ The default timeout is 0, so if you see `database is locked` -> errors, you may be trying to access the same database simultaneously from -> multiple connections. - - -## Building Type-Safe SQL - -SQLite.swift comes with a typed expression layer that directly maps -[Swift types](https://developer.apple.com/library/prerelease/ios/documentation/General/Reference/SwiftStandardLibraryReference/) -to their [SQLite counterparts](https://www.sqlite.org/datatype3.html). - -| Swift Type | SQLite Type | -| --------------- | ----------- | -| `Int64`* | `INTEGER` | -| `Double` | `REAL` | -| `String` | `TEXT` | -| `nil` | `NULL` | -| `SQLite.Blob`† | `BLOB` | - -> *While `Int64` is the basic, raw type (to preserve 64-bit integers on -> 32-bit platforms), `Int` and `Bool` work transparently. -> -> †SQLite.swift defines its own `Blob` structure, which safely wraps the -> underlying bytes. -> -> See [Custom Types](#custom-types) for more information about extending -> other classes and structures to work with SQLite.swift. -> -> See [Executing Arbitrary SQL](#executing-arbitrary-sql) to forego the typed -> layer and execute raw SQL, instead. - -These expressions (in the form of the structure, -[`Expression`](#expressions)) build on one another and, with a query -([`QueryType`](#queries)), can create and execute SQL statements. - - -### Expressions - -Expressions are generic structures associated with a type ([built-in -](#building-type-safe-sql) or [custom](#custom-types)), raw SQL, and -(optionally) values to bind to that SQL. Typically, you will only explicitly -create expressions to describe your columns, and typically only once per -column. - -```swift -let id = Expression("id") -let email = Expression("email") -let balance = Expression("balance") -let verified = Expression("verified") -``` - -Use optional generics for expressions that can evaluate to `NULL`. - -```swift -let name = Expression("name") -``` - -> _Note:_ The default `Expression` initializer is for [quoted -> identifiers](https://www.sqlite.org/lang_keywords.html) (_i.e._, column -> names). To build a literal SQL expression, use `init(literal:)`. -> - - -### Compound Expressions - -Expressions can be combined with other expressions and types using -[filter operators and functions](#filter-operators-and-functions) -(as well as other [non-filter operators](#other-operators) and -[functions](#core-sqlite-functions)). These building blocks can create complex SQLite statements. - - -### Queries - -Queries are structures that reference a database and table name, and can be -used to build a variety of statements using expressions. We can create a -query by initializing a `Table`, `View`, or `VirtualTable`. - -```swift -let users = Table("users") -``` - -Assuming [the table exists](#creating-a-table), we can immediately [insert -](#inserting-rows), [select](#selecting-rows), [update](#updating-rows), and -[delete](#deleting-rows) rows. - - -## Creating a Table - -We can build [`CREATE TABLE` -statements](https://www.sqlite.org/lang_createtable.html) by calling the -`create` function on a `Table`. The following is a basic example of -SQLite.swift code (using the [expressions](#expressions) and -[query](#queries) above) and the corresponding SQL it generates. - -```swift -try db.run(users.create { t in // CREATE TABLE "users" ( - t.column(id, primaryKey: true) // "id" INTEGER PRIMARY KEY NOT NULL, - t.column(email, unique: true) // "email" TEXT UNIQUE NOT NULL, - t.column(name) // "name" TEXT -}) // ) -``` - -> _Note:_ `Expression` structures (in this case, the `id` and `email` -> columns), generate `NOT NULL` constraints automatically, while -> `Expression` structures (`name`) do not. - - -### Create Table Options - -The `Table.create` function has several default parameters we can override. - - - `temporary` adds a `TEMPORARY` clause to the `CREATE TABLE` statement (to - create a temporary table that will automatically drop when the database - connection closes). Default: `false`. - - ```swift - try db.run(users.create(temporary: true) { t in /* ... */ }) - // CREATE TEMPORARY TABLE "users" -- ... - ``` - - - `ifNotExists` adds an `IF NOT EXISTS` clause to the `CREATE TABLE` - statement (which will bail out gracefully if the table already exists). - Default: `false`. - - ```swift - try db.run(users.create(ifNotExists: true) { t in /* ... */ }) - // CREATE TABLE "users" IF NOT EXISTS -- ... - ``` - -### Column Constraints - -The `column` function is used for a single column definition. It takes an -[expression](#expressions) describing the column name and type, and accepts -several parameters that map to various column constraints and clauses. - - - `primaryKey` adds a `PRIMARY KEY` constraint to a single column. - - ```swift - t.column(id, primaryKey: true) - // "id" INTEGER PRIMARY KEY NOT NULL - - t.column(id, primaryKey: .autoincrement) - // "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL - ``` - - > _Note:_ The `primaryKey` parameter cannot be used alongside - > `references`. If you need to create a column that has a default value - > and is also a primary and/or foreign key, use the `primaryKey` and - > `foreignKey` functions mentioned under - > [Table Constraints](#table-constraints). - > - > Primary keys cannot be optional (_e.g._, `Expression`). - > - > Only an `INTEGER PRIMARY KEY` can take `.autoincrement`. - - - `unique` adds a `UNIQUE` constraint to the column. (See the `unique` - function under [Table Constraints](#table-constraints) for uniqueness - over multiple columns). - - ```swift - t.column(email, unique: true) - // "email" TEXT UNIQUE NOT NULL - ``` - - - `check` attaches a `CHECK` constraint to a column definition in the form - of a boolean expression (`Expression`). Boolean expressions can be - easily built using - [filter operators and functions](#filter-operators-and-functions). - (See also the `check` function under - [Table Constraints](#table-constraints).) - - ```swift - t.column(email, check: email.like("%@%")) - // "email" TEXT NOT NULL CHECK ("email" LIKE '%@%') - ``` - - - `defaultValue` adds a `DEFAULT` clause to a column definition and _only_ - accepts a value (or expression) matching the column’s type. This value is - used if none is explicitly provided during - [an `INSERT`](#inserting-rows). - - ```swift - t.column(name, defaultValue: "Anonymous") - // "name" TEXT DEFAULT 'Anonymous' - ``` - - > _Note:_ The `defaultValue` parameter cannot be used alongside - > `primaryKey` and `references`. If you need to create a column that has - > a default value and is also a primary and/or foreign key, use the - > `primaryKey` and `foreignKey` functions mentioned under - > [Table Constraints](#table-constraints). - - - `collate` adds a `COLLATE` clause to `Expression` (and - `Expression`) column definitions with - [a collating sequence](https://www.sqlite.org/datatype3.html#collation) - defined in the `Collation` enumeration. - - ```swift - t.column(email, collate: .nocase) - // "email" TEXT NOT NULL COLLATE "NOCASE" - - t.column(name, collate: .rtrim) - // "name" TEXT COLLATE "RTRIM" - ``` - - - `references` adds a `REFERENCES` clause to `Expression` (and - `Expression`) column definitions and accepts a table - (`SchemaType`) or namespaced column expression. (See the `foreignKey` - function under [Table Constraints](#table-constraints) for non-integer - foreign key support.) - - ```swift - t.column(user_id, references: users, id) - // "user_id" INTEGER REFERENCES "users" ("id") - ``` - - > _Note:_ The `references` parameter cannot be used alongside - > `primaryKey` and `defaultValue`. If you need to create a column that - > has a default value and is also a primary and/or foreign key, use the - > `primaryKey` and `foreignKey` functions mentioned under - > [Table Constraints](#table-constraints). - - -### Table Constraints - -Additional constraints may be provided outside the scope of a single column -using the following functions. - - - `primaryKey` adds a `PRIMARY KEY` constraint to the table. Unlike [the - column constraint, above](#column-constraints), it supports all SQLite - types, [ascending and descending orders](#sorting-rows), and composite - (multiple column) keys. - - ```swift - t.primaryKey(email.asc, name) - // PRIMARY KEY("email" ASC, "name") - ``` - - - `unique` adds a `UNIQUE` constraint to the table. Unlike - [the column constraint, above](#column-constraints), it - supports composite (multiplecolumn) constraints. - - ```swift - t.unique(local, domain) - // UNIQUE("local", "domain") - ``` - - - `check` adds a `CHECK` constraint to the table in the form of a boolean - expression (`Expression`). Boolean expressions can be easily built - using [filter operators and functions](#filter-operators-and-functions). - (See also the `check` parameter under - [Column Constraints](#column-constraints).) - - ```swift - t.check(balance >= 0) - // CHECK ("balance" >= 0.0) - ``` - - - `foreignKey` adds a `FOREIGN KEY` constraint to the table. Unlike [the - `references` constraint, above](#column-constraints), it supports all - SQLite types, both [`ON UPDATE` and `ON DELETE` - actions](https://www.sqlite.org/foreignkeys.html#fk_actions), and - composite (multiple column) keys. - - ```swift - t.foreignKey(user_id, references: users, id, delete: .setNull) - // FOREIGN KEY("user_id") REFERENCES "users"("id") ON DELETE SET NULL - ``` - - - - -## Inserting Rows - -We can insert rows into a table by calling a [query’s](#queries) `insert` -function with a list of [setters](#setters)—typically [typed column -expressions](#expressions) and values (which can also be expressions)—each -joined by the `<-` operator. - -```swift -try db.run(users.insert(email <- "alice@mac.com", name <- "Alice")) -// INSERT INTO "users" ("email", "name") VALUES ('alice@mac.com', 'Alice') - -try db.run(users.insert(or: .replace, email <- "alice@mac.com", name <- "Alice B.")) -// INSERT OR REPLACE INTO "users" ("email", "name") VALUES ('alice@mac.com', 'Alice B.') -``` - -The `insert` function, when run successfully, returns an `Int64` representing -the inserted row’s [`ROWID`][ROWID]. - -```swift -do { - let rowid = try db.run(users.insert(email <- "alice@mac.com")) - print("inserted id: \(rowid)") -} catch { - print("insertion failed: \(error)") -} -``` - -The [`update`](#updating-rows) and [`delete`](#deleting-rows) functions -follow similar patterns. - -> _Note:_ If `insert` is called without any arguments, the statement will run -> with a `DEFAULT VALUES` clause. The table must not have any constraints -> that aren’t fulfilled by default values. -> -> ```swift -> try db.run(timestamps.insert()) -> // INSERT INTO "timestamps" DEFAULT VALUES -> ``` - -### Handling SQLite errors - -You can pattern match on the error to selectively catch SQLite errors. For example, to -specifically handle constraint errors ([SQLITE_CONSTRAINT](https://sqlite.org/rescode.html#constraint)): - -```swift -do { - try db.run(users.insert(email <- "alice@mac.com")) - try db.run(users.insert(email <- "alice@mac.com")) -} catch let Result.error(message, code, statement) where code == SQLITE_CONSTRAINT { - print("constraint failed: \(message), in \(statement)") -} catch let error { - print("insertion failed: \(error)") -} -``` - -The `Result.error` type contains the English-language text that describes the error (`message`), -the error `code` (see [SQLite result code list](https://sqlite.org/rescode.html#primary_result_code_list) -for details) and a optional reference to the `statement` which produced the error. - -### Setters - -SQLite.swift typically uses the `<-` operator to set values during [inserts -](#inserting-rows) and [updates](#updating-rows). - -```swift -try db.run(counter.update(count <- 0)) -// UPDATE "counters" SET "count" = 0 WHERE ("id" = 1) -``` - -There are also a number of convenience setters that take the existing value -into account using native Swift operators. - -For example, to atomically increment a column, we can use `++`: - -```swift -try db.run(counter.update(count++)) // equivalent to `counter.update(count -> count + 1)` -// UPDATE "counters" SET "count" = "count" + 1 WHERE ("id" = 1) -``` - -To take an amount and “move” it via transaction, we can use `-=` and `+=`: - -```swift -let amount = 100.0 -try db.transaction { - try db.run(alice.update(balance -= amount)) - try db.run(betty.update(balance += amount)) -} -// BEGIN DEFERRED TRANSACTION -// UPDATE "users" SET "balance" = "balance" - 100.0 WHERE ("id" = 1) -// UPDATE "users" SET "balance" = "balance" + 100.0 WHERE ("id" = 2) -// COMMIT TRANSACTION -``` - - -###### Infix Setters - -| Operator | Types | -| -------- | ------------------ | -| `<-` | `Value -> Value` | -| `+=` | `Number -> Number` | -| `-=` | `Number -> Number` | -| `*=` | `Number -> Number` | -| `/=` | `Number -> Number` | -| `%=` | `Int -> Int` | -| `<<=` | `Int -> Int` | -| `>>=` | `Int -> Int` | -| `&=` | `Int -> Int` | -| `\|\|=` | `Int -> Int` | -| `^=` | `Int -> Int` | -| `+=` | `String -> String` | - - -###### Postfix Setters - -| Operator | Types | -| -------- | ------------ | -| `++` | `Int -> Int` | -| `--` | `Int -> Int` | - - -## Selecting Rows - -[Query structures](#queries) are `SELECT` statements waiting to happen. They -execute via [iteration](#iterating-and-accessing-values) and [other means -](#plucking-values) of sequence access. - - -### Iterating and Accessing Values - -Prepared [queries](#queries) execute lazily upon iteration. Each row is -returned as a `Row` object, which can be subscripted with a [column -expression](#expressions) matching one of the columns returned. - -```swift -for user in try db.prepare(users) { - print("id: \(user[id]), email: \(user[email]), name: \(user[name])") - // id: 1, email: alice@mac.com, name: Optional("Alice") -} -// SELECT * FROM "users" -``` - -`Expression` column values are _automatically unwrapped_ (we’ve made a -promise to the compiler that they’ll never be `NULL`), while `Expression` -values remain wrapped. - -⚠ Column subscripts on `Row` will force try and abort execution in error cases. -If you want to handle this yourself, use `Row.get(_ column: Expression)`: - -```swift -for user in try db.prepare(users) { - do { - print("name: \(try user.get(name))") - } catch { - // handle - } -} -``` - -### Plucking Rows - -We can pluck the first row by passing a query to the `pluck` function on a -database connection. - -```swift -if let user = try db.pluck(users) { /* ... */ } // Row -// SELECT * FROM "users" LIMIT 1 -``` - -To collect all rows into an array, we can simply wrap the sequence (though -this is not always the most memory-efficient idea). - -```swift -let all = Array(try db.prepare(users)) -// SELECT * FROM "users" -``` - - -### Building Complex Queries - -[Queries](#queries) have a number of chainable functions that can be used -(with [expressions](#expressions)) to add and modify [a number of -clauses](https://www.sqlite.org/lang_select.html) to the underlying -statement. - -```swift -let query = users.select(email) // SELECT "email" FROM "users" - .filter(name != nil) // WHERE "name" IS NOT NULL - .order(email.desc, name) // ORDER BY "email" DESC, "name" - .limit(5, offset: 1) // LIMIT 5 OFFSET 1 -``` - - -#### Selecting Columns - -By default, [queries](#queries) select every column of the result set (using -`SELECT *`). We can use the `select` function with a list of -[expressions](#expressions) to return specific columns instead. - -```swift -for user in try db.prepare(users.select(id, email)) { - print("id: \(user[id]), email: \(user[email])") - // id: 1, email: alice@mac.com -} -// SELECT "id", "email" FROM "users" -``` - -We can access the results of more complex expressions by holding onto a -reference of the expression itself. - -```swift -let sentence = name + " is " + cast(age) as Expression + " years old!" -for user in users.select(sentence) { - print(user[sentence]) - // Optional("Alice is 30 years old!") -} -// SELECT ((("name" || ' is ') || CAST ("age" AS TEXT)) || ' years old!') FROM "users" -``` - - -#### Joining Other Tables - -We can join tables using a [query’s](#queries) `join` function. - -```swift -users.join(posts, on: user_id == users[id]) -// SELECT * FROM "users" INNER JOIN "posts" ON ("user_id" = "users"."id") -``` - -The `join` function takes a [query](#queries) object (for the table being -joined on), a join condition (`on`), and is prefixed with an optional join -type (default: `.inner`). Join conditions can be built using [filter -operators and functions](#filter-operators-and-functions), generally require -[namespacing](#column-namespacing), and sometimes require -[aliasing](#table-aliasing). - - -##### Column Namespacing - -When joining tables, column names can become ambiguous. _E.g._, both tables -may have an `id` column. - -```swift -let query = users.join(posts, on: user_id == id) -// assertion failure: ambiguous column 'id' -``` - -We can disambiguate by namespacing `id`. - -```swift -let query = users.join(posts, on: user_id == users[id]) -// SELECT * FROM "users" INNER JOIN "posts" ON ("user_id" = "users"."id") -``` - -Namespacing is achieved by subscripting a [query](#queries) with a [column -expression](#expressions) (_e.g._, `users[id]` above becomes `users.id`). - -> _Note:_ We can namespace all of a table’s columns using `*`. -> -> ```swift -> let query = users.select(users[*]) -> // SELECT "users".* FROM "users" -> ``` - - -##### Table Aliasing - -Occasionally, we need to join a table to itself, in which case we must alias -the table with another name. We can achieve this using the -[query’s](#queries) `alias` function. - -```swift -let managers = users.alias("managers") - -let query = users.join(managers, on: managers[id] == users[managerId]) -// SELECT * FROM "users" -// INNER JOIN ("users") AS "managers" ON ("managers"."id" = "users"."manager_id") -``` - -If query results can have ambiguous column names, row values should be -accessed with namespaced [column expressions](#expressions). In the above -case, `SELECT *` immediately namespaces all columns of the result set. - -```swift -let user = try db.pluck(query) -user[id] // fatal error: ambiguous column 'id' - // (please disambiguate: ["users"."id", "managers"."id"]) - -user[users[id]] // returns "users"."id" -user[managers[id]] // returns "managers"."id" -``` - - -#### Filtering Rows - -SQLite.swift filters rows using a [query’s](#queries) `filter` function with -a boolean [expression](#expressions) (`Expression`). - -```swift -users.filter(id == 1) -// SELECT * FROM "users" WHERE ("id" = 1) - -users.filter([1, 2, 3, 4, 5].contains(id)) -// SELECT * FROM "users" WHERE ("id" IN (1, 2, 3, 4, 5)) - -users.filter(email.like("%@mac.com")) -// SELECT * FROM "users" WHERE ("email" LIKE '%@mac.com') - -users.filter(verified && name.lowercaseString == "alice") -// SELECT * FROM "users" WHERE ("verified" AND (lower("name") == 'alice')) - -users.filter(verified || balance >= 10_000) -// SELECT * FROM "users" WHERE ("verified" OR ("balance" >= 10000.0)) -``` - -We can build our own boolean expressions by using one of the many [filter -operators and functions](#filter-operators-and-functions). - -Instead of `filter` we can also use the `where` function which is an alias: - -```swift -users.where(id == 1) -// SELECT * FROM "users" WHERE ("id" = 1) -``` - -##### Filter Operators and Functions - -SQLite.swift defines a number of operators for building filtering predicates. -Operators and functions work together in a type-safe manner, so attempting to -equate or compare different types will prevent compilation. - - -###### Infix Filter Operators - -| Swift | Types | SQLite | -| ----- | -------------------------------- | -------------- | -| `==` | `Equatable -> Bool` | `=`/`IS`* | -| `!=` | `Equatable -> Bool` | `!=`/`IS NOT`* | -| `>` | `Comparable -> Bool` | `>` | -| `>=` | `Comparable -> Bool` | `>=` | -| `<` | `Comparable -> Bool` | `<` | -| `<=` | `Comparable -> Bool` | `<=` | -| `~=` | `(Interval, Comparable) -> Bool` | `BETWEEN` | -| `&&` | `Bool -> Bool` | `AND` | -| `\|\|`| `Bool -> Bool` | `OR` | - -> *When comparing against `nil`, SQLite.swift will use `IS` and `IS NOT` -> accordingly. - - -###### Prefix Filter Operators - -| Swift | Types | SQLite | -| ----- | ------------------ | ------ | -| `!` | `Bool -> Bool` | `NOT` | - - -###### Filtering Functions - -| Swift | Types | SQLite | -| ---------- | ----------------------- | ------- | -| `like` | `String -> Bool` | `LIKE` | -| `glob` | `String -> Bool` | `GLOB` | -| `match` | `String -> Bool` | `MATCH` | -| `contains` | `(Array, T) -> Bool` | `IN` | - - - - - -#### Sorting Rows - -We can pre-sort returned rows using the [query’s](#queries) `order` function. - -_E.g._, to return users sorted by `email`, then `name`, in ascending order: - -```swift -users.order(email, name) -// SELECT * FROM "users" ORDER BY "email", "name" -``` - -The `order` function takes a list of [column expressions](#expressions). - -`Expression` objects have two computed properties to assist sorting: `asc` -and `desc`. These properties append the expression with `ASC` and `DESC` to -mark ascending and descending order respectively. - -```swift -users.order(email.desc, name.asc) -// SELECT * FROM "users" ORDER BY "email" DESC, "name" ASC -``` - - -#### Limiting and Paging Results - -We can limit and skip returned rows using a [query’s](#queries) `limit` -function (and its optional `offset` parameter). - -```swift -users.limit(5) -// SELECT * FROM "users" LIMIT 5 - -users.limit(5, offset: 5) -// SELECT * FROM "users" LIMIT 5 OFFSET 5 -``` - - -#### Aggregation - -[Queries](#queries) come with a number of functions that quickly return -aggregate scalar values from the table. These mirror the [core aggregate -functions](#aggregate-sqlite-functions) and are executed immediately against -the query. - -```swift -let count = try db.scalar(users.count) -// SELECT count(*) FROM "users" -``` - -Filtered queries will appropriately filter aggregate values. - -```swift -let count = try db.scalar(users.filter(name != nil).count) -// SELECT count(*) FROM "users" WHERE "name" IS NOT NULL -``` - - - `count` as a computed property on a query (see examples above) returns - the total number of rows matching the query. - - `count` as a computed property on a column expression returns the total - number of rows where that column is not `NULL`. - - ```swift - let count = try db.scalar(users.select(name.count)) // -> Int - // SELECT count("name") FROM "users" - ``` - - - `max` takes a comparable column expression and returns the largest value - if any exists. - - ```swift - let max = try db.scalar(users.select(id.max)) // -> Int64? - // SELECT max("id") FROM "users" - ``` - - - `min` takes a comparable column expression and returns the smallest value - if any exists. - - ```swift - let min = try db.scalar(users.select(id.min)) // -> Int64? - // SELECT min("id") FROM "users" - ``` - - - `average` takes a numeric column expression and returns the average row - value (as a `Double`) if any exists. - - ```swift - let average = try db.scalar(users.select(balance.average)) // -> Double? - // SELECT avg("balance") FROM "users" - ``` - - - `sum` takes a numeric column expression and returns the sum total of all - rows if any exist. - - ```swift - let sum = try db.scalar(users.select(balance.sum)) // -> Double? - // SELECT sum("balance") FROM "users" - ``` - - - `total`, like `sum`, takes a numeric column expression and returns the - sum total of all rows, but in this case always returns a `Double`, and - returns `0.0` for an empty query. - - ```swift - let total = try db.scalar(users.select(balance.total)) // -> Double - // SELECT total("balance") FROM "users" - ``` - -> _Note:_ Expressions can be prefixed with a `DISTINCT` clause by calling the -> `distinct` computed property. -> -> ```swift -> let count = try db.scalar(users.select(name.distinct.count) // -> Int -> // SELECT count(DISTINCT "name") FROM "users" -> ``` - - -## Updating Rows - -We can update a table’s rows by calling a [query’s](#queries) `update` -function with a list of [setters](#setters)—typically [typed column -expressions](#expressions) and values (which can also be expressions)—each -joined by the `<-` operator. - -When an unscoped query calls `update`, it will update _every_ row in the -table. - -```swift -try db.run(users.update(email <- "alice@me.com")) -// UPDATE "users" SET "email" = 'alice@me.com' -``` - -Be sure to scope `UPDATE` statements beforehand using [the `filter` function -](#filtering-rows). - -```swift -let alice = users.filter(id == 1) -try db.run(alice.update(email <- "alice@me.com")) -// UPDATE "users" SET "email" = 'alice@me.com' WHERE ("id" = 1) -``` - -The `update` function returns an `Int` representing the number of updated -rows. - -```swift -do { - if try db.run(alice.update(email <- "alice@me.com")) > 0 { - print("updated alice") - } else { - print("alice not found") - } -} catch { - print("update failed: \(error)") -} -``` - - -## Deleting Rows - -We can delete rows from a table by calling a [query’s](#queries) `delete` -function. - -When an unscoped query calls `delete`, it will delete _every_ row in the -table. - -```swift -try db.run(users.delete()) -// DELETE FROM "users" -``` - -Be sure to scope `DELETE` statements beforehand using -[the `filter` function](#filtering-rows). - -```swift -let alice = users.filter(id == 1) -try db.run(alice.delete()) -// DELETE FROM "users" WHERE ("id" = 1) -``` - -The `delete` function returns an `Int` representing the number of deleted -rows. - -```swift -do { - if try db.run(alice.delete()) > 0 { - print("deleted alice") - } else { - print("alice not found") - } -} catch { - print("delete failed: \(error)") -} -``` - - -## Transactions and Savepoints - -Using the `transaction` and `savepoint` functions, we can run a series of -statements in a transaction. If a single statement fails or the block throws -an error, the changes will be rolled back. - -```swift -try db.transaction { - let rowid = try db.run(users.insert(email <- "betty@icloud.com")) - try db.run(users.insert(email <- "cathy@icloud.com", managerId <- rowid)) -} -// BEGIN DEFERRED TRANSACTION -// INSERT INTO "users" ("email") VALUES ('betty@icloud.com') -// INSERT INTO "users" ("email", "manager_id") VALUES ('cathy@icloud.com', 2) -// COMMIT TRANSACTION -``` - -> _Note:_ Transactions run in a serial queue. - - -## Altering the Schema - -SQLite.swift comes with several functions (in addition to `Table.create`) for -altering a database schema in a type-safe manner. - - -### Renaming Tables - -We can build an `ALTER TABLE … RENAME TO` statement by calling the `rename` -function on a `Table` or `VirtualTable`. - -```swift -try db.run(users.rename(Table("users_old"))) -// ALTER TABLE "users" RENAME TO "users_old" -``` - - -### Adding Columns - -We can add columns to a table by calling `addColumn` function on a `Table`. -SQLite.swift enforces -[the same limited subset](https://www.sqlite.org/lang_altertable.html) of -`ALTER TABLE` that SQLite supports. - -```swift -try db.run(users.addColumn(suffix)) -// ALTER TABLE "users" ADD COLUMN "suffix" TEXT -``` - - -#### Added Column Constraints - -The `addColumn` function shares several of the same [`column` function -parameters](#column-constraints) used when [creating -tables](#creating-a-table). - - - `check` attaches a `CHECK` constraint to a column definition in the form - of a boolean expression (`Expression`). (See also the `check` - function under [Table Constraints](#table-constraints).) - - ```swift - try db.run(users.addColumn(suffix, check: ["JR", "SR"].contains(suffix))) - // ALTER TABLE "users" ADD COLUMN "suffix" TEXT CHECK ("suffix" IN ('JR', 'SR')) - ``` - - - `defaultValue` adds a `DEFAULT` clause to a column definition and _only_ - accepts a value matching the column’s type. This value is used if none is - explicitly provided during [an `INSERT`](#inserting-rows). - - ```swift - try db.run(users.addColumn(suffix, defaultValue: "SR")) - // ALTER TABLE "users" ADD COLUMN "suffix" TEXT DEFAULT 'SR' - ``` - - > _Note:_ Unlike the [`CREATE TABLE` constraint](#table-constraints), - > default values may not be expression structures (including - > `CURRENT_TIME`, `CURRENT_DATE`, or `CURRENT_TIMESTAMP`). - - - `collate` adds a `COLLATE` clause to `Expression` (and - `Expression`) column definitions with [a collating - sequence](https://www.sqlite.org/datatype3.html#collation) defined in the - `Collation` enumeration. - - ```swift - try db.run(users.addColumn(email, collate: .nocase)) - // ALTER TABLE "users" ADD COLUMN "email" TEXT NOT NULL COLLATE "NOCASE" - - try db.run(users.addColumn(name, collate: .rtrim)) - // ALTER TABLE "users" ADD COLUMN "name" TEXT COLLATE "RTRIM" - ``` - - - `references` adds a `REFERENCES` clause to `Int64` (and `Int64?`) column - definitions and accepts a table or namespaced column expression. (See the - `foreignKey` function under [Table Constraints](#table-constraints) for - non-integer foreign key support.) - - ```swift - try db.run(posts.addColumn(userId, references: users, id) - // ALTER TABLE "posts" ADD COLUMN "user_id" INTEGER REFERENCES "users" ("id") - ``` - - -### Indexes - - -#### Creating Indexes - -We can build -[`CREATE INDEX` statements](https://www.sqlite.org/lang_createindex.html) -by calling the `createIndex` function on a `SchemaType`. - -```swift -try db.run(users.createIndex(email)) -// CREATE INDEX "index_users_on_email" ON "users" ("email") -``` - -The index name is generated automatically based on the table and column -names. - -The `createIndex` function has a couple default parameters we can override. - - - `unique` adds a `UNIQUE` constraint to the index. Default: `false`. - - ```swift - try db.run(users.createIndex(email, unique: true)) - // CREATE UNIQUE INDEX "index_users_on_email" ON "users" ("email") - ``` - - - `ifNotExists` adds an `IF NOT EXISTS` clause to the `CREATE TABLE` - statement (which will bail out gracefully if the table already exists). - Default: `false`. - - ```swift - try db.run(users.createIndex(email, ifNotExists: true)) - // CREATE INDEX IF NOT EXISTS "index_users_on_email" ON "users" ("email") - ``` - - -#### Dropping Indexes - -We can build -[`DROP INDEX` statements](https://www.sqlite.org/lang_dropindex.html) by -calling the `dropIndex` function on a `SchemaType`. - -```swift -try db.run(users.dropIndex(email)) -// DROP INDEX "index_users_on_email" -``` - -The `dropIndex` function has one additional parameter, `ifExists`, which -(when `true`) adds an `IF EXISTS` clause to the statement. - -```swift -try db.run(users.dropIndex(email, ifExists: true)) -// DROP INDEX IF EXISTS "index_users_on_email" -``` - - -### Dropping Tables - -We can build -[`DROP TABLE` statements](https://www.sqlite.org/lang_droptable.html) -by calling the `dropTable` function on a `SchemaType`. - -```swift -try db.run(users.drop()) -// DROP TABLE "users" -``` - -The `drop` function has one additional parameter, `ifExists`, which (when -`true`) adds an `IF EXISTS` clause to the statement. - -```swift -try db.run(users.drop(ifExists: true)) -// DROP TABLE IF EXISTS "users" -``` - - -### Migrations and Schema Versioning - -You can add a convenience property on `Connection` to query and set the -[`PRAGMA user_version`](https://sqlite.org/pragma.html#pragma_user_version). - -This is a great way to manage your schema’s version over migrations. - -```swift -extension Connection { - public var userVersion: Int32 { - get { return Int32(try! scalar("PRAGMA user_version") as! Int64)} - set { try! run("PRAGMA user_version = \(newValue)") } - } -} -``` - -Then you can conditionally run your migrations along the lines of: - -```swift -if db.userVersion == 0 { - // handle first migration - db.userVersion = 1 -} -if db.userVersion == 1 { - // handle second migration - db.userVersion = 2 -} -``` - -For more complex migration requirements check out the schema management -system [SQLiteMigrationManager.swift][]. - -## Custom Types - -SQLite.swift supports serializing and deserializing any custom type as long -as it conforms to the `Value` protocol. - -```swift -protocol Value { - typealias Datatype: Binding - class var declaredDatatype: String { get } - class func fromDatatypeValue(datatypeValue: Datatype) -> Self - var datatypeValue: Datatype { get } -} -``` - -The `Datatype` must be one of the basic Swift types that values are bridged -through before serialization and deserialization (see [Building Type-Safe SQL -](#building-type-safe-sql) for a list of types). - -> ⚠ _Note:_ `Binding` is a protocol that SQLite.swift uses internally to -> directly map SQLite types to Swift types. **Do _not_** conform custom types -> to the `Binding` protocol. - - -### Date-Time Values - -In SQLite, `DATETIME` columns can be treated as strings or numbers, so we can -transparently bridge `Date` objects through Swift’s `String` types. - -We can use these types directly in SQLite statements. - -```swift -let published_at = Expression("published_at") - -let published = posts.filter(published_at <= Date()) -// SELECT * FROM "posts" WHERE "published_at" <= '2014-11-18T12:45:30.000' - -let startDate = Date(timeIntervalSince1970: 0) -let published = posts.filter(startDate...Date() ~= published_at) -// SELECT * FROM "posts" WHERE "published_at" BETWEEN '1970-01-01T00:00:00.000' AND '2014-11-18T12:45:30.000' -``` - - -### Binary Data - -We can bridge any type that can be initialized from and encoded to `Data`. - -```swift -extension UIImage: Value { - public class var declaredDatatype: String { - return Blob.declaredDatatype - } - public class func fromDatatypeValue(blobValue: Blob) -> UIImage { - return UIImage(data: Data.fromDatatypeValue(blobValue))! - } - public var datatypeValue: Blob { - return UIImagePNGRepresentation(self)!.datatypeValue - } - -} -``` - -> _Note:_ See the [Archives and Serializations Programming Guide][] for more -> information on encoding and decoding custom types. - - -[Archives and Serializations Programming Guide]: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Archiving/Archiving.html - -## Codable Types - -[Codable types][Encoding and Decoding Custom Types] were introduced as a part -of Swift 4 to allow serializing and deserializing types. SQLite.swift supports -the insertion, updating, and retrieval of basic Codable types. - -[Encoding and Decoding Custom Types]: https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types - -### Inserting Codable Types - -Queries have a method to allow inserting an [Encodable][] type. - -```swift -struct User: Encodable { - let name: String -} -try db.run(users.insert(User(name: "test"))) - -``` - -There are two other parameters also available to this method: - -- `userInfo` is a dictionary that is passed to the encoder and made available - to encodable types to allow customizing their behavior. - -- `otherSetters` allows you to specify additional setters on top of those - that are generated from the encodable types themselves. - -[Encodable]: https://developer.apple.com/documentation/swift/encodable - -### Updating Codable Types - -Queries have a method to allow updating an Encodable type. - -```swift -try db.run(users.filter(id == userId).update(user)) - -``` - -> ⚠ Unless filtered, using the update method on an instance of a Codable -> type updates all table rows. - -There are two other parameters also available to this method: - -- `userInfo` is a dictionary that is passed to the encoder and made available - to encodable types to allow customizing their behavior. - -- `otherSetters` allows you to specify additional setters on top of those - that are generated from the encodable types themselves. - -### Retrieving Codable Types - -Rows have a method to decode a [Decodable][] type. - -```swift -let loadedUsers: [User] = try db.prepare(users).map { row in - return try row.decode() -} -``` - -You can also create a decoder to use manually yourself. This can be useful -for example if you are using the -[Facade pattern](https://en.wikipedia.org/wiki/Facade_pattern) to hide -subclasses behind a super class. For example, you may want to encode an Image -type that can be multiple different formats such as PNGImage, JPGImage, or -HEIFImage. You will need to determine the correct subclass before you know -which type to decode. - -```swift -enum ImageCodingKeys: String, CodingKey { - case kind -} - -enum ImageKind: Int, Codable { - case png, jpg, heif -} - -let loadedImages: [Image] = try db.prepare(images).map { row in - let decoder = row.decoder() - let container = try decoder.container(keyedBy: ImageCodingKeys.self) - switch try container.decode(ImageKind.self, forKey: .kind) { - case .png: - return try PNGImage(from: decoder) - case .jpg: - return try JPGImage(from: decoder) - case .heif: - return try HEIFImage(from: decoder) - } -} -``` - -Both of the above methods also have the following optional parameter: - -- `userInfo` is a dictionary that is passed to the decoder and made available - to decodable types to allow customizing their behavior. - -[Decodable]: https://developer.apple.com/documentation/swift/decodable - -### Restrictions - -There are a few restrictions on using Codable types: - -- The encodable and decodable objects can only use the following types: - - Int, Bool, Float, Double, String - - Nested Codable types that will be encoded as JSON to a single column -- These methods will not handle object relationships for you. You must write - your own Codable and Decodable implementations if you wish to support this. -- The Codable types may not try to access nested containers or nested unkeyed - containers -- The Codable types may not access single value containers or unkeyed - containers -- The Codable types may not access super decoders or encoders - -## Other Operators - -In addition to [filter operators](#filtering-infix-operators), SQLite.swift -defines a number of operators that can modify expression values with -arithmetic, bitwise operations, and concatenation. - - -###### Other Infix Operators - -| Swift | Types | SQLite | -| ----- | -------------------------------- | -------- | -| `+` | `Number -> Number` | `+` | -| `-` | `Number -> Number` | `-` | -| `*` | `Number -> Number` | `*` | -| `/` | `Number -> Number` | `/` | -| `%` | `Int -> Int` | `%` | -| `<<` | `Int -> Int` | `<<` | -| `>>` | `Int -> Int` | `>>` | -| `&` | `Int -> Int` | `&` | -| `\|` | `Int -> Int` | `\|` | -| `+` | `String -> String` | `\|\|` | - -> _Note:_ SQLite.swift also defines a bitwise XOR operator, `^`, which -> expands the expression `lhs ^ rhs` to `~(lhs & rhs) & (lhs | rhs)`. - - -###### Other Prefix Operators - -| Swift | Types | SQLite | -| ----- | ------------------ | ------ | -| `~` | `Int -> Int` | `~` | -| `-` | `Number -> Number` | `-` | - - -## Core SQLite Functions - -Many of SQLite’s [core functions](https://www.sqlite.org/lang_corefunc.html) -have been surfaced in and type-audited for SQLite.swift. - -> _Note:_ SQLite.swift aliases the `??` operator to the `ifnull` function. -> -> ```swift -> name ?? email // ifnull("name", "email") -> ``` - - -## Aggregate SQLite Functions - -Most of SQLite’s -[aggregate functions](https://www.sqlite.org/lang_aggfunc.html) have been -surfaced in and type-audited for SQLite.swift. - -## Date and Time functions - -SQLite's [date and time](https://www.sqlite.org/lang_datefunc.html) -functions are available: - -```swift -DateFunctions.date("now") -// date('now') -Date().date -// date('2007-01-09T09:41:00.000') -Expression("date").date -// date("date") -``` - -## Custom SQL Functions - -We can create custom SQL functions by calling `createFunction` on a database -connection. - -For example, to give queries access to -[`MobileCoreServices.UTTypeConformsTo`][UTTypeConformsTo], we can -write the following: - -```swift -import MobileCoreServices - -let typeConformsTo: (Expression, Expression) -> Expression = ( - try db.createFunction("typeConformsTo", deterministic: true) { UTI, conformsToUTI in - return UTTypeConformsTo(UTI, conformsToUTI) - } -) -``` - -> _Note:_ The optional `deterministic` parameter is an optimization that -> causes the function to be created with -> [`SQLITE_DETERMINISTIC`](https://www.sqlite.org/c3ref/c_deterministic.html). - -Note `typeConformsTo`’s signature: - -```swift -(Expression, Expression) -> Expression -``` - -Because of this, `createFunction` expects a block with the following -signature: - -```swift -(String, String) -> Bool -``` - -Once assigned, the closure can be called wherever boolean expressions are -accepted. - -```swift -let attachments = Table("attachments") -let UTI = Expression("UTI") - -let images = attachments.filter(typeConformsTo(UTI, kUTTypeImage)) -// SELECT * FROM "attachments" WHERE "typeConformsTo"("UTI", 'public.image') -``` - -> _Note:_ The return type of a function must be -> [a core SQL type](#building-type-safe-sql) or [conform to `Value`](#custom-types). - -We can create loosely-typed functions by handling an array of raw arguments, -instead. - -```swift -db.createFunction("typeConformsTo", deterministic: true) { args in - guard let UTI = args[0] as? String, conformsToUTI = args[1] as? String else { return nil } - return UTTypeConformsTo(UTI, conformsToUTI) -} -``` - -Creating a loosely-typed function cannot return a closure and instead must be -wrapped manually or executed [using raw SQL](#executing-arbitrary-sql). - -```swift -let stmt = try db.prepare("SELECT * FROM attachments WHERE typeConformsTo(UTI, ?)") -for row in stmt.bind(kUTTypeImage) { /* ... */ } -``` - -[UTTypeConformsTo]: https://developer.apple.com/documentation/coreservices/1444079-uttypeconformsto - -## Custom Collations - -We can create custom collating sequences by calling `createCollation` on a -database connection. - -```swift -try db.createCollation("NODIACRITIC") { lhs, rhs in - return lhs.compare(rhs, options: .diacriticInsensitiveSearch) -} -``` - -We can reference a custom collation using the `Custom` member of the -`Collation` enumeration. - -```swift -restaurants.order(collate(.custom("NODIACRITIC"), name)) -// SELECT * FROM "restaurants" ORDER BY "name" COLLATE "NODIACRITIC" -``` - - -## Full-text Search - -We can create a virtual table using the [FTS4 -module](http://www.sqlite.org/fts3.html) by calling `create` on a -`VirtualTable`. - -```swift -let emails = VirtualTable("emails") -let subject = Expression("subject") -let body = Expression("body") - -try db.run(emails.create(.FTS4(subject, body))) -// CREATE VIRTUAL TABLE "emails" USING fts4("subject", "body") -``` - -We can specify a [tokenizer](http://www.sqlite.org/fts3.html#tokenizer) using the `tokenize` parameter. - -```swift -try db.run(emails.create(.FTS4([subject, body], tokenize: .Porter))) -// CREATE VIRTUAL TABLE "emails" USING fts4("subject", "body", tokenize=porter) -``` - -We can set the full range of parameters by creating a `FTS4Config` object. - -```swift -let emails = VirtualTable("emails") -let subject = Expression("subject") -let body = Expression("body") -let config = FTS4Config() - .column(subject) - .column(body, [.unindexed]) - .languageId("lid") - .order(.desc) - -try db.run(emails.create(.FTS4(config)) -// CREATE VIRTUAL TABLE "emails" USING fts4("subject", "body", notindexed="body", languageid="lid", order="desc") -``` - -Once we insert a few rows, we can search using the `match` function, which -takes a table or column as its first argument and a query string as its -second. - -```swift -try db.run(emails.insert( - subject <- "Just Checking In", - body <- "Hey, I was just wondering...did you get my last email?" -)) - -let wonderfulEmails: QueryType = emails.match("wonder*") -// SELECT * FROM "emails" WHERE "emails" MATCH 'wonder*' - -let replies = emails.filter(subject.match("Re:*")) -// SELECT * FROM "emails" WHERE "subject" MATCH 'Re:*' -``` - -### FTS5 - -When linking against a version of SQLite with -[FTS5](http://www.sqlite.org/fts5.html) enabled we can create the virtual -table in a similar fashion. - -```swift -let emails = VirtualTable("emails") -let subject = Expression("subject") -let body = Expression("body") -let config = FTS5Config() - .column(subject) - .column(body, [.unindexed]) - -try db.run(emails.create(.FTS5(config)) -// CREATE VIRTUAL TABLE "emails" USING fts5("subject", "body" UNINDEXED) - -// Note that FTS5 uses a different syntax to select columns, so we need to rewrite -// the last FTS4 query above as: -let replies = emails.filter(emails.match("subject:\"Re:\"*)) -// SELECT * FROM "emails" WHERE "emails" MATCH 'subject:"Re:"*' - -// https://www.sqlite.org/fts5.html#_changes_to_select_statements_ -``` - -## Executing Arbitrary SQL - -Though we recommend you stick with SQLite.swift’s -[type-safe system](#building-type-safe-sql) whenever possible, it is possible -to simply and safely prepare and execute raw SQL statements via a `Database` connection -using the following functions. - - - `execute` runs an arbitrary number of SQL statements as a convenience. - - ```swift - try db.execute(""" - BEGIN TRANSACTION; - CREATE TABLE users ( - id INTEGER PRIMARY KEY NOT NULL, - email TEXT UNIQUE NOT NULL, - name TEXT - ); - CREATE TABLE posts ( - id INTEGER PRIMARY KEY NOT NULL, - title TEXT NOT NULL, - body TEXT NOT NULL, - published_at DATETIME - ); - PRAGMA user_version = 1; - COMMIT TRANSACTION; - """ - ) - ``` - - - `prepare` prepares a single `Statement` object from a SQL string, - optionally binds values to it (using the statement’s `bind` function), - and returns the statement for deferred execution. - - ```swift - let stmt = try db.prepare("INSERT INTO users (email) VALUES (?)") - ``` - - Once prepared, statements may be executed using `run`, binding any - unbound parameters. - - ```swift - try stmt.run("alice@mac.com") - db.changes // -> {Some 1} - ``` - - Statements with results may be iterated over, using the columnNames if - useful. - - ```swift - let stmt = try db.prepare("SELECT id, email FROM users") - for row in stmt { - for (index, name) in stmt.columnNames.enumerated() { - print ("\(name):\(row[index]!)") - // id: Optional(1), email: Optional("alice@mac.com") - } - } - ``` - - - `run` prepares a single `Statement` object from a SQL string, optionally - binds values to it (using the statement’s `bind` function), executes, - and returns the statement. - - ```swift - try db.run("INSERT INTO users (email) VALUES (?)", "alice@mac.com") - ``` - - - `scalar` prepares a single `Statement` object from a SQL string, - optionally binds values to it (using the statement’s `bind` function), - executes, and returns the first value of the first row. - - ```swift - let count = try db.scalar("SELECT count(*) FROM users") as! Int64 - ``` - - Statements also have a `scalar` function, which can optionally re-bind - values at execution. - - ```swift - let stmt = try db.prepare("SELECT count (*) FROM users") - let count = try stmt.scalar() as! Int64 - ``` - - -## Logging - -We can log SQL using the database’s `trace` function. - -```swift -#if DEBUG - db.trace { print($0) } -#endif -``` - - -[ROWID]: https://sqlite.org/lang_createtable.html#rowid -[SQLiteMigrationManager.swift]: https://github.com/garriguv/SQLiteMigrationManager.swift diff --git a/ios/libs/Sqlite/Documentation/Planning.md b/ios/libs/Sqlite/Documentation/Planning.md deleted file mode 100644 index 5f885de..0000000 --- a/ios/libs/Sqlite/Documentation/Planning.md +++ /dev/null @@ -1,38 +0,0 @@ -# SQLite.swift Planning - -This document captures both near term steps (aka Roadmap) and feature -requests. The goal is to add some visibility and guidance for future -additions and Pull Requests, as well as to keep the Issues list clear of -enhancement requests so that bugs are more visible. - -> ⚠ This document is currently not actively maintained. See -> the [0.13.0 milestone](https://github.com/stephencelis/SQLite.swift/issues?q=is%3Aopen+is%3Aissue+milestone%3A0.13.0) -> on Github for additional information about planned features for the next release. - -## Roadmap - -_Lists agreed upon next steps in approximate priority order._ - -## Feature Requests - -_A gathering point for ideas for new features. In general, the corresponding -issue will be closed once it is added here, with the assumption that it will -be referred to when it comes time to add the corresponding feature._ - -### Features - - * encapsulate ATTACH DATABASE / DETACH DATABASE as methods, per - [#30](https://github.com/stephencelis/SQLite.swift/issues/30) - * provide separate threads for update vs read, so updates don't block reads, - per [#236](https://github.com/stephencelis/SQLite.swift/issues/236) - * expose triggers, per - [#164](https://github.com/stephencelis/SQLite.swift/issues/164) - -## Suspended Feature Requests - -_Features that are not actively being considered, perhaps because of no clean -type-safe way to implement them with the current Swift, or bugs, or just -general uncertainty._ - - * provide a mechanism for INSERT INTO multiple values, per - [#168](https://github.com/stephencelis/SQLite.swift/issues/168) diff --git a/ios/libs/Sqlite/Documentation/Resources/installation@2x.png b/ios/libs/Sqlite/Documentation/Resources/installation@2x.png deleted file mode 100644 index 6b31f459348e97208dbc8b564884a0d065c803d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 312530 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 z zfZbVBsZSt`mYwf>0A*zgLj;1$Sfr0v4{d|cj!dMuy#`K4QmutXlCsBJ>xJrlDpk

Ut~liU?b@moZ*S!?LZ`jdp)UeZbpK0$o-!CT{kPFPXFBX8V21q4K9O(i%&*zJQZ z)}@)RQ!NqS0=X=(SwrM|2pvh3d#u|L>wSAw5b=BukAPq%hL687mD&Jy;UmHT1PKx? zoRAfY)nh9D0u{OW`MbT#O72BYR_RWh*66q{TWcxTrjw51hsS&7i#6JvpM;jSk0U-& zt0m1$*sR_(>7PmPyY?YF{|Wy3_UWmCg`2OlbIpK1fw~wi_id0vG0;FKV7r4^#Ada> z@dQ|x^p>6yMM%NnI+tdMeENL<)L@B;xu+qmoooxvaDT`84y+h*`0?Y1>>}?_y>Wt~ zRYe3U8rs!SQ5G2)8K3)&c#fRs>+K?4u^zAM#pYazBF-5V9bFWVioLYe%G`Rf*r#+1S~NED;gvPog6HU$1QfTVf08qVyF=x()~u!5Bx zwNEw1=akz<1oXTGU-!PBRxz(J7uv8<=d0~$HYOjxN( zC@gh9azY+BlsM?szcGD%hl1F|K92Sq_?xb(`JGai{`F$bikbH|7{F$0s^JNvY zL}?{kf9DAaH;rPRVN)D}eCE*eOR-+cVkJwDp+^C(W|l4u#its~ayxV~P4A%^mmjI*6dVr)syeft z8QkIO{4|{AU82pUicLD6f=SiY3@|s{`loAOdwP1(krG9FaM%G_CkqwYByOH(;7oCu z*Yn-POywahEBT=_VL>IN@bzu@#?YUxGKR8fW91$t7XHTZP==QPfbvq; zdJ%K8kteYB)~&@r=^r zT(T;A30~@rtX9o-o-?6B^BV+V0CDbf6MpO!0>Y5>?)T|u5GmWe3byLV>&cC)%})#3 z(t+XzSlZ=yCV&JF2ni9}L3xk2+3j7Q&;I%f3ARGJ@8YAklDx@NgBa#bMfWImwFO?r zKt0XXFFW)7$TpPg@S|1uvm)o}XjJ}1{C(Oe*~IOlN<$kOvRU z1T5uvG+iHj$~rVPa~T=JE4a&~xZZMZm-7Q9f~r4-(?B%kbxQ0-u}4fy06@o&)oE5s zBU!UJyYFVG`Qki*dwBp;N4Yd8SovV#JPyM+^XDW1Q%ahuoU5aCfaRl{Tgp+>5|dq- z0xJ)Xn$A%XOA_1~Ie`G(JV)(yJ0W(GtMd6F4Msdu!qH@xJQe<$l+TUuPab0(<&Tz& zl{x6#Y4+;XT_}ZN=Q>^E`Ry7?N=|+BaV2>I_FRm|wj)0sc6iR zM_0S5!DOD^F~?}NMx&V1> zsyfiRTXM!^;%_MBY%1%H<(E%v9^uCY<<+P1(CqYHfQ6m4UUJ{k3LK@+@=2AB3zHFs{9Ueh?7aOyO-t1b@>@9MHkebAd~eDc|);xn#rNUwTz@ zO@T7-iQRtJ4yH1*t5_8)OK7Tfi4~C}s(1L^>}7i9^<^BhD+xKDaMfHS%S{4l0ge%9 z)(+Ko6`z3`o_ADSW#W9@G(kH8TO)p7d~se`E44Ook6GIf-;gUQ3Nt%|0pGvu$@v$wpmw$fTSP=)# zOg5LRbRDfyk$u6yh)*Qg#r?cZ&Fsj#PG7cc^dNdX;GgcVAOaWr`0LYypf0*AS<5xZ zWv$(f`QE#Dx{@WZgTwf=xIq&2>Dmffx3gEhXrcXeVu`;}`HqMDt#N-A_@VucXOI&n zal%#q$->*Wga7d?ZFs@eBfWJ$pwh7Eg7-F~-RDvX*s4{0GZ+Qe_v7MI#umBz2%`EAm z=sN1`mQUqFeJq{uHXip5+~@eKs$E4zvJNwPevO8kNa zm-qTB&#!AUrFQR)2z zsQ^2V#z_mjKM0XBeGyF?I?lp73O>7~y1z7eK-7alC&7V{(xO>-?eEU$neJbXGhMu% zf2#<^Qf1)yH12_#cFN!=`(TC^CsQx@D^$YJ63O0~>PxzoXC-HS;7=al!k&(Sq0_+Q zSk#$Q+KMkf-Hyu|+De&|S&BvQ*pS3zIv0H%m{xyB=(B(Qri-X^xow7A zjhHVtk$yvRV@DUExPMx-1%aIEqh78WXH!ic?nW_*02>&UGY#%YydvRw7U zin5qrfkm+Trvvhd&x~D)MU!j^uD}6$8XsqY3`Boz!Jh5FGWT*@kui+u^$|gOjR*Pf zU%zr#udsCbvwA(<93GmHlTnhBi{)v%d3ZG0YyewUFb&91jLI`HF$@-KyQT2`YbuH0 zoxA+qN0BmgzICAyJJ1Hw%9l6>0o#^ z1udboOA^y1aU4XH{_$ z{GG<)R9~&<>Z&4oYIp<`iIcl{Tu@2gS1}i{)~8!J^;!M*H_Yt*B>gs*WRKtR87)=0;$9LurUC+v zoWHE8ObBWi7A+Pg2MX2g&M-R{SIC^nydC+NcZjITViHy^TG@>sK z62p%w1tB+i{i8JyMVk+#`pr(}U!B6Hvy^HvO6&7xq-e!yZcswRw2J8L@X&=TT^+u! z83DFp#>6jM=lQ|)c(bi)VPWttprukJs`mDFULGE)g27EO5-!K%Z(lZ204b|YR^pt= zj@N^%PYxuc%LZp7;>#^c;p86?rXTFK|I~+RFJj3T0Xhi##E@|xMR|GisLRp_Yi?UH z%vpO){kyxn!AG;;Urg|=3MK81N3jmGaR~`~3Sj-YAupUyKP3NY%=hr=^@y4?XC)~e z{IM>ZYnRhi`<#3yWrHmpUMoD<(;nT~_9KhNI7xLD@0Tw$BsRC$P4Ab!RkO#T{eBW} zGtA;{J(r*Kzv1JD&L|v_^`|O*O+QB<$dZFh?nLVu*w*XThO$IGW*B~LUAwG}Ni5eI zkH%R(lQExE<`Uz-xz|Xs#%QXH7|6tjdAlgD1ia9eHSO|>KR-e`8@WAuT;KCm|5<(1 zK3#Hnr3?n}s&{x!SEV`7S?>Th9}R?Xn1iZ>V_OUm*+clBs?c5Rzt%=oyoETabGpn! z8IsC@=56d9Y-rB{WG$}lWqnx=E09 z`6Rm(k>BHJ6*s=$5nE^Ng7t)FvuZ9PeZ0(j-Sc68TDN)jozGRBAFEIKcUdKr{x~qq zJ!dV=Ga>GJ^K+BTt}pLB!eO?L(X5_`&!YW6bq}#{)Gi=e@7o(2}Z^_S+Jwjd?ZAXwx?% z2h(N|Pv7Jip@!`L|vu>rdfrL{6Rd!hzLr+z8hUx-oPTIkTH%QuXL5-SXs{;&ro6&38!SL6IBVUiXQ=&m=PRjJe} zk)uFELrYIf=5jjbak~OnKKJ+cC(rEQh4{~x;R1+`MJ}32DU_KV(auvU?6>HXhMEgH z2;@10sVXSE%Yk@r2g_BfP)nZ^i+t961990u3cl_Zf-ryFat-tw%|(`N9WAxNLvSEW zpyjBBi;wQl;nZ8aC3Bo(e48_vsck`M_4Joh35`vY&2a?XOMbPPzHS`H`z-hs{qsoP zV7Gaf34Zh&0XFSBrJG5UDvx~VXB+!m3Mv!-$a7$$U)FJIIZ*$!VAcyBqxQ3?1<~H( zTgJGweo||`M~D4FI7=%i7-m1;IkVI9AUN$j0-z*jK@$K-kBN-&81s!>{X+h!HV;_d zE$qhn`g(JT7G!GXXbt$tPK0#C?=7)YrPCe~hPh&RKRGFbvr)r#LY_TZTmv`jOv)Jd zHtyN!$L}GFbjWR|(W~keH?@Dg7_Q0gR1|*Ref&6G>sW(F+N5O{s~#KI3p%lWS7>`D=fp}SJqs3)ZAtUdO9l~ayzxbuZwku0*Uq2lMp z?Ge$odnEqr^@${{Qln!}q^?feJD`HD4)uxXaV0PZHNi%;KI;{La6 z3N1uTBGG;&NjF`~)BUwo_2$}cn!=MUbEcS)NQ0c8O`@0=V5 zbucM~#$Udut^B4L>Ab)xZ%(ZDT~BE>zW$xK)?PTXg7*%ZNlilvuADk%K+ifbp~HJT zp+s8(=n>-su#En-L*17gN}atcbsy0dYD=#uYzV2x>-|2yhKEbi#_b4yV>Ttgr>C## z=@ZT1@g}+5z3lD%NG)jVU?|lLHach+7*>`D)h(#tip>^Lv%`cNNjJB#lPGYNJve$z6tb)q%>9`a?HMpL@ghsCMS`*)wsy2=7>A$?6w1*1gwBUHC0GViKe7KooxQ z%;-k^Hk~I8MVB8y91n4!Qs$9`1Y>%acHYMw`AK$j44tA@-P`KojSnZ35>zNyhl$T7iZ0io6M+r&O_MZ4f5B0Y4~r!E<_jn4(3wt{7|NNn8i?d6XDdgau}#bQpB*>6WM&| zy#JBd0j+#N+*pz2FFFAz6L>qZml{QS-b{jRi09ENR?|`J`2$lTw7={Ld)EK0=jv7m z3#Wuvl~VuIDa(YED|afzSY=awK*8HPcQPJv(y-Cl_V!V98OdTJ^q240c$Euf)k~xl zl@nBnxk6*&%1cu6+!8}fTJDp%QBV-uJPwS7pve$Hr1wIWaQR~$@jw@p?&EcdHk!c% zx&A|2_WzLYRMji?XwJ`V|5>dR5z_6S{TiQX-T81-vBd73O>M9hPl%vC6y*i@1wdo6qFxP(5jCO9~&``P>abN@Gd7pAu47bl`$Kjppm0WrHf>43U0(MeVQqGr=Eul2(W~5&yabs4^DQP1x1E7>~YZ}g0o&L zF;qYK%Z0uKvgH~NF`KgUKit~|qM;dlyD+siVv zLsMnf=VUSE%0xAC zwfWyA2y6ED6miu&y>aAV_)eoBC%f#sJWC6YRuf2G_aPM< z(ZWon-(eFEg8Kx`aWG5^LJv#E6CN4)?(U9`o}N5VjZk;GxvkB^-F@ZGYm+YRp%}>38K@od_51Xf)Rs9nwzcSduG2i*e`z4m<=)3*)jQE zraLbbO48e2;*S0yvaMa%hm6!a>3-9FWJ4D*<&Ir2O_gjt)T0KV*Wg}W#izLM)tluI z5v)*-*7iW(RDH79rEuUnO`#Nif*{c6p=ogN&y&xB)MGO2P4T zZtF0gC6MdJX1|CeBu&W{)YDfX%W(aS6cv57cU4K1d-mm=S~qh4C_dS}UwUh)6Y#s5 zBns$blW6c5&b$9jtSjQ{#>+)CG0qi=$D#$_1?>~Fo4WaVMSVW~P}B=A(%FmcdIG9- z9&h{|t*q10QB$!c3|px4c(Ll2S^BtcSQ?2g!DpUS}2`j)vUKHRHBA|D#A@;^`R>Ny!$$Uu9ux zguFwKg~azdG4aQj2&GhSA{x{U{viKOmWH;IdJ8$+GotG%wF%^S$rP~a3RqG*iy93G z;rx&}eeN$zlr#!1Bmk##RXW^naj*ol1hd4mWMBkgp!VP(WVs15pu2j`Jr~~d`j%TK zqlTW7qF;A3Rz!q(c!Gj|Zne^iGIE!Ry*mb!w#$qEiNqB0(Yu3Yt)xOfM%w9}^J%nN zs@~f5n%EXRR^@G-^a$@d?e`oWGmxUSUNv#yim`T&`yV>kYZw2Pf2IFXyPg0 z?&sNEyLPQr3-5YM^_8Qotx{(1ug=ePK<<%sR4w`IKos7f5M25sE*4jz42}dp&>3q2 zE{fLdzGp4|F{MQO_A=}3Bv5(n%i~y6TivN8)J;%{hy_G61_-qkorEm2VPY)Wt2n*? z&g=bmMO84U)?nWWnT^?K+TuRx%^`5&+xg)|%Dw+8tmo(ZBbjA0iGHY30&0y9{2S1- zC_&oJ>|$A}PJiQxFMo^K=tih6XH(nrZ-|nkmZhX;$7b5)v|EcD`TUdRbVt`gJr7QA zbH-Kk2G*e7yM|JwNg++{WiV?-$F`-l8AZlT`0Bx6d#j(_`IS*fUugxb=Rj4Qk3zW z&{^kc_l@+zc(8_rnyFU3M8VP>LHuiTw8fHn$DUeiBkBdpL1+#%IRSuZ?tYn%`gL68p zs`njKoA|~}VFo4BE7QD>JZuM}dEP>Zj2$e!3=!%DZY6Gco4`Doa8?$nXrqTlueBPz z@jrjQw9*KBxh2@Sxx8;d;9_OX>vND5I}bL%DM)FEoD4`Sv$I^x*Un&sP~@We*nXf# zUi?zdgUGmv>g6%PLGspM;rc^G=pV`iwm-jB}G)s94HewEc03Yd>=@?w51NS9!8{wppioUEPcN3{VK=o zcWhipBT#>r^a(?+7L=eeb_AacbqxxS&X#IZb5z}{Kd8k3$}=!V8vYvFXm!wSkNP)1 zzb^PJah5tq`clmTOhp%rb#&p7kQm$}#di(=dGtq}m$Zw~=(}$cVuLO3W$5A2YZ&Zq^zxz-rv)Hsj zp@jl7c;oT*-~0cdu>rqVUdDMRthAD|U9u-RC4Opo+}OX15BFs#iE)KQ`37R2o{^M! zHcRZ1Ua&p9!k*J1^XRyoJ=MFm1a9=ajPZ8p>G>=yeJdytt`!;6_F%bD;xPcxh!65HyrYcEObtX9L~51k37G} zW1`>Bh{#vzK2$|Zj)V_N?H^IlZ;OU->FqoSl<}I6Mc32|a*aCkZ*S)d7|Yb1W78Wq4| zIeN?5U0x?)RME=jIw9NOY}{K-Zl z11_np7f;s>myEs^Gz_~++14lR{0LKL73Jv4?3wO6ldK%fTb&T9b1|^%CIN;zu5j)F zaPA4Mc9vwBT@bqunq430j3uO93*R_8cmmdO)(R`h)-L`_*Mo1gI$4}HPfSQdEJ_R{ zx(a`j=?;>vQ!z`GVXb-NnkCWIf|L=M^*oRd9p^+w>_MnHs>V4Ht2gh*5SVR%rx^Y( z0+g?ydO2N%OXXKDn2R#wGT#qzIg}=u8dGP}1aXq4JXvxO)MIvb*5mGI+a8`rGu3VP zA|7e)SWQlTN3B6RLl>`PJckm-0VW0(n3(%V*Qdm4Lmc!`0u^%D^V_#QdHosqn>(nx z#MNuKuAVhbj_yFCX7`vZtx^HCR0Y{$-C8R6EA$*vCfPutXJ|i^0@1xcZWNOghR7GY zmqae&ZaXu%>GFQSKvZ0UZs#GQu6~FguNp}#J6gRuG!rr!1mhd6?s~QA>gv8RX__>s zc?3{npfHAFLpr~a=siBgw=Y{=6Per|SWKo{ySqg3!^8mj62)8ygYxC=hZcG$xKsk@ z3}0w;+$NAbxNng&bN)vjT~|B=1hu&VrL99b;$Ckl-ClTji0#8(Z~HvPFEd=c4??P) zmc>6y);4vlqhm;THp(}43Qdt&kh*acdg-cZUWJ;&!n9|F!<<{Vuo% z@})mS@zkt!!9@NwF9>?)FQ3G^V%n;Q5FKOXku&J|7QZ_+gAXi>6sDdE+21$YjVR=Z zT9WQJ*yeEUJ81=B*#EQH689{0)*551o#Z&^pR4IpKN?^GxKJj@1D3Q_ZGmLfc-;YtXwcKvLaOB&UmG8c3rHdm=~FqT;V`j3tWPUIkeB~# zf1!o~-0LmdQ;M6=;Kn%Y9Op;$OlNUJfdwXrG);HtTW|V}MeJ}jcPzSGBtNTP=*x}O ze3TI7%HXk~6OyGMYlu~07fJr}ieJ9S5b*C&Wt3cwQI`k+a3~kT`^5n`uw+B6V9+V) zQhV&JnamRTpX%P}j4k+lVBt1@jHH|;PgJAQTcu4kf2M-RhHUk&iTR5%eV!=}kY6@X4W^^V_skff#P;6y)XYFE=`H zx!r#+|GNSwWC+9yfXm}~bbL$!6sHe21{Iu7;T};R@U@vXzEyExIR3NH0Q}#C{`(LA z`g%*c zxD5#P2Lmq(8f@Cj_mu^efw2mN$%Qce>9Z-2+ixwBBa4EDR#;Rd0P-~dX(1A2$`$`d zF9d;V@Gx}k9#jV+YU;f${qO(5Mp;>|Hjb~YsPttcqcQ1I*;1qStk&6K{vsS2wtY&Z zW$;fy{865V3xYYtV4QlI4T^r`!3*ju`Ip@Zo~84IRq3j&H&&>|56Nowx%LhQ(f`R`E!giF35na9Y*XA@kFB|O)QeaB135cLTIJ7pd>KyF9#v8l&7&^+@2LizZ2v3X8wNZeXB!&J&IM@Sh<6>b*B)<^^1{AFVi`hKSVgx73qBDo zi5xodWUPpPkPr+i4O~@UO$=J8S~4l8;VaB|I|tJ);|Zol%TO~TT8y6GIAoWxA)PW8 zA!$W?NK^&dWfVVP(KaFl{F<0NqnVtb?#wQX5p7PCt(VU7q*FAYo{(16twX}doMs1u1@^JYG) zaUvmGQ$j-tIEpgafuxl%RtOK&ZU;-zK#_Q4`lbN!Z&~~ARk4*i^a}&sraT!TS1~aW zrOiX>z0#tXZ&Sl&ugD0Pzd5e?E=#W%rzBN!1rOP$s&BZr3bkAP0*zLXrX~k7p3f>U zpb^4bMnKQHbCIuSsXvaX+Lv3WaE7Kti->?q-};35SR{W&$Zy<6G>}w^l-w_VFD0Ra zgaRqoB)M%tgBZD$`+b4IqSUdj9tueyP){(B(O{9dx&>LU=u}YHvMb=O4vr9n!vD`! z89260Uz(T>s$?QZxyaO3CB$?&3O%6XM2k%64LQ*&5|?D&95=D~cqrDj2i}k^t9|wD zMhdl{Pz{-nBo{$ReeM&D$P5oXC-|9-&j?^# zNy+9iClRg65B)+#;#Ys3B1uCa5(Ac2tS1npHpD?O>RLFK$uHQ^SmUaIQa`A%;-b)kXGxf5jbWdP}kTN3({Rrvt|5O~nE+sNo2oE{HU(_NA&t$C#iM zd=U&94VP3?q5k(`_+kr3teh#*ye-#*agUJWpQ-9no}fDhsd9&A;IgssT_V{F3Penl zAi6IP&l^C}(b}hUjW1J+3lh=o*wo?PI&czs{5N>#eSX4+VwWEEJcRsvdR$KW8$>F9 zL5aEQH$d)TDRLZX9Vv*0ObkQIaoCSx`+`)^D6ZfcgT_?~hFR@fJA7Ga36JvPcSKpN zAQ=*Oyzdw7boXARyy}md@0O(kGrWZys!&{C|Bn>PmB&@Nh8GsQjH?A8RMJP*7eIfOZWh1G>Bsf0FkgaIg>}zEnd}CfY)n-0{&vZz|fE2YP|8zDNh4J zzr7E8V_P(i$!%U?zdA8GX6xF&etg3bHbWaxu?}I^u## zU5GLaGlh{^RNM%B*}86?Un2Xp_nz9^_5U8U>&bK)m#m8) zpgUdy@ibAh`wWs&2d_Il156mnc`ZY(`iNIXe53$LQC58;*QoCHkY>Z@jgBrqHBHjk z-I_tFd7p$tTySk|k0Hf3WrmJZR4OF5zTS@lMW#iPQ?=sGt~MaYR6;@=A#Q|wU5ad= z5<~NA_)ICW1sW$qti|6sp>DL);r=oJjO8# zhXOuw#ox<#wA;4{J7zuJ+M8Ng7Onww2y)p0Du1@~Xo&UY_yJ%Q)4RVQS;tAySbrOu z{b?Ol(;KBRBsxSq?@HFtg-(;;IS3X6Q%a%GlWY^xUk%V#$VH)dLu;(%Ge1+6us+wk zI)!Se^Qf{@ScO37_;T^d;j&MCU*c^g5_PF0!uqWa{10^-?f=OBzdLLg6E7oUQ~UQY zBKCMDswkB{qNakg55|LnK$O$K+)q1YK8!lX46&sex3FjN*S{BEb1ow668s3o-OB(J zO9{`!3mRybz*9VgkOHpT?*j6gLPG3CN6lJ1APmNz=4u2lULzwlu~q4^ASYCD0=GR2 z_Wc62K^Lv9&a(|SN6DlCQke?H&|eggW{&s{q?E1VzEME|_m(zi&_?e_R)kBO%Mdo9 zgwm<~L*fEL@7YkbVn{@!7VFI;Mzw-ei<yc&EL<spvqCTIygzTJfwSbfJNH~L)i3Q9%}i9U#y@oIYr!Xb(2WE zx%Xh@M)?PERZ3D*a1j}68Wz0?72oz5Gp9_W&!OA<^a^K@GY)NiAy`Yzb+F3M41i)_ zsVHyei>_|?iSGcz_-gmtZzeT5whik%W#Z|LA^_KVcF-Q(`8X*!j9MxG(og!6QY3Up zG>LBhmt16)Sb&4G+`xGxKq)RnyqG?xrsO+4TJnRwj%uBEVqa~_iz60!V`2Bof?tSJ z(Ow3J=B&c@+QTu|w=lx3%W?@@9JB0Ua>^7clGa-CQ zZJY`hXz0l6cjR%bHhUSPg%$0@X#`FDtGa#<>7%&hG*xrA(&ro6mCt^7Zw^slM5N*fOU)AO4MqFRfeoHp}tl?+9j71=nPmoll#94A(CmOvQeFHeezh&6&!48@MJW%)`H9bN@ZHe|>(X{PvkY5#)7q zEh^6+DwlzmvEfrk=Tt0Fq}wf9gH}yNziwH)JAK~a1mCk{IhNI`y``Z5EJpB4sCvMO zZPGP)seG3ZuY8gFD(E-w08GIy2c~a&9-Vk_r(MHI)n4Grh|w-;w*{rI)R7RU_`CXr(3*@cM5c*MCp>7lhJpq6M|;i1hrP z3t^U|@vWF{{@N~?P^EqjyVX9;iAlFOw5pKhdawZ*%EuH9XjQI~T}%3Yh$=qXGB}qZD2u(jKdQKAM%YWX4tiIv&-JC-O641% zUGle1GN%o?hAF8OP#gOEmw7nYvgRv~6rY2W)`h3}#A^oius*j^6{4>SLsC9xYeI2DTU?C=W6-0MJjg19CY*QN|n|{NN?8guT zjh*5|)T<`}s$Qw2oW?Vjgl)jBHKLMe@_F_G)`tvg`sVg5<+$;xN}~z;u{ceK7vv%# zJDPMFi5Pd~-wjMgzW?H!{h!(W@^L#9;BgNRbq`+|n+7!NkpX6()Z=aEMMF=#hu`&C>3Gryi>h`+5{eS)1v`ZP5K1^XE*j%2h5Ln4 zcT#jdBO>-n(>a8xIBfz%+2pR@#p+>W`1oArgnufGy!71^y9q%ykr75h5?-P@gDaSl zhfMfs>U+VReIDKT`Ji(2F|Bp9@ts_&{*2!&C!vGjH-;F#Wv$E3Qtd^R9_L0P4w+%Q z&7Ixe>~Z7XEO*BvY5mBXl|`T!EoH6M=ht)KX)UbUCoWC1hhn~Xzer^X#Znh@I4xy7 z!_dyU`Q}R`e@TygFp1Fi5#q3^6-%Y+{bP<@#ty)3mC604y6NLpSKd`t?P6Hw;L~N$ zh&!X{zU@9QQ~cCIL)T~}&*8GOk+-YOsz2Dqi)gR*VRn-g{*=7L+^s?I@`z_79xP-? zS&9%>#*%Iwpc7M8DtJO=^IAyIdH?-7d(n`nJudIjNQ3RHJz(J*i{<^Km|lngLCxX7 zz(zxWl3leIg!YKs`wsm$L-QI;Qhs3~vFK7GpNl0s{ocXEoAmT_MvFWhGD-*~CEN`9 zX{Rl3Lg=gAS-b=tp;$i6q``?RNngiUs$$h|_y35z{TBFp;wV~SoK5g0dzw%)tFjLx zDpjo_-Xj4;)2{AgxzS6;PGsU+K0+{Zhe(aE-Z;Y_0;TfmVs8&JF6+SS20lgMuP494 z2o+tmekLVK7G2U~LFv&QgcN%T30hIpqH)5BmE`>ZsMTpy>C{+1!f_Xh=BTZz;O^Iv z@Ucq$s(0yTkm#T{hKR;%x#*2lobSvabFeu=ocw{7zT#BOZ(38c`znTsuEXA}z{IuW zWojP6@7u#s@Gx(DNz42BSh?0FqAvMuK{@UC{rWUoxNQFIcqLgHzT?^aVytBu(nh=P zJO|rdZ58{M>*B17&Z^7`9>=p>b0*0sA5J4n(h%l}*oZG_hP2EU6O~B1Qx9HB z&O&#_7_6=A>!HN0L5r54p>u!Z&OG_99cV>$*I-$Tbs)# z^h(F*%m)^4Mrd%qFjZy2R_T{9^Vx+`BsoNJa*yEc5H+)}%Y6-DhNj9Yj~%-ZXn;dX zRAKky;p&r;?8D)o#uf-Tg2v)*18R~V;$He{{D2}j93AfQ@6jitI?@x%RNNys#!wYn zy1HI>uHr~+@;aUFky|I^j~qCmreeL?*I$LjM!;+9)pg+S`BNi?_u+vDSa&{dr z!7QMd)UCz(i=C7>>D9(v&Hk;^3w0(ZJI6o%rmh{Y*SW`3e$hgc?z`w15+HUd33kad zx`j(;+sZuK3!KSj!U&D0A=k3#U1_kLh2UUs5Fp=4^QiUA)@~9 z=W0+?`{j6(jz_JG;cdbph|3onHmJC``02?tkUvL}a{JrA_SwHwckbN08K57?DJdyw zX=TL4&A|d0G~XUqH=T2FA3MI_%(0cQKNoQ9^O%STPkQfeut&?t+{x!F#6Dk|>`Y+m zSb6bCA*f?PPkMG5LSgZ|MY;`H>AyIfqEjzNyzpF;@>lk$7;Ubj+8-j3{ScmT-Psm7 z+~C5WIHjj-a{V$@ZcEl#s-#yOVM-mLBtc%4t2#T-XD*fq*a8bjur#E$tzSsWD;DX^C6}yUWIH(Qqa?R$EYx;}-Y+o0^iBT>WPR zEk4mD~>o`jTz9;46Ds4fvbuX^SwUVY{v6iU*WTxq$ux7GH zXE_6Lk7I&qLpO94&`%dL)jYKPN>k?9IXTn1REqNR!N9=CQJ?|e(Aoc`Z8mtmKuh=m zuyJrQfWUqky14lGs*idWNcTcH1G>3pwpz1o#y}%Vtf_h{&PT_| z2za7xQ{H=$wNyW7=^!zs2EL0)Q>4U2M5D*Oe(q(Sg|lW6Et2J2hq|hhjoBTkeuc^| zwuz2g`jUVY^*jWS02Fx$32JsBatC^hJv4kO*9^RuDK8*I9Bsr0lOpRgunL#I4d3B% zDw8|TcWM>EKucdDq2ed7Mu-8UZU|N@lW|uVU98?k41I!*KNLG{Hivg=SF%h>a7f^WJ9b;G_Ko31#1kva`;>Lb~Dp?WXsw&n{W4|8HL}em$)62v3GE z!)4LDbpf8Lg{58ExKYtXZ?nS(8?Ynw~A)2Y+-ciT60A<5R(8W*HU#WM=T0grE!ZAeB(%NaEg5Z?E6bXyy z=b}9g6{uixOZkmjjO(6-<5uc{kkI%f`=nwu%zk_Qo@`+A!R@0q=8l;tEljNYv7Wb+fn2p@w&aw||=py1B@_P&>lWNZU zm7AbfAWOlXkz;?w>)|2yWd8wY;*6Nbvt$WD57{YtU4@0C51w@_vX1SlHyZHL9+UY7 zid8-c9@?%ha<`1Cl+vnP)7ymz1AiI4-h{_eRqD$9VUP@UL}fOCSr#XPo+FPl07{cN zTMCVbawTR7lACdmO5+$=oJpySCt}+vB1A?EIH;IIn}?7x;ghW0^h(^^I<@SlL&lWQogRqX{05tX^qQekVgKMn=2;;LVbpp(kTgn&vUSA&$5jnprN7(2@8Qv zN0?%Q6Zn_<`qSDgL-|x9wgMZQTiH zN4GD770n41wam)4nqFb;wo(^S*BloX(t2D8Q-E~w#K}3keNGhJ@9zib*XuP(^`C@= zk3Lhhk*KO@YmW1(1iIO4jiMRhO;Rx9ONk0fo(9l0pfA)lKuyc(HT>MjwNBGnW2Y>i zBzpS@ts@~P;CGka8XYxlP}ktq_PicZ1La8%N_zEBzK*A?uZ{RP=d! zz||Mr2~Dpc^>5o*L|Qbsi@73Mg}K+Ec9qaXit0Fj;hD%o%9j`Zi7{{Wcw!*Z_@*5+ zd41g$iH%T#l!)!vx~Am=(+C!66~yhfnZaU#)#?ZHx#lGs&04X}{raL^U*AWQNat~n zCsOoqYRrO^>|;Hc_-@owYGa!HO~Du(Dxl;{#%K9@<9(Of>_W4loxfbku~=C9@MXL@ z1MeJe!9*C&Y^drd)!9M!c^7(O=-G~*kElV&uFKg;bBF2ZjM!3BL`}pBGL=I>W^MOP z+r9Y{r$KAvN!LLdP9jo077zZ|gfag0ho2qdW)eMha~EO5ic0Pk)GMW5T)NrU-;BF! z-91J-6aJuTXd@Lge*Vp41(uILu{0H21@M;!-jJous&`AY1=tmDcC`e)pJNfyP;_40 zFO$#LKiF6VZ@vAtd5;^e*#b`<+tlHzheO^S&iC6GE$iD3BEnu}N}s<<>9F7Swr4;} zonXZHl&arMpw5#VY=P<3+FiJAzrh(TkPw8pTbZA7#;d>7O&l{{(xSP1G&yMN1P6vl z&mMByt+HMc-0gPWl3oL84hNeu+q^!a7p8-_Tc3iPY#O;njXilgK6kOF$FnZnK<@dD zZ(ajpFhKKhx-Vg?O#5`CbcE%r6$V76hnTNQ0b6-SqDnCQq*S(>ucUei}#&zSsso-?|Sl&j|@3!8CSupF) zM4r4Wi&SxNb+@JUhHRn5jUdckCQ=)%bKBjt92r^X$fd+5XUU1LpS&#o?sqn(3vxG^ zil}MI@za##^IVs7_gqAik*tPDW!}Uh00$8v$lnkx`rZa=j_lc6Gqj5UYinH6iodE$mDpNhVG;=;?YLvT>4&_^ph1St&_Y z*#1=l)4b3#-evfNe*e{Ga(TGYbz{@>Ip>^Xl=}C~i@H&w)^)uC%yHebkpE(`p-OrX zW`67(Rm&$0Z`YZ=M3=e*?S9y2Ru;?DalGNqsgV%KD)BIWOytnNzZFAUp3fJHcMsvz z;7wnCh(c{$sT2GJQ1b0jrXp`mTRYf8)TKU26yMez98zAxTnxro3uX^RO zJEb7N5c)0gw>v2&ykGHbtBthKN~A!% z*XAv1H#M)n2(hu&ENE;*F%f}?3Xph{Rr8gN1gWDDsJH-$1`bz_pUQyM7s(v>=9zGc z7}zrxVi0J1EvTtMShN&`9g&U_$8a$4a9}V?3g0NWm0p0D!lrB6Zl*N6)avue5-U%2 zu5}w+ZD7f1t!r<^n0ica&gHYXZM&VyJ9~~@bhGF8nZ|g2VCJCnc9c&3W%ePN!@@Mo z>O0IQeC6{=B_^ZsSo`PT`0@iw6O{Ifv}`{UeR1uP6A9*4B_>pUN>kU5F)#mjg>{fP9OAOe-A zK7S7ctW=_OZX4`nG2#ZC?TlrE8e2scqmIggb*(4%Tc4u+Y0*zH=>1t{n;8)>R?6SE zJ+6ZF#?~RT^>)v*k^bL~@C%Ig7CqZbHQRdKHPLxJ7gL^n8ZW_7!)gcELvf2qYt=~Xu+b65xw`scuJhv;e~kf5u++sVtxMd z&@)-cd`}~{0B&x37>~mX<9xazQx;_y; zHdhDdEt1TwFrtTFMEW<}E}=fj-fR@;M?W4`ZC=Z0Kkm*D2#$*8G54b$JFM~E+}M0Z zZMv)`)}Kei<)_+)J?jq@P5L+wDJJ;6Usj-e z@ZR3a#eKY*WK|H)n{1#kzHYSu_o*F+er>!?W`1uYVWHNz^XbSHhIU32ZhyHMi>gH; z2WF{Ec=TqXySRIIoR-f?EvIeVTb~OW(F$^Qycn1S!AST&XVF!=8ZN1R&OPl?Eh1B0^pfBizz zRZ!r_ws=g2I|LItm_~*m?+bR$pm~&Z#?(=>s`^;Z6~M8;T(;9S?>k(DxgL%vr`#2l zcnS#4%5|a9cA}g7mHmt9IP-IjJ8EDl_dA(sg%JGfWd>AMS3~pPwan6x3mLA@qpdyF z!N!D+u&tHC^ifD@z>VGx$D?q4HlL?;VGtk}&+=*eg*HOc4a}Kde@_YA!@-a7w(w@~ z`-5VUIz4=4bQHlv8nBSs0V~ibhqL{&-lTQ@3fT=vTKxb!;MmA7)Hau7zfswBiKE@rk zS}EFfxwF&TjAZOs8UzF9@e$d}k%4w0bRMSn%9>NpJEzdf<;6rc)he72*!{Q=n&UeO zK$sQ60V2>>87x;6AsB14ei5)&XU?%9Q_KA8=Uz25Ry{H30*w5$vU8v1E6CME_H zS(Ehv`;z_K%`11q%4&8nOP>68ZSnYXAw7+0?Q!H z)#9%=BgI(0KS0+}uXp>9u1jHSluvMSYBAPLqMKdg_MTe{S5p{)4NHFLNoYIR!=nwk zZ2e4l9(FpHQnuXuIN%-whw$_G1hhRJ4-qs+EvY z(~VOE4o^9!5Ntu-_ZNBR?^Zjl2YWhk>Bs$D3!BWp-MI|ngt_e=7S96Gc;ZrqR;<#R z9%%SU``bqZd_3=(heI~w%}NNIsQxjQgz#@ioI5iyurSGZYiCsfRA<$3aC{L3cvKUP z7!J9MRNaVZEaw`Zf3M}(7I*}TB(88EHapGt&z*f2d2e3sqnBuKroTGyXmSs#=}}Sk zE4J)mLy)CaIy#NrN~pAGEXoS;+&Wo-jcSZQ{QCGCt}|8)C@Y>*a?rFj6%0||-g|88 zS!(&*tMbm0S63`$R5T!^Bc&|g2>Kd}{&iHU#E!aHG zp>WRQK$fcJjkWQOxmEORU?aH&q1#vd`cYF z_pIo`{-E_JJ#>tv)K}#<1;m>1^%?7dEqV{;;*Zv|L`jixY`J_L8Rn)+dUuefyJR%g zEvjyP9Y^!-o%8K}JD{f=kTewxkm~2kQt(+P@gUjU^x86+r`S;_yeCb$)#$M{gy<8h zVn0$^5$bbN%VWaCC$^u@4_VDQP&No_p7b5Ufa`N0IM0jWh+x;GI_qVCK9Lj-)hd=k zN*YGw-6R8>r`qd#1j0KPXIUK8~aR0Mee- zBL<4h1LH(P$F#kdZ{a(;y*37ZU3cAhUWeFlqtBPu8Nt0C22r^bVQ1rIFeN>;IDd-a zoKT8?_5u^$3jWJ@7U(ECp>Q-KLqj^) zSROtbo@Yxn<7uom>#g?-8a5epdi+{s_QG0Xa&~SFw(%;(-vsytm?>N3 z8h?1aY<-L>X=)y3ifvs)~6z;BtA8lhKM z+FgI)?8gPxdP#xv^q!6PTZhd#il^Ok!JQ1=#q*tby{T{$!FQ)7;<7iOf>O(qEDJqB zPp1xtc2baXc|wZhWPQD$U6JFy__3Sr-S$bBNAam97s&7(-8u=W0-QGbt)TK@o2Xmj zH>)@INp~Xk*+)sNG(h8LqVaLl#u;CzzRY3srX_9n;$`s6JhDbb_Wg-TpS@2PTVC2q zJE`xo8gUyDHaAxZfA7m7mh!Y(fl))gHs5;gh0GtkL2993SCF}BxjkErcyerI9Y3c3 z0iaT;3e;Eiez!Dq>KyKdB)zz(WJnu2gprS7M8v)(M*D;$7*e@ZDV+V9{rvk;DqD_Y z5JmA2qgQ^c%B}Pp?fUH5u>=&24GJ#OQqeS?C>^`@8 zejSXF7=OJ7jN;xT-sGm0^FAkCSg2lcGu?}=@V)erD$1J8n3L%~-qGkeI#0`V9uR4_ zWz)Y+lGzJ0#o6QZC?teMFLj+3#HI;o-MwWgqeA-#G&41I|6=-(00fR_@$#~=x(vk- zfJoxu;hWTixILe)nl`=L9FJ!}rSKpN{V6r{LvvtzES$udmofF~DYJtEVmk8NEwYT9 zqD)^dFv@@X>zCi(vss(FR;#fOe`Y=LCEgj$oHq@c5^9hI;=FaCR~TUuGu>whfHSg| z>(p&W?_bh#0|Knn*|Ij3Er(y7Tv4ntA0FF%ChoBeFO?g^h=o!cI$EVZvn{VO%2X<~ zx^|NK)1q$(KFi&sH@!W4R!^1%)Q#~lpAPEc-c2>`lV8tyPkV)}`Hx(s!E2Fp=C6gg z{7;|Vq*B%dNj+;F`~68Xs;#PEFuJE5{)DiKE@Si9^kdi7CT6+wNCiCFc z?;xjr5ZP>%__266-XpbO|07|2{A(Lq=v={j$DB1`W^X$V0+?G`;pIF3m>+BSC6&V; z_#3L>$iyZ3f6|ClD}7XQtv~ZpFK6MZ9-Z~6*f=%fsKhRtvqKO*in6lSia$B28IOeeU&_(;A&%}~ zo>p&Ebv7QgvvU;$BU1bp2~taGAe{sv|CLT-v6{&jixTm8IC~zUs%pO;zy^`Vf|y0u zV+eQv>@`J?Z)sZQnH6%d0(JnZ@_A*{jMZnG@$A@je~`D$C4}79gM#?w&j6p$3wrLE z`HF=FIuAXIrY{K$VNnl*GS5?;)!fy_uFYW+`o?SHll(zpLDkyb9YcV!=Zne1)hefO zpV$cl>zK#o{6gl<9O+%hxt({~V?!m|>D9pEWtWp3hdQIl@b!-%N9CqIY13^^#U^9c3N(khpq`oS_~wtQ}* z>Z{$u60eym=b>p~F*LoGY7DxG+C}i8VX{wjp-u9(kUvkEF2nonp+Vr0qM)@iQlYb8 zTmkFV)uKHR-Ecr`S5VCB2y+5Ns!GLK<#>9qzM_i=(Fem{@>Nu&^>99}NF>0nBB9UR z5*6`wtEPfK({ko!r}Dt`-1$?Hd-vjz631Msz1iUii1CH3)3jODtL$K8k3RW;crkeL^}?s(Qrv_8|^{bG$~RZ<=5M4!{z_Y_LYRjMXAA zm`BHNLkev>sQfXtnniH8!z>du0!qOrL~76N!@=OG5{jn3P%!T}6z%1e@5b!Ojym3t z(dx8a<-AP4T3opM$a9W9=9Qt_pu6b%VJJfVvni&4%p(&+Ls(3PzLGO>LUQt>lA_F1 z5T))+fyC?mX^|pj$4D;6XM&h>e}K#BIy;SGv(#~!gftGjZOdH9(%PLu1%yjjKqtsa zwvFoH62qkrNcU2C7`DH_QRY1lc(|MGVK5)Uzo&3m9uVdyx~u! zdsmy`>!c7M_n1I-Ly+`fd|Yl>S8x_~XKIRe*w*Y-{OQ*N3F{rz?1!wwlkD-4N{^g( zognG29L$w^-LUq`FvH!j=1S5ESjYtk5n&<9b}jh^i6l15PNG}SEPFz@{iqDk7EGp{ zp+6ry!TKnoWuvWw)Yo+HlcII3pUUHQ5uLiBJ zVthId?;^dU$Hi9Baf@a*KQe(8^yK8Y)K*H!^HN2KCZn#)g5OZc)P!1L;xj%Wp(y81HJ{(L*h ziy72%-nhzD?iCpH&w)Gn`G%93+#AMn%H$Mw3>iP};tW-|M*d9Elz8Re*N(jLbJnQ| zYYBN*{^sKo19m?vj;kst$;;voP?S!wFPZPCYAFGwxl~ltC<~Q~56fj(P2?2im3DWy zp~PL~vRm7Ub;b(nHGh2ne_VZIcxB7hbvj1Jwr$(CZQHgxHaoU$r;`pkw(X8>eY?-O z=R5bl^=Iv8W9^!=YF5>n7y}$ApfaG3MRK!o_i=9U;BCBy#QPLx&#TMcS$_Q0?4}yv ztHW^l>D)OPIkR$8h|TAvGrx4aEaf2@Acxgyk$iO@GXkjC<{=v=S-F|>PAzi9dnK5X zFD*`veDrnWmR}7p?^&UqWK;C?dpWw~BgK=6{A%&t*WpQI=(uskEcQ(6;m}v{XATPd z{TU)XpE}s!{W;;A|LsedAE!g?Wy#IkUM@ew+x5iefe3kwx3bJpC1!SxZbz#|`pA*( z$JsR>{M)|sapwl}&?BiX?EjTflT*!Rc$&sW;gEPo>k{`TXf1dyB?l|N_4 zs2>pzs4eP31gY?zc*ZzHh}IAiss0++IB#B=TNTvQF51>yJ5Vsns7Fo(tB60f3~RFP_s-Badr<*VI87pV(068ETA-WQ_}T{2$ny}nPhUvl#>Z7^{>OfIG_ zMWjR6L1~jlHUqrsgKSJ6K2jd>=cKl+0v6;O(5DFRuEWmmxkNIS2d?@nW#{uvu(=5Y zdR=CWDZF0-A4v}`d17L7>2aSW%QL;>dWs)xX6NZ!=tglLp70@Uy)0x#h2ao;`0o_q zo2Qj|?Y!EK&iLU9C*bwxb__iu=zSc{gfasN^?SKALo2p}fCJ2AR8<#7lE^zNtfJRC09e5KA;GGsC6=GntkImLY5mph8GDn-z5%FR=g9n4{HCg{s= zK_bnk3zfdrioSCCUMIg2ZbjMX*fDI^zJPF9jyDcSi?`yBEf7;N2#ukoO6BB~*9eQZ zK<7Q@Cd?hbHaOchOpCOfu2E~+zKWqN9+cXTjaS#Ccrg-Q2fw(g7%OZ-0R7-^%UDd+ zmhTGoT7Q(esbFtt_4AM)4SVF^547VyN)zYrd=_@O+YpSnEWqPc@alM8zMYawNIv_C z|KWBX83L7w;N|AjYHmAu`TPpeDqV{*u*L8Qb$9L!N!!u+S#X#P& zS@3am@}Doi%!O7qvs<4o@Gp?ojRs+JpFzF8U;bWzDXGyT;D`7#mjjT}h{Es9T$7jS zqsC@+9rG!buzwu|QDneD!A8l;$X%q*<|{8fG;5<9N+Y(wQI_D|F4dG&C)Hh(-;_dx zeN*iB)>w||PlD${7AYyrlpp+L8UpcN;iZFSv1QI7}@wO5BC$5SF}nIfzGH+S4O3f*#b zM0P2M3wzZP6`QCrs7xD~AnLVBMFbH~erTUm?=J#Ld28Wp-sBK*u62%x*hp9J<4^8k z%UxGPBB9mY{3nFk_L(4iz-e2U{3AGJ3NW|qND?cgl$!BMO8^>|r4rIAypq_)$e)zy zoIeYuWMCM1OQ%(up7_&SUMB{YRng-{drb* zeiW_b;!hfz-!WiP=q#X_S)O&~o~8fs>kH5ieTu>MOr)8X zK4?X71d|*zW@G);j<;s+YUA-&+V?B^PsEEXs@pf)lY+fdz6=`K&+&$!SF|^;k{8ve zrhwR9KjFhNyy`-3a*~5G<%JlWYs##QpEUAo=YoWmgibp5R@o= zlkj&KzFT9t=VO$uc1cC$m-rel1+G;Q^tAkb29EN6wK1b|CWT5Gz#`mUgj8esd2-CI zn%KD*rtdC~`;%Q=s?J=?IloN=LrHyy?V|wJ0`>ra^k%ftT^P+f@*;B2&{=3vKq6fWm$zUxFUPuGNq4yP;+-+|#JqK zNsHu!>W46m^?>ZnpnLxMJ-R7%4^>Y-RwFlm*TFI8FL}oTkx^EW740Wj1>zh;LfHtr zas>I6W@DmbQeVDA5}0mW$cxpqWthgi-NNFciFiK-Wp8R!9Vr9SY^c84EVcixlwRQs zRh1}YR8h4wLPjoV62e~76h7!pMMp=@NIq52F|jzW1c7wK8NS4MwNm>WPAlw#nX1h$ z-nlasHC^~dMGOZyXY~Y0Gp44ZlEvX@1n~8!SLUp>*kZHUXh=vvx^M!`L%e}~+>Ft0 zd7V~UT3R{*_`;dPN{-z(J%>B-Lr$o-y& zG+nN-D#{wSaD7hK2oDCSNG%xuj!y?#)$l#ewHkgQr*e7z)l#TFz*GK1j<>Tl;;RUbsA3t1`6nME3{{<~mDLdfspwZ!a`+2G zd2vVHZ!S?YSG~gGpYKObF<0CeD0BJlOQ1a@-y*3Y-0>+<{YXH(<1jGFLBH?=vDivU zOSjr>oK$m_V}xNJ7PPWWUsNSgQ`e!v@G~BeU@+V7Pdz$HAr9@=T^kL~ z9U%r!No$;`E;x}lEbrpTy)*+WgoBy$N`V2m%G(>vCa{*4f>Ky}xM;s~co*x*WwmIXQv2ZCP#}hWXM{rDEg07JAlE=W04>mrVv^EGc>^q|GAoFG4Jx8j!l; z=*ivuaMDhAs#I&+yaZ7@%^0w4(9l~5SJ%`!2=%4zPRi_*yc~ttQr~`pwm{sjb8t;R zTRs62JEs@kXF)~Vuly}38Kp#x^)e-^-z+6(NlKib5H-{otg7L$wINxN&n`Nx5PnqV)9WAe7Wo%t>@MHTS~;qTnpggD=F!u!nwYWg6M#y^-qqLCZYNA*&%Xp%?Th%Di+shWY)PKza&lvqXNP$P)Dl+ zm;UgO0a^y@Zg$>#Fp z0l`3N{@FzQ@Q3thcPonyy|3t-vu->WxhU2L9|63h?hg{@{stm$O6Uh1BdfNKv{m~P zrIHW^3WF~|(@s!v__Nh(2W%ilAbEe(A~fe>Wp$EDs|{e}o$dB^e@s}a)t~Z*!{L~2 z?P92ojj^Ay4-&4pN$k4iETu<-PLi&9+s@Bo1W5|dAKLe-cw67(Jz6JGRgF*bBWcu$ z-QKWZ_9X=mP8Lxi^ev$ms3p@_^Q>aK#S=R9k=LT@Kkg178XKtnT-1 z%iGx?sX`To=)|Fv!D3cFdz?wgR`{&bM91I$b$4PmqkdP40-q}{~XJH&)0mTV`4)%@@!dGr+ z1gTpQ8BoL09250b3KI)g4*d}GnL`yEsY-!TlsIs;ZStL~?QSjI{Uhj!KhJn;6KW?= ziD3B9e$D4s;TtryiWOs2ViyxOzPb?-O&Gyvvtv7XM%mO|9O_m7Tpc@tDkKMxVK6)7v&8T0e4B8`NEKtdr8I5mrL%u|9c&dT?OV{tn* zlqUR(>-RmW2qtMdcPYn5QwzOGP4ZD2%6gn$q-1SHIa(Zsw*ZLz*)##yfAtAyy5BGl z3Jd8Gi=hn>6}jD6=FkuohdmaHt*!?n{Jv(C!j@)31WVQSV7Mj;hRMkMUEZmbY$Q+S z0Vtu{Q-Jf@(BUu4nd!vutk!BqM!Ntu1;3{qh!18C4vlKHwB+RZc}S&v0LIX|>yoZ? z8r=qfF$KW-YCe@CJJ+;cj=v}(9!aI9(>Hkzq0H492L)qBA*ZgF>`L?QRLlVj1E~O0 zi@dXVU4ImJM5NMSzP7X3%`I-V&@r0GJPfBpfhr=)(V%PHmzhH1Mm5HxJzs81!FEEQ z%jfjw)84hKP>rmW&Fh7kKT5pzfc1J84x@ZJdcz!tSB?TNE*kd3;BO^Z>;ybjsS6B5z4Qv${<4a#ww8~HT{PRaNvF0y7V2r*11v`S_i*|$0HPCLK)}y7 zyI-gCg#o1P3kwTSP*CT99f`w%;B!Pgo!9#TAgph^LG#Hfd9B2ivV+5tTBgS80Lsj|zKc=+NS6#;eVW{P@BXSU6(QLHRV;!@ zu@yeXQn9d}p;-=|;{oPti}|wI4Ba@(n#;kh6f}Fk!{2ZR7Ciw^CnpBo7SWlWsM(f| zBRaOjH9ZKIFu|w!rx_--+g`^fl`}MLp)Oh=i@+lFe`_HIBt?odqr^AKKvBlx zawk}>xHOl#tce>11#_#|It-zBuooyPi;HP{zHiSw$_h*(nX1B8DJ|BvNMba8AdojE zEH102X+RNl2wF*IzICNwKJF+b415W-Vm&cpT7i-n~Ww&$gR(n&; zioAhj3Y)zrAY(1)62q#$d&8nH;NyCq&}bB`EBTkL zsyh_egFKVEvq^K^tGG1A-QPc?g~=t=NQXO__jVwc)7Mi|{OJTZa;TLBH}zSC?%Bj! zE!5jrK2*uoqT?7SHfdEi+~(k7Wb=5)IK{{fPm#ikp%f|J1}Yj4X$?n6V)C#JntB?o zJ;vHjE&RR{V}x%Ov&{@`Sev%)1- zKT2!5u0kq&G=Y?D3^<_+u|O)77{rK~m=ah88=H0{F@lW*Zv{`rz?pt%q}gDV69hal zLbcVLRKo~F|AF;lp+kx8H({Pmgd4e-4H zG*M>+easlKlKt0##X*Vyf>?r}gsVz&t*M$xe)r>Gs>78Z@ymyA##=Q-uba<4djWyER<{+%baVUrSXfs1-0Z6#!Ezv;+{!0smD41Z2^1 zr5rUnDitFJBKt?597+Iv8Z`&|^7t-Ps1l3Ee1(Ink;dhSMaC=Aj81;L#3Predy)r- z$;6{>{^q9QCpaR_+Aj7bDETX`?6qdBD2@_^Y>dHlV|srGvXs~yOBC__s%4*Iwk$lz zz@`Om<=l1L<<~+p40hLKBSNw2)V0NynDV*fE-q{f#`qFdh4qlNK$ZtNf}EcY%J_fw z+8+yKJVaf9{2wy1Z)kzwe@&pgSPVb~;NpEKk6apSSw}-5#wi&Qut8fQN!M$d zkc9Ue<(2ghUJ?^mjBcRsM-*fx#{PzBj;DT zkgU$%-q_hXk$F2T-N?`V<5I@g_PWZhk3mnn=)1`5ctzl;p6u>V-GX}d(oCo4!J`b_ z*Wmd-gM5_=C>R9vb$omra7M9a!TM%c2if!$@CgvmCT~+@9gViCYD!8$`; zpZCSP(De~pca}4iMV@jiakb@we zBeFfS(o|_@ssv{{eem{Q5`N#`-#Eu$;m8E`@g2A724a=k?CvAn!kLlR;$n;jsctV z53&_VO_{Hb4uMB3Qlm=A%N~R(gy~DpVLiFWnQ+9T3ZA0f zNdE4nOg>DkTKb` z4sv~iMRY&gw*2ZWfhz^!{+E3+kBp1}d`)0rV1WIc731qRG|Zpj0kSv55X)BpND7cw zL{wBT_|Kbk{!H;W!8Urd6G-qKKz27=05Y|9=cAYV(i8^)`HE|+E3sS=(!AdDCO_*T4KWJeDQ51+4|H4q@ z=`lt~Wi21wHYFb0p{9Fq%uJjxk2L^JgMWyM!x4$QlY z?Dp-q9aVNSIDiY@fNJ;V@A2U-(uIuP2r_1eSzLhxhoC*`gj?3iV4^eFyoAQV;i3GkS+h3wAS1$a z(~UGwwyKg+gHp&=LQ-Df0Y+p#BkemIBzN)^H=$(F6Tr(Vp#m+|$AE&i2>Dd|rr1wN zqlI2%K}ePuqKz?!Qmp`84kbhb4=N%Ce)XwFw^`H38~?myfAmxZOtdEElxh}r#>Jz@ z(_v{|;;LIoRdggKgGRJfzP2A1nK}v5<+JQ%9YRf;q|PJYR`@aWsS; zPt;X&bDLagd{? zh)^YzZ_Ll>dpK)V5QvO@JXVr#Av!(Z`;XPU9`{kuhzEmo;^7R;5nN4alMlc{v0k8h zDQ$s4dvjR*lJhEsVMKt>D@kb?MPmF8Znxq%Xd zIGvpe7^rqor<*STzJ6t8rNz-!=>Qa!S}IY35(8Q}s7NZ2_j<<%@}~ix$cxl>f4(P& zkIJT>{!*n1i65yRsnK4iMqYZ%lmYa@_x7i=wE4whOEzdBG>Yu8mo@XMnuF%xvR!IV zu+&=K+leEK`0kclL%@W!5y)QOg(?8RlCba(*z6n<@z$g<9c;;;8Sl3xKD$Mz5ms;F z^pJm+7ihVR>&2jtAZxmt;o3EqmI);)mDb&g( z-9?t0(qy_Q^GRN(@ndUFH8vE($v>m{0!5Zom%qOGs=Fky*^X)9w`H*Hx=u5$XE(_h zlM3rRHKE%qO?zexs`RXdsVc1QH#5TI8zY7Qu(6Kl{{wm(K=xC$NnqDXcfo8V#qf6^ z2*h{>YoqV03A-icSFvItg%+e@1(D){7_p>%$*X|DX`eij38XVrCmNW_8w%f-UorTbvzk z^7RJfB_?48oCwW1Ub0=1^i@Vnk+MeLnf#wG*5pb2o@BXv@A1QMqY%&$P0$mkrQ^$H zj;3_ywKX53zAmj=(J8ME=mCb?Wmm@!8Kb)8BiIMi;^MuX6}GvigeX3~8W$`PmH(?a zr}0ls{Q#anNW%ZN05Qp*QMFwfgtAgn8Jy0C0M^lS9DUCI1~H-Vl?t0`5olu}#dIW4 zC5WV|!d7%t}ANJblq! zlAbP6;uyGOyYK?AgRbWeW8OYiBhx^D7sXsyRY+fa=r_plHO1O#wCn9p;fg9rTz{J= zy@x9{!oe!iVgQ!_4g#*~%H*Vm(N?Bp(UQn37>UtUdNf>4K3TO8fx$Z$=CYFd(x9av z2h+*5Q0VYn$+skV5rv5>nMwQz8_DpM>3U=WxNwJt*yG3-F* zGZawtSmA^+T9bT@;Sh`!bp~Z*8O9pqG8hkw5`X4+v=;VUS;6Z)AC3ST? zPc`O+tL+&e-@1RWF4W<$RB6IwqrACQ1zX^LIBF_wfoZ6@f&y910F}^OTT+MlEF6-} zMJR2s>Wmz}^xKFn0#>-+{Fw!s>15c@u;P6C&?`fz)2RLSpWmorUJ^s}0Htvxc@@pt%0d1Vhzo&5$o zD@8WEM7O6$I>jjwiT~Wx@DqY@S|(l&+hz%_kfveC7UUeE)O3bTH;o=vkqEbSv*7;N^kSJ%j#CU-2nu0Q+D`u|cs=_>a;6kzzXXW)|D!7izKm zJv&U(@_MKJm~J5obaH6z&OT$}=f+7~POn&b@{bon+u}A=^N$UJ3SnJ$Vf@YvBOER+ zSq1UJxN2S%tJCDD)!ST%tyT9Ljo}lg#?Ng3PwMYRSGMk7)z`?J&Q43WGwdC$?kZZqFHfgnl%@SIo4#W=<7F7SKrJ=+wQZh__}w zh*n2mAlRIN$2++VegQDC3-xS7eWxS%-9~lQ5nLVTt*$E+9=~2bP?}`wL?K zzr=$LDy#YEAH6!Ac*pIp}1PkGvit{^%x ztmHWz)VP0G@E1uZlDo{t(3Euzkao$J=bL~?j;c=DcT-L5b`7U*>A>Wl}qg_Z<{||gGOpD3}bdx z+fml{IPFWQt_B7coA7$RB@bgRP>U!A*SWcC)$66->_D&;>%JNsHrA@l7`EtmyIGs!^EXwW{ zmP`~>+Qdc(RLf?_=1C^DSwfK36)~aEHuRx()LI@P#i4eTd}sw}5R)4RP@1&Tv?K$w zOKNmD7wGCwnX*Fwunds@sY8c`yn25%hSYfn+hLJe>Lh1ivsj=IXx!sfnhUa8NO z#VuY`haKd6c&`egqM>rb>O?G5;X5`aKD!kxbhE7|Ogq7-dsI?XR?Aoepkm*w4qAK) z-DyL8akyiUW_hTDusoUBbv}Pdf)D(0b^LcTt4Vws?NZ?OyxHd}AxKcyP{b+~3rEY+ zQUstu-H?AfyaVr_W)Y|8n?v0Ju>><_sS6T9!w-rlWwMn7_(MrE^$`=5=wTIHtbV>0 zY?aqZE|F0t)JiX*6~m=&8O{ghTS<~fJ7?k`qfkXuXB|duuyHsd4`RX++!M8V>O>Xc z8MCV>W>$lKo9E?{DBbTnajDwljZ$QepcvIi@qo9_31^3=cQ>3NGs) zqEg9LPiS=sZJ|w8I_RcfG)w)Ryn#Md6%z#-;0Kfu8iuPEjLuq&U*Py}QGuohEU!ds zy)=K4<{KjRm!`5}Q5GUnr+_a?FtW^^)&~iuSM29Fd(ZC}6WbsBGN*RTg6i5mU zF3pW1OI2C^t4yPJsr_c(zLobq`&r_xQ2F&Kr|!$buV{&i32snBoh3XXzJ(3XmbO^q zg8H!F_ont<4qlWLCZpA=?@MlRj1bA6Oh=2CQ?rx1 z;I1e97bV}>;bp$M@VL3X?zW=8W$hv0@t%l{Mp!p%wYR4_Q~rtE{Buf8L4X^)^d~mn*TZjM-(}1|KD?KE&el_fSHL z{SQv&be9F(rHwL*s?5+iM_Xb()pKoDLZL+@LXapYEMun=VSyBqKV$@4jSCmCtRW>C z(%FsShlq?JU&fszCGhc;HW7t8UY*Ym1zn3(V%!Vw_vd+s(W4><0f(a&#OLQg#(cax zaH3Tgcu0zf-zcaCsk#Z@(BBZ~g|ZhGT{YfS4^Mv4VrAABJ#C z22s@dvI>|q;*4#PECvTic1YeK!6lJ0X{kb;=gA6wtI)mF>uVE z*KI;N#kXyVl#;;f;+4 zqQOgnV@1_Z#STngkklslimkqn5otwa z`)hF;*@NW-f$n6WtJ)yn)xpr*rJN+R%=ha-@;%MDOK`5234inqm0=@1kK1AuT1I?m zu(81ZUI+wkg*T-SW4xO&jAiD&_O?^j_`pj~2owbKy5ic=HCqSixb~r1MxSpNN5itm za4X}A0oTU{m=+1VDW!@nDV~Ex?e37qqQS09mnQwvT;Wl3B7JHeg3=xi=$ho1H;j4 zIJtq18+z6{QyV!aGS;OCL%n$OYn^-}{rv&YmyuqE^tj+tzxA2?{cRh4wmxYs?xcjI zJb|l47JF=kw7UO^WWWzP+51)4*npmjA`=+=xP2BQ@ zi7=*cwrHfK{8LKG;MYr~iJB7CUV9rq40E-e%Jo{Q=h9@dsr_d{lD1)!9~%1YQu1&aAXGRio;*?R*b@3uh=6BBQTtr#c*2j;qc#a)q!! z)}yM+y}wLKchcOHh6|+Vs%PteJQVaBs01ralxJ&Cs?9%a>?ct6_l`=xPSiBUi%D{i z$@PU0yUZlBvc2e>jUsn0X4Sz&VfuP&=^%7uCBV5W{ZBXIBV?{q#OZ1L@*Qc5^?bo- z{F}nI?_ln#Go}e_c>1XTK0o~V!BXVFKtESa_RmYaIWgRk>&X zhe^<$2qXV(=FUtO+c~!GHtoC=X#kfYcy@2I!G500KkzPtz` zD$lm1;FmyPqA-Zj>i{D4FZl-);t6Pw(`=RvowvCwfY7q+T9NE5Q12zVEP12z)EVRL z+VgwKy?tM&Pc_SP3y8=6KKBXSw-NOasjlBAhv|r)_Ad#kGL*}{g`cihv(DoSt1l2c z&mx!-FB!lmoZfWoCM=RH8AmnYzMQ1P_0@!QncijA#+_NbBCgZqC-?|$1gIK0b~KNw z=+N~*!_P0ahn$1+UAGP}%*?Q*Agn0XH!s{BYEL&b!0M?%fm8mEO6LWtcd3=SOQUWg ztUaJomPxsnbn2;Fd}t5*Pihh2mewzyxbR5uDqt6#3&i2#S&vP5Ui4}}tn|F8g$VeKv+?K!*y1X=~^@U2aAFT7Al}JHD z%2#WuUPMcnPt&J*0hqH-l1g`wH_HO62^Gil1!g)UxuEvkOiBcO= z0x=J+|F(Z1JBPLt`1S?_DJs7cscvKkJskPuSdTUtzW$|W&z5Pwr)w$L?)7ky_a_?) z1oQT!iWIV?+_Ol6uot!G`R2I@7<&Yk@%uq?5iya|dqYKNR)EKztg=Izs_FJhF=jOR z#&PY?9Ip|=lHVfTml=6d`{n8hzEMs;zkZPiUjH7>Wi)|7n68 z8xAGnFiD#U4WG{YD7eXb-^P1>2c*-<368VD|1;mGQLATPv3r#IW{VPj^7X(Wfg19R^>Q)v7QXBQoBydd244jdGdTlguL|@Pt^0btU^EBB z%;#1_3DVW&^Yu1{ZHh<#u=j8SeW^>k89^5he-`e4A9oyrm0cfE>(`11CyM|GQp34z zjlGqI1P{8XunnridnxU3KR%Xg_;5f_nH<-*_A;dsUgj6nkG{KM>I*H`5_5HBFqPYzOHRtb+P;4WQ-!~QB*Sl`(U ztnR$MEugI^S@ezm5f1Zh9pg1ld2A6EeJttnWx5Og^WA`&JmUB@HmBq1w$#pTeuaF1 z=Y24&5UG&r2z$+c$UJu)@1Sd0&ap~bpt2L~?XmlgYD8)E-q*!$=H-kMn? z5UWk{pWgpXAGbv@zLbJmd|ghskYG&v>}*4BIz1lprNAT@^rQ1_x{2v;R=VxBhhQ$^KAC}?;vYU zV`&sDHrpRy$=W5DpdXZ1JX0xwj4j+M>@h*O3jV9T=PEA%szac*v6F>Lu%*MT8t}dv z(!=J{R_bpZZ>|$lzXi6Iou+rQ((IqbWxx5a3~*_j?u2ZR%9FVp10KV81t50DobiktpifJr*7 z?EmM^|GD~wZ^wv4SR2-1_f-a+Ba%wa>S)e)v?GEcksymO7=2Sf2_`QI>T1MKwfMlq zSzW$u?!Qo9LzmUAov)7@i}hV}=?P)caN|>h_BeOb$(|?IyL_z>!1_0O`R9KEdVjE5 zTomEKlpG+6&QuJl+cr>tH|`|n5Tz6H2bY#D5b@bbN~{cZr8jULBpJoxaBRgZ!pl8{ zd#nt7uLtfqBQwJGJiv!PJQETc$cKbo?4RTt$c_ucK3L^_tT`R~U!4Ih(FlPYNYD3< zt5(j=&I$<&pC+YRO=3l0SRx{slJymA0h{5&EPm6_b_NR_T9Sex1sBu`w4Ln7h-wHo zDVkZu>a#**42u{a9lGs871skj44d$d)fAXwEfQoZ}4$89Qw3^larHN zF6;Mdv$c{^qF7%{Def^~&fIa&WivvAow6^%A=vUkL+0 z9O)4Fse!L`aj^xI^R_VKiC|Npt|hE6MAQJ1{BQ*)+`kFsrv=-xidRfdch!zkou^u~ zttXRO`~5K;?h(z%g7S~VKklWn2h|s7Q;gDtS7Rdz+FVZ;0fkg0#l?VR?gd(W$watI z@@!B?lID~`-{Xep%(aM7pOlnqq^7iCn66Im+bgOKIWA&ox!swnXAgHPl7l z+QftPhi20mT5bPdbnT7C@oAe3q=vZSG*3mnvYvT)on6+O`*E#=NW6}Vm6G{wGB;!* zp@!@b0@W`QF8!`H?qMFkS<2;W2C!2I?(M$xp5yPXLktN28NzMtDm7~H$Wc@EJG1eb zVYgV`6$q&W@EU?k{~sjy;VQYXp{|-{>3AP@B9gM;>J1LaGaVZnla`b; z>;P?Em0DQ>62qCgO(X%c05zMDTA3$>1b!dFIYiuHToWcmjNn>kA4Zlb6HX5QVH_wv zA0}o34QjgPMp^wMEww}Cz*xVAJ8iQDszyc2aV;`>R8X|B{#P_YEqjQHjhAQ=o)A}e zpPe3+_j}~cx!lw5m+WU;51Z2xLR54h88KtT z*)U9C)&Ug{hF2K{k@%6S2-`U+d*zj~D7)E#O;$oiS=4+bgT2F;!k{dv?eXW~xa?jd z(I5n@)h^fQ{0xTDNqx$ELn5rfA(1rn5gijg_luy}=MtFEp~{e-T-}>}b*UpB7xUkH zWr$`$MTc7K^3ip0p|8sFSPCK1NZ~agROPuRZePu9cm6uC-?=Aj_>XM@wlSuuo755PQt>K)VXn0V zhrt1I42On?iPM_g>&uW55QdxftwH-Le$|v^zA&^WQ#fhK@LDp&4r`z>z)})oDQ(A7 zMDdt4PzNd(TuG3*w2UiJH%on~QHlJtyvH}jJ4f32O|JW4e6To*_588Q`B=~HUmRAKB#q*Bz^s4 zJt-~(Aoo6Pe1F_f={=D$cfaJ(`qkP?B((HbzT%&e>CBae`GERuC(6JQz*6zP>Im zF9#3KSA$AbO$L*bhE&`t+-Hni;X#8*mn`zgNh3wdL!9@ll<58qV9X;TMw1cAN*!s6 zCt5Gaq3H;)K#`=Xu09h~R4l5SZgQGQozVq9PF|_knlHpoJ(_WX5E}-~Z?#v#Dv;GGb!e8X!F#cUk*277#XV1&+K5=BKXO{Sc(RtL z9qJP9)KocMomDR_<5Of*3@uGJ_${=kzV~UU`E>Eip;(Xs&ZK#4BArJU3LOJC6dL;Y z3~&b?lm{$j+#<7HP0H%PwL`?{}@IjyUpg1xKDdFZ=!nKUA8dwAv}igfX!f1a3zivABw9Krv+W6G3J!e8Es_`lE~`Mi)ra+b z;Rk%l#@y_bT<$jnHAH=tKo$v9-SIdbY}~_%27^cA;N?F@`L>66lVcCK1kx3vQLRAb zsx_wWtvl^hTlqv_`k6u=d0&JnM*kp_9OddYDlZ7sGk~?u@eS+NYgMZbsxKofAtvZT znqN+c!tGM8B)0O7^y%elTe$qY+;dTxQGu{YACDZlvQU?L=}mG%HxQlgtTbMC7FiP zPp!BNx-pCZNo2is(}b&9air|7rqU)FXfr+c(;~8c6vPd-vF$K-CCj8`$9M21!N-_o z2BTezfa&?9EnT{DlN&>dXR%s@AvO-K^Ep`d*Z){*$Wo$X-^;9a=UXY9ovg@HRNlf$ z!I9SG%sk@%q#H9m#*VtwyzyYE(dERiUg~FOUOv<9Iry$Qb#I9t81F&gJSlzaFSy`;<@wSO3wo>)7wVb5O)zjjX;y7i#S5hlR z;&xK7GGf@0rg3oVt)63KyX^Zm?hkkI%SYS?}_mxnExGnU}ii zhFw{8;PLq-=5B~M124P6gVc`n?6QIb-~t zrkbvdga~1KdndZ7r{0gZ@W&u4eKnmLDw*qaPubvPx98`qc&B}!DE(N@Uw1@K+!e}u z{QsT^9+;!`%(k~{rUHwN9^bY8Q2m2LHFjjP(D)TJYPl2%OHeLT(?lxO2a)&kI0A#} zg5SchB|`7V@(Y5!3lv!${?ZYu(wPc%?bp@55U0OE+e}tgeIM%59?d?+4;K`FUR)Hh zqH{MTPunW^qh0QM+Y`B@A`|Kvrsf4sTh({4S zmU5$UuG?dU;BVy$&l1zUr1R`?Oa+};`N!6J^VDngRNYw@fTnI)q+G=r`+0_?8;bHR zso<{?NtnD_Kn-8Irs~rsSk87f$qIKFYQx(s7)lZY)uXqhL=qEhdR1qyidNT3rt`(! zQ!hh54|HhZlOKC&I$y_QyN7O`4$rd1R|>sL@f_i>z^X-`SG+M-#ACCVGb&{4$A|ib z3L{9JnzxgYZX_J7Q;V1$d;&Pe#kN;Ug1b7uo(mvX5G}~oDz84d*o?+BQ zG9hzFo~e#DRI9gG7Lkm&u~#+*h$cjImi1CyD1jJ1$dR>Z><0kpO(b-um)CHpYYR29 z=FRBBlT~Zgy^dF~iVyuiw%#(T&8=JiuFwLdSb;#%;_mLn-QC??gHxXT0kR86zJUx!1gx%z6E;xw4pG^M%>&#rDIf*a-&@C()U?$cMn} z#w!VdWNw9_0vqxN3aw(0-CD0{=mnkyp3S?Ir!s;C<)pf=%Z>F1Q#NPzbv}G_I*s@9 z^H+E4k|O)(^C$!DO1PNp`tq0Q$z}=`eIb^e>9@ejta%bLm+wdZEADmIl2x^fD!O{( z{9elUUxP#Ugw^Xv>Gte}vC_wgy)N1$KrSQV&)`1>5R#IbKpAGbpQnrU)Den8Z%kKI8FfkF{3%Lms0&I`d)i3Cl6Yro zVHHP=z#}cRwLhq*IN#RVLcpA)pMDvWNHIx`5=qXO%&`zsetOmnmOCC|B?GGJ%}}jg zKKgK}Rq^tsy{u)2Av=dDyE@0?uEh4>4)JoqHNZpiWt`TMYx$NKM|X<1%=p;n!HHI< z?BlXpuAsdy55VRsgF}rzdi#SMyBMMLIC8U<)YrQt)`I2p^HZ}`;`xzYaP>T(+M15R zwExdWI^L9;^r~fnoSr&eB+d(!H zOTElkjci5sYfrC(SRf9rzs~*TFSP<+?Jf@6%a_{KlzBFo2Cx5|OytF2e5t}?w^g}b z>!^{1U8P1;sx(Q+MkFA`_$JF!dj#-E^^ZAjMRbh!qq~Z z1grC(@}3O21rD1+_*6N&`>SW#gFw!F;2J7&gf-5I`j265`Mat=5=Pvwo*TAYa;r55 zQ?#W?X3k-8KDUug9cD{b7oUlH2MWWr2HG)_@7fBkB`&cOFHwHOz(IrT4(+P>8On`` z8bL|T&mZ3-Y74zlh;gU;9<3Iy)ks=nn4iGgcqvS@$aL5cW4HoXC|{CiN@1dB$KI=OHqFK`KlS ztDR$j%`7}Ll#0eUet3bwZlpSek6MN4^_F-TQ*{-{%myc6Ll&=?1n~ zy-~b|%}Ct#*Re|8>C7Soy4KBXSC*YRS}V=J=daK%tnz_~%R_AzRWaEWfX8qT8Rf;!0ydx1uvJ4xds*TznrlTLFMc^hIx2{qCZ6 z%cF1^-TW}zKfS}ajpHQQW|x-LEINwMdm}Az0CC@2DQ?umWn(}6YprhD-Gb^XUwp6= zsUw)zE8^Ly#JN#pXMNSS@ zjtO_E+fq;aN((K$epym&JPAorW!bqp;t-9tLEg-#K~q?@YFldknaq&Rl1AGw2j`39 zP}w8ig}%_p^T7(GU_ME5lC??F^PM*bmxr%NrGA$;r-mW0&aKT~Q%lnBZ8E4@KkYHy z#P(4Gyz2D(Hr#lGm?F!n5EFrv!SZcPVH29ebL|E{D1(c^f)C5P_E3kqftWrBUysQUO?R z)I2A~TPVNeuy-g(W}J;I>6IDNcpgWy+u!gtj>FHH_;s=cvLt- zlaQXbCwK$|r-ljAr&H2WJ(7p@cHD z^JM_pVJOyb)_yk6@q2H)sSAOeQ;+r4g11PBYR-R3^R-ZJI|y#Hy=tt4HH>Nm3HV&` zNtNfh<7@5cxxb*JcIhhCfB19ZIGzag*l$z5=-bi=UF;k@tNO&NH2UBpyj2kVhnRDJ zh?1Vgr3|lv>z*1ILXkcrWxD8w8+xY~Y>a_S)8CX|P(rBMmK3sZW>2uQIh;!&n+OGQj#T zWXN286T{KT$qEh)6I1Ol7c5Nz+KQr~9zRP9Hhvh5^JMn^C~f5zZnDi^18X#eW1{%o zx7d#r`=-2YTXb5Tb&8MlYq@TO+$pcec2}=Fo!R5*w36fjD#T&2?u6n{4KmJsL3SO! zO|#H?JGD$?C#R4RI@&?IAV^M1vR)B69Cy0WS+F0w#>mITR~rS~d02@7(x=J0Z6QOhUz|aZ;Gci~D9i!P;!Z&5j519Hc@^^^;7E@8A&tP-E zd8Ul8;hj93xTR0exVk53x*CY^<>M&v#v+J08+)uB$*Ist#bPCz6<*`s*a$B_O^#|l zif7d<&Ww{>;e5P~mVr>QnqN>4i1FUnhCrYczGO6$V6kw}LA{9Yg^ ztXfblUP=g{E^t!uGc%x3&1n%~!z0rK$(ZbWg&t2SuI|CQoAS{dU3JtHAuN0KY2H&0%i4tmZbZiNXYJE4d$tgMk35u-x` z7Jn_K>MB>&D0Qi_)#80<7_yPyQSfqJ8!Bydt+9T5CXy*IyVcsuE|P6zhNx@Lb}8kF z91Zcps{2a-d#k(EFCEeG0(i-m5AQzW^iKf!e{)|3=$-Gs=j^M|iNLpT5K}bTP3>g! zxf$L}!@Ut-Gdc1tM0Bd7Ck-qzHIzZf_zF~KMO$L(&$3%A2o2KcmR@CZyb5W*TumAW zW(qcq{3)jsWt6s}V%pJbv1Ch?q6oT|d}yG|X;+lk`pE%q>fe}`2xC4@>AgfIP1}uDlLwZcSthH=IRdWNG_Ka?y3BW&xvxwp?uf;Z zQdeJ@*#3ltbAr9#xlpDzlet)D5MsdEXS0%PH~m!B-R2FO#1=FEcExC#D*<=uDVHg~ z%~LtO9jcWkfrO{a6asB5vie4=&E4_G zAa}M>rO`tVo!`@c&>ibMY$yKOn|L3jlt~a>hWR_*ABriq#+0i>k)h%z=-e-b@}HaU z2VdE zE+-1g89#0#ktiAbWF%7kZAm_8=9iZz!@;;povqX}Yl`Dx!-1#WOc!juOp63p3h~iG z=Ii&%j)qhY;T%sFi*BSKptuboEw|00*SC($9R_AE5kp(M@jT&PblR6(HiMBRAFZRXxSV2KR0Q!umT-5q-YrIW%{p%^OQ}o=iLi`bw)+$O=&7P? zhk}8s$w*gd7mp<(i(zPb(I7=}-F&gzzhF1Ms-k|J)~8!MTfM|3ZI((-0kzxKG8!NI1gJ+ zZrH-Bgm<#_JvNE@Uu)N`xUB5h*cjMxTaxq@inV$S#-o!cD4WOz#;w&1PrsphOJZ80 zDj%*tQ3zBC770)ykRThLV)yJ;%dkm`O!3za^9Wk+J%JB%Lc-&<|DzvW|R4)`r z#f%`g?><&b_R5B`6D_4W^Q`%@p9}PzSxR;FTf5DhyTSfr@^5CvKwJbc^zL2zIyM`q1W=$r9u&(?I=dBZqTx4uxC__e`BhyY^Z0TsCl)Ka_LKvtU(I+R8X7 z2>hm=(i6)1SjxJ|QvNGkda?OJ-*_3i1Nxa*EeqOX2^2;VwoTrU=_D?t(sJ1Qx18WF z°_t)IOu$Rx=D`WA|2G?@;)H_S6Byo1_=rTpq$GRyBN1fyLqJzn~7D(#?7dmeRU zNOq_cHL=kSti7HPKX5AXL25B`L{2da<)m%%%2_@JcIx+uQ7bd~1j&Dg@Hz2^J>8Wj z^Y6w%um8?%hZ_T8F3n%C=S+&UvqtZ-Li5x1A{i|$}@c) zlYy%*&K*qWNQz9G{)^HYS7UPoUNzR_p2x}&l0<0uo)@R@V+|{KC*o3J4^x|9a}r>? zuZKon<4_(7HHFpA8fNG=qyDbOyP-sgLerF|@ziRn7lj#DQPh<7BQ51JcX`8=93U|^ z4fM_A8@rn?IJ|ijNXjSXSk$)NP7MqP>9W@j=RVkToL^~qdhyh+hxF9;$5S6j7l8tO zF2@l}pi2$N&Nk&QTdBIQpvj;~S97^a@T_R}chXrzX9?Ju@&@57hWRTF;t^$=n?s)QgEGriSztI=$2kIv@cG z^P~oV)PNGAWLbXa^+XKG;zgdzOiJ%fn?+O-$jfp$eR>UlV4RBO_(@weJUoUZWy+}Y z&-|&0eNka&w7@aOt)|xsb6m{-YrrY(>L_PDjx(x^*?yTxr11;fff6iJ%z#f`!xX)8tX+4ba@7*v4MFTweB( zL&v~K9u3|@RPcDKqR=6JMru_HdcRxN_E=I~q|8E0$T5tv$&$O?bQMoMRZ1=TJ-1il z)aUWGw0~2P?EUmUqKD45-}KEGBf%8;Z@(mHytSMSoL$DJ2dMytww~W>&n`p zz(F%-q`PD3Xz^-~={k1R-{AcG{H~BhIvC3apc(BZIWI3B??rysqol2#j>7|hu?R_@ zQ_X{_Mlwv;Ak!>dFO?yPug~cS+ZH4GAi?;c_+&H&qgBnC8=zQ^KxHw>kfRK_p_U1w z8#3RZ)3(=S{Iayw&~zbG&VBpcSZX0VZppgemea<%RdzDrz2Hqw{=iS^YDk1Jq`D94 zo9Ak?)XO^Al9$ltEm#It=pK3HzL>`;MdjnNnZ!f@gsUA}=nO5@Qy!v!3T@w|GbK|+ zGdEA3POIP3yQB9C=(^id|{!hwf|+SZHr8qb`2P7~0au>L`H9 zHC=}{LVl>0D8)39O2xKX4`poNp+P_z?w)MXm$=W4n1xC*g9Nx17{qT{cC0zDlWNGKs6(Wr4kMrIpvTj= z1sejXyzG7FoHseGh^*JJNfm!(A+YWFmmZQ1$RaZ;6E`^i>O>LJ4~Fe7sUni29sqcqy42K_m zD-RmU5bpRyrg~}gjG2!{fvxFcC|A{mQf_p)Y6^~mv`Mv9i>P}&#B?R0bUR_d!pKf; z@?=8EO)sqV%nLuDjVlK9j}j1w%6wOv?M;x?zrt=fXoq^NnCKf?>W z2zoy5i8)!P710)S(5AG)WI9$}kAeF=$l$gsEO6DqP@|^LWhJ=oBjyb>t9sILHpwsQ zj0pH0e+diL$x8|mks+coje73mUrTs-p8p{WJyZ?=Pr-%KyyBM%&zlQgU7984oSlz} zc4N<4w+U_a=HrWUx>{Fa`MX#60b)Ke^=Thd*z4qd3VH13>9(=Z|H=wWP zmDW6A90iJMFJb;@@NXt=T5E8bAcc zwHo~CqY#Nq7YflNX9{U&~r0a1!|F|bT*Tzu@2Z46t*zY$cpld{DdZDw>T!jwQD@=A} zdZT9Y!^gs;=1KElsxU=@b%?M=$u~*WD_AB*3`I86Vgqw%!JD%{C+fIY(Wj=o0h)1% zJ{GOAOd@jGiw>`8P*D4Ro8h1xq@$F6A}-otorlz{q$YOk6+MK^pLp}=>%*wZA^~{^ zrZdvTadPX;c`vx%z*$*o&iD+zp?w6&>7I4d1=c3C zy}V&YlaeO0W=4CwD{7)@ZG|2S%VUO?%plUMt}VBAex}OuYx&dPLNOyY)YQ zT5G!ANU6Z~`==hzuROZQTf476&|~$D3V2&(7(uN*s~vM{3?Lki^GqRw!+)hXE<*BV z3VeZXY_z5up<8qk&kZltlIxODIi`VIoHJv!T=n%IR832+P!vCFCy#y^H(Va>mdeIQz52?IkAj<{iYUr*O6uTan4|5TvjIRSd)(2G(6LPL zj3pwpO9P(q#R7k}a0&&b0jd06=g@@j0erV<8 z<>B(U$-6XRD8z-R21uLIeeZF#D^|6h5yGwYhOoSyq;8}!%1HbG`YBeT`(4E~2&IO9 zkeUiMS!iNFo?8a3MI_rM2=4k|0X&&~<_fG6zyT3?4d6AZdZEdSd)f*ZKf0feFUhO> zbcEpZI7|`)fi<4y0X?W(V%@AMR6w){(2T6qQSnFQRKDH$c?m6Px7%HUljh5S-ro)M z&%oKaQ{NirL`yQ&pPdMMHvLHO-t_^f z3_;5(pyvU8J~mFaH?sehd=Ea3jf@wJI)iig6UsE47;)uMaRvRfKz) zJqH;2u?5hu0e~-GHgmcu)Rx3pFp@s_NUGu1aDjYsg%yb*nGqlW zhJ}VA5%4Wn>UDf922uI8-0!3w0(jZkF)0hGv?CR@wY_ZD5ZL=Z>VuS<5Ekh=zYy`% z+EN>7{g9ls3E8x(O(Z3RUn*b1A7*Xbd(yS9x@G$iBGOMp@~!skS1R5!PnuuQ%v_6p z0N6iy-W!2jM#nWx`1AOkp>&nv7iMO6DKmVJLQ0IU5p_i(rqd+D@>cnKBtLgFgz}|D z`VCEI0Ur(!ySUy~{8h>NahpNMGx!q`2Wp90Id}L$U>$ugFOoW7?Bxh)CL+#6i2Fe9 zu@Ntc4QfO)9XnI1Hpf!@O~nV=@BQ$a7w4+r3lyTp!cqrIf9Hv!Zzr^fdra7sEcv!~ z<$Qs4wDPkHagowxaMPnXAB}$CTLxXq(#ju``k-E=t;{>I+lNDnAT#rP!uiR9pU3Nc zizPoYP87+ z3(W9QH^ixzYSPY+WBL5UswphO68@Hr9|Q&0SG!4lxw~}+<0=#++`j6`*--4d2;h4;yPKh$($7x8{7abi@xg}bwYNz$D zba;KSyLqq>zcj}s-*gDefxQH%mf|p)Z~eo>)^{1h(R-*OIE+wYrYY}6Uw2=1v(LeQ z1*Q9bZJp#rpL!TWgWLhwHj|6RzITyOq^wOgf9^$#iSotudv98J)C7$qR(zahZfbp# z8{O;CLhWb@tCNmDX-YB`slab|!Sd{=tkT>T(!a&T&>!{kVZb5bhmR++nWH$goC291 z2yxNs%RZ1=cURV=Dmm~TE?*iR*7_tV{6K5&ACQvgl+j>&$S=%xh>qpPnWGbjWUTg| zxzXOL5}}*?fzX_X4Q&5%AybW0GBL=?h}M2n2+5;C>y*bs zr4wvJNv|`&ql(~|P9f^tx;k8XUz0;7fBZ&!12hQWS|~kiyD82bM;)TlkcuX;K*3(3 zYpPAc#KAcXg(+oWH@eHSD-t@m-&`DOFG0AOt32i5vZ8kB4NqeQI&%XL9Zk2w2h5mD zMTl2*c?yIWpf5;Me>UcPLAfpRr&IlU%@D|Kaa77_D%O-S;>Y*TVBMv1m9;|5TW{?C ze-YQYw}@AuhVkhF_nJDF7&Eszi**c1Uo23)D71P5cas!PvDueEIHxstZ^P!2n}DYU zBYTz-Wil&RQ#M$HE`d?aiW6&W;PM{OwfNh7hghP9234aWC5(T(ohOU(A@#-3*_mbh zl699zv%Dl=?MY{L&66~U6Vc?!VB<8DNhpve=TU|6C8auG=etfRb8Wx#-iLIAH=XrJ z?JYlpf}rkZLp4WT#!$ImM8T{S`+sKR&F^(LSuc?%B6zvEpgWqvlrF^IQ7&>H<}`JW zYIjI%<69N&kDkGd*v(#vhIxtmzg^7|v^3kg?&~%3y zp34tJj;7FG+BA}C#!Eic!tJ0A5K0Gr%QnjM89lGH=??Yy83^;?L$f6eLgw8=p^=2p zRtY}k=t|v@*9xnKgs;swkDXR1?LynbI&-`2tibKNH}*C{^yU8VSpF3E%->e{c(HxNh|eD|uzLDO528&PRwNUu^1OtTW36p%oj(J!(e-FZ zg;LL1l4zWScZ|Csa1e10Wum8Yr_xc;73d-w!d-$HIi{C-+N-q;_Hw}Bzcdk5h%Z++ zjCSlivS0sQfFZK2<756@ajA02fT=^*=A{v#?6$f7B1A5W%LTQssgCtRK(HxJML;@U z_1zRkLR2T|cKde+{cE1Qex0tFUHwXb)4SV8=zGC`qtY8|LZ(aM zRDLX^4T2@^w(9HFZE4Y-N*4_#p>C~&OF-FFfvCZil2sY{H`kJ0bV*T=Vjo^kn4l)I z5-j~8AzUtOK7%B$Z*GRw&=`G4blmpQZuMOzhR2AgML*SOSda8Gy&V9{(g&n!u2_a!kS2|>pof0g3@>X4|WnLR>YclA&892q#Hh5LBxCzUB zae0>=P2Yi5uH!{F_tBd&yJQ5 z8j-=De`EBo4}3o^Wovr3JUtE+LQ9sM+ceX#t&Yd&K4}jCZbVYIEcxaT=lhVZ|J(~O zoa^hV+_tzI(J+i!%?}l{q*#4_s;@kBu(?FAq)+H^KPYrLV^mF6S*AkOAey#`PFf<0 z<&^M}W{`v%c#F%W8z|cEsOllE%Ae$8EO?r6#{^GBOY7o(8xK|>=6!B_f~--8lsK}} zacAS&Efnz-4}#h?DM1lSAQiYa?|?}^JVowBWBtBgzAy1EWiOzN;~0-?gT@Ecp*=n`74H-BXlkL zpW*c*3<_3C0F+lIerkUtRSDgn=vJoBC@w#7vBWyErQ`eKu~xtFE%H1jujHZ2k2gNK z@gssm3W6%%937UsHb5GCQ)#?(A%bGyi;1d1!=t3=6){9T&Y{sBH(Q8DwDN?I3;$I` zdNI&3{feau`?J)S90KeK5`-9%W-2g|%>a)hed{T{M$>WHmfutTlO6>`44S8?y)Boo| zKtG)-1>BYFte}CoX|Uh@nlwO8{ZJB)Bh|iI^Jzy6VR)|KXjtX#kDA26-1{bXQ^LmE zY8C0x_gj4*-b%1G-|Zvu%yAK@0kqhDFn(Xlgk*jHO;yWQB|b<*jQ2~Vp*b|Ku{*#w zCK7vsK-76gkm%jnxY=MQ7R^xL&q8*7>aLv0ae%+EhASt#Qm)oR!J)-n&grb_l6M$# znZ|fa&UsZUm*uD$UN^$ZNo&}(@{z9 zMk(_ZJCvzYpz%3bp(EKBmb;$f9wX(6MDX?d)3)N^*53#D@wb83?)$mXIw_?m3B35p zx58hjrH4vnIQ!1d{)+>4!%^{48Q4~%r<-bN;W%pAJaR9gIaO8Y+es!pED?*BkLM+x5jR8kY9zrbUsM z>}He>zn96W7~;)UDmt95i5C-@nR+^mF}ce0IxNbodJ|SGXa@s4$Q?`wWwYfjen?w} z`XyY&PEB&bl=AtSl=JuYR^pu;;*>r(x3l9>Iu@+S#;MW@j}QEUCU?zwN!mXk*iixS z%|vUX3KvHtXnES=q|^45 z%bt}?j6%J`wBFmwoGT9_v3BE^`m6Punc#?ky#M&U-OwbS%RQSndOkRLQ*=7mx79#kH719$cMOx!|fT(1h!kEM;@M`p3r zs84(e`|1J=r|q0MUaM3SJ0>d{~3nE%*N|8 zP=uDe27qb`Pr#&b*`+B|UEEhV(92~16)XUB5CJsH*hQUOOPpPGz3a~C`(<-`-d>t` zT#nVq;M8+2rlhIXGHykMj9waIK|?~A%{35}XQ?491^Md;@Wx~mp{tUfOPu#vJHMw+X}?S0(p+P^O58eQ2 zP%g|{m8xLt+xVa?wVRlXiM=sX?P76RJrU*`l&?mhZ(mVCLgM|Az1cq1!98xh<0hVg z@PPc5x&s@b$%&ui_NyhMzqpRITvL#Gv<8+jbY%3w?v+=fnKaybS4$^t4a=rbX$-cP z7J@Es%HyMEffNcW7&y{NruoafPYgiwg6Oa`d))pYtQcgY{L6_xi>WW5K^W=C;PoAG z51w2^tk@^vJfN3oljEkZi1mQ0a^73f|3Y}zZI+=P!-@Xu552%fVJNHVOwxI!6V-2y zVS<#aSc(Nrufj`s<#DdRM4fSjw=3grc45t{(e4msplPELB>3O8xt=5hH>vX|jz4_S zbB(>6Z!!?8isYImkkvwwnL$-BT&uwd!^&q9T}jDW@VkqqMJkuH!>9SI;r$U7es4v{ z*yEj#dxwp^)}Iz_@wx7=hT*A8t{r;m3XVy79C{U<7IRu(%S zG(S%+%WwGoSYq>Csh)%FU*JV5dr?&Y24e?ZFgX5KK-g`C9+!r?0=08JJXtfuVn}2r z*vnG^ETHN-a|;^)af59@O8pn3%|6u#gaAoC%I1f}!muq}Du&{W!fRq-; zMOSmzO}MVGIc@xMIE`!}AtX$aQ8mW5t) zDt^@<{Zb&3Dwj>(s3>QO7KUGg@*qPK_^@syveyQ`LLk)bd_^(E9vpSNj!Tx!2WeH_D}SqV@-SQ<@RXjWBwqzuC6`&94y#CVwp_`C7hzL^=e|96 zzoKuTS@{e}VXGSeG3oAH`q4VLKqp0DrJrl)+N{xQ0O>~?zg)2`Uum3@fPehe{}VE9 z1R`E4w?TK7?^`LT)axx(G&MD$wq#l%)Qj+t_|l;onoy!IjFVJh(M$v24y_sm2mu)HJ#w zD+|q1vCCXVkWioy?O zJXR#+f_ut`q8_Cg*-FVswrU;4RS@JI7YQqhZtpDwM;SkVRxQ5QiQzne-Hn=hp|y>p z6`$S7>Bie0rf*owDjH{_)f*%;e;i;gzUX`{_5jsJ|Kx{^4CE>^5cll`4pN7Usv_Bo|n6!BDy)!f1O{v{95$4 zH)izaFnygI9ia_7C!jsp^YTa{vK-8QDFsFS2S~Ptb}=N*@Ube!xg=EFV%VlAbTb@k z09Y_jk}m4inhgzy;z$(bt&g|ak@T<#paNB>G|!{$@ZB8XUBp*1G@dIZMa6~#G8R~@ zHer{Fa_@i7?eN8|+X|)M8T8j)zGQ)}<^T~gaOD-W%NG^Rb2r}4)6?7cs8D4CV|ED} zl{4pKX|+-U@s~%a*Jg-;wmWy+{XBGPz+vev=B|!dyVYH$bWABC>8tV@6slsJA(Y?^6mFy9Qy}XPQa{rBlHj1AFS|8D7AXt6I6I-S;hwycxT>o z99QRT64k;Jwi8O89=W{p>RQZuKI2TjMc1KY(~=R-jr=s#^W(qom_OIg(V?p2VuXOe zVAaD}S}i0~v%-H^Xi}-}5k0(BIT8uF`j|I}32+Me>Q|}9jf%hFg7Gn6u(9BIE(>8{ zGUC-1oJ^=W)EX+o{(_+k`q13S=~I<_|3;w?4Nw2TRUBBd5hl)h*Y-6~SYoW$P+)ss zPU^709_Y54?#>7DUC*_uS`}c`0Y_H2 za(y-O`BdB!eX!&=&B%7HO?bfdO+skr)X!>#m7W1H zh{~4Qv;)Q@Ns+)mhCqdD{TGnb7^&n2@AGbnK~*aW@18uDFfEB%=P~dJPjtHM?L7tQ+@l^ z8VHrUTg4355KjSu;dt}<1xHpx0+ZRzP)Wl?c0#nJyw8U0e7ItG+H_`&NX2|KRrZV{ zqpeE&dOd6(7vH5SmpMZgk2Y8F0uJhbhp!xxE4K5a4!=hkkW(K(Mc~`FL$if%fwb<( zytv^IO`w^zr=W*I9V-RnJhdvtBV4LY@QTiTIR)|Jxmuz%M{o9?WE6#m5xkC1j7w~A z0L8$>78lzsO)mUaX92JS12l2qinN(lPbPZ9+cJj4n4EB=v!Q2kQnL{Yra3HAl`ABl z<)uYU)^3Flp3mbV`LFl)4Wej!pW4ANxhuQB69|txAu%x#Dr zt=ycS$DTmNqg453EtWJ1QC<33(VsvBJX$#jeWvL6Q!N(a+g=eO6dcniMT7BV^l@jW?&fD!qkG=3UeUhJ{sxdF`rXYQ*Rd zT?u}@ExE&Mi$n_n;wZD|P#rcQ`TFjzNn9_$V4$S@W@$|= znf^7DFC0B(cpwqrz|&vz!$KT>BI?~QVU0hGu{!W+UxLJ#qDe#YRW0M4XX*oppX97w zurAFL;l%j&F9@g`RcG^nKD)~Ut9LeI*z-ATZpXowl-(YNxX$qWXiA@qJ_h4 z89Tlmj^+um)ztztdLiJl`hX!#d717 zcs-Vy0BzghZTY!~w|s_ZK8OX)sNK=k`5g6(6F3p-U)F_uwLmkl{?Ae4@4tv)HQ#oO zb!MQQLg?uRup|1RawRDC4u#*TT3{STO{zj`IxXM{)luiqk_M!0z5y6w#m{-@rAWRL z55hQLg-lBcvXDfhB9IZuLX0)VQEe6E06O1ULP_Fh8*nHos6x>JDXMgfOf8UaVhfWK z5s=Hhj?SW_^~=If^EgjQQF}_*A>j1a$_feZYR zgV?V>PQaXNNb_<%_Y3x9sYCPcFchgDHG2B{rLTn#!hOOR8B}>71PwjjCuB$tPz*Z` zpg^nX(EK&Fkb2`?ZjQV_HaxNR*-SWmA2S$hinDuw_;fQP{8u4;#dPi6RSPBo53|!y zX-SH(ARVo{&*r95s9#OzyzKdf-}}O1CrI~xC5#V)&37pqH>JP}$QCS-ayMJf0&$Kd z(X17Zr_Z{lh_MQW9745tgvAEe^q4OO{A|7SJiD577Lrat^|#*$ya!d%4e$gG@z1?% z+o2|phrv3-B_|L=FbisUdxMGm@BM4I{p{BNJvBdYkgmOLUo}+Ak@===Z_4tuPuR7_KJQJ905YO#55YX&ArltAp=>i}7y^x@MRV2IKWH;@ z*@A(zomD3r;b=nr!j=B_+b-8bRZrDQ!(W=qo?8FIHLE@)Oj)@tg^rq7RsYCSI0Z8> zk-CXLlN2&y#)S9~Ec+5a<)oEM< zYD~x3sNH-8CFcedZNB}#X!DEFN#Gbul9$ivuu>hhc%+zaCQlO@6tYddy^7@rIBMwG z(qJ=yy&vi@dgy39oJVQ|`3%>?>EqPV_vrzsDg+98kl$86CUj4WDhhTA)I+B0t6VDa zY&-eRO)C(!>9Z7p`ndS`;Om4}opukE987QanKy>6QyW5pg55nv4E?_|{`d5}S=WH! zrx20}`e;d3FyZp{ac{EXRr! z^fP;nB?)_;Y`I%qP&h(GDcXj>X-n$?Y1X@SSh>b}bd}F!GZx~h`Z}^Y8j0@#ENm`6D9u(#x_im5!{ z-P~IGba&S-TVvhE^KsY{J51GT%dwW9Y`6}09M{F1ZGuD5nLcy|tyuVv|kE#ZNNp zQ;+COZjrF^x<8dDi4WKM3cT(bmvZfZ@?Nd2ophq)6bz645op|hHAh42i_(52i~n0>nClPnaoLM zr`HjruJ=Q7&W4Z8Ro%-zU(ngtTD-1jlXAQd5o_Ao%#@D}Gc2#{>iuZ=h9&AEt$#C9xX?GN>Q`Ob~! ze$=C5*}=4+VIsARrPUbD2hf)Dr?dZKbM6y-+NXvwH*BS4i2;+%we1JmS1*rI?V&cU z;0Txa{)Rp@hN?#KbJ`i)P+Co<)A=9P#YTODYt z57!#CK0zr|?2Fs@%x7?nyJ)@mKJXPP#BV4keC84>n{&Id_vjVdE@RBJGR#CFd(jYY zjPOyxL~D)3bPZO}>S@aSyB@o&uTBHl$`9K`_(ZSA1i(y83awzXnJ7CvUdb}~chzW< z!RuA4uNd0Y^lxq}!hs&;Q&O<;@pY}l72=eWV~IdDHg$@1oI|)`zQZwr7^HrCuM6DB zon$4iejPyIf<$b?zJJ4aNP$VcHM()}p#1mf^7Zcy)O0XkH+w^J_)%f+Fy$4#BB8`Z z46o*n04SV)$Fo^D0#AK`5=$&HOC&N&=wJdt5BJ;t+lW@rQ}0u6f=C7#C09~Fzdu3) zY<(#>s)-zcs(sYF-Za@~paL&r#T9X2~d~I7$Inal#C_@ZYhKK$>6Y`&R0{DLWr7-b(Y(`x=zZ;b=9x*$Em(taOy{-l$|&spMDPfH>tnpN;HLyaV+YT3d|>N1r-J$pWIMt1 zcpqoekt)(*&=`S-TWntgZz_4eGk_QTa2xr4uD}J+A>sIL;d5M(Q^M}mM!=?pj5wT% zDJyDW`cTz{rh78N5NG2!&C6%Ri6tFtRfQ=b9Z3i&Nlmvcof)!JSZA;<>7|K(JBzfq zFp1!Pu$+f=zf<(g@mDnTrSpoR?p?}M&f6zw<9pBDOLS&{3@hkxLQzLV{R{fi#$R6# zUA*<>Wv%dxfBP)_7B#zKJxduYSQHTmYh7w*g^ul>mrDE5X@K3h~L zz!fk36=y|#s-@n1-jB5V?kz-w8IdQ9C4cd^gJb^kP))CFi5iz=&AV1$auX%yeh%6c_3L7U$DdVHV8}A1mndB3Ir4JB zCXAf#(^Dp7voKe$jKhRhDtLV9`SJmmv4KK}^O@v&4YQ+=gBw@-*1NzN#loJZG}N4I zVV3&E>byjW&ixOws}FcH4XeCb1&y_$LZ)dGH%kFRB9U<{^(yWJB0T+*VAr8@b1c^? ztw?fT-0J&sUzj;}S}k5^LM0TIM_8+eMJ1A$Xy=q?7|W9yW|Lnm_15>r{du+I{R6Dx zePPO*`Z%xc-RBgWqaBYc4$@7CP9d3oq1+pRwkJ1T4~!@M{VfryzXIOgNM2pN$#iC1 zi_Ip6@uI;-%SGm7vPC7#R3>%L+2fM|XxqKp2_01wjt8Qpp%taNRA=$DBjYRdmnQX} zF-;W*T;)w(yR!X%OubWloYD3_Tm+5nG`4LtwlQ%U+je8yZfs7>#_MX(P&Ehz=bJ?>EM81NUg!b40^I{x|Kv7bcs6R@ z`ipz-$0lyP6PZc&2r1t$vOs;$6PdtKwdRf2t5F+8`tZWv@%}E!EQ)HG(?ZmD>Lj{) zR16GFD-%W8y}fwnwgWqU#J}~ zoGIc{<=uf z(QW{mz-7SD)jr+6|7{zDs3Z3wCE^*cH|8l9Sq8z4}3tNq-1(@U`n*DdC{E zf+3vU^!BuOQ;BNsS*r!m>bhcrM`u6HR+3{F6V<%~u}=6M?#t8eyT4WJaytLnrPJkU z#M$AcK8Vx|RhBeFPgL42ZPAI2ilnab!$hV_CF-TT;JYCps&Pp2T3jdn4V^k>{Y7<& zq}}SS9=c>NA+*zPyM+p=^Vdl=v<3TT#k{t^IqnbK;8ag=qvd+}j5%l4#Q1nv$hS_% zC&lNvGTZ^IWw7w7pG&L&K?FrI47`juB>U7!ndJ2mA}fuCrA8kcRpUZNn$eeD^>A>? zL}?+KMhKdJQU-rl9S*J(e#X9&?w4K)$XYrA9q+d_TxhcQ!Xrdv&gr|(J`{3)|5uIn3Nih zac7fnOSkeHT`1Y-cANGpr?P(lwZ=f#^`orlg;_QVwxXtr-C$J(CC`yd6Hg@mb2wkN zgOq1;zQOW3*Gb-lO{7zKd!90_35_NLRde%Oxw-~akRURC#?#eJV_#yBIn(VBc@QZl zAc6R2^1d^qgbOKnh6>&9i4iah2S$a&s|5-p{vo-_2^BuHB!uVsFA`Q88vpX#WkPwx zXkWHh!$W5~lSWcH;J2~`PM`3IVVG*gGA_6Cs4;DaEnQ;H9xQDK8oAP-8J5sYM1)?o zsfQM>g1kQe_W>5O7ONN8^f6T@`#=n~j_Xwi=Jk)Yb&rGVhfXHX-oq*4jpwrnO#~-@ zn@~KB_vyi@Jh2GxgYv{G|NlXkn!2u@#yCHuQ~LY*?#@;gezUuNH*%ZMBQ)pqM}?@& zfE<8jsUk~wOd=7huB%TxJZIS?;vsEWc{};0AKJtr6(&%m)FL7MTwum&e@9QOz2Af~ zFsi}ZFCxD;_|zHYNbV?Gsohf9=)$t7%>bWXYk2lG(FA*EGZeonUF|xaIuw`!-T77` z@)e&kRXX>Kr=qL4fI6Y*l6hdhcx^JU%!YoD6%B~qYZ?KOxe_p2!<*&aI8f(T9u8m{ zRmB-0auUxoX4FGV4=^zd*3+n(tg!1H@rDef_K+er}b^^ zxzlX7?}xY&2R6oW6OsE?5|&m7US{0hI=cS;^5YXS8X9;Y$afW&*It+qKt@J3iR!fV z3Lak&V!{~~JA_upz_#SD`J-_>)4{&BM=*jdtBB;rH-yR~0=fGJH`AL+3LE9c+$_21Ll@SCsDxPavX*SmG?BumIS{|qG`Pl7XUG$zX! zAT76+h-L2>!E|htVMerqDI9bKd158Aa&7|^y}y=8#0-{2D`BxCL}H~zY$8NnEf;@8 zoSs&43j?&j!j?qj>;(9xQ%{Nds1r71Nx3%CRgCibriGA-u(@l8>=^94SNuPaI1ZFh z^;YAZPYSI_=CX@vdJ2I-3aIyMVq#L}gpEZza{^nETq$qg%*d0mg;Yo>$wG4I8iV{& zW&=wOOB?WUMXOO;6qU{4-R6|eHW$%|7$;$lV>NOyC2F2M`eoS!EIkt)7Q&*l2uymXT(j?;(2{wlRua%Gx&Z?Ru`f1mkk+9ff-V98JR?CNnHb+I-QT5ieelCH*%KdCBih;B+dZ-8= z=VqG^g*IG7z)X90&5B-<)@V^uLSn(Dq`Dkf22L}=P&(PqI0yef7~(fXPZiy{7fGZ8 z9tLS;=><o8)-0G%cfiLBh(Q`S7lds% zNM50Gw5W;qa5$jLcPwDWe#CDj@?l0t`ZbAr70`~4!(5_}o4=~Q-DnXyJD;dFkSJ*W zHowj8E0F&0&h{C+E4SIUSqt5qg~aLj^=`UqL#KN49V-5L)l&($Z+Eub$nSbNne!H` zhJ%5OT`ErzvzZwW3#AxhBB7&mK1U4zNs&k4@-DOG$Q;-x-aTR}w;xQQjnxI2AUfYp3| zLxmI6n%X+rG0rFCIZk{k-7ukFv7m;-Sa#di1d0YE`Zz>^<@Ka@xSr+J7iU=7AjsHK zLB;{irnq6)ah>2f4!0T$;jFcvZ#G@z#xpCDQf@=7ptJt2~XkBm`Cko{Dd;2y*g^K?m@KiJT>!G1P+~$lRDem zu}{RzGB->jsd9G#+BbF%&ZA$IHK$#oHAZW(V?0n`!iC`OJx$A}$)% zT8RO9RP}e{`g1ha$j0_6_2(MzsgxDcy znZS^HlSaqM9UESr-}R;;7k^5Vb+pq0C-(zKf*#yBWo55YgH@$k%5>s&J-l6s;*!w4 zo*(Pr)MwXi*wEGq>4LWI{a7MasKy!+j{;#Xw9N$B41yL?ml zRwCN|I3IwQ+kJZN%gU^)O*B~jI+X7HJUO6R$5IOL`knUtxjePP0Zj5{D&6)k( zB#qoQZsh>srv&6|uaDI99U-u;`zm*r`{~SYMP3gBCA&4b=EuhkRi`awkA%?^EmfTY zLE%;3pB$g1d`uL?lD#}P=cBojbah1%LMO(&a!tw*dzqxc?{ERt8j z{Vs_zv1mL?^Kq*?Az>yNX44?P*OsrbWS2S(Bt`jVaNXx1@atCp>$J}tI7uOkho|gIjR)y;)-%LEmnw_x1@^GqFDjhAirOp z6}CNWe)5-&kU@&OT;!(j3&~urn_E#FDZ;*46?3q*MjIz!Z=wFIk^DFgDR|{+xu6|t zL4RxLf>viyY>CbWr)h>y%0N|C+=Sm_vp*MXH&$OTybyHNB1uq0K z+SWEk=a63k+D&+8up*s(nrUfKffy=!JBX|&+j4`s5K6z*hr#rojJ&WD7qQXgmuadCjr?p5BLt2@p9G+XzNDfNAJ+uilm%=R@? z?vI1%@fuQSvYcAjZv}*o=hLhKX-OjJYuuE6m5Ovm(#$oEqlK%t8DGNt6iH$d>ClMv zH<|vWE)Wm%*Fg50^9Fg!iM0XVwg+7ZMr9LvZ;z8QtP@LS+L?HJUB+<*OdPbTbh~`g-+SzzyRQ>=IP9-WKof*{4VsSmE(7d% z(f*L?!$R0RVJgz@6rhF`o2IRr;SKs#XoW_j>0IfgVJ*6*vSgxQNer{Sv|d_LNqr#h z#LGd6&FQQb;9M`lPF|Qo00XHuEDTp;VQ(lj)0l28I>v1vjo!H&=?yb49x|%qU_D)P z$sZMMKSZHVI7o4CbX#G0Upw!qEJ$j|9t2RvG0GvHA!%l{yZF> zI&n<4TEkCzJ`dXPOGrfLrzZO>pnNMtM_f*=f7 z%R?y8)s@h+L^o~f2wfmZmOO%)wi7DY)yp0#HPO^!aZriJ3zFieQL?LFPPr#Gp+B+T zoZx4_SZzLWOfpTPKiSUOyEtF6-wu?+Kc;-8VGJQJLrkdGC_RRsosG*Ht;f-$Mh0!P z0@)*;RThu=)==5g?WXs8tV=#oMzRwuvDPM=1qoZR7<%F`S z@shsmYH!ldFr|`No{1|=X6QiKir68{Fk{oSTr-Wb88md%3_g!i32795o>q`xfXStv z?EIzc$=nQv$efgIb;~RxMZ?Y@<^RngPN%HGF=%8NcScUUxmi2Jq*&pn#Rwh2b$Pbi z_9cFeNGz%BLFZ3i8Y}+sKY$(}H64DcQ=qCd$sJeb{cE!WxsvP^4JAV=M^u>|Ke5Bp zar-zt2Ada9?AVTkEUYEtb(WVOrhLO9c6?YlNOefaq?1GWIWc`Aj5l<#7mTvBXT*p5 z1b1#-Wy4S<)m3?gP4Q0xJpkXySx)_K+te4yCaYf6i1_L-nOc_9Z4=u00jYY=1UFX!R(5_EG^?3op>v5kXu3aE4ZXYTdFns61D(M^c(^RwAc2#8@)?B9J4a zpDuz^uOm55Aq7kRlpp{qLyE?=2FEcBf0X_XA-ftQx|1~hd%SdX*=6vN%o+nl*+Ze= z;5bw5k@X5es16Zh=05qWv2;xi>IszbenR*wObca6=_&g(^o#v&UX2purVMXR+OscW zlc0MJLoS!&srZcJm{IHN$t%|5Rnfo$<8b+l&x_}M+*f@cfhn6G)RDF^UYi3|oqTk- zxZ_z@r@Y#%u)`A^*Kf6R-=HMKg2d$@+<<)k${UspN-rJm_g3cjLSHqho4P+#+aA_i zs8z@-LcTLFxnGrr-=-#3jf&9o*a0x$sCb%h1{RXSDD5RAYObj^+G>b#hH7g;|ewL|4`+A0u`8Ims_P9oVb*U-pPf zq?M6VuE81lOp>DAk6Vvdevam&g^MPd#?W+*wVlj-g||XbKzK3V^VdW3L(NiizqrL; z?JtD0VYWRi_BcO179~w|IXwZtDCgRIZs3ACdGEa)fUJkQCh_KW8Q0}3XkQM7wFkh{ zx;?zrlWQ4$J7KtPK6w(K^X{XS)J=uynu(w41Q-)#gdSv2+}pQV@@aOjC`GL z4$JP<7dB~KD%=Y-CXWH+38ndn^t)>xg!WXj{*U?m#JzD|o_FKq2j1T9u01YO4v&Gh z0T&LJ5W#022N#QrER~!g6ugtxot-hx$LS!fXiHnZKBp{qmryT3#oEv$AZAj8gEQdx z&SNweNM2g~IB@tm2z1IFsVN`lyU$}(SG9l9HZJjG2d0CvbJ{7&emIkPSK4nDfRrgV{@} z##xjfgBOs)`!lvvX;uf}?UJ(zcCQDdH|LoRJis=O_pR*y2%ntXb4h8^o9w`e=$D^2 z;5KQL2SO0d;XaW*wxS}S!gjw)g+9W=+Xk-=8??Ww7_lP*MT`xa>|UbI`i#RBE3K!? zmt@*)#)rl>8XSV>e}035IhiMI)^5EIpa=P6RcO?!QlSat5K>i~4_+BiQWnX87e<^) zZ|U%w-|{vh;GO!OOOkn)7}8bR2RYyWX-uzuoJkF(Dq_zPjL-J6SxQ09ge$P-+*tw7 zi%aLm!^k~{Ml#s`%8b#$z|p~?EI$%EvhLBQ#WTDM8dJ!bj;qq5eV@ANsnWquK-@m1 ztXrGp%%;P~uA*F+fl3-0KB*LKzrOGB%FDo2Zj?@Ge@x|*b_)Ep8wbo~VcYvt)S1Ft zP&K?1O=Ucp08o{LDaG|==|bz9>?b9cY@h4@x{OKUB9iwxd|!?hfEsDz29mng$%QF5 z_)qEm3*wVf<4|+-JG}|O=-u}X)E zpH&gi$_bD=*CNfetbGIKh;>Egrf8On6OTsp*!1Xq;HUj59keO z^YfIEmyb^=l+jNU9_Y{Lv^}?fHWIW|HBK5*o~#rKKId(*V8P=BzlAaYRNHi) zYGF)tb+zh~E7Xc-5C*EnOqtq-hE3OJFx;#`m6NhB^oGrwu|iao>W2wjebv!q{F9Jw zqz8^^kRK}$I6%`RSt5KG6JU1J>At9F%9Pso$m%ZS78uW`H+?)8PgSTUEe7ZP3>1hC z`Aqxm2v!u%zf?x{_gg!DdB;M17#Ey}d*7y*y$qS^aDLZsC#>2Atf&3s*h+;dflM9E z_WnLblCAp%)m7`^F|@E*LxEVu*apoS2)h5`+D$QuIkJV^*$9t)zm)VdkMUh_tMt(P z+`VCG-Z({n);XQLw@@x7`LSC(!10PidCx?(t<;wCNK3zHfK;k5hZ3Dv`SuK-knUS} z_t=-cZtTOHp^!_g+kU+@Z+Qgh?Xj7Vn2(K93PKk00q0(@v2zP6sCXu}vTscpRyz9F z{=k!hMq+njF90>xGU*!%IlsK$dJXq-(&i63dp{|Ns)vMJRgK~w z1sTj;Pvd`Ju>w0sgz6r8Y@{XFnoeyC!e`wwySiao={Ot#!ZQzN^jTKaM(JbRkMpxw zA1S>Wd9v?b^Y$K^le(ZR?CP&Y2e9xPFDkrBnJ#sr)u>-;GYZ$p3A302;oyn=2{}mj zcAqys4kw%Q_$b5$7>`l`>^4i~%B7=$`{ix8^@7~4kJZLwX-`H#>c%|g3IXLB(|Q$G z1?-5qjko$B`&QOrp5z}Tj1;Wv5|QfoUsYqp{5P^}=P>>!TK+kd{J3m6laJIph4)TF z@YKpOA050*04ipgGAjt)m&O$t()muLvN4Tn$r~DSU6J+l>Y769gcOZqA)JYctL0YA zI`3xy$r-#tADacPx*at2%O8Al+~{huigYawLiL+GwhIp4yY>CV@ysJf2+@-Bj_vNBu1JeF^fTEQI-u&1Gmnv$j1ax3XILrmIIhKzca<>NCxR7TTN zO%oPTR;*0S^kEnyvL9zY@qAZ-AcTkSWpNY^sC?9PoC^;*89SCZ<7B_ji4C&DUn|m;eQ?4q-)=^;d@K+ngw0>;$SS zJ-2K~P4+G9xkQ(H5-%MjHGbOAM>V_M7E|Be1!-1WnA~P=)wl5cik#Us4|W8rl`>Wr zEsco8`uhn71V=N~p&l98u)7n$ z1uE+T8b)$6Ds@^!HWSbA%95arIEwH%xA{<=-4YH?GGRX4#bTv_V&gbe==XFn^S|hi zO=|XsW=%PkpMBXS?sd8Qbh}nteMip?mSc_7E#o|r_pj6_}F~wwYWGg3!H{C z&aq4NZ1@M4`~)8BWpZ6v|NH+YyB}u+W5shvB$fOqK)F*p+yS)?8}!UzWw0w@7Bn(h zGf5j@I#7w;$B2!$a6a&b)aW#tMmcZg(!yzTxhfFH7n>&GY9NhAaUmJAa_<)jgEh%Q zFcr*8$vHMA;Gts7){<-5<)_~zjZ{bd3I_RoSZ9g0&v*KixMByKO67Lt3^)4|-&sYM z%9RS|uUA1*53u12C#)hvOwzs7U{SL`$c-?QmAt2Cuq5S`J>SE?LHvFxb$qHwaAoZj~C9>f2 zup-1hV(4%)doZ&mabnrlXBnid^7(*yLq#3M@HyAw(+&pn0#DmaRPRh#mRZ5rCl4yW zStY~#E!6@SECMI;={x5)E!~WzmiZd-Fh{%?T%uR2RRi%Egomu;Rkl}eLrHyv#?Nad z$pPYN#L=>vp0Qc;%4bXp8XlZDrj`_c_)tQE8l5;@xVkI#1@jXED2cJb-^sr6P@ zURd*qFrr<2x1jyOm#0_)VqkGO9UC&GGBGnN$rhzROZWB7S2GycC)0`MDdbK4+WzZo z@bCHEaVhJyhmq$tUak!+wAtto5D=&&7rzrsfbO~B8L18F6OTe13CE_{O7Gep2;1Y* zR65pBJ%8x~a3cBbMsN^QMu@0qiSWb?eGmKztWD_-z?dmCOCu#@dt&gim3sMIzde{( zuSRtW=%z?K4@X5o03J{Vny__T9pM)*ZKlpVQ^sZ!Bd}CMf|L`W+VTgT)cWYqdF_7e zK8kKQQvDcOy`7;9$X^q?>|oy?wTYmC_B{3+I?Ao^!S%=$(<}(aP&#S z!K-L72Gw`t%LAR9<(kkL2uVrf4FY zd!t_SFIN?7XDRBTx5EJ4IVq;ljARFq9ygSmE*$bpccT_Ze_d4gq?8Fry3iqNGD^lk z%`Ow&C|XgYn-rHA9?dAT?eZ(eEm6-TS^)*m-P+<2^;$?#NW0T*ekgIAR1tMer_{6_ zQ_bddYyxV6*N|XHt!e_Nr9fq99vVbuDISh#X6J?E7pC)13n_^Fv$Q3)egrP*opT>J zlj}I*B=53GzyDAtwFI=*SyY5ly`{QsW=k(zFE;L(3apT@-+$$f@ILA|-&&BZNP9SP z7BdSH6T=#@zLs=Ktu$M^?!1u0CNt}DbfJIrMhr)l+`oOGZ?Ai;L!DmiJuKxqww?K9 zZMFCAC4EAi?u^3c6}%cPzuwm_wUJT3stx?zwm+nv3=76=(@4A9%nx( zY(K{vEoE{$<8r%$tgbsi=CtRE#B(CT98uhMYLENjR>FimxP;EMNtd*hjd3xI;v6Fk zAv=gd;pg2@LFg!P^IDvW`PD*r;%9A+V#-D zhmR*D?v<82#V%&neUmO{Wnuo6uSXjGhUk)Mj0LIYm5h2)rd#SOqJ zw$&W_W6v5clYCb{?!CtS`oGO=@3#hXm9?yKWC=&0POXkJpik8DGqm zNtkYxrkWcx9A*ghurl&|?Yi!txiBxp$oqMt=nX$7KEBYnGV2KZu&3!V0)#0HYtHuGsgScGKio~x&j_5Jc^}w zHA&I>c?kv!JVYTdAfQheytRb0fq*^P0OYdy^wu~E!erqxVZzc0Sb`rF;T}N*iizSl z)lNg#rqBQ?jU`Am6EYK(eo&OtU{r9j^PVXNrJ{8Q^|FN{UE9Cm&=Y^g25gdIP}pz% zqJhB;sh^HX80#}}wx+1T#ayxZ`EqDl6hGAn2fOxhz*_P<`ooDJ&+FoHcpFL*leKV2 zZiHUkouKUks6xK+eQnsg^dKK2-8#jgqxYbJ^rnH95)M#Em-hUlGmNW5Xk^{hJ+*9S zb7_M&Zg2j^s*!OQ z%Fbon$D(=MjoFOPK^y_HpgRFzNx^fF|C@xfVbTMyI?AM}6Fj zKkrOuT+h!Y+Kg$`kQcF_8MR6PMVm?=;NLbJ1O>xn=_ml&I$8?wq zluSb%x(Z3FeCqa79L8AiZwE)kY|y6nU>^9{?&qWpF$f&CW*%UCcE6hVe7KSaGhB2w zcgG@$Io+l)96ZH-=PfM?`T})$_=To9h=c$hQ@wg%Pw3S{CN{_=mTTpZyU9%E=<2LJ zz2#B5>4@yM$UtT;yYrQ~{-Jspz>5{c?|gB6#J}j1p>cn;&W%pC1W*DerGGp9CJ|=6@fWEX=azB2D&)6@V0Ar*%ELoMrc>cVaNoVn}>oa_gGKJnRFVlZ_EC3J8Jn zAG~>7xx> zDZS{&E9{&`Z~42(KUn2ec$*|qSvvT#B%0OQ+;$K4_bZbS;WPY|(TDr5Vf!Xi8mPT` zzd}O|I7gz&%>Z5qzPWBgt1OX%!a^ITk|3;76>+P98d85hJ&abx2Xf;?M)9i1+B`aL zGxMkSx*95=g>k8p_xSnn9lR9bt2f`or6`G5>bIJDkZ>n;a9uRQ-~qgUIZdv5n`39q zS|Pb+;@;owcwm8<#}|{i+)Wd#Ns3GIv4-OUQdKtz;!7mqRce_I{APlgzHgTWlLF)k z!0XSZN=N{+SHx!1+9|P#BAb?0ax>4BkQ&KtzkW@8v@qA-Cgj?629EG!&x}R7i_e%( zp2`7uSScE2`#8NDn^>;^5)dP%t2a|s8{Xv}DC{R?`mK=}A9K+zUDMQm$03N5+H)qi z?6^(iU)@=(uUKiTAi00HmY!+t{6R+kyI#LO2`f4wPOuA%z5>JX5 zDNDo8XDIAbQA+9VX0I(P1j}D5uior-*oFYubN1Qske>Slp7I6S1o~}Bu?-*#GBS4-ENML7$*;01~R58I>_r4j~dPhM<0dW1T&$+@~bkPrHz7Dpq&V652sGq~=;u zC1BnOPUWrLPHA?N|95}>wTgvM-X~iK`5g(6u3kQNKT)YY5QTTEod0Yc%y1g#%8$L(B-kFt03OMMB3d$r5+!)i z-kH|NV+d&qF`-tayvr^1YpBi#r!_Fcy!VjlYh08zkK z3erV82Hg!dTYOn!QUqMUzb2+V6if7=@owtdqd2uM!j|88f;)QsZTWnXUr_#lXw=QR zJ$D53$^^GvpVJcNA9u8A8wHXistiq252O)B?MOxU@i3EMm-hNgY&sZtMMFtHl17S@!f|W+_&z3S_sSnd9*%Jp3XygyFvjyk`8{|Y zgQv{WsUv!%!{_PQX>Ik_gtny^oeL9cUNJds^;=-@ zSH6`dRTzITVIw_P1FXNl726X3R46qpu^m5U@Ncp5>!gHy?)MJZ+FWF2D@0)z^p7>Pd(BafU(l3@LF<2`^oiw@IlwE> zV*V;BJp5#)NKV|=ww_Nt33!r0;*=m{Lqco5O)2>}CG0Asr^qLWCv`(-&StL$6nYjdYc!2-}C!H_b{E&D$=e!Im%q z=kI2$u?aD9*^+P?;m>zcPZ55=a+Kocymv3onI1q)2$~9w2jsUG4tM8g^OA}ni~-!2Oq>V3Mz-2v8Z8%9;Ws z48xtT)?U7sip*CgCx3@QzfSy^ecH5bITLAz<2kK7O__}t&D+Ocoqv~9SyQad!PQsu zY?{x@on)BXVX4l!RhG$C`pk53*c!F2i=F?C^(QbyWm2#9Fns#)h5V{N4AKwhYanK< z>4Nr_A@E{T?2sm$&Us1Tr)NP-VYZ|mqx|ZlFYm3@JDak?YiLym5 zgVG8~7=jv_e^_hLk^uz7ku}($358i1S8;C%s%hZOkWEnq@L!KT9F!Z`xLnTzsgq7o zX3X&L$%-i4^6sIwTPle+UTudpjE7<-RzBW>w31D&RDqao^Q3lA>zjk~ z9}j>ef45xMRm+5Hq_i+fv}nkj`vX(qN$I6c%;^>4?JfJg4p*7?8=}$T69~vu_?vhv(5#*Xh6Hi8g{Y`H)A|3#6BX zt&HJD<>#TtH3&lYB!Uj#fF?t)DU5+t@lICE8C z7~i*Ls@m(xXggz!Zse?9jF&A=hQoVrak)f?d$s`No$nJ%xac*U$q1gD2Z=q30leIO zi*HBzEB#@S1Wr!~D?sSpK=m&mGUMfc$c!r_&8UWW+Rf6-U&4h0N{>xHDQ+lzz!@fJ zlYtkL9vfkv^o`2Hv6e6h{$q@!#kAbr^hotzq-0yR*yr|La-#8mi|VHA^52xX#Qnw; z|0y(bwrCL!dm|W5e&3h9_tM6Z<5yn~yT*TFyTNdm=C1Ct_LJfEXl9^KnbQv|ttVGRAULgbHhM11G;NY)pW{mNnX>dUz(Cm5Od+`} zlOCgF@woq6K+1Q%g0*JJHKEqk59y7w3#)OFCGLH`j=WxVEvCZ5tKQv8!ut&*UUC_U zN2ejA=6LpPLwDZ<$+@N#ZSAR~wQsts^}99NQdHE`UITU$2y1uu%Z`RiZ~Ze5oY~v) zcvy(kF2cpI^((YI?e}Yx77BwgOS-&^B}2c4w3DPU;ue9|^>);;k|LwVmNp{oc;8o~ zWm$LE51d$PiR-g4RxhOx*)NlPsa<>}{+)Hj=9|Bol14WSs@61)nQkPD8g<-_)=%9I z=nuxniq?Xb0W=oatFHS}c_34P`sSzTgccu++V_MrbiA3*nI?Gk2t>is@8|0Nc;FCt zd`|i&G%vB(!UyqEj%N{+oU;NK7b8@^9RW>A1N(`>7zF~#pPPlXZQP5+DRq-6C#(J) zMlKBA7kkPW^Yy@C25Ar|7Ss~nwQrsXUFOJ5$P;8%9EOT!7(ouQqY?j&SW_F41J#W> z5IRhSMf-^11n`4wJ%=U~PIfdm!?w#P#@}`=4O?Yoio6AMDYL`ITKFTi`1u(z0Z=|k zXBQ<0G(2rUW>-$ogmYLf&K4D}W^L}uuv@-A1d)R5DvfPQl&%jsqwmDqFG@&-NvXA6 zefR7p=(B*P=Qut^Xxy)qnmo7HJxLe38t%PhCX%E^?!1>vuZMDckB&mdsi!qP_?b-i z4N=3>8N)kxJ};pz>pGqsQgx`s4cw)gV`>eXE75!}c8#V6^3&RchSHvgQ^6PFVNeO) z_jmmEB&-ukRtXFpvIDztvH(aSqQ4oSIKs8oBLB=+d{4qkQ*=Y^_(|~=hj2h)-7A}K z92=)hXd6w-j!`5L4$L*H2rX<4s!u&xcDwCm9n&KGB3G>KF-vQmbVNwKQJd1dUh=*V zYc=mUKb$cu-B*SwBP-{pc;pcBTg2V_4tUyii%Paf^K29RR)oUGfAVA0klm zQ3!X>s_)58*!K-xNo6YX&>!ENa(=l~ZU{qiqoVa2ZGJoM_sU7^3e2@^g1Y|Nm&=yY zi=NP8tKuC#E&0I3$Wc&YoIF3L zDn^Ovn^)duz-qvj2Fk$BxHWKbdBrLe0Yq^{%!_k-fwY6HgxF{p#Qsx%l;fZqQtWB` zTm#FASft6zh+6zs%LUOHBf5W1GR_rf(i~r5x*R3B)`kRq#VUxSyhux@PD3z6#rBuo z3w~#8i&9r9QMPWFPS@{&quW?Wt%D;0d}QztdLm#kfmQNmaKja9~7V-TGIWOf5lGY>hoZz3&699xIjd*g> z=c;cQMis+FVu#Dt5@?yHCjaaOJk=Fen`*ChJXBs~dGJn}M{?V$zV@TeYWq*KX}9x} zw#{CFoMXiu7Ls%w>n}f4r>H3crAYj_cY<45%$^P&QVU-(b~EPFA9BtGiXSceH{s6d zxzfRDGs3vVv5%R3jCmbJXBlcp$KK`P_TSEgN{i85)qMtx?v9b2O8hE*34{l2!0}il~V=rkR3(HFYens48ltS!P9gW~t`X{~t~7z+lPN zG>x`x+t##g+qP}nw%yaVZQHhOPg`F<=e;+7LDjCcaz`Q}h!;_CuEhgi-{K=r6dDWTaa)a}y6L0##f^4d_#2*&w*%zj%+2dr%R2Te|^3 zSD7!LC~2o={+D|B^^q)ih!!X1`#th6_3SUw^$wcih=R?DBjeJST9yCxt7>8*NC)-L;tCnal z3wSv#S~PLMMbfJ@3bK}>RmytEkNIAvdDa0*srFdWFrS#+xb8kIBW8k=XU&nDhlna% zyp40+=a`&uyHiJ%C#LQ;HTv3!&n)RZ6nW=1Et_}FS#5yF?3;a* z$4vbA1*aX#h9``(3DL^t)`3OweMetMlX$dX^vfAP_Pp$ef&CP6pI6%uOkQou9nfqVY~iTn&k ztU;-e{^sJ&hcaQHm2^Ccnoo__9^G&@LE1e{n^E5`PkZ3S?*HMJz8ImhV+biHb&Dsj zsR4o^a}LLmoOh}+O4q3j&BzuTGCOUQRgIzZc^@Bn$F|qNjWS;~weQpP+3VFx=b2=w zO}&5PbWemFCpJfaZ`=*Z9ga#Ykv?_fDqp@2hmX7PqWJjd%e zb2FGMs|7f#Lu2E2J2Szm3**JA9B7aD`%V__GE`0D0kG!~{Y4vni+zn*a#I9l9u+p|x?MSNHp?*hp zP@B2Wzz3D;M@qj}ZJDH)_4lTp)x1hCUf3*=V-_SNw%LEm>m}1*Ehj(Wm1jR2%#$aQ z3hjiN!rM!a8t0CE7*<*mCqQc8t;6o_svuyAJTLIJt#+v^7@E%%ny?OCylKXDEa-T+ z%)Z%hz1egsTS@x0i25Woth7DZJ)Dr{-VE~G4aLTO+;#HQ#J;UYeca)5jp1``okXF0 zv~Y%ndi@V0*%$V`GSJ2S?O2A_Djl49s=C)pIYOvSx#}y3&pal7D z3Hh=|_2N^?#)6ZA@inxYCoDiOi(ms=7V&4GzX>r$mMSP$%u9zCmM2@=r>JJu;4OMf< zu8Ytv9b`a)Y$BMQd~=3}RH;n4TZpp9@;PPeXla|`SIGopyoFE;Gn<%-H64dEg|CIU zwK16IwE=`~IyYOlq~DplOKou{kDC4}$+~6t(P3*yBtBX(QDVoCHzAR->Cx&sE9|$p z24i88tcy<~P>o%OstY%Ho@$Tru&5Uw%V`Uw1v6BskA-)bZk{QRbv`HMkcQwC3?6Dp zG+T(Ct5s7sPGCw{S@GYKhH&>JDUX3}T^J?%+Q=-+2Z0UjD31py0jd-#-HGN)F zN1bNj(*8)(d3<7bS$3>FG*6?%v_@sA9c$fv;o?+VY`TRsK0ZA+GbQ6xzs7yqgViQ3 z3BEt~FMdYRM61g>hR-c4vV*8jJ^SG?iC;qFxa5al#w2CrW ziRZ_mr#djJ0GyzcrQpr_5erLLyfb4OkDgW-cH8I1hU!ZR4mb8{oRuB|gx8w7GGAw* z@nY+sK91b*`RMD2xWC#N`In1zTu@DU`S~BRpm-9(C|BzU#nN;n1#)j?T~)&nG%a3O zcp^W~;1-p`U@{n;M37lRCU{O@}h-Sc1gpnNQ1g=0R{Hl&;6NXec9m1DK-dnbkUn9`mSNEd#J8Eib}G-w(t3)p zJ|1-NKMJS0KD{kC;SHC0%KjmWbxg~Q;U_}#uLzea z22XO9;Rps(v@|{niIMlx-98pN!oy&8lbD1WUqtK|>Fg8S{StU6P({#*9xs%l8K$Fo zowy5cgx+xFWyAkioc>^8^PckMVlbQ`zl zO_Wx{hoJ=|q#gg%o`KBMe;`Or^z%|3peSy@DJ<&y zdSDZ`vvqjZ4PB~!UGNfpfiwMi`tF~Wd>gxH(=3aU8(bakPv>4airB>}PU7N=i6cq$ z%KE6*=_7CZnQ65s-Uu~$e#t`k<4{Exc|*{)>;1?-8nv;;Q7$MCN6A+mADj^G25-V! zVb6R7)2%~ohyw!m&y>$NRjO+)yJLjU4fFc=Q62quGLsN*wU+|DZ*sJUtnNvux7e(z zO*K^Z&7Mju8;Qx;$yAP7=E%CB~M#*LPgE~~2}a$la6kpi+&J$1zy=^c3sa)y%Bt*Dln~>}2y6Ti22F^hPzmAwAoNuKE@}V?> zYpv7>{xm~Jr|;J|{p}Jeo0^%G!9#q^&Wdafl8Z&uoPLk6tPRYjJ4b+KY7k@~XqLq) zg|EMTAHEM2K+mIJx-c*j;o<4RmX3L>4&#vz+2I7ytC=6f|H3R|9%&7di$=2^Ymrl~ zlvs~qTVm139q-^ZOp@6oYDyY}%Wa2@ma|V70X%{wuR#CYr;G9Bt8DXa8)GYEIZ3~1 z+4qK)oQTY3_n%(Z`5M#U!GqWTUo;WDHcx{z;$RKHHesdv*Plf-ql!fl>%7F#G9j3R z)(N2xhPoP5gm& zSiKDlx}=35FS=AiG-11mxX)}~CYD4Wyx(e8DDV)=6dy;yHMFv8L?I2<^zE5(1-(K^ zqzv{kIa25VM_1N)S9R5vt*he4iYrsjV1_g{F0wCKm~zLMioZD6V<#otQH9BomHF{c zR6U~Pav!u3@jUk(y+z?bj&{eBFPdfb}7_W zzq{VT>|v>})wMJdZzlNjU|aZP3>-#)q ze(2%FXf(07euaq%EzbfIj=E#_OKeN}t@-X)EH#AQ!NlrI2jJa!j|<0!agnBI6K;{s zrLO8K-CcLW6IIo+Y_1q3FGDZ%VAloC29F`$zZJ^?If*cH7T~5t3@7-3l?=mL{IR!Yb zuNS{7O<0GEPkad`Y`3V%^h(6=mP2omgl9)tvTSzlF%3Z8kC1MhaB-i()OyamSpVHG z{U#)426ugmmq1t$8gSk<|Ar`{Zlxf8)t0I)8b5a|z9(lVYk##E5`4M*%84*hvtaZJ zp&{*~s78dQ3xFT`rmuIZIkW~|kgQb5hl~kuc;LsT4m2%q4|qOtZhJU47ntZ?Lb#n6 z5C40$(Dq~&^zv$#{>AM5bn&q|?Q6|~T6MVKBO4(kRx}BxvW?rDV;q@>j3AUhan+nq zH(x?gaww1--CSiRdcx^D-`9jy0lBMi!bJ8|%Hp@FFy;+Ikq?E}>{yabN3DqXx# zig5GO%=!~PMRe9cQr_4vRprO~Cp^T6aS?cUFl8NXB!uvHEqpGjVjBw4Ps8CSlz9fH ztu#WcM5@wY@J*q#pzcxMUSL^J*X=&p=B~#<*~lJ@D@x~{k0n`z`lFT2941hvoh$Vr z8#4?#)Zqt7-=P5Ca^s>Me?iqX8=rIbAK;h^FnnCPD&bb#if*IaFRh%-z}7dzr?gIH zvG}g|2WATlLhWVc^v_YcQL%Lcei>atm%$GX z8#V2W{mG{Ze2QWfz;7N@}n)@>l+2T%x4h92jyg(hS~~!S|xEqcl4g zMh>2>uF!i!dIHq5(Wkqvzn$Le63eq;{lGpV<8n*WoxoelGN!Lrqq$`9C&bw_D`&@iVj;O&qe?kcg3&xeDa8KQEn}$m7lX zch}gU7Lb>SPycuiwWJ5>czu*|I(1Wy-ixly+nqp5l!#!VKzeg!(D%M@gQ;~GoilvS z8yuaV88@5&ZR^`9!#=g|SR(RdGRhwsJdq*ix8(Q@$zP{21Rz{#*m~*Ok|AAV6+Lvs zK2~cD#emOJGGkd4uGi-+ho7KO&6);9zATG;THo@S0-NM6;qfnSRXe7E@UbqIvc+20 z{!T9w!cAd9p1K{@Qi#fx`LZ!t58D2-Dv63*(;W5AWy*WkZqoAG_1~#pT0?NRB}2F% zU5vffcs?ZkW9pIt^wj{VyX55YCTsC|4AIsr3cu@#oo-owL;K`nIAWIRh zU(Arn|Ckn(4tHl|&?-!J3Eg-WPNrP+LLgrm%(qdn6M0lY|5}?-aC3q8_KH8!s-bf) zQl}USk>yxP6~D}VbHKZJpd|Pxa|4bZWwT*g_Wo}4k23}*4vPMNp$Uq`a4J9-mIeqe z7;c~uSy07VId1&B397QJlAr_Qjqs3Hton9x?=^r))!z2musQfcwG^o8ld(Aq57zeyACCue3=jfRB}fZ zX|-q>6Y#$vj6K2}*|%4(RxO-Y*U{0@(9lp&FhCH{s>H|&a8YL;31A1yQ+aDCVpdYwK;_@y`EC-CLPE%2QZ$V!SxoQPOYtq96etl(;?2VuDL;y ziH2hN7Q-F{$=K0hTG+K3lK7iy)!cD#cd}ggPQgHGl%ouK7M%|3w_B)X_~gCFg8Vr? z)dC|!CeeTLF9nx|E9;MwH)RG7Of1r@_|$$4q2ut?u8i$I;2Y>6Vv+L?*6A8Xo)HFf zLD&~0dWC6j=lSVOD)lCWFWbVG>|C%sB)x$T&8=wTQoa&Oq`j(=9BB$nNUqk7l9Nxp z=Zqp2^}oV#_}L4LZMi(@f@e{0yfQ%T9AZdIZ5V9E$JAE?U`H6b(c?dE_|KLEWWbsNfM{O>8wAv~Xg zm0MgD$%*mq{tv*SiQjf1OmV-p(@i=slls@tq~&l`PW4umQ>bCVICiEO2Qwg1C(TpE z5EBJP#@3fKnQ*!#hz(N+$A5;GBMG!Vs%VG1i)3HJ_$U9aj5C9Px>idmXE`E&hMjDw#xUe9qKg6;*$$C>MDXC?ZmB*^k0*egZKp9s* z5IXgY9r8);tPP9f={qNN?t&#G#!wIv00zjA0D>6I{iH!c00So&xPs#7D&~K5Ocgh& zl89(Ygsb#w;W+l|8Z)Vn6+F^#a5o$v85W56${a=>A|eHuFP&cRTnKnTi-ebgd*c%r zuAAa^?QYu#KIxFr2&VU0tPWWNA!HU;v(?$x1T>F~`?jwG1P`r&3MJ~af}u~sMp6yx zZ7ZSy=z6(P|x>@i8Skp=9kZ!MDFAyrH%MOf4#WcMAEQa9T5+a#$t0g>_McjC|J>qHns5J znDyfq$;Y2RcyppIA=q6&j$n|{?vXc~^73xpQ>^iWs7=-?p^IYz+a5P7@TXvhtCkJ7 z)fGmKk)f4@t+bDGSDG_9Ur<88syIPCUryWeu&5ht&2j)QB^!0prMccTG>9tw5W$R^ z=%&S#_yFTf`gY0*RP@N-94t2cXj)4BjC{kOG#{!76F=V#{o*Q{(u0scI1^L=``qOQ zm!qO6lnVT6!8OY5MgPoEf{9S%tdFr&T#l6a%2uRzGf{;XT=o|hirnGKXsph254?DU zU)qmPC)C?=7l6}MH+l9h#z+jf%*giVi$4WolqH|#t5=FF6h9cJVAfTXM737J%`@y( zfx@hSrHOd}W;Ww+b7O=m!Vk(z7G_i@jeycguFaW~PN}crJ6rYW!3T;hgjD^muRaa_ z?~IwV#D@^T2b+i1KRRtkI=*A5z5o~-~5<`T-I*gwg~NvrPNux&OsEriW+3wyXQxALhTX z1NI=%sJ=2W8M?_a5Q85@LHCf6P*ld2-x<;6?XyQix!%(=Ib|8=I;`DXcI{HZmK#$6 zp|s0Joa7i1+lps4ptX0S^Ai{Y4|UGT3>$WI*ya7+?Wmn$OLOf!jcEP;T9INxZUIXT zdrND`h~s`AQ>&Hhs;Lf>lL^QjO@{Dkz|Z>%yc}&qS?i_7$OJ3G)h3f>`03L0!sNFQ zQN}ElF6F3&Q-=ZNlAIi|M%LP%Y~Gmm;@3X9swX_=Iv1hZXbqc%2Oh5o6{DNW3JSrm zg$^sJA!7Te2^R!~LkarE79wGG~Q%1sZ*r-e=n$(P`156Zk zTxg`{pkj05X~#+C0(nHuhlv)?pjqI6Hv8r-0(zfg%7AiW?AJcdxHB$J;*5!|MkT2& z64ZbItAYaI-HPhd6)-0+8VKO&yL*-$&*hx{Je=L=(j1RddoKCk!_)kEQ^=41d|x;q zdUhINJ?#8mGylV(dN1sv ztOWLn%L%eE&uz?4x*myR-7`R|T9hj20aNvx@myU&3pVL(*w7td9JoR#_;j)OcEb92 z4Z6*}g*@BPhdo^S3~>n;27OcRVvGcdcC7=ps^9*Z##@1Rs}L|I4j$tF?-WF@1d?Uc z7Tq$xo!3;KMVgMLE+P9#>Z%41cU3WapQ5?W#y;G1SByrhk&=}wQ(;PYvKZ#fRC4t) z055OUWCK&C*xx_W&g5#v5q|fQUig8 z?XVBva7i#Z%M8TKtPD=0dZ#+OY@N1TdY!w*F%l%Hmg3_z0&S@P4hG1So{y=X<`viY zU;%PWF|7CqYq!;*NhtkMW}*rNg3SpGB&)no4Ai6;X_Pq~7xd5<{DITyj(yq`w}Dr7w;~fx$CHW7aO8 zqdmHV z7Jzq4r8nl@$jVlb8A*eM5kzT%5k?(oVA3*}DIhY9W6~a^AV$oo6Bfl|x0D`98xP!m#Oo9QIU;bvjV-)%b@2`XQXNkx$Ob2l zG?P|&LNLL-O~KCc0ZW`z;w>&%x-R~6jX(W8&$V0e4Q-Q$-jdL4ax8RQ4Q4oNl zDjUNj9em7_&y*LB&?as@H%0Ph8`VyBw4ee~D&~%3qGOW;~8A3B%tJadvIlW?$gChlFK^xZ$64#8`R z@KhWfIK=eJ-{CI`xK)>h$$?aag*|${$_Ze_xV{?2;C*k1z^jF7!dGf1-{puQeV*0u z=c_miE$PaW$EeIN`1majm`B-Ep*4mX zG(&yt-wb6ct^O5vcN9GGvam8avaye@tA+yp|ATlefqPKBdZl8q)Va1hIsVN{$y%*h z-f1at(rS0gle6ZG;HPit6!W@yl@ivW94OA*3ajejk5L?a>G7tt2AKIn9ddO+<> zIHNE0Z+GyMj#z+8lw^&3fR5l4e1Q+XpgDe_3HD)=^0j?vm~sr3jVtYar~&^&WqA)0 z1{2M5x9YJNUx5*k%LN?6?mr4>8@AJocw$C@O`+Dg{jH)HbonIU9kLAO=-9$M30nq) zSEhV=7)e>6i21xp{$Xe8W2uL@ED(urn_Q)bLNL+ZZBYm}j1pn|pZ(;|&RbGF%romj zVl!sj;ktf_T$1PDC>~Pj6Czr&tjZ>CK1jM;P(5oSIDbU$4D)5mQo3xX&TjPSb~1hx z_cyxIc#PPr9!PYfw{n3*JTfv0Q(d#Wu?C@r#Xb4Ir=`-j@@*8l8yT^>ZiHvC&x@oM z@PF3##`9V@;iz9d8?+iSW%K`XY@Dfv#0u(tI2RZ}32nWdapBeDf zh9!aUR4FZ=?{nRd=~gTcnqk+5>Eu^gFshMyheh2uuI)1+?~gL=JxZJqJgUmz7`S|W zjmejqYtYQt=D`O+Z#bPR#|$~@D~j2RdE=%L4eo7Ux9g&?x*7cMz-u#s81*2Tk%tSx zOsC6`{SHW;^}KO(HSiAdT}?zbR&&>%uNX6;KbNrDVR{P&F3WhbZcWNAo{0W$PEdE| zvtRlenUoIy`{(Y*AkL+e;cmT|`0vJVz}s4V)7-fZ_2=}i(&vwLQ8ie978N~oD*fIm z`w+*p8eAALLv#k0JZ}{bOg(5+Sv^w(IA{c6PQ@)|B2$eQCa8G-bR^1^mcKKHvCC;V zKoL;%wI;Kl`c809_+dFRyf~0JLExRDMhcjT1oRx^b@yWiY0g!*IGlZ+8IboA8oQ__ zD~qDo(m-a7ZVWFE5s%n&I?~%T{USR{;}87?5uG{GzN5wbx_iL|&j7I@YQ}liW#lwW@d575~LNu+Dvh9Ib~HJk}ao z@sPh@Ap?71(9RCDaWv6xnw7*UCc|$$r}AQ=GgQ-aTs|6$1_v_t0xeTC6y&wJgvjaE zO|{64##^UKe3Lz1SqYK%`0u0(ye`LSwsj4Mn%lhNyl&?YtlPMSeWZBYk8hDfcIGi< zE*lQ-vRs!9+s_|z`dx_mh4Ll;H|l^U7L|dybiZM>&^q!CdI6Wm?z?srt3)6e$pGpb z7c7OyIQH1dtc%sN(ZJ!=8r28%-NBx<;T@?FK(r$A0k+c>iEqNtx=z?wOYn{1RSBse^=@eG#4^cfPp^Ql-0~IUdn4_?*SR$Q z$OlErE6tnPo7mUWfQjuirs`L0M%8R#kYGXXwAoA$zD$dh4#mYqZY`^W^OJ)A1pjUa zjRah}ME6~H0Qmp@w2-*8s<1bZZH2|j`M5|wM#Q@vQJO1pz68KEUGQ)#?Z2LVvWV;C z&zCTV2#F@*?3L)BFBk$AMI-FAX^gd;rR{qaVd%8_sm^Hs=nwegUIG5y$uF{_K8opk zvNy+B`^vfJPCERl4MXmVn#=W=A-m*5lU}SpCmD6yTrSO7U^hd25id}3>vm+qNB~ka zyiB&=n|qGbVAx_;opw&gnuQvcx$ zsPtS&*rYKdWu*R#vb=KR%T>i!otG9$NfmaN22Oady43yJ&fN*2K$ws}p;WY>ie!?7 ztwRt@*H7XP>%gZ4i_9{S(@Fw+2FA^_BL`O5HRpz?IRkpjhbj-!cH5n$>Mt@ zbE2BlKd1FvzrC`Zoj1`8&Om}=STRJDD>ZR?JwgN8k6*VZdv+YR9gowkfKNG2>a+w1 zSOF9PBmluCk!9E}{Z4mqYLr{SV(@M{S4zU*JRq_%3I@&sD_)ShdawD`-T(vW;BJ+0 zdzlgOKKz?JR=Z^Ml`G7~7l?N%n4M(}_PFyBuP$u&En*Lgw?i+ZOP@e-XRNAg<=omd z7;47DE=85A&u~3n^8#-K{T6S7H?~SHHyoQYh*C13yk*&rUx5kg)`t{m1thZrBg>O` zg~%Her7|SVX)FIa&0i}e_DZ8UIq-fR3vV)G%iZwS_jd%Sl(Y;>fAm@0%F3~$bNvP{ z5#5=H3X{DGr@eN-M6SRu_gJiOU4|)-ezwR+cTAUI;)mqjZe*+B`6D^wr?LflTmu^1$jTQA zN_`Y+v8XCtE{vhGHI&jd*VH}##?Z0*>b$ZO`K+1u;Ni!2>vVmKN6Z{f0hdIfPorpJ zE^9u--0tE$6MyDz);8WbzRC=VZ83CujfrSB-J@g5zH}xt3b5+&xixq(=zIUPb`763 z#N|Kb>@h27mdpSsZ5JOGJ1O*Zw177`G9PNCdw?T!WUF#{LY0YS`aD9tXW5s2k;jVM z;)Tvad1)g?;5NTFgS@nrvgTI07ci5_4{ISaDJ{zW$aD1_rAm)SS6-Xje29K>rN@E^ z<2RG``n$FU#ZnOl>+b^cPx#j~rC2VFS7e6D2bB5&SDHcP5E1emggCRUbGK)#R}y@k z;qb8}YQ`LQMY+`>LiR#72)G3hu=vg=n&z#si}^#GLj2dc2zRoiZY-F6xbCoDYRu)=JGE* z|5uA*OvBjO@%_1fk4H)RYhYeD9^PVY+3WMDl6lWL+7HpZTOYFdkTq{y@zjsCQf>R7 zWg}4g2?3XV2%|cL|2aO%2Ze5RlCST6mwOvB=DJ+P0BZnzy&9O>U@#q^P+LszrwN<) z;gIrfzeqV`&e;;*oqMI6>g~Z~3JL}`qG!COVAZMF%W87iQOTJ|4&eEE@T+e4l~E6R z6%@kWKP;)f3XJ|oSG&b}oo&}U31ei3b&u**f4PU5Fdi|yd*ble9@KNss;+fylGdsI z_~XyI8)mEAtKUY*&Ki6L2L5_E%5^#?ue!RQ2p4;6JKpF@3}TCom=-j*l`KWyht>Q9 zQ(v`xDCG=m_h-_LzCSBsxy>H@8H32`?+|<>K?0i&A_SH3%-kBdG;W1-B4X z4OOb_LID;o=6(tP!mssfR)QY(cLN@6_uBw$nrz=^o|W@=;E!boiV}5~l3_{@R;M9^hLaJD@$G1XTmZDY#$NIT? z^H58>#U~f=okNU)iLHj(!jnL!-w}*c+$$abo`1RRX`!(NO}7Y{OQ2CSu1eXI&RjFi zY~UfkE)i-+=xzg1;mmB*BY{_7tQsE z!Z^y@u+Xo&**5TMpq=ZTz6#4!G9;T3b8_W~1B-!h-a@7oegrNJPJUh*pu_V)BiG@b zd{8=nN6Y80wtBK+Qi9{x2<X5FNtophx>HzkeYqtZpwZND)Uw^NEW)n8_Fz!|) zQmdGMc#w0b!9c}*4U}7)=nnWV*Z(QAWNF>VXK@hX;yO?(Nd!b zJ|&Y=gU3X}t09I25_}!BwGHdlmkl?;Nv?kAkTu@`0O_7qkO)+!O4&CsfC>TX@Ppc5 zendqY_1=3$O-_k>s5Hn(p>71^3Q|jC@L&BdP7P3J3137g_q0`qy2=4L624TxnI0@$ z+3cV#ALuvjy}i=-zWo=I^K)Y-X4JnK5+^!Jx?AiMp>z%iHnIy0ev78c@&0lfr-2Cc zbjhok>bvq?4T`|6%zmDYtl%{eWTJ5%Y=F_Yo}H7!G{pwSVLz<2;oS>~=k^ULffUr4sTsV4w1hKVe*(h2o}4=ItFM$B#0d;KyocL5V< zXAQAw86Z)(DuyRz(x!gWr@QNoEOQC2Wf>@?E;!uLDWL$pUjCDJHbIHg%FFsNbMBE6 z^lUguUu;yPmCAtx10Ay2dmhED2nFTcvXcyY+~wZehhK~3z5J{qn(i$!ItFMaGPy4g z-Oq=Z4ylBiT^3G)sj*no)kVxzW)jgs-@c&ll%19{8@whSAtal#mxGZcdpp9;gn$^4 zSkkvd=EjQ`o~#x8dLWPF4V}(DllO>cTV$M1kJH7V+eV5fIqdlK%Q0fD#+{%}+@k=BF7(j?nEj_T>k_HQy zzqdVcKbyZk=2pDclT%Yy8_ibg>gm#C#KQ3;5=#Jr>Rv=S&;utx=VsTtoB_e^5(vLl ze4&JTuWvU^Um6OZP0PCViIZ8U?amxGldi+xa8BzTdsZ^lmF`l}>JvS@#;}0{%VeEB zC({}BsmzE7P=h<84G#PAEKefBCP9n_F>KtzYE%hM+8@({M;OPc;4ZS7h5)-b#|-p< zkQ$lLT}8j?;WBv>V#U(5$lBUBWs7 zgqD~`#4IbafOoR1CxwI8tWRNu->>dk?|k$^|C?d66eV=s|0{Rx{ob-B_5jK&byDRn zk)e{hkfUl2{8jzjz7*UXjzZscKZN~0n&G)es7T@F4Fa)-hx?Sg@UK(nTHWBjOy#rj70QvNRM(KNY3UDs75 zjw4LTT%c-N9>-c&LC0My0%Rb`_6Fn59k(KUqj_iH(jO=9w@cFj9|Y+vR()t*tX|TL zDR7`EM`aucTT6mjQ>CVrF;Z>^tYTgQ3$;)egj3B6LTxr?-EjpS0*DYv1at5(?L8A{ z+(i%;W0JqSN#M6%INuNdhWiqSux_Q;3u6PccqDHWIT2XMu>9ti1p_O0%2dKy&90{H z1++N2y!ZN>g=f0`bk`w&_RAJR=o;99RW8cwv`n^NbVjcQgi9vi2LEpyXx;Zfm>fdm4GwbrkIRsC*u zD_(1N!ZX~WokUeSbtgjF2EBpAK_^(6#G7}g^Z`cZL-T%v@qUkDU#Fh^ooHS{ipLb= z%K^@+%kSjrzv%@Gx?UADnaZ6QLR(#qCB^+9WNoixf0V^jHqN0BA>P@*7E-gZ`Zlur zO!p<1D_a-|hlvEP-|}0=H?8DHvnSTl(8he+Y?|VYS8}|UFXr-MelwCJNwi~uyumi0 zh{WTU&1SLvVMe2AuZu68>kw1=-QP>l9Sbamtyd%gx9G+PT-hDq6UN~~jMv#t2$v4{ zZdCP*sQj{x5589efjQPkZ}}w{ii2vlXjXKAnPX`{yW3#jXdW*GFAyu6>+oi$0r}H; z_xtRzBHIui%{S*WOHuFAED0Uhts+X0zRz<0tqsHjqg98Ww0yx8#%Uu{wfb)W6^+od z3M4VqP_=HTV7-fEP-f|i^d>0PYL;0#ojiUF)gOnx#fcMp0qL3xSo+9cEaA>17J|I3 z*cU$&-a@}ynfw|2T)k*|ZzbRW7Fm=IHqg^TeAtxpv@x}nm;&}1o?2N^6T5UN;R^)g zQ_J*$2co*(2d&j#?noo<$DrK^nUe#mhYKE7gHRhQqBaf--GYKQU|NP{DG>-#3uQpz z%%RVvI_*_|wWLL^*KNQ*+a3~;s~wxoEL@*=wCHx|N!)P1tM(jDU<5$nR#$rEs|gev ziI56N1#>knn!?B!2ok@k5o1sM+hJ@AG{8t27q;HWtE@8rUf^P%DEX_`%j|S=uiyOqVr$Nr^%Dq zx%6Fm2sJ7nQZIAai=P+-qRXsCXqO)| z$d=?%J2@>@VfTC7FUry%I5;-a-!0Z_@g3V%>_0jeZGN-O1qQbFGdU82)ep`Yl3;Y1e~!#wnV<`QD8JX0g8E1L4UhC6HE@)4%>N3DYCPDi+M=8SVpp4_#;N9l z#6Oz7R#~JB64lBR$Bw;8G#~*eAsRO}@iUN8Lm)r+QdG?T{yLujxV4By+eR1n~S_r%BkCog?{(TuF^GwzZ>5W}BR;M+7wK7B>rJIXC z|7;-JBjZ_2X=&Nm+}0aR@2(L!w0{;&GNm<|Oy@frZnf(t8um7EB9Tuq&0MW4Zrs=XV^3vJCJ3xW6- z&!2a~KLGgJ8;{~Eh=fEU7C*i(>3g(XY$lhXs-&yXUq=IF{l_X& zxuo^kTXj5o3)m^y+y}}*?FN*<{4I6Hi?n`sVe^>-5CG6i1{v{$v#mKc`$>nu@N#Gl zZb!~7JD^Aj?j?ua;fYWZcq^{M=QddyK^BL?<ljZZ8|}S z(SYw@4_qQaVd6BEzqziw*yg@~3~|CClQ@hvV%#!CQ#8>RtXf<<3azC~_z4UXLJ}R3 zfB;$=4oy(MH2nxJC-Tp6s+#hUu-Ib;+gZ@lHp4%)ty?JgK~0?BD@q+30Qwb}S+Va5 zLu#h~=(wH+j8>69*z2WQ4GLX*!~%yI`m@uhA246R;jI5Lam$p^68DIXi(6X5`8mH9 z*g$#>BL?-NLTbib4B^vTCKm9dBj*q(7Y+Mj?TpI7mg=|eF#4F0bQ4ipI`*~{VzM-o znbU-aRqEuCGg%s=#M|*pAKedk7eNPIOOv~A-)53uRhvu(KuT5D;~w-(&7uK5UUCBq zCQ81AQ^AsK52v^N@V(UJN=1Z;Rs~Bnp+$=_{LxK>^(2vl!>7#URZ88de1>u>j(>k6 zH(h)el`jy!8XL&z6>A|*!GbV}shkOcMlYfWblY+m-3ovLDCNU4-xdWdB%Hqy{&X7S%eK5Gd53hY^GO{%PG-y;8!T;7qHNs zTKBBuAl4+6FF%dIiPLLEfFqTjhP%)KKPqV!^z4F?AW-^w_;DOyq?Q1TK18QyBg~+s z{feY;(W>)~5U8-;9hL)}d458*YJ&)()w|jr1(;D4lvF$a940cx=N0wZuL9hF4TjB*#%l?(_sQ`&C zYyP-S(qCw~{b6R7?T`>^%V32UdGy26$=kXqDymG7Ildjt`iIk=l$y@Mm21vde`rjl zm`jJ0T(H&FLXaImY(=kLJB^vU=W+?UZQsnZ8dA#ua{gYN?yi6R&5X5vP^|KCPIHHWVsn0gS z;;Bez|SZn%!NV3_$Avqj(FGbf-96#BoJ++jt)-NQjO z2ZA7q2#2IpVNB>ASncmsD$PASZ6$2dx!)VFOG9}iAuP2@d8yM^tYSeUOa=bzFFmep z!!^Y6P)}y0lEuWVjg?RxZUO8#doqa(dZzbHoRts|_ZBAmc&0eL`vRnv=nEl!5=(92 z>MEl3!|}=AhL1v0GWrsEn?0-A`Ie^2eVuz0eCJDR`LOmCG-f|%xwmQ^x%MSP1FL)O z`Ur6q(-TMNn)-}s_|8Q9G>wbY=9b)~syJ!R&_3k28+d+FsA&fKf+mn0)+6>6F*kC6 zuq~L|-HtEw)f?SKmON?;c)jT81Or0QaJl$_%b7XeSP_|MaOrd~GEu*2mx6!J+x+`o zKM!l=2C?08s@^SzP{URt2GyfRW9E3DuGzC|p16Z3w0!{E!=U`ISm3vN*c2dxjk_*8 z^>e4X_=8&qQOdb}0QXlfM6&!t#%ZJGO7+xB7`5`pUE_1BBlsYwBixK+6LoSu=RE?0 zmHPV59rJf~Z%!Id1g;qsSx^zU2_GkJRh#Y=R@QR${IbI!hc$`+3Hf_Xdnr0?>#QG| zMCTSmsN(2PoT7o5ueGY7(doLr-!G|EtIP`zPvDe|n?%?n_m*)F^qbUMn(OA7x}y7rBcDiK^Y&D@7fqHEF)nR!T#Pfx8;ch{Ru0T0JRVq3wqk&*c<8n@B!{h@S*G)i zfB7DKo@S!!%n3SwNc?S|)CN6n0oniizV2u%!pYa!D)c6dnw2F-%x5-WX-FuwyrSU!$BZ6*31PTaYWwD%SV9#|*!v2t+ z?=EFlj-7prN<0+{vc%YDIuENJ$r)NZ0q__8+%4@{cLU&tuV%>nw?7bAq#%$6gFLtURBBQ8@-jEOa7}P zK9}ZY6kN&F-B#l%v)oBv8WcSCuvAC*Y3ZsPrI26MEHU21Jh$^rakc8X;_mtVi=jjR z?-9_~Sg~!Loc#;=Ebw;4u|RI#QarmF3U&1VsCuU`NxPs~v~5n?wrx+_wr$(C?P=S# zt!dk~d)j^K`}f{wpOY8$)Wv&ISWm9Z$czYi8+qQSD`8Z{OwL*RVe1C-H>$KoE)gWxtQ(|B>^v@pFrb^tFxHHX++D z`rd|>@7L)OL-p6Yx(^LaFx*PKI(YA!cWKbR)0qTu94t@a&!`ZfW8=|)fF}Jo0ZgF8 z{Q|}R1rH>LYw0L0Fv&ejz@sD5*<=R5gyE9c7D+e&4f3ieiQb5@`5+ z()_(eSJ;K5fRwXl>mnr_VwZ#IQGZr!NcWSn-FWybV-w-bTYLw$I)9}ssD)Nfi&!_D zEDd-L72PLg+B%(Hgjl@RHJT&iW3wbCc2*&fp@zCXw2Tgi6tdWDK;dDL@0Bbla2}?= zv3kaA5%ma?FG=2Z>c>w>4If;_=wG8QzhWH0xqAGdcON z0db{w3Xm#PaR&D8M^!NeiqKcY3ard0f+5KAP;+7qz!G8Gi@8%BUMSc%`nCDv#>oeVk6(ttJ_z!(p>Mm8y6Mj`t&0jQag7HW zA&=H5h?#hh4bS?^pk}k`R3E46hl`S3XAKr^3Kv4`5@@P% zP@v*%p#O@3BH&jR{RTK|ch13@Gy|3v`V9Bf@#Dw|ch1*}3V}vZ zbDCDO2{|p5qmcSQX0pg5uyK}PVVaDz-?iPO?|L1+I1n?xF-4Wf$8NGcA@X-iLaRdG z-1Jg8HYjgOp3&yDe!&PqhyJm|M&lw<1#iDNRrfSz07D&_`Dryd#=F1W0z38a6Nm>{ z$91_u!UK?edLT$kkNiu;pw;@cA$|i}EK(X=)0I&IZi-&RugywYgeUV}y2s+>KIw#z zc|KM=BUAxg*323^u?+l*N=IGRT|Cw_)h;GdCMmzw1gM%{dH|oV{MM6H&wr*Q(40iN zEX_rw)8i+q^O_TI~}zM+EA=25r;--ZVhFD(zq5_q0ss#*HJ1m16Fe0$MBmzqJfon)GPANq7BNS9c6p-UdxY z#<>-phaUsfS+r5H3$^w@dJ@# zCfYuedxP$eqq`|ASt6g_?c)ByiUi|crn z5z)wlHW&Nrc<13CGv7Ly4gQOXRQF^DFH=p~OU1q7(9R@>k{&5(Klg)AmyV0+2bR%C zQ^hRX-t6ZOw}bLgeOr`njl~yF#R=m4b*F*vPh1G&y;Ml)AT`~E@au9`!b@Cg5r zzG>}C&HKy|tZ7>5OKzVW>N}DsJ9HFLIoa|KPw2B9nDyUZ&ac{-1E|s*lL43gl2cHF5yQxG316~30}L_w64RYsIqNdquVWW+kgB^mg5$;Y{y*ApF#Tv(-H zMb#qfos2{Y`jVoqDIUKRV6ox)j>l%?0JCNV6x2qd~a5Ti{?a^)@2$J89FJ%DYeZn zDL&$(gM@)7SpZH_14cU)e}u($Z1E{g!5np#d4ua>3YXg2YWlq<|MMww$b1yJFL{tv zFS1+|&)?~CuGFJ<`&=tm#*!)HgA68g7wj3&3G@F}PXE2Bf&HFVhXN*&Ay^G+ZQqOB zH$TYP)!0y46BNtAu$HheCJfqoWgiCpm^a?;$0Ctg43Yp}(}xqM2wF7f0)zTRjGl-D z6UGoGKl3)-H+|ByMK?BWFB6-WhF_&ho%g2S0-*aoGc{HrF_Y1ZG1w!o`K@pRzIWA8 z^~<01)b$MkVu&6WDm8{FpW>P9%#q#eR5gNJwfw+B-7%9knIC)8R7np~Hnsac$RxE{ z`J7KbKgALO;u<%%`yVNRb}GY_fWnQx5&7HsU_kEM%-NSlAGgw*BcS!)#rq@6%R#{@ zXZp{h(`%qVV7~g)qBp}p2Kk?Up{Q(3G9rG?@&}(pOh8QdJb|{py|y9VdC_BHW_+ne zjgK?8W^VA^ai5w_CWGJRk-?s$km@S;*HA?5-XVVXl)fv<(7}2%)oiU?ltN3rog{%2 zd&{m6db9wtmCUBT1rB(Be0b&VmWcruQMhDJvybUN{=+m8z?~hcq)pN#tF-|} zc(f1ABI-H;d#Wk4sQpG)i8E_Ib=uiI&ih(~_2~qMLSNwYR9?^j;N1m87@MhwrvysV z9P)R6lFZ>1II%hH!Hm0Ew+uC0=N(_; zW{WQnofl~3j%Zz&iqxU53Lu3YUa?k}qD@E;s%u`~GBH=AuQtq+luOmv%DyU=v_GuN zmH?Ogh9Hptjuo(y0zdfXYa;JFi|*GPhEAQr<*E`v_v&k6w}m3?qz{|L-#_%aow%G1 zdspjCpK}7DG1zRA-roS%6LKqC-` zR$Lhh3c}w%ItjU zcdV4g#`Iaic}+UsOP>*>>R6LvPs_cJUHDXA!^~lBjEj@>xpo!CJR1iou#TFuCF6=QV5qU!G+Y_xY{VKN>=Jj#K(- z?S3Xnr4>LSaN)B0gGuzSi>QW&`d04^XQOOH-Ug{=+w^KDzaM8LI2+}^QoKVAfJY;! z*SYjkq_B8JuT)J|-Vmh5Xxun;>-&hQxax-eesY;(G*kHO(@8;!iq0Ya1xy>`og;Mo z<=kA`_rt@YP2Jrtu zkpA~ek*Tm2ns_gwU`uiTJ*v?AYs`XV{ar2<1!jx}`mk013yq*8Pz`QQb(k~HkSdpf zKJr=$A|?XgB8o1?5JK!JLTX{O7*RvLE_%}Ud(O@1`*t07T@3c!#c>-mP1Ti7qh6~= z3jbpwyLftOkF#}*@Qs*zr5-uv2Im6CCfWEg$fGw!Q?K=wN_wQ;wW=WyZ`a0ALqqb= zfbB%n<-Zp9 z^m1_NhsF2J3_`@C^xIjwiB5&y!@oO1$}S2R5HX{4Rg*5Zo%!?}HCSeGlKi{A2trtAr$K6o+B#jHhoi<={Dd1XVZ`U32*is`ZDn77Oztqda(bM1WG{ zdlDZ+?cXHOIvfODCX&`9BI&X#-Mq?kg(fgC#J13d;$jrOpA8@YD7>~u7nwwufdws(QA(2W>0(LjG2*(`Z0B(=bn|S}9b9Tr8{A+j&sSwvC73(=d-DawY z7%HQhT#A-780uc=%p9CUP2>pYs|K8fR;y!moB)RFDy6*JRq(ah<@#*a5Hb%o`_r%B zOp%l~PhGZ*ln{z51Y1wJo(;3Sf?pJvLAXo|8iI(YDhAGdT;fbCF^U$c)Uu|I5Q08V3fh9ebp9v9p1{CJem&b0kW#7$CXALglvo_ z#OOGMG*!qpOV8@oKrsIq!a(?izec@PVZbhv1_9We2sqDwIGBI@98>KkQJz$^T}(Bn z3+0kMWC!x}m0#V?hsF-_vv*+B^2p1;IL5b-ILB9^la!;$-E} z=iF_XmdO*meQ9?SRIym(oLtLUyLF8(wOILeKGU_j7NZYWn|Na6OT{MxYz|D|UnjRq z>r{4ID6i>P-L3u32l@2Wyf_2=hYDTM8|Psw=h|3ZTnr3zw>qlAdktA`Bc1Xog5 zAnu5uM?a)#M;4m^0I}FL;3@iKaLh&f=?o@@-q(Y>{UKX+oP2%~663qQfoyi$1N$$c zLh*R~h6Vr>DSbkN{~0L^cFwL3g@D6h_xZZ}0~RFjzpW5U8iKXxE8oj*I*CgAe`aj| zQ~J$7{G8Abl9(<_sZKHJt5&Ie#-t#b74c()V~IJC8F1e1WBp}-F&PHV0vAQ!FRO<{ z7RDU{N{du%%y<8bAa_!$qLs%*NdkqHGJ#B}fxdhyb^XM_27*V05TOz!R`zf;ce{^AoQ=P*Z1+%%UbsnB=-S8}+^2doe;%|*Bw`1S~G{f+4EpC z1^u`eLa7d#p>Fj>i<~>#7Wi!#o8V&@&p^QJsk*nz42F}eU;lukVE6Yncy*~AEkLM> z>S?*nxBv(nm8}l5#X`og4_`nVS_0g;;Uap5io(bY{M!Z%>f<$`6jAH#DI;#PZ|YN7 zV8Y)Elnkqb%Q)65&}~Yd;%uyQ>I!1W+jUk(qQ1yFV0*ly?N=9jI39-tV^Z$6HRrjF zy=iCp!qwaI9AxeiwEIrVFWK0mK0vU3aa@IsQ@A8M@KAqa`V>P13*H6w|>s3<9n`%U{kq7WDu7zA8SM$d<%hzO|gAtA*Sr3z9}iCK*W z$wTT_fSy(!XX2P+j&MOa&ayIUe!=|=N5k9yr7r=J9M}GwkLa(#u^0$jOhzm%s1Ar& zHTqF<+zoChF#+@^+soc~8x>LqtF9C`vA@npJAV^hWo#79XcT z5}>1mocpdnJgjKd{Fjb3fov8b{Y|^+F23Y!vS{c(@+tk6c=xc7E^8p_QFy(BEeYr=oV05mYj_8+7Y#JH7B3tg zv{0JPtq`UGfvwRhObS-*=3c=`(LgA=3tCpCtFYxP!P2*eN*@$ZwYZw@Tb_3)37XKc z0#fGv)cm!wnC`#z<^yD$N1IL+fyky8bY$;nUV8rf`4I|UoDjUXPp&$y;`3sEJONu{ zt6x0tyl%7h!OEcdPf3D8o2A{31>zyq?r>PJ{UgF-T6I$!Qtj^I6D&NFrDfwNsHA_+ z<{q#D0s+HT!VWU5A=f{h%;k_new&j&Eq(tGnk;=SB$>m`L74PSO-%0mX{f1ZbGVe% z)JDtXWn^%fjD}yXHxco9$9K7XUhfh~#K~o|P|?xN*t5}KLUrgVtOz^w*fxTm_kt07 zKOd&>G4wt5Lv_2{3=94*+Y&Ifk$cTvy;s&tRno*l+jbhSiHlLAPGwd)F`r38yH;n7 z)_@3|7#J|RyU0)I8*dy8(|{Y(H@EDHZOwQaW=_IfR$J!KED>Vguq&g=D)_p-n5RLu z3Kf-Oz>%lJt;py3eR?@Sb2D(zyGfz}w%ajJcbBV!u*$n|5-vKw!0g`j+f=@1+JdG; zxY6v4q8t+>B^Vvfs}_l^C!J8_&(6U0Q7E+c3a>Nr%K{_txp_4DwLbjL&4xW=FD#X)# z;~CU7wqD%oxL)4q@P$k`5Rd*&HO%||?`fc5IU+Uen9T#n}^`n_a%=fukYy)D13? zgPU7wjb1!1RcVnuA)@Yo@>m(S07#{4Z^%uRf*i0u^}G&_^WTn6v)DMGYm!pM!@+pk zlzUo9lJDvLrhEGgon<8>izS>uLK#XPMmbTwUi$r6RbD9s z0$dgVOFs-zMXee&r=Ekyl&Rw+TNz=65a0LnvbJ5nkN!Z={|?Ts+emQV`0fG9-Nfs# zM(6*x`^o}7SehLRYKfjiIsnxjh75| zm5+^wQTNtIi^G7Yb_-vmG-_xZtHc5-LXWH7T#6{2*Vd-)A`j`~6Q7XZ>Fec4?DP0R zBzj&H>=#R{h3~lz3GI8FbTR!p0^n87;b-00PP`5u6281Y|6qrDom*!-Uq*^hh=;bf zVpeikA5*V4cbr>@d1F4EExXk19UySFymSapda}Ebnk=gGem?q0T(!HaF&>uwS>9rm zGm@z#mO5!SIjr1!wb_)2{t)e4Qs%EoUnkP(lgwvn46rrpW=d$-lnr}Lp#IJmTPL9? zb#x*QD1Ek1w|c#YP?*zLNcn|B))hNL@Xl;1gaq_8qrd}{WswfU>u53UQGaAt#W0_e;G4n(9qDnzrPXro)k<>NRv+bfdMc^EEyYbd^2zsoBI=kh4a7R zP*8}t4#B|UT7t5XR$&4E#ow#}N0woehBc7hfXgx!=nx`q+oq|?1K18Je@+?Gbp)?# zlIVf`D(JG=ea`Vp;(VSE!>0)JCRz~DE<@z@9Sb8x;G3wZs8ZSNR-=)q@J+E_V3w>F zv0e+~ZOj^SqaSnR#y=)W@7SRI_U@<*SU3(xHT{9RsHtiju0lJwwK2%`cIi76OKRqv zwwePIKVs9^djus%J#8f+jzHX5rEh$_Rz6DOZ~rP-&7D*%JLG(QFIc`}=A+q1AUAZY zR#Cj2T;qR(b+7dum5HFOJYEOAO_4)@G~Trx+H5X(jl#^CT-Y3bP!(TsK#U_6W1OHX zQ|xN_n)iDrLh7NA`d7D>YJR$(D@!J+&V|8!$(2wuX;DzC$&^rbivDCdvtUNlaIh8` zfBo>pe7)^155irOhNX)bGOM(I@D?y?>mfLnx7*^WZ>&02w8Xu$ zpLRQVFuKwyR^?&bPzDCsX5q8mWeZo4IjpVe*M&ClP7R>@uzU2foOltBM-$RL#o<_6 zyU}M?w|#A{hBkj?lh(wQfXFk9o@Q6`8_)crBV)eIlV{J+*%y=^_|L3SOeW_7*4JxT)%oKYSO)AD;IN& zz%-MM`YeeG3tAi-G_4C4Bw!#ZQ2v6nUdq$A&}fWUETN$xO<61;F<*z7#FDNWL4|o- zlrLNKySL;!3N&&61uc-UJELi5U|^V=o8!QQ`xO~-zZf*;)ze#9S;-TdlY{H=FdT^j z$f&Xafe8`NR~n%q%UOi-ZeLpOTW23TNd=HQXtqAQ(>Jp~?_`WVxRio^4(vT{gUen~ zB%odzInuy`P0h8QiAS-ZGt|eb=1=x^ZwH^ec@C>_Y)gwP>VMI0$=3#=KHrr!{I&cSc_b){t!NooXY1<&<7bi z+quLKPnzAYR7UbBK)c-}XVUM4&!w%i`zcW%+ zs@bm|SsH0`hPhE9z-fB(^BX8AfZ?bqsrnPsya2SBM~4)F_AMj?(-58JZjSGv`aZX7 zqXLY?_ZnK}ElTJu_&?zQ^Uqqp0Su&9hPr2;05!?IYTdL43yCsS3fzak%ZwK(+8Rt$ z2U!J(1!W*ctR}fRCLjFSk#tLj(~wy)Bz)c?L}V9WFwUUg>*F9}qRB;0#3lv-phS?0wdHAnnDX$5sQi(Y`i zwK5f!QV5Vq*0s^<{)a!L-rZ7JzrBgv1o1kHO{nFRfUVA(NsEv=wBKC&Vb0y8b*{On z9!68V$ z=S8mWPA!d5a)cmX$n8n+rK@6sqIrM#>~4G-A}ev9n?S7Vs#C>|gyKE^Noik6-NcCA z&r4B9r}J#%niomb9oSG9TS12La6gw{|A_11t!j7$_>_>Zvu>*5ID#__d^T&We6L;w ze!H%8$#lFwUjv13sRe2x%a@UkQ>u4P7SIT(UsiSETx&*3#CK>xrGIc3FMCY<3&{%c zNz-`1jWo7VZG7pQW$_a!Im*pGZ$fC&i+w;%yo z03=Y5Jb4=q8n!o6ugscFIqz^LYv_6#Lz$8>5D03T<+@av0=}=B)XsESByW08figz< zmd31w8X>%B*=lNXQieQPgZAX!;|@+Ti55M&pw7tHI5|1_=ljDxR!mt@(eZdPwY$6f z&mThi^yov*+QQ%(2YHla^4W~x^^cI(Xz2~Ii`uAFO7?0mJQJ*4f3?$#-L4`Y8bOkzZ3Yp;a$;*3ly9*S}p&reeeE^z`36L$uoo6qG>LQ zmAM}y-@Kvd$R~o2QUCmF^DzO{k~;7An%DripR?7G3FgzLPF2l{^z-VtYtAA+-VGhD z+)f#DREZ;yIQJ`f2ENA^*q^ET@#@=mu);d4K^3nLCou@my5u-gaE;uL4Ue~F0t{RF z)=$fr>&2uqn(G@f{aorX?s$LO-`%c+r9JKDm$S*4Vjsnm?ffXCa8HMvR)6*m@?`yU ztM_f_FW7ws|I+WfnSQ-4R~X5xIBsoGZ1CJRB%-Y{U?}zQD4#6bxN7idkp{Oa*&jp~ z^R{waNKXL~5R2%0^=Jn;&jt{xTngysNp53&C-3ASlbEnI4qEd+cWWGr1wbBf*-v^2 zB{w(^ysIc>Jgj8LYv1C^4vf@ff6r34{qSa9?z%6n1wzNgy9k$Uba@_DRKtWn4&J3i z9)^cSR>^85_jnIvDFeOAWN`2RET^{F-p;2l+BxL)7hj_Ohz_!)V&}{xN4>@xAwvC6 z)F9oA(m1@19X=E*Ns76|FbQN!ubAhd2so8rGzh_CEJYYrp1CcT7Q|#LLGQr@Se?#W& z8*y6=JpB~n_`Q?lIyNP#ZH@+)(_4_YqWYjsovybRIVdgSg9ap{r)`6ybZe1yB115w zEfUnKJ6^Srp{zHv{0vy4atQKog96^#%Vg>3bpNKLr*?KR@itTZPNrJ$3`R|!v5rKR zMo9Z|DX%v3oijfV^K<_QHwUHl#Qym(pBKPb2IbBapK84*?}QGq2VHR_0cD0VI}}(ZZ}$*LVb}t4ukMLu5(XkFK(of;Z7tRYG7bGJIbA zXj0jCeMFT6K5wJn=mrhI*^r#VNkbItI&g;y3^3C~{lw1@1$xBA&_l5ql87=|0XXII zL>f5+brB&~Q>zGD-7sRFeXcIAZg@cMKp-F>!oGP#n4_nUzCJ#+BNUh{_Dd}k_8N^) zcGYsZOqtUgRrV6{-*z9vFZ}!hr`%J`%Ks24)w;PAnhihIf}+7I}Pw_NqU__|SokcM)l9lCeCWuyAF5UuN!U z$MUrj!)#WpDI@4*1iFp&7pWX#lvU3L65F3&vsI}8&G0{5O~%VL-H9w>WKC6ceJhZE zXe*pwLyg}8P|}e`FnitpFllwtS4sT z-fFmQIGEZl%(TVulB&i8pNy^|Uzj;&H5QB6=j&m7d~-DI5vi4w6dVL7uC#NbyRvs(dMp(*7`ZjuU?*H(p^E+%$hiGC2bBHPMHxuMWjAsbbUw%aTX@g(Rh zzwuGLRuGE6kSJ1uyoC)`Rj>X1MbYw*za*s|TN2xEskX!q6ZtT@2c#pegEc*h?;!YNW^D+H5#2{*Z zN%e?eqxD854PjAl&8vLz2{=*aAV;K%b}O}f^R6Md^Y?tKWxK20PZ*y0-j}kE<0dx2 zh>5h9yiVi>Le@hsi*V)?QIEF%^++<;&@Yl)uojjaK9^Z;DFcqi!R;PcPP%uI7OfFy zfVI(YwttqK52yGf+k*4HqcK3I6J-c=Ho9InjrCM^nB;@f|HJykGOwCiT*7|49N}GWQjF)TLd{I6G6ceC@4#n z%o%A7txR@~*qmv-+3aLSj*(KKSmm7dyykFe!chD;K|M_v zOD6R|Gpc8BuGs_Z`^DEmO4;%1Pmw6HH+Xj+T-hUq-C!Iu8q%=IX<)TMHHr8$LEd)a zu2PYnJn{+*8x^%&Di%}Y*fQDyNZCJ7`t{M5nWa)WGE7NbXB&Tr1~%(&23d= zW(KmYlN0%<9pL#6DF9vHmM|o+c8yG|zsTokz`zBjK{IC2BSs}ko<)Ev`m5{BoyY_{S1J4QS8kR{y@n`IbH#E7W@Ow%Qw03Qi#;P4(`j#^b&dE~@Zjlf&CY!wXv z7owwO$&*#6L%EFc+nZFjdWjQ&a%VqWL)HhUbH7vEL*uyQ-hbS`t5F4WX0<^`_oDF(Is&DF%k`FtJMJp#Gioa)>0 zemm0EArPEcS4}>V6DCYmtg9v0DtVvI@=57-CM7Z3qWuMp)G^|rWlgKFJKAC!Xdo8H zUTck2I#X-ob}hM|ZRjacaB5H~Ua5%XUdSnsR9902ANF%1QqxRH*H$nB8O#{gxZH>v ztvu+?;YlS&2`71ig-1++#T!=34p5?p6wLJ|0k~xSngH2ohBm7uuTn{0fc+DJTR_as zK1fA%UP`>dOzj-G#qLvBQCU3+#_6^ZpjsY;K9s&WVMaaPsizVJ3M@|g2#<(}zNFB; zF|0UA)?Yk3Q%HswVTVEM$b?`LRnMBBjM;2;*i!|NSDVlw(zpJb^;9fDU3dk}p`vCL z@K=0tY^fwPR1}SKFI-$4hORA3(wTwc2fwEjQU3<#h@u5ns&rMw%8@W#s$i)yCrFBq z9_b@2j5@PQQr1yS4*8jKUwVin`0}?qx|tcvD8JRl8d!%Wb|9_Ic(J)^e)TxGU}{=0 zVuZ=!aDSdiOjAc+%?}K2MB6#Di=M_FqJToP&`tp#7l147)%%3J6eEV1!D-VjRMVwi zT2KSRFZ+aT0AvQPwOR0>7Z;_5s(plkPJQalD>kSiK8GgCk9wx@y$xFytt(}{kb+iu zW9fiPt&YF9M!&)v_0UwY47@kAwaOt;Q4T7qsGYhED~JQ3O^*hwQ#DxzKg7W*Z0Y7# zxXPkz>Ch^8a(G*X`e0y}s;crGX9%QgwH%D@xRdh2URT$x?(r`VAF|c$k_f7ZI@*rV z@B>+1AjhJmGeRz&w`fkg_maKei3R4_aDS;M-`xWPA{7$2&=uukIAL#hAtWAb=pKT({81!7y3EjnfFGx%sfQ2~xp=2}EKtKr=j zNz<4(iJK7{_}UkI35_j`L+r3XBpefhhM5=yU8PV7I2gF7Pq#+XP8+<#2F&9}pF$C= zC#a(eM!R-D!Oq_bmmAFb0t5%++iA8c7}Wu_i)rS*3_)u0b~1Y_HPr6+Rw_@CT|H=; z^3oC)adQ?9W`8}zuHv78Oh9Kz$ol;l7e{b*c}Zix`SRQAHK04k4EgZ41t%&{)PVbT za#(Li+o_&;!PaO%`3La0DN!4b1R+pWBb#lo&a_^>i;MqI1U&Lvr? zNUs519Q2&B)l^g^KdI7WZs`s65t@$zy-sCHsF-tb6U^?l#^@E;jJL8lHNB4H;zWxgR9sKnkKw(b#XsJC z^zsGiv&0h%U(%=kZDY0G@8dBH`kuTysyF8Txo`I`PAA72PG{MYE-@3x1l7I`(N_nZ zT(|aAq~Lh?=T7#wj^ymYcReka2AUz{|Kg8#Yq=6Evs3lcPkVj*n+0n0b)4U3%64Z! zHEtV>Y1r*MZFEbQZ}-6kre8WaQVb>E1$KSvuNqfM*(Tf={9a}wNS)6- zs*WTuI3 zhJsw{?+d$J7Xh;pz9o!NJ^}ZfqtV*iw&D#H7LTRrQyy@SNyGC>3oDR_5#sP{zSoIU z3X@a|uwKRKVV|A*FPVAAq0w~*b@VC3vxg;Pb^oo@<0vwx(8(BGSpPmC&I$Wo7H0Rc ze>eUZbxb#7do))T`71%Zx#X2dwAkX6Z#Q zMY~w(V2CiYUrkwVkxfy{wo4W(4e(`A4YP;(c*qQGTfsNYSvResTdZWb#4POc@59fQ z%6?Ztvfo<~4J>(bcgHJ**i*N~dbX{K6X3-LJ!F{MoA~704a3OiEAZi>Pd_A>EZ^wA%T|UhY#t`MqtES@H*|A+Yqp#bNSz+; zV3{LSX=M5uUBCB?uzOLMMl#6Y;8BT*`~m|+$OrDUb!v43@N}ai7cM6)fF(PAo8Xf@ zW$lG*SkT5pDgyim6Bl9ZOCf2lS9(W8M0u&{p&&(?n$>$66UPrwDlu)}d7xeDsC|Wycvg?b@;(*A> z7=_aEHm4q0@_?m7RsXZ50za=|;3)2>O~jGGS-rpe52EEdQr5qQ%{zGD|6%}z@g6id zI2g9ejbRTqOAkoH!cfYcGN5Wa(1iiK$xBCbAP2Y^5epaO?#%~xtf{G~PN&1^bQTYR zPdLyM1`H&Fu1P_yM!zF*REHhXVdO-X5WMUHtTAEM|1GU62f&`6$bw@&Cn;jeBpmh zP4>&Sy1#2>ryhNRulYe4E}xl zI&USzxs$16$%9-yoYsA5nE)hzwUFT+3 zh05ycbT@oHYV%`sRw@dt-3&wIJ#*%t|j+-ZKAn> z5hhIF*;>2vj|?dAI7jYOG~KT)hcIoTdf3Y!fvq_T93PV*R^8%!nkn?Bp6MLS^kz;5 zJkjD~VX>(0{|!B)s~D}2nOgmRS*B}RJE50@zlbSw0>=LxgN1Ru=GClV>z*oaqH{W% zyD3hcA+T)9Dj+QObaQseYW_0|is_$5tSX6jl_$H-MpgKt6UlchqAF?g!bn2%LaTk& z-zZpot=;9LuXfFWQ9~e;ot0&Ox+;n3ET{AYx6}=~8IrH@QKNI)I^vk-C+_zKTfZ5^s;2NVx&C@65mXibBADcJZ|yo>NL)Z9(aJcUGTVGlt9pk zt&}{P3jJ@4xYtS%FhJj&pRaFWauhhbJ(|N!ZZU`yR8Qeg$VEoX{0j!~ggyH5xg>cl zVg8)?`-=@b4!#B#-I~DZy$77TDvhtIYkIj7ux#wJ&pKw0SFO206Odj}n;>SzbZ#l) z?XyLf=@<);+sEIzCd98T`s4kb9&ggNcw3a}diip>E(aVlc~Vz6M`X-|5!e`L5~auW zw^jRd!Swfr#OpDi*VD6w76$&Vl8hS6mjQ;wE)D-qXOrcy?4>(Kuh*-8`k17rM(;^9 zQ#+rxfktW@8)O*xx;eDY#2O!w`9E(dk8o988bJv5KA%=~ocacZ{NlqjbG2O3GaF%W zd2I%6{!AmZ=(ZmxGx_o9jm(Jpb(l8_e-k|Q=Pn3Du%-Wfz3!5ovFvE5uB1wLgzYzLr@jv+W=}sbwf!qWm%TiZrz90;Ym^{t24SUUNsx%yeXM1Il3kSsdw zVeiF2{d1z85khW#pRyWnS@DD-@cC9T>u0A`b6v!;<6V4^Ux!g@#b`L@XwN^tBS~y` zcNb~QE&2wO1G4~-r)*tvlETTU-(kt~TZ@lRd_VB#`0}BZ4p%L<`OZF`Me+KO#V0<*)GVDlb>pY21NG<(AMhLBW7yHrS8%* z2E4d_6sG0f+w)jVdL#0v@AWwIU|oo2ey%meyC*v_ioDGTsC}l@4#33Q%il5qkZU`z z!}Pxl%>Jhp!Yh%%>X7`K%U-=_pU9I+6MNy1A=j^$G0(huseYXClL~2fuQ3f&!qiCm z=lk$9f4myJE!!&JhZXIdN4kDECw!#0Y?mHIcofszIKIZSVj)?9a$Y|?c01x>tSPtV z&2&_->N>TmfLhdE> z!@kNJIJ#TK6(q(!q4h9h9Mx+8Lzs=s?07g^3fHW_=Iw-YCaVwQ|IA1h0yge!Ip9Dgn2SYV3(F@MV=305PRz|ap zk6U%UU9q=J;QWS1Gi|*2%IiQl{P)jSyE}YHkJ0^^OTl)aoX#gQO^9j|^#dkOhr!?$9M$UHM%wuxkKqRL zqk*+T)lgVS4g@xbR*dj}Y2l&=EZU$n4+|P6QAr7vg8I)mo%WHOK7K#6==IacsjETe zqN8n2NArusUNkRVbT1|hq5qdigS-LSsue2OzkVHLXSB1B*HU>u@E9NXCMOxpD+Fi- zQMP+7HfT674jwy&3KxWg$&ec(>|yce&$a7$q6#FC{IQ^3SdeXrA-x+_fze)hE3(&v zZ+nViQTq8Zoi}&Z_cB~kR_@z&SX)UC#o`Vb5$iZ98E%+JsX|e!oM+n$7KS@y`qp^C zli!~2dr^i@=X}n#3_jMW6d3*|o5l9imvX1Eqc84snNiTFz_p^tI%oh9Wk3dvsdR7X^Y9^uB+*N?5`y%Xuh|cWWG!e^JPOZP^ZO6edc0C zvc}GGwrZaGZ>-hi-iv88G&ZU@bv?c`dv+oj_Zw_kv0tJbfD1FJULNLHy`a}|4`{mw z|L&y>&RsMzo%dww2S-NxV&0g8+Lr7e-sel%+&^`gj<`_ms zb;2BnO&^xQKU5}v{_A)OVj9Fb3|8FYlwIy%Dw*mgYBI3S=k?rjf_T!&Nxm4%hCZ!@ zfUlJ1d7peV(aqO}@UR?h$=(Ez7dkC8Zz=E#AzkM=P+!xoNE_G12Tnr<;$~MT0-^}S(nv{$VfFEUl>dL4M9{2wu>U^ zA~SiPLoxI+W);MnXVH4X5erM0_nxq9XV+aeZm9vTjd1SZ$VjXI*2j!0p0W1(sq9Fm&g9fPwK0*?{W-` z)ib|J$Omo3N0g)9RWQ0alN>$LAq&D-ERWt6(>l~Ht%V)Z=|~u`hS1J1@O0$s>q|mR zTwCU{S)wT5$I}Kqxs8S`RO%8OI#^f$q|w7)H9(1o`OEFW5HaVz-H4yO37%#AQ?qV5 z@B%+A7oNC~lL&_7IQW>I@9N^xK|x`9rpGkOP6UE#=G6M@P7;^zwQEKfz;^Ju+8ZFL z;AolFw7m~}*8lk!E0|O3&L(|S@yp$*7OQO&P$q^0U$s+GE+r+{n(Q)dte2ogCx;|N z4A5?q28yVZH|MC9Ulj~5Hwe08zoz_u*!t$^TDot`IJx1yv8|gE+qP}nxv_2AwrxAP zv2ELS=lg!IU%&3r`;R?pj5E%uUAtD*S$poe=EPA%<&f-SFZw&8H$Rv97MVkYC!|t;Z4;{CQC_&R3L${Sn+3CcM@@3 zYz|M;8R;J1izP(JUflF(iNbBJR4NVoO5|s%RA&6$mxtKJu>8oTIb*DAw#IJVFMZ*Ol%Z0zO~xo0MVQPKM;{Q zB!ewd<<;^sFAIvR7rA=$@bAA%LPHiWoUxz?2h6+q1Fv>hz2hc3QR}DGkRLH`l*}MF z*Vi}nT*`EAb?ziqX#oM^;tVXmD977`n)x)p1Ub;Mb0)daWjLzM7KqYiY8qXeXctkBr=V!_pB= z%GV5%uLYkvx-ltXrklE^d!m|g6VIO?D;Rs z_opcY2z$zMkx~`nz)> zm)UBYFdnObG&^=oO_!ML&KW=O#$g^d4!ZHZ4`mPg4j&W#Je%&lT&_8j~)b{CPGf?gF9bQOmJzaxx5PA zH+e}E-~Q|v$~>g>sKeI{opca#kFrF4<0WL=D&dliQove+iP4qKqx1xi;vB?38vd$ zcqg;jN@W?~SaT1whKX!`nu0yoL`4aYI%>=`)j)y0!=YDm%nFl$fI8Ox&KsTuW1|b| zBCXGad32joqkOokUpd6APNb^Lfv+(Fr|JAt!e9ml5qJl9V5Qz97V%Q0X2r5r6&o8H z*8LU($dcRM+)!HCpu)6#xTc$MHEsjXe5nfO`)sS%)zh?h>?D+HJZHYLTOr3$t&%Mi zxLlyF4qRW8nI5$<56k4QO490^S1B8StQVNa4<^>-Ce&_~3W}YOU~avrJmDTWe+W&k zZ|`PK?62)*KAAyyY&N@s&RA`LFT$!IbSIbqeF{XIc7-E+^Q(X_BbA^P7JGIcQ(b4jK58<9K>=A>jwqa>@{R; z8C6xyMJKVxJ+75qmpdh8`OB2{859?G4B}CRop@yZj zk;$_sR(@eng-6?n4<23@0x?{~O%Xv$gKCUdo4tyP}FG)?Jt1&Kd);>>%X0f*(`N zZ3UGq_`u2lqeRukRuoOk->vh_0&9^=PEWU(H82k+O8x<+h`g;rTU&LS5Li1Nph0O4TRA8oQw}`hU z8`9eonsH-6!v4=IjgTI)n5fF7hnwV0Ow`4aMVEu^?1rGV&bI4JzL~>m*Onc-!yD(j zv>L*^rr*DH1t^ld9`|>~)KN>%S7wq2AtYsc0mCv`9aV!lFk?uKHw+cp7DpI&586Hldu% z`N!fs5K`Jq`QB>deN5n0d-o?J6-<;HPzcgxArZqLeXGq#1zPi<6&?ICwZ2|@z1#XE zJ^$JM5~PxqLcd$`_+&tFkV$#I#metZ)f!*@E~H~mOv=Ia$9le1K#B~@%Nk|o)rYqD)VE*eC+9|@X6A2v{emkNF5vSc z=t*w1TZf;+0rjFS7dWRSWEW3u*9V_k?HlKg&iux?Q6#-3V(pKQ7J_eg_||KZhn<1n zoC+0?aQm1E^l7Fr{_b-l!-)%XzPuBY1SK{7lUVY)Y|A$PHihvg`2qLC8Vv_&_V-Kl zzBPxDU3G+;9_g3pfkwOnNIb`I-}p{Qv-W!85?PcU-pzKeKTY?$owat>H*vcZ+Lw|*mM->lD2z(G(Vi8t$z@txSE=lIJW|> zOnrnp<90SXYWb>_+sZ?Mm+Ehk%J;YL9HJ9FIS|^#pBW>yx&{hpDuL{ZK&<;9p?_V@;FgNjgCZrJ6efO?cf|czusJN zFDHt%I@P*Zk#%$X#Jz7`w%WXJk%h}lr#hj>pzCHQ=2YP_jYGb(dop?U?g}|b=5^ij zJoUe7`qh;3pX^j(d4D`CA+aq?Vhm9%RB|R(b;0!-<>AHcaOIUBJ=Hf^jobzOcGLca z+HAE{#p#1msan&9?lbL`c`&U_C)C_U2V}bB{hIHC{(W zXa9AosD2yLggc{Rs4CBqTCubaPLz<~lB&U@X?Gr#+aQ2^AI7@x^&u-=0d(D++hleLLHoF4|OO z57ah0s6R@KN+p{gtG7hN0B5UQ5uFw*}>|SzqJ+m6tf%;UK0UF z2)vHzbkcV?@<40DLLCNA5Mh$YF~sEJ+#rY5@e@!8%!E3{3wZ3 z@RY0rN{56PJd(b&|A?Ig^944}Z=pujWxMO@qy575N16Bada77T&Jv}Wmb-f_3iAV; z@npT+p_Hi-(hK$qitGEsCFk86U!|fTWjkrXHqL@iz2Q) z{jGVguwbzSJ#dm3M4Gy4ZO~d>+Hsx>?oh3<3ui=ikF#IXJ@xqtOI~2Oz|1X zEhbfKzqviMNu@IzsiXi(XqKPO=V&G}A7+=MKTETpqU2;`n)Q>LaVO_fC55e4QmJ&h zY9Bk2(^lrfdJ=Hli&bgPmWa~WOxHT29}I)NGAqtvZdUINpo;CwwZF_^EODq3-rt)7 zZQlR*o`$_dVq+euP1Cy3(VAk#qj{}IU3Oo5m`{FUcdA%rZj`bJG#z}tU%Zx=L1Pb( zDXFkfsi#VOWz2WORNLY)g+2agIFvM#NVe)s&=RC-1ivoJOK(@9VpkNEnS6T@n@GZA zbNIPOR=m<~{yEfdmguISyEOA*20fsv`Ii>3^MPmkM`(6^Vyx4XV+l8vjRI}%Mlpe3 z{9`F9V+@eHo^p zpSpLY=L$J>fbnO&pjz_nsd-`e)@tsWzpe0DRt+V4v&Q@hyaX@9Qmyz_ zlm1vY+Lc*}`%e~Ao6NPlkFxxGn)Mil$G5aSGWVl!(HBiofI<$!Z@*Kv4_rW52IDS^+F`58J2f%zI_8KsTs>--#} z_ZKMW?X~(x1p(y414X_zV0f=qwW0{`rVo(>F*G~-?&`3vzMkjn{q9@5m%_hP#%5HJ zf>**6NvP&?ZWuxIoi|LIAl<>J=oL$#Ub=E#rFBAq+K&U2(89Z)zCEJdPx zX+x{qZKJX?T=y(Fj;AiUrKp%ofJYSG{Ij`J`fQ5=XbDt2Irv3DbL%#p(>Ba z^$w}-T`m?fa9mE$yNx210(Hy+Jg+(D-FQ|l(9sAL@B2OC!vt8HMvv_>1M}p9?XTW8 zRaLf0|6wz5B#yG+qxu@5Ct*_#T3@+37iE^XBqt9! z(!QA=UvBDiKbjPxD8>@+nd>@O6B}0p5fyHkdy>Fmk*(ikq5@XmA37#<+D$2urWc+H zf>C^-E~gcKNXzQsk63H1rTL%Rt~p%6En??mDlJ#rw@h^AyF7Z^OOL<97x6S5#v52z zmY;szw#%e;QfEM)%;Oqm@}zyO7qBe#p=xrvdp!p^8wg!qViqfm6Psn-v#bErvRKb= z#+IBnr-7{w4^g&OFYxY-_8T+750-Ei6E1q!!7q7B$s#b$N*;uBH=k_DMzd1xg;puBdS$CL4iYGmD%-I$;jD9g zh)tXOb0N~rKs_=7lSX5(OO2}Y?0ys29f&jB`6B2J8_&gja)ZV5kq?Y-we{NI>9qLy z_t{q(Er1~bnLaWEWpgg308G)?M3Gj;CywGd1d*LMCa)&o-{+GGrD8Rxkh=TW*6hs z552ldt+wQcV~njri{XKSmJ}yF0s`n(5Mvky6XA}?BPm{Xtns(Ex2Y_yx7UZW<_rQZ zF3*?SgL#m7>?m*18bV?)GAJZ?XE3p!^Cf6(Jo95o>WdlDcY{Cf_p=;|^#`;X|HRYV zfOW<;3eP&EeoLWZ{<9+j;>SVDJ}3x+5uEiLU*BC_BU-28x1QzCE#$EOELQdiFT ziG!*Und*M41k}T`Ble6W2^8NuaE<6f(9z-f_PDdNLo2YB4Zj`Xe(uFcEEy{p63!<+^8|kyCvdXS%3` z9MRD@?o8njiXTDs$NkPcuv7Ane!SFIZ!8{k^Mh$(D}@yN;9UPTjXuL#&;9Qb#UD#m zf^>tiG0>yGrXD$Y46kQpbWU{@MCcv1O}0Ge)7cH2ocdVxjYodhTKTZT4|~WTe-?xfvDKJb&8>~{P)LHJYPj4Hio0TLW#IPj7|(@^qu3< z`OZXCD@kn6m#a-43urj%uT`EtO)P6;;xfr<#*zRzIHH1)0CF6rWHtk7>=~mn$)fWZsV@D9tS#RQB1376t;3V)VkB{@{?s<71`3%NU z7v=kHf2B3dOLC#nV%9=U^HZn24Dcl2t7EgCrWLBA@qU`9&@YkM_M|iy-5W10ViWo< za3KUZUf>KI*!h+m^)J981xt|O3vs?8^W?mZiwXF(Fb`cJJ>54H=an)n3=Q2#WHFh@ z>&JBdfFzMgc~Rc_lY2Ckou>3C2y_(G%UF(Y*@tBliLuPKyrolme{&;83XlGExc`kL zyqYcug}3+={?=OIOs9@eNH+ae<<3rH($kG88M;$OUUxokIEfxyJ-CX$-sPY{2vKMo zt(4dLaA9t42VkMxSbgoQ-jDAFMY>v>#)Mehb>uW+%w8<0A?YVNeZwXR-=x)YWxt79 z2t8X#Noh6ymV|HRR*CbW5_RMqKuIdlL->F2gv%1Ex5tZ2gFTCk;>|7Gu3phN##Bl6 zPVMpqWkva%N2NsbM&bO0(+9U_K-AtiYij=v)U!wIcNJ^6A>!`<*iV|+5J5s0TvFXy zY?GO@8$w6>&>7PT`SPp81Vz(%0g>p*k&)1_u)N@ERbAcf2n>cz&nK-Eh(&OF>@EFq zTt6XiS?I3{ir+IyNqyos*m?Q753%b2Er{wTj?*#omh>MbVhs%em+}%Zz_uz+Od&(& zJWIk-iyO}f+EYGnJN?1=5CXg|K(>$PYAsi*jR1L}e!f+jr*9j{4Gq3dTqr*_Qd3m~ z{6DV@zoC{htIEpSygpuI2n0H)$yn-$gyG}l!%ju6T(BqPBzasRST zxZeYs0qCjoWgUKqk-%jMM2Z1H!DE5e>_A0?iDeDnI+6ME3AyjDT$eMHUyjTlcG-jM*|rU~Qx=B9nu&7wdK#0vpnjdCE7v7cLPKj>)F?P^>U-NI9XX4v{%* z5$Jti-nkF60W&fSQJg&XmQA~&E*ONhY4Tz%kySPzK!T0gTBfamM91nkWX|2Qipap& zS%s1c)oj4D;wGR?LwHJ~*616i5l?Mj(@{{?RL@D|*)aHk8^#}CYYExw*8YbPgWNem<;0ncy<_iGPs$tmm}3ytu0B?f;Yc)p0&C38P`s0(Mng zq>4}wumUHL#9jM_O6<5Q{AdrWbz0j})K93479(=K82yD#!x5^sMk-`T(eBRj7mP`& zC|9q;6JA~2-op3!2sM(V>AY^Yx10+xr0{vV8GDDPU|8U$*jNV9#9j#hVK@2sTW z9eYNGN*xMnp&Il84e8agf#mwo{0uLN7W%z9YDg%0%ERC(&^$?%la0-J*6z0R`!n8EEb<)mWiw@b*8n%N+p^43>ap{yXu0ah&<7xxe9*YBp2RZ%8)@> z1;kLWVm&`D*Kh&!cuG>zph5i^99IT)42wZ*&GM)=2*#c`8v$$uYN-#G1H*)DI!*im{8(a zxVYb*1l8Y3O?yMZ{&BCr3XL`_H0*cKd*DuCj!$ErfY<-$`^!cS7BGddJpP zPrLQNL-y7HNyNc`2>hR4{BAB-jS-uoXC35=`$*}LXAwqKu-F0Jcat1*MN$9&6<3Rm z&SE4MA26^T9$r{io>m3=u6XoWWRGZ!Fp@E$Xolf0Vffs`ZPqc~6j;(ERbFTp;wem6 zv}IU_^sG4ZeUMH|NU75F!@`P=Nfa)hb(F=wQkrWAf(q-1Qn@0t9Lxd#M%{GT&#zf) zIqRws!`rGk^t)dgfBw+U(t?2WeZcE2#m=>JswbsaQ!Ld#^HxLVg_MxDhWIP`|NB*+ zY4noLc)5vQMwkv6{aDE&$)s;T@|~*Bje0UN1_s{Jdj;}+Ztid8hq0X=L3Vx(A>~B< zz}EBe_VaIWv^J`exh|3xv@4W`)X2+)7k#EFl1^F=I>xTRBgsdq`sTO=Icd1jvF`h3(SyX*C|{6RGIpV3Xn z{SpB^`Dd>pm(KvIi<4eG>i$2Y_L&AV#o78BL;UA0lvwS~CSCVII!>*X#1DT|Tms>I zW9*NLI1f*&BA$74O6jFb;;+a7cpgND5N_a4=uuVY{l<`t*Z#oL%pz(mV> zE{b(cBAgs6!R0@Hf}l$218bm`Q)|n?-RImkfhIL`Rh=gznGQrb)~{AJgMhMM!@wD0 zWBRrba{m5l(Mz@9v&uA2nw~wOzdQq(IAAx(xv*c(Df91T{MV5G_sIXu^XoL`U`UDZ z2i>1znk4qo8h=m(wX=74d-GXa`^cYEE7Gr{P?mrIq=@8Y{yZvOi+abkBdX}<=y@xUp&V|O!DtS;Q#9Q z`**Al+Xg3C;}^X#nPnvW`*#!*5({y8vr}UPZ}5gJIfT> zI0T^Ne&0ZL_Gmq+{ARZV0}=9HQoKVko6Q}EbvsGInyo-`$*80qGhn!GZol9b0W*I_ z(to8iGr00*mTC55p3$(gvl9^H78DGa(Lc{El&ho;WEF!|8NjAFup@cw*@0m@b5BW9 z^!$Q4MO#jOgeZSnaP(1=ZSD*w{R#TdBk@1m4tLPrxxBsPYy5*))I!#%5+ZzX|DGMV zN0)TI-0N!{8@3DV)K7G;v4k5)6Gs$f2uVg3Azewi01{m+K6{k_SM~L%?z$kvg5T5z z%zu}8KN-8s%>&4xr(sdk2g^i+c;_np59$a)NDYksE?#i%I#RjTjHB$RBPIE7g}{g=9@1v1Hqp!q{1~+x0wGcC!d-iI>B1AQtKpcE6a8x; z$Yd=XOU8Hcw8b+;#It3my$aDL(X5O@WzVuJTF}SZ{6A>&fA;~9VDlc>i*EqZbERA@dHBidnvoeRJ zx1#V1Je3PYJ%*bW_?gk$QS(VYKR?OE znX+Bhmub!gk+AwR_MX!#f{{~IXDsY(33Eq`vF{CqKUNn1=bu(hl?Y@jRuTN0$ zZ@s3f*^~(3JDB6^qHor{eBwv_Vadz1Zkc=ID10T)1op+USCbryX=RiK%$!@T;Kzd_ zQnu@1YH0nWa;`ht{|tuj;~hReP=hxYekR?A&YE7k)|Bvrnib+?fPQU>QmHArR1x9E zhUfMa;bJBx!*}T?Fid|7Wo`t3NGxw%)tc~u*epGwp&NRtzs?Ec%LUOrZSb~tyAd0H zog=mhc+xPd9IV`%NFHBZ)vyCKaA+QOMi&?}bA#`UYJ-JWYUS_i#OK9UMU_lb7H zn_A!2a=Z*O4E+V=%qe*-+H-81%TOkHU}1-f+ue+?T5}tcL55j5(k6lLXnFNuzb^SvcCw& zG!caSeK8UGH3FgACvsQFvGsML==g`{>vFEk!=|A7VCt-U%G3VCitzG9 zh^A)q?TRA(kEgE!_uK6VycfJ(S_byYJf;1U$k)?GW7#Pr1O}bmPV(I9%CqqXTlY@< zllNGYC#CTH*LnUDJH-mG_f2Bxm-ABGb^3}-zjr`?*YiiAVB0{46bz4!J?m7{K$k+7 z%h`yaq3M4x`v22c;$%&EHQTY^xZluWUiTQ%E1d$UF=dkLC4R&a12tNs=xJ|^whbjd z$RNg~_+5zrq6)VGnMJlOsE`9VvVY{V%jV9cSSMRN7G#DCSQccz#;5rO9$LIJm;yyC zy7h<`p$b`$L)!UyOE`#ufsxJXACmLo6_pOVs8;T;Vu2T?z`6&#{7ZrbUYq9igJ-4qUw!Lu{8_$fs;EQnvJP&8FgBJ| z+VSDYvuqV!kvmo7r5L4`@9&c^7Bng@+B;!@v+T6?fu#1lEZo+$!*4xCrEutZmBkLz zohrh;cnmn**5FOg&o$04guQ@87wMpMoQhHAiA=r2Dq^{jkzeE0B3_?U!|u>AjsKNX z|0lEl?i-w3Sb;a?TgoB8sT;aeh{cei(j|)!wMK-LDTDyA#P!AS$Bwnzn{K*XHt9bc zv+zqJ8_q9S4*B77xge!W8K;;?`P zv~7LVPD$ekZ*;IMW{@|0@HO5Qk6mX+$w*(|5teaNN#j2JJm7V-T`M)W{*i#Q;`HN_ z==7<;(Xl*ytr>K+ytEx*d-(o>k4x{;k}K{&{HNU0QL^=Fm)*$d#TlARM6tMGVYRk% zU4bzF2m{_njpxT`;+Zq$%M{XhX=Jt~*+TZGxJt)ZM_{*A@%8X~GQ`Z&S}V!f zY>J@S*JW{B2&Bi$S+>OCm(9p14$r$Y`9}mt%U&A9H4@KemqGtg{;@|Mx2DX&?E{1D zeD)Ky%|x!>&0}h~Lx$G|9t4F= z#f{*{B9C@ftDuM+%>WzA<*Nh}LLs8$4i@H&+%94((ups>qV}Gsi70M8|IH6C{$$xh z*1D&8JY%QAfEmj*Z-omntA|v`Cq=nDX`S1d9(3bQfb@G!D;`4e?f6<V9;3gd`4PoWXc8*p33~2UxXc-SLkf z^eq4HyHy!prl_}*_Gr@&3Mrf%j1N6hxG|Ta-vzGty++fTG~ZRms>SM=Yu1o(-0T>% zr5TsiFpuP(Me+o~|C{B7*Z`x#K&Ps00S&Uj(0H7BPi>);Jd5>BuPU>>`n`bOfRtDF zlhc2Z7z*=Ml7%;x#oH)FC2SUFwI$Fk&nazrA=qYm6(g3_?B@iP(gjCsf5r%#*c-|( zP>2RJ29wK-4STpW+?CJJ-osOW{w%-`4n1;PGzfhCzRh_ z4*Uo@YYw>|!6Gw|!jU3L+9_WCpDKPzhlX1X_#Al8v){gu&cE9t_KsvaB^ismJr5JX zz417+wN$M^GIB~%Qc}qAn#=9$Na)ix%G9~5ykGwSpbfWE9`Si+(qv;nslvZCjO(1Y;_hVjag6Dlwxlc$4# ztG8*aI+!q>eb^M3#TA*wk>dQ}=1=Qz-s(Kca^G@)+K9KWlFeVBKdGafFKlvKt%7_n zy_%T3ER29qqCu}ZM@6)d4C_0~VED9bwwn|7eTRtpvG#{4()Q*m;2pfvQ*I}4%Q}W- zR}9IGus}W)mv=P@akp;d+1Eh5B{%L4(wcApHj9&3H93cKXDWZc61%SulwLF1y5 zcAUgVqUHO(70k$Lv}^ZptPB!y3gg~=&_Z#kmDdJDC#%`(SS2M^Zoo|VW{7qJTP*qR zdDnxCl4BoVg?tR;*^T|(a3h2FhUDcrqrQ7#>fMWtNFu*&sB&682? ztKqMG&~W&e`CEx8HFoT`vgu2Eb{fueQRXhb?Ucs(_paPPXxKnz{Dg~*%Bwj5`k194 zA1K$(sd3*50#3k|C;kR>F#gS8Y4GB`U^bgYuEx?@%KA+|Ty6Su8ek?SRw#mIT1J^pQym+Lv!?%KFP zT*M!IzL=q~!%#+M$t8^y9i8iyrA5KjJp3!7SRaetTL>j2mF~e_1|drvqFQNB&+ngb zX9(Q9s;igvCtO1fH68`zC40vh17})|d5jmAD^dWK^?2RXH+b$0#JMm?PdFeTi34 z^Fu`&*uK)AzUGbU`7`7x6zjyK_(7T}RdebS^}6l!FrWsEXo20B+)sj!JE!g_qNTY# zw(A9g?Nq8x>CM;07N3~qOVam>i!f7gH#1H1ND zJXIR&uLEO{%;hsmyWDeDc3Y!4Zs2528-z`!98y^fdOkODBrlLM!xHF_Umcv~XF&ZN zAC(UrxbQCp6rwqdwl*FF1Q58#){OYNn(H2{jxQk;XET}p?RTXJT~(46WhYx@Foa;n z8LM6nw<7-OC(ROgnQv$E?1)X6Ol|2{?~;QMjv2ArcW{>+c$H?ss?ZWAVGU z7(#t8`5Ui zy%n5grfpjPR1J=^aBH;f!&J$;T15u0RMS1up4 zwF9S|H3<8s|fQWYL2nTQ0wypz(RC5vvNRc~nbGLWSxWlUUGvA^?Q zjLfj_k5~}{Mb03C3RlR#<^v=XO_p;msC_%lF_uch@OVTgs0oQ`p*27F`_tXSmzl^^ z3^`k}KMSA;nA4}6Z6Dymp?;-#zRHr%hZyy;7W{7SGCYl2gL1!|u;IZx++F|<73UHa zpQMo|VAj9m>QfJTYrn%$YGeF(R^h=O0)_N=+?;mns@l6(?B+h;{QvAIL>D27k^ z8-gsjGY0yB+DFbcH%(|$b*!$LclPKpd*9!77y#?X%lcdpS<+LF%uq8U1D&(e*lxWB zEX#9ew+n1_)9UxT%JJmQXl?c)(=|F!ZSFmuXBTrkBA6Ir*CPPlr|Iz0y)5Rt$64_y?3cC+ z!0UV*>=*w~alnB)1Ozun72RJBT|I?8UWM+xy4OlF#n|5+XMOxAT%abVBO-;rK(tg`970JRNU<1BMvJgk=*O== z|GeO|8!wV>O(%sj7YZ#%NLDFn1wm{7h)5`m-u2$fBxb%*MQb=?F?YyT{!UUfmil&w zF~I31DJyxRU0`O_H?S9*8&{;|wZ8~`gq9#E6pL{1D5 zeRgb-FoV>upEU6o6JWg}!8*A-Jh4ZxpBzEB0p?WNSQp)K-kb<@qvvao9+5#IHzL?cZN*ZF_Z_DyScz>iyjolGr*uwR*jt*qv+K zQ+dMIh3KrYEr0qpZ^rASnX`dCxt|?pt9Gc=>;iZ!$6bMSSFSvZw1Lg7Rk25=ydB=_ z^+KGg*BI}x=vcL7$$Tyf=FEwg%NQ)3zgrue7aHzjd6HkwxlXRxL>(hSb;1Jy)r;C& z+phnl@Rro{AH`dD63x0li1?c{&Z+OyN*rdeC8^__Ye$%HbwQO7GPqCkikG?mc~}`2 zsbLJEIPnRPuGFYGRJA@>4wj@s2^T~9rCj6u(04ZSrAAj?{0UMjS8ARpi#$VwIY>rW zu@sV(D2#4){)XgiM8_3Gv%=gS?%B5fHF2+VpGdgBPgI+MTz@?|Lt>-peH45JDNBlH zU$}N(BEErN>xT1#6z3(gNvjc$v(=-eOYf~igU&5*w-qAG}_(7L)f4aSx_KaN%YsiGl}xB zS46HqrL4MOgR-~UVtXEXp&SUa#1hUHz9l*nTl>+yHx_PA>!w!3c`@F0QLG3-m?!=t zUV5;|xcm8X{}TI7NW;_0aOn*+-_ z)dbkT5lr9wsC2=)4j77pJtGGV(u0NYcQGL>N}sLwAz==?4^~RcKOShq*>?u5rciuX zpuNQxZnf2$C%vUT#k*1Q*G$ZkB#0+Zpv0{o6ITichpCn#OHm`5V7T&MP|dsBiKLO% zB|5>HYP*20uU%s&=Gta$+1cCO8&0*feh(??>P|5yvRw(ANDHhPUVwMLY_h{Ci;Ujw!LKa>b?I>N^8lcj6XSu%Fem`5*pv~ zrLT^PMi#j4FO*taWuCIaXS;crx|}*8LG*s;y5LX7pFlto2?xZbOi=cHg?@jN{;v0D zyokqjL^o;eXwy)BdZ;@3 zg%$)T5ofP-8aiUzZb-8|KiFk2NKnjafGSMyFs$k|V|uvfYj3Q6mQFeaHoF@FRbc;b6~#%n7H1KZAKU9kQw2b-YB9GC$uogu1T?VD(5zCY5fv|6P} z1R;qtw-GLp(L0*4Uk>?%Gohe&8!Xb4d0T9us4x>5e>#geA!pW3Zxz+zuVOghxug7! z>MY}Vr?$1Y_@=P3B>8XbO)q0m@q52n^_WeyeOnqs3>nyZ8UZ6bKLIQP&&rFP3;P^7 z$~GTBOyLkQJbK{j^SWv2lDcQJ4@L_nj2~4d-nrMIGj$WMqMCKtmIVH)ktPf=g$(FL z0>W|7zO@3-tQ(7J+*pf&ie;1R3`rU<6P8-^;6p-#V-fZ#v;Ic9sL_f3Y;6sV(ZCri z5Vz;Wypw3Jak1XiZ3F@8X#;;HapP5caI8wO?EJnq zrMu}jiWct945?WwzA6)GCa$tkU+~vyUN7_lT{`9Ap}9IKcAh#AdQ5$^a5;XnshkvC zZq#YwLT{q_4RJ@#ucFT^2Tp1*v&gP z`x{tXoLKbuaMEP&*00^!9xMwaH39>5gn)s2Q5J>xsPJpp5J&8U?8lsSTVfvEFm9hZ7ef75zWwe zAG!2bw^2J(Cox4RE5nCatNMigO(%%I)FM#6xX9+^C6pKgu54lZE3*x5jz*|@oI8Lm zI3|7Y2`UBzt7!kzOvTxZACid z@tomv(OF*n7f%>WR}a$KuXd~x?XX(t`^|d&z4E(te_l=9s+R;Rb;QG_BPu}X*r-9M zZ`8`jDRVj3lnxFKQ0NN;*}+fOayw|blI4*Vwo#CeCz;sM zxpZ{4@5V+mTLlwoh(q3jVyuOOgj5=1{|1ir0mS7M?p&)l1N~+wDMM@)v-*jdWJxEf z$>R_wNFDATpP2Usjns6@j8ZSDK?-7zjOD1#Fwpg>@sP}@Scd(keWZAB@fBlDroU4h z$4V(>4F9fG^N4({$S zxVyV<{(qgl_FCsT`#k$*&sERGS6_EeO?7p>Rc{edOw5g~uczrNpoZ;3Wl!@d~>s>jH8D!}F6XnfNpVuO-aWA|QESdAbfdn{n#!c3|$I0W|NlI>j>S+jz7 zhWcC6k{T0`BwQvCz2BVu0>?Q@k%)nz=(VaTEE>dI72T-9(0ZMxv9XW}B$MQ>i_@Yg zS??BsZJ_>=JTcQuh*TpWSK=_yTG=0x!syv?8!?{A+1SzgphNHq zuFaVdloEV}?)DS_S5v3f{M>Z849QY{vtb*$c<8bQvRbQ}zb?#fw=BB(31k2~yUGWv ztwpRU$Lz4Ij6q_lmEjVU-&R&0&$gQQEFX51W)>wAEh^P{5bskuPDZNbI||CTeXOz; zUqJPjuxTD^4|aW$r~F9jRhZT6HQ+FaIw)8~6e{zu043T)$zLiasqR=%C1$mWqP z$-``gsYB~RIa-m9x}8SOmZoXF?KWh;R&;{a=wIafUUy)bpVsPX{aI-pU?58$6Ky5K zOotlZd=N5=vYK1v<@U(kS+l0ASbw{gYQ1g;cen)Pje zQr3Z^dH$M7T@75R5zr=c`1H1(S8TpYXK~eQ{;XY1h*s_GVsf|=1(oms#y=M2{b69v zt{2$^kFGsUU6kB7O8Y?`fC@b@QgH%yZEKn2h#C%|X{D;r2JA5*#M8vm2R?`Q<9~Z#-XW)TyfAiuvr6!nSkP-%|`f!tY#8RM(o702MFD*JgB&)ElaPGc*|PC-`Pt z+os?nHt%8oiMZ<_0P!=u{A*Wu&N5Ou&spE=t(5Mu)ib?}fix5JM~ zM#`FK9(F*^t&=V;=9pNp73oUp^NmmXqTo30CjoRmL0hBu-xEhUginX(!hRSH4`a{c zu1X7L^YCTXOWuRO)$CZ>ff%J@i?Ui))@t%E%c*|580@+auUT)v9~=X>E0b0}9QE~v zvGg2@l=$s0Z`rYAONIz(9!`Eppr<>KzLX`A@x}7FAQnNBUiVHPg`6SeWgBouxORkAc62GRKuYaTTm@YohHqMQjL2!y=n{aclS*7INg7%QUv9aS7F!!=b`B$Z zOz8=yd{1RY*+oS;NM0@YQOR);ngoe-h?w#o5v7qZT1HLFHI3#rbItU>O%>mNdJ5+- zX(y>0nenAMqK61)TY5B4sz5-v9Ca$;NMY(BIx=Q{{k%GqR7&~HjRf-Y>L-czHKSgV zw}dD~LFCrw(i)NvY=#q1q{76m63qW{IPef|m+SN4!p~k$2(Ght2fe8$$_62YY5JO7+Ys=v` z_VD=jy3^3#2jwF_aq(at{fj(gbrTko zx191%L#eoeMP&3#Q7Th&8#O-&f~PX20~Q)4G_Wg~7+zo2+Vf6BHK@afYcJMC7^AW+ zRq}8h>RVsu+<6gbEKBO=k$XIH++s?<_|oXrNVScA({3c{vPUXTVy@<20~nO?`P}WM8U)cj0s1UK^tL1$WIjU4Hddu_w|N4ezf&(9O8ly`$>-RjqD;^PPhZu3P(rlk5x7tiZpFK+J z^1CuJ)5!kraD~x-oVIZ=&^}qbT#bQfeTm}j+91K72Zgom&0u#|UZyRLElUZ^s zkD;(EfHqwl7S=2t@>i>}L+r}R9jicm>WQNpfzh(iQbma;A>&nlRq$R?%B~e?BWT!4 zGJU8n{q}GZ`05-z2XzeKXq0$5dT!XI*!(v?hGYkpS$^H-Z> z(_tr&Ke>CW?qLmb>eQ=U`oNcZolI5Mn3K|eiCXs*WoaM16xwKZJk^&4N2%v^u}g)! zDP%{esTvjujb0R{iAow&v!5Uj%XnZBq(POo%9tt6E8^jmsrQ{YDMI6NFS63|8`;|( zEOFR=bOSCRDXF?G{pkA5h7d6cF0XJlSH5042Buhwbaw)+`|jKkpFTrC$dbo;l#^i% z^%j6ru%}gD?TIO%O-okY>Su3%yJ+UVm0<@#icHv!O6m zzy6N1GC*502RmCR|I+yZJ5XsD&A}X&;`m+-{p**23GL!C(zSf{p zo1TYl_rWQ*iQxxRR}>~~3sfXK*6Y`wUE{ad1lsN^2ikqwRVHt@y+dthlfAp_^;Ki` z7qI2Khc(4D5WY9-$?<3a0`SEGa4u6iT$UCOjD)w+@ocl`mt@ij-9d}f&hO8}U(9a{ z67nlD9^YKKQ-D|dAgQAh!|XXg+ryr*-^iOuMbt6+ULe~? zRv&+}6H#^iEG%u&LRw|pMql3r!X?NZ$emTvIsENj>x?VcJ$iHMG!Vp5VGdux0D4*2 zBW*D(@_?02S**>cj7-XS^z1qO1EU}~94)E6{$Vy` z0@pp&$^JG-yR%de2!L^G#U-SYm82!5gnvnUp8tv+-F1gx)59uJJ$-^tZl({uvXAe| z?ek8_YS+>730OeZ{1(T46^YB@s2YxlsF*15biKbGXQ;Xs@UTO0O)Bz5O&QnnlNpY> zBCD-N$@{XnVL^;rc$z@d_a%Fl%I}MA(GG&`HRr+;Q3EY_S)e!h9!iwsp9qTaZN}Rb z=ol2Bl#7EtC;G=P=ASr*Y1|(CAv1yv3>u51(d&D^gJmlky89rwj?esZ4koe|E@cQ;1^pRx=vikX4e9kmqqw#K^Zrt_QHjmIzG zKO8rou)qC#q{7TADx#%*;n-fw#Le1vuOZFG`jr7T<3ur@HN_B-!r3YnI;HQ1o?$ z*o@87$`zsQ5tsb$T*0S#h+VE;-`j8(kM@s5ed#02F*MYuIufoAkOKnWNpsFb>C4K^ zU9s&Rqfl~1MiTIOTnuqxdYl#o?VVg}2f4%feQHKK?V$}=lJo`xloM7RbE4K2{zEi8 z+!JbufWNQnwARiX{>xn$2QLME|1OKjAs*R%rd6xlRTqp6Hhw6> zsmAI^APo@zJ8T3k=-Fy5NfROVZaU-i{aG|zt~JFP#q?Yf;xLC164o8nNU1u z=&zUZ+&FJdAtw)Mf5pm>Qa${x+3< zd7o|k(GJDMGN=Sj##PEf!k4EGb_J}}nC*GH6}()ahWlUi1g)kRv?bo(lq6S|w-s@P zo;!nTe&E9wV!zh#bTx*zT?b4BN=+F&z9!cMW!p-v%7_yQbH8mIZaag0c3aM`6pChL zn5vac9E@WG^GgjQmF#0v)3?(~HQckap{O6>b#cn-j;uy(rqg;WiO8@@P|z94(cIM| zBr4W6AyqVPtqa58`T8IklHCiHCxmDqlgVH@PT#tPguHIU?Y|LC6PgK|2#M6E8yu1` z6$_4}vCZp;HIK^VnzQ$+H+fweseQ``{p9gv!={P^RplG$t(xZVSnUMb4t2Vy; zllPI?*UA%Uhge<5hW@SJY%iO{vx=_3m^J#RpIz@s_`uP{UK7Y_@1r|L5|hUUihJvt z6qobcY;kQ!ltWkc&Q@G?>HF*TO_HG3^4i>TA+(4{emSE3#VVk5wD~?bov^R@z;;jH zF@HCpt8)c)Sopx!3H7HgGG3>>cJfX76pIQm;}?{-U3H4?KP+eqrO9_=kFe!?Q_a@3 z4^4c}y=Uu{ni;*wN2_xay{CRyE9n|Pelt)H(KDz}p|e2QRzxo8OpI}Y5YLXYucOt(a(RRfBD4MF>KW4N?vE)l|zf@Mv63T|T zuN)rocyhQQ=LMX-!o@$iMID=>7f;i=d3e1|#o6^Im^TNC_NLwhVr0EooK;3q^(@}( z3PxC-A9{CeF1JLeB*fO2tY{41(s<~g{Awh~p>#M$bKSmxE@LD8RWVn&kA{Pxo)9>M zMMUH?8ND6v+?! zGLmgvt(=fWU0|S-d(vhRp^%%EL39KNjaJn-YckCngvZ7eKWziX$y8_L;z44y@9da`GY7@;B&6Tbt6jr(G80`SR?~j%b z4+F)JB*~+-Bp~DH|Dlo%S9~yzJvLX`xp7Cusktl%3=vvb$(lhM6E0}bAKK|HV%NLN z-5&!Tg;|$*`!=jZn-qE1s%J>?+&ckk-B`8MjyxjJs}VCi3>>)&c6%e=Vn-=Pv{SUs z5V)~F5$8U{k9){se}AhtAS%6jC9hTtL^kMu3rv!VdUTVs*jojFg0q~ zv?hlhiOP+*%R9j{a}O!O#0X(m{j7b9ui+lE`NNCeZ~?HmVu}WMv+HivrtxOd8M9=Z zGsA{M10d~7&zz<^9Lw5#z}KPSW!+@4Klh2YYEhMBYrlGWV$lX2Gu7`8-qM*Yw~JS5 zvCe>ORBXFP(t5cI*HaEUqH5GQjbBmj?pfY+$pf38TsNr@m3SKGDDwEOQTb0J8^g_x z&yqWeSZEL{&Wi%Lm+PUNR7FP1Tq<5e%TstIMe>n*nfSRM5K$ zMK+PJERIWlX0Sm`O$T**??Jr;ei<31{Rt~z*_GXoEHPT*2Bxawk1&z8-;slajY+~= znB+1O0f5&PT$U0ZntJjG6D;?kh`)G3UZEpMF&6m%;W3sARsV4!Om^6Ku9e!Chz}lo zG#HX5_FG$mUkrflh;CsceX^gL<1rvhHJ}hTlM`9!lX=vqHldj9r=Z0__V~7SCvv8$ zveL57oSZ5#!2_fV9V8MWPOqcGR)~qV3i}+8y(kV`e`UqePxm^u90$8hbGXSk+kB4y zRpE&E9~03RkvI-)l*sJQ&J2mqJK~Aa6WA;zW>VHHxbt56I=>5q;D9seq4r^_-PyVM zPmom#foGZZb{KexvOjvg#Zh0yA~gixS9A4Xug!i2UIk#{>$VnkHkI-9=N{t>Go!-7 z;?=85S917o8;S(v(Phe?`j5NgBOXnHvjDm^^*K3eT&H1*)cY9#?v{kalia7B_7>mi zqO?huq!nU4-muVcuL59`4?*qrS{EuoZ(LSmaGb}{PZ@p=1hc7jyioU1skXS%&}O@0 z_)Q=`uS?kC)Y^gn!_nLq!yA4*QoWm_@@sARg+&Ao(^VS-*XPyux8~y!+io}h!W1M2 zdR;e{ASXP0+*Qis2}eMz0d}G*rwYdR-o2oJW{Nesf!^ZglDBNwV|r6IT(@Ql{G>$1 zL?Izn`;Isn-A3<3D+|S6r4qXszhUz*KlwLj_bT`k6ztriAUme-vD1|N&h9h`9l}kE zGxRzB5iusu?wLJ2@%JTVg^!=Rp}u}KNnmW(QV@S=wzzK$4Cusca{X*~zQS1kI*EHv zMLT<2^sjmpsT`Sgm|39xGCj*ViG;?w-aYW*N=v=fbNC zi{)yDs9w$avo`L2S!p#ElZ8c_5`sC``2D+yk&?g?a2q_y{oD2F0WIQp-OmOEa}(M* znk>GY`7txJ9m7@eIo-oZlzhNmC6`k7@8!3pO8SnBwWTipINBRg7wT@78ALhS-24&* zyBcboHvT3hOm0ddkkg5adh>9uBk0XCB8Qa4MaWY9GS*6&sI0Ecw+_|~2Ig}F& zd;VG}eXVIAJM4UFBEtZ?Z@ny#ng_=QCG26A)CE%DOPkK?muOW~R77GlG5lfwk0|3D z+Kz@mjHKtq=Zm`f^3z|WuJJ#XD%!wEDLgd&0r@jtH0J}~Ljn?`4B^{fmRyPvTJ3o~ zO^)vZn<>^Mie>x$ah`s7UP-k&9el6)1eIM{8kSV3f+(~YT|*3vg~&51s&A6WCD*!v z+sg2mA`Eu6O9})Q3LLBrp_tKsw5!pWwhOi}@h$}w1_hOdA%5@y*l-EkJ`MWZrBGj} zJLxohH#Db?aAAPr#|U%NUuTq?dC~hw#SHAQEJoqvwrmpv7s>SCJ``UzAE&B2JBO4Kbp%K z<5VXBV*nw}1u%pgAEDph&FN6B_zkphg-hx&d83$QI_-e!fhvI-*@7L!+)B)R&8Ql>JpY@lVkY|8gG=3X){yC}7aZf{hwtNdkjq#eit|u3p zJ)HJr!RnO7&Wv7mK|H45H#~|Zv-)N+WDONm6?pP3Tl#bmP7p&Lj+KkcCf|3fY0bf! z4#RTPCWZ%x6KObCX>NQ;&LHBNQN&gm19_1^(ARB!a{zcj>ggh+V$<@bfwr9HRm!q~ z*6eMVlrQ;D<%`yfn%`0Uil7~dqJEMd`v)A^eN{5jq^=yBM4zZ)Xq5VozCj#i@kCsw zv!R79Y;Wd4W5!W$Txy6gWD*bvXsywU(2Gfk*3pD)&@A=ZKo8iKD@%gRi)CA!)BS-1 zNF5~XcEw*s5}dxvGt(`SPJ(AwF6)Zv!ej` zO-k+JU~qh2cwLkNWMsrzRm10TfHpn3WQfk)bOk;Z`x-CTF0^r|^0|t~ElZK$FlPDzQ{|HxUmtElf;5{&atj1UI48 z=J9xiR$S5e=^p1NcyZXOuX4qWEH{}g(LDZYwAGl?t2V?5`TA^)b2dkw>HH>g{hi!Q zOwR6hvY$Wx7RLE>Z8h+=t_)-GO;Ui@WO5RdVoa#PK;$ul)vIjTExkiH5akr>hxF{? z?7Xs0MG9MsHp-3`C|Z+(oX1{#Z*1|r(NMLpI?^+%kdcqFvEt?RAOVj0UWRb7&dE7P zGjxvZO#StPibAmBaZeAKI_)EgFsgLkYWZp=6p1o^@896t4?nrW4W9@OjkH@|-G7SY zZSb++KgC0a;wyhJL1gzauAv2K*fuM7Q!BIlc?zf;RP_lA)4)L=>P+EF->1Dlq&}Vx zT^JsjnF06o%=GjG*tP31i!*((4@NfsAjG%K-IO^FwaAMwC&RP~+mN2G3DAcpL6}!0 zte=pUr~I_HF>PDL{|{L1?Weo-;la=KKpk5r*je z+1oqdJN5Eo9OtDmqEd(izHUyL-M=GigYI+QV#*#T^Ccw&v|5fCE+2Oi-!oS9o(2mJ zS>9)+=u0t3-fzQ1K+51@oQK2A$JJ4Z-9x+|Fc2P1Zku%eaEzs!Xhd<0{uA$j8D*Zx%L}hue7fFwBUeR%G zs;ZhOJfn$LtD?tv2sdXBU%c|I>`aE#=Br;y9g9PF85n2 zguQ#}o8_{UhkCqwA6V3PYX$z&*Zt$k?7RI%4+Ky-7ee$!*mP9;kG&n^nIFxJL zTQ_^G)&*~V`0P--d%cZc2ph5!UMaYv@Q5We>y@pV#LV{;)VnuPiw73>iF;YfmQXl% z(xSN?RniKz8+FhvHSK>p3`q2#VR(!`bo_*Z%Tlgg6hbqrw%=&UtzB+#_Ygo>&mO!{ zxDZ~-J9V=QkAc6^az#&@T zipPOZN3KqLJ>5XafTKO~^=!esKN^0f!*qq}6ZQVqd^+n25jID@;D8?5@dRT;g<<*E z#k)I}cn+q$xumcXPBDzGRV`p2QN>?rOHJCn)MCRZ%u&)}+@IHgj@CatnuY!LK4>fZ z^~Bs@d)_aWCv{P6&WfD3I$!%imiIK8mV#Qg<<2=u{lQgYGHuFb8j zh%S5_VTSWgN=d`>Cw>8VhQMfwB+1O@Zgrv$#ZIL&ZKS0@Ji)aFl|26 zT8pmikHx`a_m-+%%x5QdJHHKVVM;{2$FrBDmOs3{oCob=S)jFv118|b#==Kul-TTk zL3e}O)cQ;C{eY{=2uamQ)2`q-4tUMs6))1(g6$(s17k!Rg#-Ka0_xeT;js|XClGR^ zhzRgv7B(suSLDH9)V_!<`J3^Hj1BYGEJ-S|KQ>pD^e)K{DNbh=%8tPzjmYS_m<m23n#0l5d?eYN!l+SY4~1=9&~9UA=#`3*8B+_~?ESMvTAj_@7j4S@6Cz6(>FADLI(RWh3v3J^lkS>E9SX8+-i;qDdF3kY=Bm%_st z?0nfgVumYME>$R1lE{~0U`+ZwJUk*fGAuD7F)~8F%QA%K2!y3&%~F&brc1C##|=z% z8Pzpkf=cN8b$V8LgE$5IY}5A9Pb)1fEUlFGlH}{>0FPlO5uI-wlky4WPUu!W#K~xY zu4ZMzFl5!p)6fXL+hW+OjvDp2Ce{kbdjT;L{_^Z+HVglpPcz`sQzGut78?nuo%@Vmrj`+pnTM5k;JTk zyu2p=3Lz{cW%Wa~z6tKbaO{p0cu)ET2`YS^`SQb?hg5M$)lVR5fnJ=*PxJ zsbi@_<_#|Sq5S+-A2H9aj(k^Ewysz(sOiCsb!y`=N?Dea(okdlbZYPFSOX@)<;q2K z!F^lR;gpkeq2EIM7yVTEoSkF(T)u~{45Wy#q)(^}?RtPFb*xdrb}5Ywj1P2Y%xByJ zPRD7 z2oxoyO(LdHpos}9&=mJ&S?l8Ouq>-5c`8AiOml4K%~C0Dx8 z;D3GPr!&9p$|iIs$J}~3K*2)VRvgQor9zE6KO-puh?ITYh7IFG5JN-uiik!~-Jamw zT6rqUEv+f?+uEQgC4@X=kL{I55bS#udTmiIIlsM~y|KGnC!(F!T=->+RwEt%s+Ju( z*jlXCF9$SYh6vx>e20t^XN2hfyHK^@^;eMesPMw=pz`UyU;odL~jY}GR*m<*7yJ#p|uzJa%D5`&zS;WDOomT0Fa>gWke_R=5 z8le#loRvOGe|GCX(d156NJ;F;HYM-5VoxYv&o2t@Q2;hU>$zeQjJF+I$hD;bVphF5 zB$bwr@@HpS{fA47;`o$U;WI~0z!Gu8HZjf5jbEVaa-GJnpwPsKHAy7 zQiie3ojh6V$qto-F)4Ya;_7pCUlKzH6#%;Zm$ZL__pk!P7z=rF5&OOR3K8H9B zY?Nk%W{Qjw0rY?KoMeEZb~;+)$?g3|%!JdvBBFks*m?4yWBJ{mKQ`&3B_2gwOam=c zLg*V3T}md4l5vy-fGc(`!@OVuH#Z%Lp?9>fNY_qyduxRrD>)DiBy0n|}YbVWPNKFZ+NmT!%l z!-7`CYgR0_EvllNpWH7b`Mdu7Qy|Fa$;DOhQ?XHJ>R5-lP8~L|nz}XKdxCOI83RKi zL84q4?Y&+d$+9D7wPX<;pCfIAJVLqGYm0WIvu{zEJ0?P@K~qF^_qqv5jjiR-KH~>= z8OjbBlO+GF4?m2vMvzS?EFG7)F4ENYzx7;Ic&?_0l^{}4OOziUd4t>)jTSh_pTBsO z=8IVJ{rRhFeqlDBIl*`vezVuL!U@5~zT)A#bQ0v@#mSHkLV_IOKPty5`Ob^HTg*g8 zJ2pr)w_5NC^4EZDuqo_3?Z;|1Oxs?$`34F*eMP|e$?Ein8hx7=N;DB4M!MK$*)HJN z7j7EWT1|>V^ic;jM9qRDmxYWW7kQf-Ob_8=c_*OT|e|O z%nV+2@PIsKT=AS)vj#(Z0Z029M+U6?&_Mt$5|*7qaM7T;sqMf)8}*Y8x7r_A4dRnJ zjua&?#jCg;iIBNrLst&yno$-3H|3wCXA}g@Iti{GTffg z$2;jmIrNB^Ekxd$rloM7{CW%*B*YqegRSkth)oYDq~ z3uzZC{t@)QJ|-SjsiA+7%vG7$HLg))V1(+5 zl3He}FzG18!b*#Oh$UEobU)Wpdogu#sZISaasQ5P!|fvwkte=dfAZbrknrOz5th{9 z*z*AlHxIeg&c^*+4y-7gKQ!y5znL+fZ$6}kg9c;#cM%a-`#gyo5$v)-OK}%&jMbt{ zrD)sr`{BH049f+x%|{?iBwFwK0;M))yy{L^eKl_O_Wv#b0+(4PDr}Do5p!+QceCDw zi95e{xyque`&en^=}`HWYDdwatNWBU2v5s!#!p_@ihrP!{SX%o$ zO1s{ipAi!ymgcK+iAS-U6w%E{kxaT+UbZ0GxvSxzZdbVJINj*!@4_36q!SB|?r4q` z|C5{GUzu{wRM!csahu6VaNO>(b&;ZFPYyk9JanqJh-;mzBi?~EI!bd19ENjNz15XNIsz+6t=k%8 zOe1r(CVF0r65ob3ytU%ja@~clnhLMYh-+cfkp z=A2RSLNtY;0ROLvZ&3X{r)_;HKFJ2Ab6mh8kp-(|sC*Brtw>F_HFX?p2+Xf5OIkma zk(|r3HS;oeAuLmOQ{LvE!kydAq1NrY%?q68oZe-vQ1UDTU0hszxIvg07%9@CCoS&x z3>k}0@kM*ser5qbrB`g#_!9FmC=dSx_iZmVGLY{g8Qo7cYq>BoxiYxb`TQfi zMKatsoEpDtxciK9!kJb;Lhkh9o6!q5b{&T7xmZZim6@*f*k6L!8?+Hp3Up(io_8}O zeD@f?R|!EuQ$9&u7F9(_Z38`@ic~LY>36Jg)N06iU3s&-p}2UIMRzjiU( z)#p@#>4LWuj|C+Hrm^^2<9~!v!JqK5L+>cVx?F;Cdimz zwuQg!M?IEK0@XwI*Z@A2CsFw(uOglQS>>=m7qV=>BPvWcLCW-+fhcWFw5ifO+(dlf zBZwL^S}=$qv5xox8{;jeYbZeiPMt1NqIrV89?dMxXV0g3G=An@70X|~GfPO1Y?t!l z!S<@}8273f_FYyeE;;NvS-|B1tz>^oI)BvZF0Jg~F?Ro!4*y@L9FdOe1=MJ@_6t~T zkmX+Bx5?sHvQbAafKyM3`7Ti<{H0K(q zCGs)gnFFjywgL6(3N&*>2H242Yat*qC28Qfi5?KV)>R1Az zMl`;wzyBkm^ay0oCKHF-A!ja#D*ghhcRWOW4~Q6 z9%ju#uwfP+=H3m0o}(oP<&(~4y`gCoOzB~oYDt+gMa+g-t&XlVKm2;FIYAFDA9Uvw zQzU*1|LZL>gD74;=Ut|JG8tXl-Hf?*I++073wH+y)D=l-OaZD6eBeE~&aiKtel#G6 z93xTZ-5XPaw(oeM={Q)_{%r3S#a08UL`I+blEvmv!Jv6)XL7kGsU-C1(K7b5R~sXc zpnZO>RYk=Cz~g>>Uck=sY^xup34AdEK8__LYsn~tFOO0}Bjw|(J*^X-iGKm2ePgj3 z)Q*xu?3n@Hz|9{$fQE0Q&H1~ajqYHFk9xR8z@I1kDzR|f8qEqxiT ztOW$Mo6V_{YSJ6(I8o(OGx{2KeEPD`eu4Xpp)5#APp7c!Qq@8bA%w=xAl%WBS8cf7 zU{6s{62EP0I{PNKUSf1*wm=#FWb>j|BERLY|Hr-I5G-R19k(XvnrdMwf4)!JdWZ94 zZ8;8wEL2)T<+@nlVjx!JBNv`3d`;fwaeqNz5l~NoRiA@F`nYg!0>+?br=N?{7H~an z1RLH~Hr4P}$6=PS)@jD@^KEx_i%Xs<7uOg}_;NZ@P|2(Q`2*j6d&2mx=EN5C(CNf^ z=SrFib#DN$CHesQpwc)j-EQYp^!0MiS6fw9okV_EkU61#4mJ?ho5cQ~2IB|6j*?Bf z`ql=wy~3=Il`8TOf^#rRqJ3mdv2RnZ0`7S~UYcz!0gRo|S3yNEM&N?nLg9k+kknYZ z@)AY4h)tteZw8m%(Q&!5*Dc(3*Ik(FFC_dDI~2nWArs5 zLNEyh(4AcOBs|FURBlSbKLDY%)}Cj)x^7nouFKhx?6fueaL0L4t4h z1JQy;kF%v)c3zqter+9FnwY?Q;Co^PeDV2vyVX=68hmSmmGQJJD>Y$pH~4vaXb$8C zYCg(EjoHBz*(-3h-@3+0YQ&HGl1U)oCjN2|n^7qnGG^=+@#qE~m6#}5Mn)G}fblLo zcPpEV-+N1IarXs|1lZFXbzCk@lWW@~44a$tjS}=Jkw6Acco@FijcE%@3Qk*FGwU`2 zIuWt`mYQhGm8rf)4Y*NA!g&`$Mks`E;qS33v;F(Kcq7T8x*)BeX3>{B#x}7)t_>>p zlr&QL%3z>yA_=Kf;ud!;D)NthHsr!b+7Lkm~^Li^fkrYeu@&ckQj>1zmC zrOpns)A1cH60NUaoXj1W{I-%U>-YJKXS~G^P&H%2NQ;7%jkeJ({_EC#(w+Vm^uiUz z&3z#SQlEpf*|R|Oi3zWSd=)=l4- zV*$KMFoT(Z;qF3|c50S)m7n{>*nuv(wM}QCpv*}Qt4Y9}n`h6;DED!tUJW!Qfpp5O zf~vK8>2GewKR=aS?^^O-dmK_t`8~R7%AUhejEwugkEhQwBnPmWVQA(z$kRKDUHKXV zL5~4^)RH@jroMVL;tMQfOoQt!(2x)=Zd4NjSxy$XNt!$Bn9VRpRym0Lit?M`_147a zKXz~;*${e}uqRCGgNJ@$fk|zhXq371H-DoOl;Z&sjB;NT(O8r+b^RJzKi!oWI%LxT zUx?USe~W4b|Nl{$FuPwW(W0C6*683*$7^b{I1X9*^WX0^5+WfwUqp*5y%14zgMJ4r z29Mpto8z3Fk30W4oW9xCezn0y!M|8?|K)nicM|`Bc ze1%`iK|KcZsR+y&I*FvUM!wA`|7a$DAT;pPewnM*3YGIfqAw>bqB1m=KOoENbm)tM zDr4;&CS5ImF7wUQQ?EK=B6sehXW_-CQd9V1gWKiXt5`xgFA-H&w`I}TCxBZq;4djcX!qBGd_7HlgB2sCkjd`}I|i)GpJOc3no+oNQdbo7v7F1F z1@3%TT+Bz_W(1NsIlL|1G^Ih;Q@k;(Il!sFb;?lQS5Kv*Mxpt(7t&X%&|)K7nYW7XT5Watt# zwA8Q_4{vtzaP2za*vpc*sCjO@9;^oO>{_L=6=9IaDrjkC?;&WMaKuqb6861!@QPd1 z92EW41j*+<*XgNKEw^A|3XW4n>*^J^2moXfoebvgB=dI0g6L9~%L@!-83wHQq(t|f zPFYO5g5kvwE-ofZ7KPIZUpI4f*_}-y$}|de?KD1VG{yd-wm-_bC<6UnuiK2GddCV~ zKdykkz5dQAQ&94iZbnY5``8lD@A`5|xr2RYa^UCte3fLm0Aq<)&c5GEQPrzD4d&|P zi9kO3-5eUy`Wi31#9l(y+J9U&8}W7`T&Ddq;fwziz#UjfCR{>GjuSS8d}VdHiXJwN zy7Cu{ifyzzSv%8i)D*_J;c(M_*#zkC_a^Twj*i^GRS{?8$ZK#U-f^i!s2{??XlWH( zqjgVKbS&3-^uK;#KEhV0&)C+;7?QLr2E|5XwOLYUFu6_PO@(n#exsf^19&+RHji=U z4Qx=yQQRRo5BoqsunFaHH*#6^I$klyxwzYaiCw4T+JqYn_E4cmwO*q)qz69 zIYP-iecGOGUi0o^utZgFhZ-AXqx(^-Tk&s9Lua+9c6`ygto%7PdwQ=lcO0 zVq)Jf8{Vr%@jxD4ojC@3%^NKgj?Yy(>}1FvJevfFnAjDW-57_KFR(%L`^xBc3GGx)?*oPK;{bDaELEHx@=d3TAOE{lcg| zs6%RB;YQE4z|Uy@0I=ZPQpJU`H64J9tpq2m>`(t;#s}Ce{ZqAT`O)0>9{8|5l0%+t9Skk%h|3;AJJUCEgEpHVi|x zLX?xX_>#^Y&by2=wpQ&TD-#Dd^ZZkZudI46-VD04t_2<*r@a+^D#0_N9@ihfb`(y+ zVfkgI8MDrwo_)V9$4KUYK?L7pqXam?yw|%}zs21)gjF>q&f|8YBiEHi>g{5%LGjHY z!i=V6O3{smx%?D@6|swE8qJ!EH_=)-ribDIl1#Q-Unmd9CL@Z z=d;e{_}tw45-&ud*Vt%(JUeTsyGLM=wADEOKKBIo{aW1h zh<)UCV9i(cs#abTeVZ^}!?w(kmzY$HMKtau|ba zr<6A516Zc>Cb1qdG{k5M`D8l_$!2cI&v3y?U&R=BEJhcc-g?eI(IEEdD%COK9VYs0iTU zA;x1c7wGP}jQPCb+D7MZVHr*76iKBw#8F~_k`j&eIzv7zR!OV#NW4-J?Bl28)hl*G z5w&LLx*cbc80!&^a>H-6F~Ksnrakk=bs6I4FHOBoCfRIEW;d*az5Z|ef_QI2y-R{J z==FH`R%$$!Kh)GPuI^BxgR5(HhW`gwZy6O=u&fOe5`qPX!6A5X3l2kYcXxO9;O_43 z7G!YO;O;WGySvLr&Ry%f@45TOtXU(yt9MsbS9euEPa?lrjAAZwe{bVu!{s2de7aoX zYLi!)e0YJE7l@byR8(ifY9?H-ObUO&w{+BY%yv#$KMkn1>KXNq``7?YTON2P&9)3^ ztgKU40?Fz5JA5;Sh87JOj(chAZdE4@m9R9a6I39Zm}u83nF|w)+qe)7=lOdu9ZTcm z5v06tG*$RqZ@S7E!GWuSp*2cFdI}JOG*}i=^SoLp$*hSOUZMEwNGWQiq?QN>9aT>% z=f_xl=J`BoIRnt{RJWH2ZWEO6%o!YHsC3IL*6UOQ=uNNO%2AiG6slCna=C<&Wr^3z zYxoy-$R90DmQYh;h;E%9iz%*C)6tbo5={&)n2MeL>{OOZ(~uQEwcI(xMn=auv1qtc zkIa)V5%|=xGbo~#prNXke|?1rhm?#x-=#2Extk=b!R`7aEF8>1x(e7|F?@RHeT?V& zf>nNb6^_N|DLm!AzDuN-5LNtd1-A|l zE%P6}t$1DME!vO?xe3epr|j-I9+@kdVZY`ROBop%MM9RucKP-@|DhS9&BG^4_$m?r z{X0zyohu~InUE+%tqTi{QB^VsNPwo=X%s(Gjvw1QrH4;c3*D-*VOXu{hR~s$rVNKWNJ4;% zj$=VaAm?>f2G-S&GI7efTrP-lMUg+Ru7;W8qq;pl1_uq7-=W2O{Xjs3t#5r-dp)a6 zS})VBI1F=7groV+T^QFw_WcxRauSOFsX67U_9r|05B6W;S-+f-NfTx@3T3tAW4vYf z0K_+Uh_Fb35DFjBR*o3S7PpA?=Yr8Ivfq?_kIiN)q!=_7hm79Rw&ViIaI|$s6)2={ zyNs$KY!t29GF$bWe>)NMZvL80>DY{do?a5kZeD-r9c}zr9{L)yJPe4XJ?}*dSgQ|tyd)T6kg`l#%eCM`oW)Q zrs13vXS{I%QTxevW9O(HyiTZcA3rzJ>eVdJX}W3h5QaC+Nsy}{c-wLAMOb@7bWPZp zl=WgS!0L1wP#0}4{RV5bj30}EiMLkey;Me`fgP=4Lb&YAiRs#y`JhWr7*Gl~jxRbQ zvNn}3?0B7b*MAj#3_RP5SHDI@-PdRyC}JfU`?GKVYm1iruYq z44cuCt=mP1RE!JbVd-98UZz2PPYY%vCSmJt76PmDYV3ydt%QJW$VwD z#Y4F<1H2EW9s}Rw0hWI)GqguJrT1CSYqKd978p*3vnCoe|LA3uw>7vgzMqooFtkb&lkOnuP8}gtc;=wTQ!_GU-FlR^tjkC4%oNUdZr6Tj;czh-|>g>GX>8 zoVM%3@2AXKLF1+QsKFDWhs#Tol4&cmGlh!cVqi0*x_Z1K@hxGba8>sz2(!xd(&-V8 zz#<_DWc?)===&^|6@%@)d~!MA=}!v#h@nWOHcw}jZ=%eLdJ@xalkw5m>XDIM{YePn z(JF?)V6KRY5RB~wZikybJO9f!(O z!8l#5q60OJPq5eR&#v{-FHgi--EUcJNA4-DaXvg4Pn-39ip1-;U@0CQ9h`5cYo%bdI=} zABVfBIE6eH^7*Jk5~Kk0&bVGeC^J1z3Zu?=YoIU?Z|~QeAp;Eh?^s0HS(-(hr#EG{ z`<=>kdaJ}{ZOot!m+2JMR=A}*nsgtV{ooRn$vRyv54UaJ1zf7JYoXN#B{4f)-}0@z zlgmWKrC;iH>Lcs$FgPp(BlP$|M(@?D2hvW?r`Pn}wa>yF_~SXCVU7;7wG$-kX|sOd zrBAfOII1v`q#56;c(mtRFW6ffG%YW*!u`JNK>ud*Q7?>pzt1={OmD3waJ4vXls;2- zU~{H)MU4x7@0XN=!amwtZl)+iA9i{5I592>i|W*M`RAx$RpTkpiK-hnCq{5xp=G_j z_y)OP#D+R`cV@bu2p?k;q=m_fCa$h3M#4suMpw*pyJBxhY3xqR=w0@d(s;r@FFWBg z=>Cd!4nkfD;~K5;6+?SgM;f+b+1SjwiM-#7Tt-yVw6tfthGB{}D%`UD)~WmVVXY{c zur@|a^v?VGC{CvmXI*)v2#Uk=9ahX&`D=;b>=68HU_vle!)Q2jKFhMiwf46xKblKs5y1iTR53N#%VPu} z-kRqOmw!$3YH^tmjCC4j@1N_O4D`4hh*OuU?^;3;6a{t3)V(T}`4G>BkG_ zSTyg3BuiI0??UqG%cgH`9kd^paKW>9W`vnsuJHYfQ`C^-;=Lv+4qn@5p;`G>f;()m!GZwJ-VGtxm^D z$W~2&(h*ZvD3RM^JVTcK80#P%+C=nKCqr&Qt^AazE0pJlbgr0}iDhKHAnLnHbu%KU zSVO#r&E?Nv1fJ5Ov{;$ExYlR&P8X}}uA9g&LvyC5$;}9M#8J-T6m<%(*?noh+cbwD%c3 zi-m~OX6W3qc_B$jXJ@W*m_nzA>p{`9>1jtLkjY%7A7_Xe(c@)KCrFU8?l9dx@! zc2mh~UhFy2521k>qOEgtJZuxWgyGSNV%rD}S>H9SnbWo&{)p?!E(IG%m1=Zjer6LPea?;Vh<#Cm6bQ zc9;({1te&Dzo`WpjqXLnJFnFaka!%d0L!#VwcPdw*ot36JUnDE3YX<(=w7qEN1HyS z=uz@-WxvyAMB0u%rvuMN&py^lXGo=I2W4R~{MN3TqTlh4L%DJx4v$u^ZgHp_$_`1M zfs@X2p%x)ci7n20M@tPn!5=%c#TNXn^Ll_K87JWe2T4 zU`!@Zb+mL_njWP2lOf5Y$n<@!W$P4y0y*~mdaXQbX1SKNH7Y6|(Eebn!;~s&=$b5( za<|zaQqEO84ycr-?|jx=fB0Td$TX>xwQL)eW@^piF?AK_-$t2OXE-nr4$f+#804_8 z*Uu0-BmsbaJImtDuW((AS?FNhaacUhLRUr{EkJI&a{=9AxnpHtGc`g5USOQ-(dr2o zFf-YSn>-k0c%l%?N~L+z#<)kU@kOaqvjv~fw(}gtanNs0lE3E}Gc`U$x+lLH#2M6&!UaGT%ff*Uy3z6 zwQ7^T;h#`MhulV&{;Uof(2u-zv}iZq3+rz0nf>9rr_ z{hxr!B7JduGQcSz-xtHLg|u}JaVLMBIA~KmTZvgnseri#{L3jRwyAxk7Q^Xm)PK&k zb3qyls#vn$5fQHkTz3T@LHsP@wwBKvZZWgQ3oC5F>Mpv6kE_MIHXm0}?laU#y4$`O@^W7ttJiSFLg9DJTR3XytT&JV zMvr~DJwf9B{2#0fg%Z@2XE~5dG4DG<@LaRXF_E7d=weo8c~Wso*~O0eu8R@AA)`DU z`L!RjVfn57?6;x5^6bpc+vn>Ro^WFi<;Fj(z+bGnv?V7Fb3PsM=sN2APhH4aKaWJX z9>Mqy>0mEyEY$)_g@e&vQ>^QemYTr{TymPS)P$WEqVvf!^~KljkhD$E*?PF>=nnz% z)?cCO#iOG9Kp>IU9#SY{1tRGkV!;v_!=(Q7M43np(U$p&K)d<%k7j${H1EVnEF({c zqNLRU5e12S!xzsn$N1!ubC0VRm>Eif>`jOF^Va=%TJpS`%UWeR4P*oRUM};U<>L-) zRC89f4SX)Iky0{}WpFs^MX2jZB>g-OudHDo5^C9TNeC$`FNW~9SL4-ZlI3&|7;Vnz zWw}f_x_tHPH`jVk&+TEe_U%-cx-WsYqKy=5k56;4PDfe~DVW+>35I7{$`p_gww)`n z?LSh7AF#@`zVi?4M~?@3t*$*jG!HIOoY&WNcD&#CV`gRWT*kU)TXO2-ymzfYkSz5r z%onyTI~8{Ohq%Kfq8V`cUFZ_$jb^iz8Z0BpNBi`;5>5~jd@mvw;PK}Kww|yI|0ec+ zp5mT&uF=1s&SqM|$n$c#e4ubB(bdm0UiTe^3s0y`Y8SRpQABgjtkZ3aFlQ*#<6&zs zX8wZUefz5BZ-{E=iO^r+5Ml6VFqzlgMArizg~{;y&1v09{O(AycbBP(BH~s|_4WQ_ zaTyJu)RN`p)&#n5$_z4i^nwRS4$yer$4w1ZB*nD%Vpo^vJ#L3u3F+3`-aQJ3`UWE;UV2VX zKxCm2xkB_pQc?z$`nZUSI_y$V%bQ95Sy_`KDuR_a2ZYI24}wcqS7?WUPULwp045oe ziuDKB>yIvy);tF^`yXr;vTlz`)&BLyTd}zdAoyzFw?!eD1OE0M-5lS-KQc-Jt5a7p z8bU_y^Abj4Cu^0~M1}rzd)hWdO+;`RlZ>H!=Stk&IU2=uTAxupHmk$k$s#-e*!6Ml zxy$ZzP<{S6lzI{FpP6W*=~o7?F27hkZO9@*#1tS&78T4YZElZzAZqFH;K>;|8G7m+ zVE*eu%dZ5LnQN4GoSpb+xg`uID0h(vH+$*wg>rvNhY3b1a7?p<*~bXwp8hRCa>`*H z1~u7sh<^U`4;bNB{0riKg&!^P$dCNzPePL`nowVeI+XbzESlECKFEUUT>fVE^B~p+7DSeELlZKr z5yk7ONXSY#amLevlI6bu*lD03%;4=94 zp`s%GYKoRvZvl<6HkdDh5d4oYt4&Urxme@EL|FoahZYTEO0$#Iu@)2iB>eeRFzw<; z3+npQ=Dw?6>zA7Ao9v8{urm%47ExZ^>*`WC@53ymtiBhNQ&G35l*pH$lU@eIce15qw_w`vg4~kmPw9;0x z&vt4k9O|=(V6rApalsY#LNnCdVpzqr!_(6n<&beFAM6>2Ylz`HQQ^kPW1iXREA9=h z-T7p?3}~V#uv+cho2A468QQa_(v#mdGyXO$kC^j@%K10pOcg;5#SH;gb_ZMdkBJe5 zBMmS?^f``Jvha^s;(}j4m{uy^_^dvwv|&#V7VIb0O|&F$ra)U7ob?s+a$nTe?E`kM#LtRiw}PD*XDEBz zZZ2h3`IGX>7$vX(>+_03@xlYo`8W3J&33aJQCi!o%f<7qUv7_ZQ?t}%?KU0H79LEg zu%tcT23@a?x@e!BFOqjGMl;SauyBO5LXL)OrayLOBgK{S71kLS0pkluB+z&9sXsG* zA+z4rH)h&$6*bQIz2l9_vbX+q!q0shZbv&`M4F0(V5SbVb;5c2xkB{0|p+nDq-m;LNaBmVy??zTEx1x?18OvuBkLcAzHIgT4lOK z#Ytk0clWYiK)TKLJOXFWi2{p$zx@C5jb(*pc#g2jJxfCsM{MfSa``<~P+eVJ-d|ms zFp6GW-rw`R(M%8NZy9>D`ZcuhDYU&9A%w~#*piu#hJLJG9N=~n1NW$*&*;r~-wTaK zlH0F!M`~%9AEkgBkC<8SZ~md}v;sd*L6PDipIZ^JWZroE>&S$_^hIZH*4sp67`{p={EpSO$$xAQ0-Y-HP!29eH{+9#fOc`)H#?vQ)tI%Ik^j zG_tu}6fH%6*x`EaPi78Gg=2tJ@3-a!TKDoK6Ks7HfX zkwT}WGzG^L(MsDL=Ig&~;jio5l9Qv2l${>yehjuo2AVhYayK2P45g}tq_y96Fs*gh zEJ#oi6U_*Nfy4lBH~=J65oN=-zn@q*G$=YRJgo%!Xe1Ap9@^?ehbnUG1y9FkCO?{8 zaS4DH>T@190IXi+P&`Fh-L!eO{?#DHVu>YC+*pcb(%TiI{2s#}?EI2Lort-L;Tr8# zwZvW|Pd%BKPvcUJ5*SdAdnejTghpPj{_x_}{Ok9bVwRgJF4B2##ij;)7}TQoehHzu z3Gsqyy}EH9YXtRKl6=Dl@%zo5jUn<>iT59q$X(`=A|)DTGYyOV-SEJm%p@F<*CBT+ zgi|?ho9pO=jFhqE9!{Hy2$c@w{#jMPA|1oub)CKKSl0)^TzFil`omRtt9ByER?Px2 zPWLCeZrXURA&*`jql286m1b_I3GYFF(aB10&C{m8%GB&TPBWD$$ywgp_fmufzgut8 z04;~w#NQHx?s2eJ9dx_Sb;^fikp%pl$=6bn zv!=y+`s1#P#yxnQwmF-WR1okKpE2(BPi-rrg>p3Mc=yoh=u-4fm842~ zf|dxU)1h^di?;8ESVmL^n}W#DgN1}bk6+jL{rz5bCq59PKk_isbp*00&`|I!WehYT z7&J+b;E_;&r7w?)Rkmnnt{Iyletm_uLbG&42Tj;g;IX?3C|MIt$6`xXMHLmcWXt+t z_j;*>i{2VGH+JUty+bf1r=a%HYImdW;@n^5Oizzte^m9~-HD$d{=Po^?ZIN?&82w9 zfRB+?v15L3_@$BC6j`_6@hvR&mrqI#q9jskFTbLHtaSeH$jHn*@?5>IraFF}^F5j> zewQ-gYTKc_nUv}Dj+mIS#V%}t)e|Z7*}9mzf`>}r((jz4%S%%gMq;|xEcKfs81rcA z_NS+31#MB1V4E%^kJ>%Tt;+LM{2(`HtG;Fj82b058#hOue(uNN1sE<$jRrHRrHGK) zWtoIF_NKzZ_{(-eZSAUOWvO)7b8m+B_^~ax8k@4)qNC)qwa9D7Q$PRDj|}M)bcAcd zDy^pu)XCqNEhhsVk0dxKv?pBj@ zxxOs7#=Do4vBB=%4H=xE<+JjX;-#W2z!d1I`8B~Q6a}5I|ITe&E04C|brFMTTt))d zMvS`TW~BLtPta8eq44WRUNILwG2{oQa|dY)o0HQ43luI;Q{q&PT+HKXSM1#j|@S*lWP<=7ykB=KXR+7<)YCVepNs^QnJN;UJScssj zT!}EDUg<<4=1R`-?*9G&sB3((Stol{EjTm`e!s?`QYXi6jsN+sT*pXD>5fvJGmb1O zjgc{QF))0m1)R)Vl&F5wgR9mDc#Ub>nBye9xiGCu8~)g!gK6^@=xfpx(CkRyYVj1A z(PXCIODVd6zbFR4_R1lRrO}aW;4*!v@}wm)k%hW1E};>kWPXkG(aUT(GulRq3{<%1 z8zQADp3DOmmPWD5~`hj5U~T}Tdz=NXm%S0r@Ek{uF}pr--#eda>e zN{jptVRc#_RpeP7R7QNezBUr1V_4E|)8Ef|;UK5QF#qOQqUo89>bYj}f}(?CUF;aXe`{tT^l zu48}bWn3i9mu(ecWXr?zUq%b*Rx=n%LQwazs)nlD0RErlh9M-+z4NfRU>D1=ef^J; zY-dQjbOIjk>G4F5Mh~9bpM(pMS@}qkILM7o+mVsf%JBr?0kQ#CTzgZDb^Kh%8VuI6 zj<L-%m)&NrUB8U=wKw9kWs_$+N+FnDJ(OJb z;*=jiuL51!2sx%H3pm6=z@&<-DT8Ya+asL8Tx8ufHV&j#-zqA3YB=Esg`i@W>U2vY zn-h0|gZ%=bnot47{i|)w9P>~tsxQ0#&4Tm#OKe~Q_Bx0varn?`*;X}K_1d#rFiNXO zk~Fg45T9dO4kU2v+UNJ;4;}U-4PSOli{VWO^eh&}oNx9{Rt7@yslI#VatzpzSoPm8 zFSlLfq^|q{W1cQwHU^!1Hs3MYFP8i`(2d51`OVyb+xE2A&bWC9!Up9z$;hCJ*@`0S zU}@%ER=s&|BAac-zax*6-@fNU?S_eiN(Pub)nRkta)BVaz;n_ zk^dAO{iU8C09a$z;lcOtS0GnwHpk=?`UU=07oAjt8mYE78w$|fHD=pHgc_l9d#iEI z_X}LX3JUzyTjS3AfO)avFu_tLQkRVMn7In=M)6^=A~0B)Ll@ElIUQCKd4{{WZ{{pa zY6ud#USXkWWaznir`K+Ru>7BIT9#sQh;rV(%;#0Y5Eo3?QuT)YS-d}ycnG8*I07sW zOB8^9v^@2O4-BU^ybUpTF7qg?;rZ7sB) z^pT;;PJOxB67$?{7g`#QYZF*jsa#Cu!(4ZMN@2azATd}iBRpJFWhlz0C3^z4DFuME5>f;ZkPP3{1DG^_P z9dqY>8Jm;!aXJ;ue7+Ujmu9m0dKYS>U3WM~Xw}x$cJ{L>TrTh0l*hKs@>aTeb&ioGXf7fH%Vk)So{NIYO8*gvdJdK&&wh~ zzhRt|$k?LJpI#jqwd`%HDmSU32zY4pPrD!k(7h`(lGxadB+nm`c*qer@A=HDf057| z&-;br{bZ8XcgCPT+u2{eYFLO9^Y4qD(wm3eM<_$5dgpKhb}9`d0SO2Q$fJfI?`qcx z-EVvskh726p^D!g9v_@AT&1%Yyhev&KZ^w77o#VKg>xmZwld##y~+8man{!`a9K^< zb%q^&r&2rTD+>QWtzy3&$abVed+KxjzPsz6{+<&EI03gdettHqW?2YrxIUia1)fIJ z^axF}F1m52j^`X;zItvcr@!T{X(t9Izb~}WPMpBURXNyK`ahb5{8)M!3JQ(pnPr?V zE+yr148WdttEwxtdKo-!cD`A&wB^svC=3omq+6eGoBlmJ4la=b4bp*49OcVp zznEMPtiualy7Hj#TH zynOJE({Mc)uJm|3OtL>}m^`mH338p4fFSvIzTfA*nK9{5llSuY!di7uh&Txsou+rp zqqCkn#9L+%%AK&erZN3M*bNhW>!noXBYgYS_TLey3;JInQoGc9uvjzlpq|-0zW~rc z-e1c$(z{=|+HU4WX$;G%7s&;6B#Ad${% zAI663cfqHbM$Em^`e0pmTi@SH|bo3N9j5;>*P8n1Z!!o3s*ot65+9*urqp^ zxwPzWuW8%2;s6=#8*^y1zPDr9gsJB~T0aV>xxR>$yh zHqX%gE<-D>xu|AW4VBN1tE}ON!Psf$}fr@Qg0XWmF@S9#D*SqTN(@w7CmTRgo96z zoCzG$tm3aLU-xq2*#ojlE8IVhqZBWZ?QuB7c>J@84WQ5W7*QWbZeB1Hft-x@ z>uFnT=q>LNyZ+jK`rGo<#0jq2y%}MJn}e}Ns8el-y=&x4CEQ>=VOjZFY}A=R*i+h`4j`&5^oeD0vV0fF9x zh;|w)_Y`-M?2=XQ4H>hWE0&~@v~U)GJa-^}58p%(;!O`y)eyeyc{b-TqyP!^yJIy>Z1S6eO0^OshaQwW zH^)ue>$^xopw*HtXMmz%TT9?7d53Bx;gbt4<86KO>%s_offyyTNU(SxIVLLgXG@*$ zKT5$Q;rlXYIJg+7s9Wdfgs5|NSGD2&w^b`-Q~65M4inN=6wJr=Z@HoI`@93aawq{h z&(aatL?8U4o`1QDB+66nlmsOx`DSJQDKp1T${0LAtZhQ4v{SSVE#WRfbb?R11N^^5% zDj n@LBS&HNvwSqGE3YHY)A;MTgsl;WA6Hy&g-obvR(3!k;PwlDvRG@fEqg6M|n z+sb6)L6mV{f<%PBik@(9){_Yd-BVHjOsL;VngYSy(|S96CWEbWI{+!wwmNL1fRqd8 zh+_vO41vBCN{LEJvDx2aRet$IuikPh3b9?CQ&kD($x)Hf=93r!^`DKjS1!8KHEcF= zhH$}S7s5-WHB^bpfr7vqh+>ryr@xkGB~;V`#EOOdxit{la2p`!rK2M%1oCSU?YB<| zEZMD7lvEg^A+zQ?xEs`t0*~UZc4E!q0&5w8Ssk?e0-ijlntd(qS8-uS=B0BnKiFw@ z#)qWRqZFQ<9-XpZy4mThi#apZiv{>|g9GdG6;!CuXT<~fk#uxQ@I~enlK|_KByDX! z=cwpAb0#N$J!_9Gz3vv(${7dz}n0>x{p0qxvNV9m=?IYp|H z?%3j4l`SI2ZL(EIVNCD04?KapQ%?^MLE=~+;UDO5=0q^v4}Pvvkx-JlYdG&9TzcfH z@edXxABB^p`m)$b_-h1x+t2D$Y>tQGtH6+5;#Yze{@rE zhnDUA+``$cODYek{37_y&=FlvO#>{r?5}D512+VrjqDm+Z;ji}=_IOZ7$Rn_HoO(s zH-fZ2x3SD7Zrg|~ZQOeVuM)Ja{pk}8_~P2WKweq=3KnL=GF}9FbdR8hc((K9RCP$> zRB%l)M5%VcQsKvKAs``Md{wDK5I{g?kjW_vz%h;E)Lp2PGfJmZG?#O=!)E>Z!eJo8 zvpHR zG6WmyTz==x10oc^Nu!sibF_EDs1DIYB6Z3fw`YZav)3370a$T^R=2MP-H&8M z6FX?mP``@Z;=4$#zOz;hKBO?#t#Biy>TPLniC2!z1+z-!whBG*`CCYDX=?>6*byyx z_8+7Y1jK+`QgY=xEG*6wq~NUkiGF^K(Nj2&?_w1tk?dyzV*%T;C{!_5*|t&my^c>g z&6|X%lmMOhfG79v+hs#!C`V7XsJ#I~7fcJ7f{%<5H5+$pfnGiZZ^kU#>_3#FoK)V! z2fDvd*PuumNQVzG9non3i~2ipa7)1`g)l1-7&Lyna1rws6Z1k9z2=b-4XhUUBi1KI z*Jbb?YX4TPKEji4L!Q%Z+#uzVQ*CrC1E!v;DuxRNT>T*Wm7g9&51$~?NH*KaJLln7 zCU;_l$!ULsp4+!Hgj|LN*R)IF5?w?EB?V)UHUEKB{q)wX%Ll>lMKKn`0qlh}woYm2 z&}l|PckwuL7b#W07@M`x-b9KX)wC>^pvZKo(g6(4q9Mp-t3Lhk(3dkFe^oyVuMFUvCC! z+Z*mCy1zlTc7JJyFFQ}eX~tX$aQG+K|9h;_JHRFVO|{p`H&`r*&C0fz7rM_h{vxRIPbvQQx}fhLTVA{@zPWh+HT zLMB#cst7hj|gwj(@ zA+*t#hTjxGVoub1llrLZr$&)DKMP~KOoy1j#Qms@{omXFd-sBi@{`h{>N%;+V)FZF zPmp{h5UQ4qz@hDca2-W!%wn62hYhTYhR|<+iR$;V`o$7srta)N0Q~Q>GIF|3_>0YMLV!{Ck zS*Dk13$Q6wBTl7=zCfeXK-*i(!vO?s{?8zv2i3M$+Fnmpvsa;UWguBg!r~c+kD<1D z*yB0a3D+uAWuR53Y1YG>ctu~OJJg~^{@VQS-fRGc|GGxe%~!8DwU_}jiXDIOSZi`) zIBWGS7Td^Hn;F9a%)B-h|k(6t{vejEwFI#^7?@riqL4NEN?S3%Uv*T-c4!w~^ z&9ITH!#fyL1Rvm1bv{z64$7gFiK+Cp!vXfLhx`8=TKVnHkN$U8AXWkgp^Q`|t57`v zeC&3do4sZ!w}%T|ei`G~%MwAE=15*g(-#5Uz9zMO<*5(mvGv5 zHd>M86NxVat7%{^$@n|w4-uhFf2KXxn`3Q1*+jnMaEccRJM~eeo!S{#Y>x(g0d( z*x5$!u5l6rwY=$^9~?11hQHyotArxc@(U}ZbZtZzlQOD;_k8K!+|2;~K(=FPfj{pK!6G3-2-~m(q3foedY=p|}bKr)P~NnK#jH%6;JPEDsJ3 zx9F4^vpfwyEdBg=Y4O5JVtfko$d&y82M?b+@jo)y!gKUqU0ubAe*{f2p*6%hvq&v9 zFpW%}77x}4Qys)y~_r(o;jnX%G5 z?9~v!HBPp$+pX{okok=(9m4|C7QIN{lahy(Q58ll=o3pa1kFrX>)x~hDH&p>fj1$| z8;)P&#*gk344YP&=3VKJXk_w>-Q{_M=9AC9={faYpmG_gw6rC<5$=Dynk{B*Y;1LP zH4q3SjtvQI((kU)J^wdDH5zzYFGj|yrW~6xoM;Mug{IJ_%NJsBDOn)xK3n?|V)O+` z&W4)O^STKl@>m)*0&XYmIBI$FPZ9cOk*30A)?H%NM<~DA{~lFS{RQ|)Q#ge*Ys~5l zj@S5DBgCHW@{h?+!hGtX{I_h??<4hFr-Y(X-Nhp~MJzynzzBa@6KZwHvv@G$ ziv7ddml2jmHC51mOXg!N(t|s*QG`yo(H7OG_ERZerWbGDh8lNNtDQY+-+l!y_y(g4 zP8kiYnqeetRtG(n;%1E5!J=c+1DfY#4{=lTF-Pmajdv0crAj=ogyBmB-orNTz7S1v zX5fc-3=?13#t+-R>T;Cm=8}`@bF9!*pj2nLNXM)3$LL<}%f2l@v9SQfAx`1`OGF=I zIQU06u)D8n<_;wO@p`##^Fky|eoLBkP8Ka?-zqUc1L^Qs42dqhcdO_0&(McE`4bhW zb_%)Qfs6BBEq!Dx1qH4!8lID&Ji=8M@VV6O6fzv(0LCs6$&ocp3RMsAf6W=FT|!jx z>b_PI1J=`Z57W0ieQXOBR|<6Xyr}+sOx z##5}q6FqxD^@|(_iD`Wq)A*QBkANGxij?LbD!gE|iuQjbQxjz6-E?D}Ng?!R{M1yP z%GS-gve2T+IIXU2dE}=>psS~rXEjjWfWW1WBCMm=Xog#uzd?=?Fr6|Is>Um;yRG?F zT4Zvnos`v>XMDNnvbYu4h5lXiC<}65~jX|?hX98o{ z2;zuQu3E)~-fP2vRaptJOqf%3;m}3+qWe!Fq+lcLT+NDFb}$*KW{z$kAxl`)k*Y{|>l69I^e@Dtx!CUpWDSh%Q|7h69*jG3oWuuhyG|a;f_J9xh zQ8^DDaZ+j5Q$dSzzfBV)UI=ym88J_x%;|l8`qRN5S>8YY(c+8X5Gmpw$6`AQ+z(OT2^@)x4@Zwa8I~MfkIaMJS5G9$VW#RTVfOXJ!uE5C;UIVTwCC8Lr zbFd77f(}BEl&vi>qPux)beYz|F(cTp`lv>G32JStT7+TEa3>!BS(*iiYY#Jlb z#Cs_#=yU6+S3zYk7Y+)`j%rUtyX*lG`jtLZs;2(x)*ihg*3vPZB|#8 z-sYySGydpe;-9i%&F9NK;sE{N39mXEbniwSwv}u4%Kr@NPwEBF%#z09*h4&~%9$Kv z3kXhHeHOaUNhTkPt=DbLAJMeD8dmFi8ia|xvk=rDN`2?jZ{Mf)lF?lM$kmNthlaJAr{VvFl&+>qbI-4JkeR>Er%Z9~6lwj`fc{8i= z=@liH`NY%g_n=uUBFQHnzy6f4MPeNieEGy3jMoj^n+j3GM;@4McN0WSauLpeqlLp! zC@aoKaHKc7YdY_{?Mx_txPl*=!rE^uVO*V&U~{Fjp-P~-YgmcUHN8K3`HyVeImspq1H&9>>cfLT#DKY@5^Tj95~knH4kqJ3PE4OX-?_es@}n; z#ly4?N#v2~oGtDJheUm2o+E4-!h_yNd4ZR}dCw5LzB!4$y0$cjU1KLfjee@kJo#KS zw+C?^Tn&ZQdbH&RyuqqJ38X*mx_4kN`Se>0YpHYc3jP#)QAwQBJy}v#K6~EFpRunI zygZ=L5jWS?3Ia8ljT_T-1!r>PC%JQc|_V!%Kd?6aJ8SngRU#Bq6B>WpPcYW+GFHPe>98h zaQPu4N7My=;phMUXVUcN?Jl(+%n4i3z&L`p!9;HR_VFIIg>_-a%}tnxMfC1;1c)B! zcF9||CWBa+ep@!QeEr~{Lv67>Ol&v@Wq$-ZT6%g1Dm@$}PuxXTog&R;zq_A=qopl5 zkjR>KXo?{hno$F2Cq3%DRGY>Qg{H@gv)@#umk%*eFmqdyXene~j&Bze&)=I0@^yN8 z*fN=(Ve+-adg9z0?{7onP^GLH@@gM=<+I-|w>`lY>tTiR)xxdtwxetD;4veN@BN8DxBD^D7YD`%k1(rip_r4)A?N-FVHf*{{Dp8=Mr*hj7U{+ zs?ot1d9%GE6wdkZQ-7me^7V3C(V$S2t4}mHcT^EzV)?e!e=v|OW=>YE#HnF^Olj{* zef$ky)8RqTc-lX+yr|@1-!f`5Z`)|@r$ExyR~-FyD)FBG$&v&Vxq^)r7c-8iXxfVD zxGxWnJ`2|?9nsGv%%~(4?HnX2xlnM&PR}`(@t;)+nmGplNXQZaD#US$H<@<0HR3et zfy}KB_&+oUVuMa~PzB)dXTg|iM;vA3P#)KgN(L?oO#((=L}I@RE>fxBH<$>AwnBD> z$dOdp0l!8Ma)w{?dYXGQ!OU+v!xic8|HsughDW+|YY&1+GMTVr+qP}nwr$MBwr!_l zYhv4;*tWl(z2EnobA9!v`&T{ds#;aGbl*!LhvBah@?n34{L$`yQ=~HL@<5g=CzfS! zGHa2zuqp|v?zx;g0t3U25Qd)%^Q%V|?pK70(TV2bGHVIL<26EoLY6BBH<0o%VuQiQ zUWmK)bMA~|~-;z2XtR__yuAL`JVXJ(bl|vJBa(v1m1B{dNA^ zL#U`top1X=T?qE~>s3+j*V+8Aa1It_$a5e4ghi9mHuFOM(o|y#Yg|TCK%%R7T+DU+ z2xvJ)W#oeM$ERCoK(5pWb;BsActdJ?ZO*xYaet=3K0eqvI`^yZ9P0$`TKx&tk?T_+ zHs*+Bal()#0ViV%Ke{ov=VJtxymW>9kOi-Kw+55wc#9 z8Pyg4ujbgnoRS>Z4C96eco~|*Sl(2a^t*eE88La& z>=*2PTht2jz@f2ddnZg&@>J^rZ}~IuPxCqH^q)U}78DTOA9>y#3uhU;T*-a|7s%8h zMF~x*`6*KjfEJ#s9sVMK$0r~_h5}uRS}#J37f|0POwtR+---Vr#8ELDPnf(iNS3;> zAtqZ+L0HNVB$JzgZJFBes1fOXm)v9m!rg>26|C16Zgy~V!df3LUo@Gb4~V6;-&&2N zEL)suJnc41?fuONrvIuAMU~SH2gk{Jgh>$v)Q%`P#94_o*$f#1dWvHrC7b z4Qt1#t(>GysB(J)G9J;>KrxQu_P1@lkq%~37ad?Duh%Sj;&G22ux=7=3rFT_I##pq0jqFxvTyW zLu$IWi&Bbx;n2^{nhKH1<_i)<{`~$gB?&~Gu#~(AaAJz7r51$BP#T*6=p$H5u} zuw)T&88QWp4U5@%8tJRqSr|}BZ8HHp`YvBkEu>u$Rk9+<#)(aFSGzVR!|zKiUL6Ue zpcr{_q7lYSPP=Bm1m-l!%80^>+03zDErwM;l(BK*?bWeoztf18vHvehq3N0%;)Q3& zXY`iLROoe3*fj#O(uI9AD^*zKBdeF6iNo31*&KcSig|92udzU2a3dlJ%da8Pi8g0K zd4|*yFo%98IDYDuC2U%^EI-~B1~RFlX$YI@6;4XZZ`1NloIJ%52Y5M{rWdOXiba)@ zW1}OXO+8K-5{=$1ud}@8jXcD}T46R)-y|$BMM45il z{1z`+NG~zic-m^wy3h_7md=}=OV?H|QONDTFDkd^{p&%t@5smqh7>wHJReD8wn%U) zc4f5~(ToKMc7#y~^(|MXidYB?=}7n+RIZNDH~7>HsnENSS0%Ax1n5IWu-z%)s#(RB z(gv1;{Sn#^x|2%nCC8ot-F^4?eC)eBX-uG8m(4X+tCNqzo2>$fI0oH8uN%J*&#8r=*;@Yvi2?C8YFNQp|Cpx zLI{f;iW)9-KGrJoA<3k_i^`xccHg==j1(jWFA{98l#Z1}ty|k<7Al(fwpi8mT*}m# z-W7WejU7f>b0sY6(tfmH@4&r(nu_q=))tUB_BnP6icDs>Z zFvAU_qAW0tac=w)OYEzc#Y@~@`ZRJiqp{^&#AP6-o0GaUO#Q9q5f$glI zV9_LNBi=gWKO`TtfJbG~?MrlWZ%xcilmCwp1e4}3Aqd1G!6=Uduy)Z**RdR!!DT~9 zRd%_ZYwe4bnC?w=c5|5#d*(lmLHuz#fa{umCuKhrLOvTWeJqSyZ?3ivq-E7DF@o3} zv3yZ^x6M8}wt!93-^33*c&I4ujfij|lFlGv>pZH@IK01f+*yUJzG?^NPM8$ur@18F zdq0y+WR5XjDH~ORa@533SmBB%+**p(%|E=UeWRvoUkXZfo|uOiDaK%~Jc%jbeD3Vi zdj9aej1Lw`vVME9ls;I~p3Ad1t&-SZW90N%O1DXp5-CbgkkWCAa{13I@k$fFFQk^x zTgc=z)QyE9F)2!|wJ&}8Y}8<4=p)q-w(;Z>m~J`*L-Kf1g5|Mf;P!(;}Zo?yhlP?HI!k*Pxl4+Uj0&Ua1yXeGFyT*_*vm?Ho(kJPQhtAmOc z@hM2WMD(GO5naXK43x_q(Nk{z+ z(V0ZpImg0Lpb~4ZLaefE92go80e7SAUJ&m%Gn|l;QH5?Nhh}M2Lp%^a>TI=pbEL_Y zf2lrMw;&}&ukw~7ID7q>kujU*j+M-F#BV3tr=e?RtwYEh1M~#Jnz0qJ-QGN?j=LB~z}b5KuDKX<+6cE8p|gyrmFw zE|65kwj2;S6b*|lYJZ$e3%6bYV^Q$hZX>HbX{2B-@&5WW`?hHDpgA)=(j-vcFumEw za~DXnAEsv7`-w-qsMrZCh2xJSTtBIx??VY<4E0p^1>- zyT3?%uzQa&x#k(bBq!qA6qCJde<%_A)Imwt$tdpi6Q3x2kWwB*59vkKR^MMaP=>0e zYbmoKJYF`?32jvCt?O+x2aHH=2C;1q>b@0P38DVI(?7ZXX(d(kS1be*ePZ=6r3(In zxwL!cRE^M>T9o^Vbu88zD>#k*D_hT2lC$A&C=n?tBvKLhQyOsK*#V<(@}OSsK%jn$ zo+FQ-D!$e{@EgHDK^GDUDrp&+s7xm7m3sWyrO9B8?{XoxDe&-fGO7_wfhE{=CB=B| zU?k5bgGJ(D2|amWU0QmyM+v)8c8sGc25!$I=oGJRucOb01FP7lkr#G)6sY7 zI9?(jQ(1`_V)<4`Nbr%}GXnH^|3YA)B$2+OX&WQD@Zq}kP}?X7`EWK{DfzO*@;MG7 zdo4>}UZ;f5(efcTPd!r#obfJ_@g?z#;_8_E`cS*@J8iRJhOkxS&u=y$$kpf6zz)B_ zxaKFxWEGutesEK~kKu3>41W`;hR&%hLtLDNepMmn?*kx!dPZR|;mqfFQ`jTEVKG+* zIO`=ZrC(Fa)V@yADJUd#n4~08nVB<$(3X^wR+=4?)i=^ZAxDbwJAQOPw(Hr&(nV!4 z&-`i($j7DYM5C#AStofs-c)=r{QnRP2msVeH-TcXp<%LzDN`&YBw8j27Desub$%EX zfsHo!jXWNJ5dYp+dmVOppK`fKL@unehcpN-are^)#oIUx{d`mI4CEbIkB605YD_p& zf;_Xu&M{ORDY_a)0yPlFgluV5apVkj*D;9jmeE=$C7DlGyV~_Fh^ZxsjJxAQAUXla zaP!M}sksHtHM-!m<#};HH%eQyM4&l6`T9xNDMl6#GvFmkA{#Yvy)vP z@XSo7!mL%M<+a9*tHfJyDT=YIbQ%k$QexeV*t3G;DgQ5$OjT z{hvTcqHj-)*fn}OaJxq*l4=)L)NI+#RwTM?(^^TvuOa z@xdp}DJBV0d#L+3jk<~!;-4YytTtJ%axnBP#@pQ`F3H{0oXjLOr9l+UtLa$EYzkwS zerZ)qm->e$A;G;_#AkQ0VK)=Bv_6j-Rnyj(^Z(ju4O6+ZKo-cDUZ{ z^+FjYOczlGqwnSp;;OTbOZgeK%S={7#A#n$GHbW4(WrLERMgrZI8S?C=>p{b`mNFl z{QeM7U@WHHL(vd$IBS<^Ur&Y-A_#~Pp}&1DRH8@P-qpVjkrN6zf|4Ua|LUGWp62x{ zW(&E8ZjeIn2gf6w4JM|AB?_u|9*5}68xp&61bCiVtCQ1J>La`b?Jp{BtSd?{qU z!{1QD_DWz7{Ev5@c0}IQTunJEQIQ+Ja<{f}2iWa%WnWL(^CLfl5xb{~y4Y&o%#&XD zG<)5=-xS4)NEN>J_F7E_NfH>EO-srv`qLj|6>y0Rs(nx8OkMz%Os@XOc$R}Ko2Q`3 zpv`lA*4HQH6bhA{#6jN|*2UXE$j{0c7OL0c@#z*A!J<2%*J#Uwj>cukrNsWoRiQ_a zKZYr;Qb6S&<(HK`>_0W%-TDWP{~Yiaj=!J!6s<|uNA91?z)NnM&9BkjtN4X@Nd=uUb!O$w#zYv{g#b;`X#!ojg%_zvvq6 zTJd@>T8{FjX+yMT!qptqShHYjS;%M)=THN8ey))MwT}dc`M!^kRr`6?v@e{zYJ<9E zQ2F17M5hMP+nAou?&{*D1)8FIY;dAF*lq-ZWecU5zD0k~q1==yILN+pJz4!bdbja} z3JDJzG@OAxqseM7Mq6aOKT4Y!64jiSL3MM-aP@f!SeFVP(chBSsoQVgz8$W&Jq*W_ zR{BWz2$AT;N2?SUgOPGGuS*5$K*h=fW>4;lpi^U{it?jk2GLt!rab`s`O}BoTqULK z5j8p&kG8g_r$(~0dB#x>m!>@DJUnk|$5(T`qP2TLfzuL>KPuh!rg8^2JS`W3*qvS(HYGdjat#;RW}Apxnhx#7PWf&CzrP?t4ql86 z&A~6HUdL9R?AAX5r=1N6bA`fUzT^(sbv;8i+^<=Kn;XqIO0Jk{OLTc{DX8e2jd)=Q z@0V()9?;0>vN1+EbMZ@C>xG5<@i8;LL_;JLp04ET$c+<#>q)L~B_`N?u#ihhsoORP zzGH>$NBTzK;e0jTCKt-YZ1UbOZ{2f}*Yd50mZqEbEki$$yJKIbQ|q^ycll$IOl7&W zNQ_7_AyKkwn(_W34}QuWmRlqXS*|W}Yh3V1bSA|iT}IlCDxjc{oUHEUR`OEmKs{sY zFRq*#q7+C)SqW5`FHvIVxWgvaZ!rBK4NcFzQM*Ve`H|gm^D{b6>f`anM!dE(J?7J| zfDL510`eSWasxqdS>cau{VlobpJ!Aduot_xLQ_aew_pIJOEVP?3Hi_bUuL?&zQyr< zF_)}uyYMw(S+?3Fzp!GteDO)5<9z9y)HHQ5@p<90mF4lKEXL^O*nR94ocV6KS(U%Y zUVTNJ-17Qu{;s`9u&phb&`PB|X}36jB>IcwB*MTb zah>Xd4|G7NDOu@BiGoI%U2>$MoZ}>fhEfW-Vp0*) zTXxMvloEx%{Q_Frff+K}G9;(0bFX^3V*4w$EHEF8$q9RQWC>M=otx2#uHrJ^AN7yq zRe$n>$Y`oUY|O`7zqcv6MV3=gb2aIAu0%J`;C|kM zF~v=3Z}CH1?NlzmZ@C|I!KQCLI!~2!MbuF5N4xSau#~bT62azjZ|?(YI=Qtyr0F** zOy~O*7HD*=pOQ&eOH9gHuDO0Og{x5<4{RVWeIr)=Mk|0N94LBkyiQPfJ+VL=z9~BFHQzvu(O{wQt2Q^uocWz8ZpDwRiq#U_EDR(WMCphqZ=Xfr=@_jfs!tm=trhRfq*NB_3qu(~h2ZJT z50vbLKS&3RK>egtfQoz~_vFRYf`e3%QR4+=JCNl5dYjPwg{4xfvq=v5@n&IibLr`# z17jejl?UyCLFQ;>(T?gQk@rBWOp#nq z#}oDDxph~CKR%~EvFHR{qG&^_{G5g<5eqDFC_tvVf+IXAf>Q}eRc0-wjpl%?A6LR2 zj~EdzRp};x|7%4b{#>@gq0{>f>igq;55pN4y{l%obVf5CTC+mSPW~Owk^97vEdZ5K zyj%x8a*o&lYB-SlM{$byqbXCXj}pOoX{SN#n-fdTQ{b|ZK29#D3l{ovuHbK`!TVPl z@7y9&Q?MU&W-?N?o5neptu}jIxS2FO7OzLi?YYvcV3czyF2e;+x;RUX`Zo)2q}Gki zyAal`TGLI6z5SDGcx!F_4L92B5(G5m!YIoQLyfM!SozlUY^v12(XgKi!dZVlvA z)5}^@T?giF_ql_aE;b&9J~q-i>M~~9wV#yN>&B8$sN+~|X>$W1Z^|Luc;sBz$`;KG zDk=)J){r*y3WbBy=5JHj>(m+RbRU#rA%?dr-KDvsaXI9jg_G2K`x`cgmaG+S#*)zT zx9ttcQ>_)od=h~cQ%v%PP4#URRqmsz%JbyqEglP9=dZSayDngA1civ;jw${^~!IvX%?(e>Z z4V^9*BNy}4?q}bt+6ZHP2S>OT+_HsFj@CdM_6b>6_44W5bzSP%Nk4bFSu439giK9H zg<(Kc)*u5wW&QTM{vlrkJp6J>^~+#kL6#!bGxD!*VQOn|AAg`x%Hif0eXBKp=NF0x2_=(+9xUWraV zBMMz+UH8^5YMPjmFCOK#vrr^B z`xAW}YP*%Q-frij_ZEFKu5EX@#i zmu&#hOs-K{E1r~_znw*q`o*LpIM+hRolR?sT|87+N2I0ASn>r8cK7 zbaKa;&T+gLkX*!JeQiBjWT}J`-yj=*b{kZ1+#*}=5=V@j;r!8Y6NCdK_67Sf(D8P) zAAfE{UW&dw#&t6|4Q+}Ut}01MNf|ngW;j>h7d>VHhOKLkGsF0DkHSgQxUkTt-s~z1 zh%}mXEFiKyxsD7DCC9mp`j1x}qd5gW;=l z=odqA*FQAN-i74X&hSUj)2p3=N{9G5eiqjS04L+r$0gek3a$0pJ%0+%AQQ&o8WbJW zPqV>ha5x95Hk4TTHV*ZaNcPNB=@s(~cIw(*S%HNM1fqaLl==Zmm zHq{bDmVhQ`ASIFbh*^nCx&yhIi2vh+l|fH1#8%rx^zIG}@v#KN@w{qcA@b&e&vW08^ zd|vt&>XbUWa8aI@k>~>n@5TGt`wZXc&Fa*G;ORBxlMaEBy|>p6%kI1glG0Y)Rfg5v zaZN`D2OqWi)|4kL2xXL4auI67q$Fv?KKha764j#H?q3)CHe*QG+TZsp%BvEQbHXw& zI&L;dHzhbIN86hlqFoRL=XmyRcW9N|-5VCB1=AN<>e@?FyyPa{sDuc{tW}!oH8C1G)3xj_pf(E=n$F{%vhron3O}H7-j$MO#bvtLOE-Q{gVOtsh~@Jub*8e5jn(+=iP?)Z5D-Q( z#ob0utvV3?vs(o{x?8hoj(6ahv*Lzhc{IdUaz~Z&Bf@=VO7pCoCh;kJ)qFzWlHIhd z8gSk@(YNCs7H1KfIBuSfHnG}eE2V4WvjcC&3qb^>5UNp~D|dYv1uo5Fd$e^X$Gx_+ zYi{jIUTl_4iD&Ap7r9WNJQS)>nOXlT(x#dsRnn}v z(1pnM&Q#r?%9{J&lITEm$5Wtf!85#JucWOFp$*Q9#mHPgXMuNP_JLGdgKz{DVAj{I z7;NIfd%uE4d%HhtSo2|;wA>{rgWHl?nX+{> zwi>(VR**NKM@Ce512|u|PxbNyO6RO(>3aLx*zgo&kLH8Qu~%oimOYvUER@uzV?n6O zOyYihLZY1!9`!8`(uaKW8<)N8QYWRXu~iPw0aTj1`o$Qa#20Z4+VffET9-fTM<1MW zcswYm7PZImsiQtiWJ)iS3_lh#L(e=LS=-L~9?s@@>^MZ7sTy8&S+Tek_wCriZW<>& zZ@OAGN)6I(53>lk8$R6MgEy^_MATDKUwqV`kDht^Q&ZPj6#2zO=w~wB_}<@p7upr` zZjw$dz|N+Ev^^vhCwz?dcsE{+Zh+jLK5tuHRk9zYF=Z!DKjW!;h?<(G8lGpfh%czM z8s3arnkTaJYqzHsE;ipUMHiv+#e0n&zDLi+qM1G3rp#DGGdGyZr%Kc5%t=097d~Z6 zr`K^`)cdo^pq{GVZ;=8W$HC7S@=c-t#$E8IjE!|$x}V(=1f0tXCWT@4u!Ljmv?VC4 zYI9(&N{(4aIE{by`Mgz4ck+7lBStKJ&S}_~-vVn{jD3MtYcQmyQ35Uw7vOl{9if>1 zEtvcx5sky`a<;O!B9}0YN9}0LQddUd-~Bs6WZzCM8BDl985jXkjLaL;VnpGJf!`rN z*ZQq6k2mR7MGIQ;Hrhbufj|wv1hI;PXq>QUIUg59O?JDB-Sd*a*>(HpAq$W|F|!jG zjpH;3U?RCoxs~e*?q>#4bY|a7UK~7XoV%Sc3Z@T2P_i}-|A7+R@4E7)Z?Jwp=$q~{ zzy~nHY_rk&zAfhh(^*$T1%VwwnS&DO@hEL!ZAZ%otZ#RP-T}amKg*arm+fqAUL#97 zVICV>ZzO-7DHBL^nU9Y<7`v!RcYjC2Y(7rk^giM@!McQs{Hhz>M34Hh7;)Tuv7Wg% zr_<~>ossFIDwOKFHZywmDR%zgyenbid7D&zV5!bzD~q}BAn2ztEcX27CM)nb7##QQ zk1wHj_hs?N%&=p0hsny+l98%YRgbl<^yYoyUS1cM&kndiG;GIPTE~Si;qB4{;Kl`b zIc9<5F#74i|9JoHyra|YdFG5bAmO9dYJzsuE4*|2p7Sm1bTLUsvi}$Oh4f83V@-XB ziQXuYFt^ni+ie+kTi2>(zNw4Pb(AVxUB$1jmVR;cD(LkXxuhv<$uqPknH{E;w?m!s z(czeAUyE2t8e1w7uiE^h!rHS4{ z$^?1h{ETrs8zKtUIIg@uUO1a;G)9NW`jj~Mjg%lN;$!93-RbJF>7v+jq+M{{D9Pi&4rl~|n04V+ih=mYAXjj(7&_)TH)#KHnnZKF( zu(Ujj(cy$1FPQodXN$jzY?fN?$ck+JJXc1`Uq1AKmx)yc0hQ8W77LD zjZ_2O-B)XL=I#wCdiJ@|DTPSbY`l^*JpI%K(fjksR7?X8Iyx(!!nLyl^_ifYG z0{3Mrdb@2;+O=8s^+`$IjvMWGlXeHsgP6ed=jimeSMIm+#0ZSDGXBL?6R&%P0*_2(j6j>9jO(#nyg+&XWUfjmb#s0I@Yy&IQ9Xc&qal)rNpSNP_T53b8Y?lkGi z8ucfk;5Ikt*GGAO&oqyo!SSw9t|C&jO{;YbWcU=s7 zt`K=dPJpYvoxP`5iNUcTQHF8l-=&V_ez{fO=`bF0%P%#d0$C#n`9K>iUG0dr`VAXuEFi@bbDX?#J9u7N1-^ZVA_E!@iPV zXI!{_>8rXvqkXaK+@4x1XN#*dQ7J1lVJ)|fqP9ny8|9N@?&Ck?8-@tVzQitKXc+i~mSjCmZRwCSAm&189t z5{egf`~sW37L_QwWGKC(&IHepj+Z4a^5gi>n?$_D=(19FeVtU~4*73FivUKu)yaHt z;jCw)uLbc$Ih3qApNzH;W1QiFiAn1VPh}1RqWrlxpgutkSg({nN8cZ$ z;wXpuF>n&!FQUDnWIvh9EMXgPW_ZL^PLX@ZbzRq;AN|1oa2buF*w1Hxd^2HjZxmXc zcHa*lVfB@IbH`p-))LAI7rUs!JMHtP_+(Tb-jZL>wzLA* z!=?1ubCf?t{(H=yf_bQtMOrho`1`gQOsqcs@&+mqA6~uD*4<4gC@6_?C1nk__MAg0 z_ri4>(xQU>N(~L_+)gve@Mv64k6H<3@MLFY|m^cc__^3(-0y?#*urLQs!YB#E_!MN@vhL4v`lixPZAKu9!Jb*SqL!GRT%~u+iH(BzZB23| zQ5$x%#r4)K)W3jb*o8Ke_`KoF%ksEqcKbKClQ(2}SQZ@1GJ%x)@US0Jzf16v?yxy} z8f;oeL=UKGcypMA{=B zm+Hw6NO#Yy)kO3rlo1lBjoZnCL4ASx^68lJ?fH(=>#vM7Q2EdW6|AI09m-2F87s=v7_DT4Jk<&`y<1e5s zm+Ll$RFuu=5z*$A4GRsCnOzOJA+K@^{op@W6Gy$iANVu>A zcSzOfkwJX{t2K$ITSVzmq$0P1CS(+r2A8jAXl4eF&X|SwO1%ojkpG{h#{xC=4nTf^ zJP%s|v|5}2TjoID!4AE=y#+ibv1O;dWoOrQZUKhQgQ&9T{`h-|9GffiAf>$j`AIQSvKm}^`kusZQ5q%`%BCsQV{ee44KE9;}h8xn0?$sNuI^kartpWZ$c!V zvJQaS+Tj>mJpSc#FW?QCN}B_e@;F7lN<07=YHPnO8bFN5j=e#!470i(M}-0?4Tab` z*HcY8oF!GuUN6M`tJpI6v*P1L6m7F+h0Vt+J9a&&U+8Zg~QqSA9|c>S?NJM|9s;vrmz0Fgdo!!>P^9o~Av+fi4OU za>8!lQ*myY`ur8Svr5X6a$Y0l)@w_w*Ml(>omH&8>ZLUT1@m*w^aa{o@F2Yd6(ie>0o`=7-g*&$sH0rDe^fI`Pp|n=R68cDf49#~T{Hsch|7R&UUK^|t5)K0Vs^#2Wvm z3mpr*Jt62CvQvEnDZXL#ToRUi%U;01pc#?rqEry43>%qXY*})r`#Z%ig2SX|q)2_b>b#<3(XOCrR`%H3QxG%Ltuf30Vx%e-O zgpY13(w3B!U8{>xf#qiIkrn!>m(Q0OmwkdCM;lWo#PPv;gI`x`g~gn`E8AWpd@7#A zFc@C0BkEKSM_FjqVErL^^O3JnwT{rU-V z^oGqDcQ#bZC`fcAz7rvpX3({-Rr}qRA0y0Q7b}sT^Qff(_-Vnz!8Q4*D3r0;-=j3F zkL5vpAR#0gl2~kZctU9^l^RgybIDsvAA7rzz;Q@i_nl6Ho9$_sKGvJfmpxv>m!bs{ zra>k`p}4AhDfG93Dp2lKYdG$Htg9{4Dbd=ciWd}pes}~t9nD)K`OtWr5QKYWTMgd3 zN5kT9opPbO=1-@@#UbM2UN~{Er!k{_H>q1T3kd%DDTgMvW?{dw^6;PP-k)@?c5BoO zUCB824MqpLNv9n2=-G@wX*sK3r5B*~7S&`p_OcnT2h=-UG0%T)Q5fL5>we)H)%`t^i&Pzt0#{|vkL9N|s_9N$FaokA0Hk!x*Zq}tUgfGEOMfa|grc>4-pbe88r%WhZh`0PZJ-p} z%LS?nG_E;=^=Rsg1km#4T%45^`NNjp;Cbp;Hd*>(D}_+5@iQ$iQvt{KrkZj8Ivp2Z zc%&W7%$IA`cbf-?97d?NB@}Ydy6OiF z+vxNmQzfFHB}W-}D0KpnsYttQg5Z)^$VzQx1R`FBDI-3=x5aYaMZPu=U?aU>TwhD(re{;bbl^fwIgcl^A8oWD+_;e9ein9G~nGq_H}JE$8X zQ)_3Uq_Ld6Jrqf6p4FVxefa3^W?uwrO~U`mdRIAHWx5piJRCxwY_dPE zY^-FUW{{mr8e`F>`{&5~l_`Ta_&!&2$a0(9c%D?9E8iLb$C#JNcYBEXlYX1@%D$Dcsw11e!yJa07zOkViuw8 zsm!IMp+|!VVg4O|UipC!%6ReEfaP;@j9}3BHdwfU30XR!9mXfWnA5#Kk?NYG-%Lv+$#JN)SNe?`#2~Jw`|OQ zH8|PoeJN-6a@!l5X3jqKx;WWyU?xlPuYh0!L0rc3(tI=(KU=@qJljit{YBL3r zBgUbe`C5({XSY5yS?k4W&-X>#r~FsmPZPLOWsX5^@FUvO1{UKCd&+UTDDkloPdvOo zF8S3sM_{%s`l>`zPT!Rh6h`3{l|xg4j*jE>zh@M&?ky2M{~?j0@w+0k_V;6x^;HfCC+az)mg!ub8iy4M-;IQLw^0-?Cjl z3U)`AqT=Rh9Yj;gUfV^hI%{Lp4eim5{a0SxgSMM-dw=R$-_=<6{t*6M!T&kdpAMiP zxFZ<2zmC(xx&sOi5~&!@6|o}e&~b+jWs6Ekm5Ed`=*0@}oO%s34osQc$K0OvI z`^A6Oe!5;>{2JPp@!U6`gB0v#uCDs{ci@1@$HQdTKgh6uR+LSa?$9Drc-c=}Dp+Bz zSbyYHNUED4w-?9b7G}11^)3_ei=;3~{dmrnnTqCaM?#xS&3V=VCDNpHKOqZ|$?vbl z4Wh%YUnL)3t!Xv!ytaOO^+POxZMmpAXSH;}x_Q2Al#RyG;T&+3-85amS@#meTP%NQ z#MXY9(B*#Mx;j4||L7zU+WjrmRGo;vqk~J?InNit^Plbhc>|_s6gEu=pT?0cA!uq3 zwMJT~&!jaGB8)(^ayF-?|N4cx42Lk$of!6Lcq>!KVsH#h;%lm;|lh@O>4@`i2*F><2GTVVz9?9 z$_lAoPbtf$7hdJK-cyk0LS9NtPD3Mp`_uT_&i|n014w@78}7f& zKy?b2ROgF&+||6G!4Yy4#9B&hd?LdjLHWh!_lrTu6OaF_VfU9TGQUP~qJAs(J(Y)M zPmK^4AE*pFG2kwQLKyeIx8^4cs0$i}=mM&u8wSaU;6^1}098vSxn|#ttrYW~a%Y7q zA3=d$>|X}~0$~(=%cG7=LsH6fK6Neib0kQvNBH;zKCwX<&bWJN!`}WsEUW~(JutM$ zGo-0fhaCT1CO(9b^TKsmzPlfEVuVJ&0;RB=zzHIMfu(+*okkIk8M$yruM>)Xj9j~> z&|09x!%FVS^T4IkvXA81QN*Rtb&_XPyOuGH{Q(@T-O2N4Ceh?VOPOJXb< z7tJ2oPlxIv{`YgApyi$-v@bsSuTWFg!V?+GeI3D0Ptlr{kO(b+OUldfWxy;Ae!y&M zR|qouMuav#*_y%61eZ*T5*^})Fs*d_v?Ek>q7L#G{&yUIp`jt*C{u5Ds=&)05=U=_ z_Mi^zXVNU0Wx^pZ&A>O}f>a7_r$GoWrJ+`cy*ie0wF^>8F$z<|_Y4&g=rfp}Yjdvq zl62n-dTRc6H0w|Gmf$EPxgbb7@-wJr%B$F@8An_lrncU8L#xW8Ts`Fw&??dz*xU6Q zconnRW^C;e<4mY2J^Tovm=6*@x0|}Efc@X;K7F#FKh*xTbDZ8k2^&r>j&+Mv)U4%x zW)P-{U1K_-5%`^%zQ9;Uj0U0PQneZIVzv>1N=jj-=Jn``?5uE z>MbQBHu>lxCH29Z07o%D%b*>~<&K4@@^rtR*gO#wvsjC}G|Byqll{;5lOdA&pxg(d zd5LXTkigglP#9A6{4}r^~s|`Z8VW7+s$PG*3g{lepBb;{{ zaA7w-hN>Y9ZO`Euu)9|T^(XY1M0~#nRQ&V?0C?0mTrrr)|2yN~-*1uPDin*eDj2s& z+ZQ^0k6b!GbQmVv@f8(50HtPRl1efs>_m1|o5J%C)O)ca=E0-2N7j<-OnPOtC1gWK zm0#PG&_(8V=Z(p}Vii7b6V2uD=f|#-GUXulP1IcaecwU^t?|!qS9goLlU`@&`n_BA zZLS!w+t{;9gGE}7dH0lJj9 zU(9yi0D;nXLfQ0b7a!f)1PO8V0RGyTVr#jF;)MO0WU7VQ)ukVnZCZl zf(WV+7cM@dwfhsze&4S5Vdj{tb!D|N{Zj)hqFB_`p>iSqp_>TFEv4rAjLPf26q(_~ z3fTPcZZMLQ$SGQ=l2Er;r9YqoH&6Srl+!&@0QN6?j32$tT611r9xpdMsQ6_1FT2p+ z0k1DbapT@+jYIw+4KH%Vtib)&Lq;;4^`KzMm}GJ+r!Crvr}-h(|a%i-CyRv zL|z?G5 zRanY^sD9#@96!SV;Xpq?DsL#1EeXN`xI^uOw zUKOm2_ZCB~ZupjZF2|q0RoXmp5#LBy(B&Ea=iL6J&GXuOvTL%z zou+Wcl2>(9j^fP4@f%gD4v7f#DA^_uDAMor5nNfXPPoNM+!l4vajO6dQ5Aj>`G!vs z&=t#Bg>NvZgiOYm%UNK9TyY~%?e`T_9Q*SoDlY#7jusbS$us{b5I0l*{9Fi7xP7MD#jV7A_)Z$sCpMZ*d?4a+LJ~sZwrqV_7*a*S8yflUTu zW73gSO5JYC`-pwJ$i^NynOmOmpXx49QK;|&wqT~2#@1d5UUaU5SM#%4{>)riDlx8`4Doh(TdWU_)tEx6hoh3)p!s$^POx5OA>n7Y@rBE8Yths!KZR?U?P5qf0%6cFlS$xv%jD6%Q?x(<>QEB%Do zLe;3C7rM)k+S7&ovj=)ifwbJnLN9P?u6=MI>%$Jmet$`(&0h{1XB)-@e5X`@m-1y& zva@^{_-Jvq@vF&|Cp)+ovG-_XP(^`AXGRUj?L07dyyn|~ILHoubnj6H>Ok9g;l?T~ zr<$h_C4fKw3~G`FGzzqtD%cIuQOt&5WlH^eBq|nId5-zOP?eZnjKIyONNywuQx#GS z8UR#g+^KiRA@Rx;r3?Z*fD~#z4TWhOe@`77DVrk`DNXE>)hqR1>2hb;CQjAb3uoR6 z+kL0YUSl&EzCJ-IC+=Tx+x5__m8r*JFb~VfGC|gw^19f$^2hq8NDaecnwXk^wO5r> zOl-ac8;vB)l_-xog^$6Yuh#g#z(^473`=X8Xm&_80#K9V0w7diKtSkGZkG`mDr=5L zNxGI3-IRyHY+{$TVI%V?rnZ{-?bN1%?MYtQu=(mt4rMKQi3t#5J5StX+9y*^#bols zSv%KlozQ9aXvV;wo2AqKO2$)Bz5MrmT99)oPuEaXPaJkM^Rkl+nc? zOjdGqV&XQIx$u-|okA&x%C#ziyG4IADHT{&JM+4EkA*~GUR%&;vq&YQkE?^Ze^PfUK?1CfAzj%|c*wo>Mg(}+%___(6ArXn3Q6*yz4=#zM0eLEY zGxM;cx_$};%Vw^<9K7Du0*&G|et^ILv#*2>c?W!dA3Qr9I}+dY2JD&_>bG8GAJ}K# zmVv?;B+sV6iNudlS9gQgKpe%QI}gL2+n&1eh0~{#p&#TMr6Vfsyv74FnOSWs-*Gt2 z*W}7YOHF@Nq&$z^VgqpQLM%N$3W|eWByP-}bo;d!R z1%c^=eRu5G%UJMi`*FE-kc923J(;D!xdUuq{5G0$d(|eO!!G>thivm|>TD8KC0e5U zHdrKFea0s1VJp*qj}xbB2R*l!6Bf_Lfm`1xv$jj3l@OCqQtA;O=gN4({&mnh@OGCCFfdyA#~q-GaM2d_!{b z-gAE5{4)da`TUqB z-pnPy?{D={|F%-((UKX2E86zPx;@oZ zzipye5AJnOm1%3EcGA~DZf>6lz&C`&=R;n6PvdNtgfZKLXRZ2qU;CGIq!4>7LpwKg z9`lGL8h0~%{=(M?<+4!fK|#gbH3IN>lazh(7ZQe%A}J8EVVr@lU=IVHXO^u{V)SHa zK`L3pFqLr_3Oe7|QsckQtPV1}0} zg6{o5sk7S(E!vR#1$wPhTzdM^{A{boR$7FYs#46s?;2N#nN6-(Q+0fTW?Z@1a)omw zG`)7CYGLxB=V?TA8|lVtI!4C3oKuKKctd9JV%)JauA#;IAzYl@a5y>S{g`yXywhYp zk$|fzDZNR?PCtdI~+4;qo5anHSXaKJU!WR@6Iv zyRu#+(t7W_H!U?@vK8Js!JWISIyJGeGmj_|c3+oRZj-$c65zyacNCjBTJmRL`A`Y9 za__hn;Z{jOn{A}9)hX}qsei*Tx46dLh>*jRS*J+#pL>AEzxCEg`c8#WjxCuaW*=`?YKWg909u2 z-bcK=aV76)Sf3xKINg~s#_<MoFb>J@XToASt%ii*2fFFDMSJtoPI)gKG0s5yX?krZG9`oawnX?l_8ZV^OIwIQoq8ncZJTpu|T>Z8CRGW?EZU=%x{D*Dm(&t95;Jq+Ph`@XF+0 zXHqGzUv0s|Qe>(=oQd%%IP#=L+VlJ!kOT{&KwWU0ydd*utqGjaU%SZLf&t-cop5`oAg#EVE7z(~l)U}3evmrz$UeiD*;j|9s1um2Ab(} zn>14suaNb>hg(|8da7fzWkTlDt39Y(Ho06qyfLJl1VL}Q#su=GCDleUauh^^l_`ZLn3 z+@R&dGOJds14j7(2V%;}h0d7a-t2f>eHo!a|UvnRmWxBiqH5v9aa1?fO@cYL)XEy4Q<^eNqKx_ zUPBetcmFj1r6p~(l)`aV_Za?>(Bl~qGs(Sga@iVqGPuWhyj2Q<1vCXS%e*4k{Y{$p zlAEl=&7O1=Gj!~?!1m|xXwCfy#g#;bh3OR%ib>Tn=NOZIJJ)LqQ@5go+#aAcFPWKg z$u9kRkhf+AE$MQFNz6>Ll~?u#DM31}>g_T1p&4q`OAb-US#avwCX@HdqoH6QX!#29 z>l^~YAW=C0kI_ssJYNP^oQ;=;20FG_4~>DDmz8?WD9{!kAx<^6Gziq*Cz7@xU(FbA z*FzL$rDC_xJAySJp3lD=d*a+NzC0UgjO$7IZso3!GR@!2qI38ZQXAhSfkxg|Mos`? zj1i5Lv^-b{zbJBd=)InOq`u$QqTtmujq1kUs^#m{a*tLk)u%$?55BNTq#Xg`B`lq> z)9ym7=S4I?F#3aocZRNQ*0a))m-w$8ry2MpJUgH7EbazRniX0RrF_VDlf+tR@ z0!=T$&;pE$0Xu3gy$5D8ZkJ9^&Bieec>D8p(8`h$C2v%BU?vj3Nfu3|` zCN?q=JlC2jYxLaYLzr&&-#`;H<3#ND1F2~!aBZS_$!N#TY!IBucG(H{^3=W~^KZ)2 zZzdxAq5HD*?_E2%o+g<6aiSijRKhn`P4n;VX>8wY5=W}a>@nsmO4pj~f0FLVYzf3h z4mnYvb=|bf`-wknFW9C2`;?Mqa}7F6}v%B zyVYwb+#~l3?b646KOCG#!inAlKV`0m-i~L_O@GOhTMv0O>W~GZ?H$$-V@@wF_xMPa z3Uf)&$&fi)+3%T{nJY6L12jW#i6C_rNq9N8TT^-$NLuy9Uq}~w5p#e>DXdxuBTNC!2FX}GkFRnF~es^(|jvt|2zZ9|9_bF>E*Hp16%61dD0 zM3v=JJ+aktZ+D;dQiuk3>d0du%eMx@`G?bs@_O|u>+_{#mB=`K2&Gh>00V)BaM2g& zd=ID)axEE2+c)cqK1FQ=b8?wX~&wQCKwaapRTXqZ+AW2Zb!Wf(cOW^ zOW5U~Zeo&^Kl&oM#Q{Ly%3vVT@YGMbXDF&jJ-8#tw;$aqZ3RDF)mmy*bl$6dL#KXR zlP$$r=(X_C93v4_+8)5^Nxz(Pzp{v#rXUDY=Wss8mV7uXCpFELP55GL-&%hjlvH9a zAD_NNJCz(AosL;)Jmjxmu>h(tA(>Tfa#&GUFPus%VzHE`nGPlGyKhlX>e+ZB=_RP9 zIUhsKWw4kUqdm2ekO4rR&R5>P5VF5^sHm_Rh+phKYK7$t${g9$-S$`21R{FfoFrfj z;x6-G8UM{*i&ULhry`ffN?uJz)rkd6mvp`RxFaJZlFxT&CDS7EaMp_`CI&eRBa4-i zr~VY!2sM!{3k*OfS-}c%w&1p$VD+#>6GApn+${*y7IxhKE(UxBtMSsK)!Mn z>Nn;rNZA{MYfZfHSB#t9D2*fX1)-R5dTjjJv2t~z3^;wNBA6AZN=y9)2Yh|8a*P^24ddMP&!*`Km@A zm^4>a&atK7X{m^%#&dCFx=Z@!Z>S}a%+{D>V1Ha|&)Z%8JiM0UmG+0nol^{TPp)do ziq~X+eZxp;HZ6*V#3;0AYv!w`dgEXx#5__H8KTxNxotkl@4P%g#f6GPZ2pA^$KpH5 z#CMp=o@_VN0BO}?UZoukfMx{UA-sZL;~}7nsKbE^f2#QFJJlC2k*u4rZlqVOLB1=N z`0+GJtEI|frD4!c^ya)N%5@0cC*AjYUr~%uNvL%@#Je({;P)b1w-bba&{1IUI5u}S zw`=R`6ldw&C*zJ^p5W?tFFPzrS8F&=EIqRd6;1V#@P4Ld?PS`Yly+ERFFUEUG^|eG z8ZK-e39s9nR=4)Fio!gnId6x}i9fj4IR%W!U(q}?Ms7{7J#(q-qDpB_io+4tI&L*- z7#CA?2Tyz6&h_AXH=RZ>z6Q_dcq;F{KkZ>(`R#VZTWOpYxxYcj8s~SQ#aJ%ZWuUE; ztqJ{EqhfRg+()uDH#`qSvm6;2;MCH{v_nY@l-x9R5qGY2B5^qL@%vCeNPi1YpQ!G* zk1lA^=3eTlC?+=1lAuz+2f1H%9!Z}5`11N1dCy`397Ze;qd%{OJ&|UQ@ljBNlbaH8 z_?a)%XUAfpP&c$l{T?ALg@oncx?f?Yo^;$k!b9bkjp|7$)w6DzKoQW=jyK_YF$FPyg)-8{u>4}gm?Mne+mNiCe7!G@R-L8| zWD-KS;7~MO3W50kAYL*GmKIEmA!sn4>R-5!4Q@{5Y zLVY&f3iof6ycm=j$;k$|PNdoU{;Lfi>#mT9_Z@D`=gsF5&2`@DyAtaIah!h9cW{ls zhSAy6#U%w6JT^nJD}|mK&yxp6+ROb4$qK*L@}c)(y(osEZ!@^>*Yj|KsR|1zgYA`C zcuj|oA(1k*RzpJY9S*nBtP+QhwhuSXcHwa!Q%ImbU;xri?nE=ZPP;GyM&7k}1ewlV z-#MHL*mV>IEI%2ECZ!>{&wU?)CF446h}=I%3lO}vnwo=Aer(ln{$*4Pi*|3g296kd zoTAee=%JPNdj`-vdn|qblr@p)lXYmmTxWc6bL!o=Ut|5u1~x*N4U)d|9tkc*M2nj} zyo&k2(!z2zHk8V>A9shrwu&PTWeYCW#@G&5YW9u}T29ha7vcf7W5 zp7vMN6oewYo(CUS?i24Mr7!9!Gt6m{-L~x!tvyUc2nbe2Jg)AO((%>sT+VWR_ozb6 zM)D}jXUuS>cIR7F;)n8oLcwZf)U961ZbVLhRR}E;y>8|?V7VAjxxwu+qNNp+XK$ zpwG?0Jnr|rsnuL1Vp646s(gG)w2^pWkHdxU6K_j-ZeqH|^El+FVve`4-{wwd$tMsV z{%qsie7?!)yu!fRCQ6uW zh~L*@*`uH?2OJ^I%CFZAKq;#`K3T0pcyvVBaI$!Xsj*D;y>HBlr1u}Co!;;4^_q)* zZYse{_~ZWPqlra{`ObFnz(X^2T2ixt5F=PUmRxFn%4x{|R}z~NVe_4I)Lhdg)B zC1b?KXFsTzQm6ZAOq@%v^A2Ty2Z?j3sh=B{bWM!Mchgq3#8xN1*BPyOtzC>!B<{W3 zBVH`GX4iS2IHaE{?jJH^w0%*&GJJ=){ewA zeLtV2uomXlPxVW4-)beD3gFvDB$&&F=pypEcq(U;zqRBkbDMlg`~siS=-g~CU)nYBt&7ZgxLeZF3w?)ogTv_NHq(X?No$U*Wa41q15C3vIMxm=^I`-)&)59B(Ir zbD#POa<9hMa#U!xbb^8J zFOVP!^@s>^Av*^l-Z6W}a*x|H1Y8bcQqp88(jUHKCQOrj6pq$)HK1*j>N-fUg&SAn zPfSBdWOI9k;lLY>ql(CDtA>?5b84jjp{DKhbicR4j{S4lw0VW$T(E#Ec-wnMV%-GG+YWfZ5wt15=+z+c3#%|cp)%}oZ+Ege~5Pn>o4WHajmL1oy(uV1=`RJ%$>xw z0e_4nukw#;MKXD}8ja!z757!#AikMO{=>UZbZMa`>M{dqw2G>VhPMK8knmxhkW1Fx|g>;_C?RsHY@lWUl%Cd zPGQ=k$YHBjrnELt*l>HSnv`~uLM4jpRgh232@JtbI>qGy#wZu4T5K;6B8KlVvt#yn z-QNDtiF2iz98=$?ZE#TP;_II}Anz965&6<6+rHp-8y{qqgJ4tiJ_9A7(VMIa9z44@ z3RrTHyw?H^Yv~3lXX(?C*InFE=D-(|n3cYSJ{#33#QNuh6rTijMZcv*NW;Y150;9!a1&rNY z_Xn+*wiU=u%4O=9a`o*@a^9J$7Fh-VJy`!odR#9&9wt3SNOmCT7nFc5ZLW9fuP-7d ziM@`6X6@xQ9`DF_AswF1E+vXA+2&xNvB7k=dhFlj$xPi{+pPh>*Nw2({MkQ{g9;9PIs4BuE60Jp>BjzKWN^qO3fMx&^6x&ps`n z;ASwFy`9VCh|7`*NhJND3o#Hd${=RYL|nVDyKmP(a`T%ZFHdEjo z!*z7eDQ%!aB4JS#R?z;_6Mr5^a*)YuH&c$eVpyJEs6p_lmp-fcOV*qWIDA|-t2rcb zh4b08O>sKr#I_^LZiqp;SwfLQrA?>^N!11K7xH%s@~G&qQK$tdekg?hgNE63|IFCk znJmZrq%8sO2NCRRWyx1r3dG?4}U3t zCz!K6jbj#}o@Zt#reqrnRVH&=FCsUmWg5Ced@gL%CGg+vUkxL8VQd};mYkyLSidod;hx7zC9|iaphuMt8bFhIn@Fo!Ow0+SH;GL8KdF#EekqcH z8Zt)48(4Of%E*E7BnSGY{e6HyCgu$JW1dkkX{^GwSa8syVQ=DrET#={T{Qhh;O_yo4X)KNF3w^Xru5Y5K?y3f>=-QuNj|VgUYF zQR%usm8v`Y+;T{3R_rVqgLUCYk$B;Q!3;uEtQ!8Qzb=%^gxI6{CHfA_@;K7v9V(@P zL7i1@#Vl`jUpAS6PPu@z27S?ziQUkkAlu`jq9P_tIOAM^pU1x?8P$oz4P3)imi3h7 z&;3FdlC0umrxYJ-6Y_D!>UaG3{aduxk1k?*fVPRo!w=Yd-PFcn;pFzr(_Qb4W0gq>Ji91@e6NkG96}ybI7bKb zedPC(og;A>jNx$X@VWlewUPh-NhEq<<7x-B&mns;RM8bk8@k_j%A;c{V!!+03vbXe z+K&3WOo|Iq^HXL|F%{9l>qisxyD|(Ymj%`ag5=twfhATj=&-q}XF(HU)kTb=lY{i^ zz%zDIADqrJWymicc2AtJ5wEs@fqoS&9iNgM>Y(Wx~cW}gM zm45ytxipaOaBS^3uuYMqEdK);_uoFigI?J6@rE`W?WvCj7$>RA(B3vcS>;z2f_3Up zzP^e8A|M&dpQT@cDrbuayXcXlma_pQ*SGzFrD)V?nP!z=r{EKmu?mISd|p)Vsz=W6 zox6?!(XM0}=9b7DrsAik)I_Jq)X&_HucMb^bE-)ZaOhn$j@Z&VF-2LN2>nD6$78a| z5QvH!mAyC9c_aWu^(3W~#a*lH;?noMh2NKqDnG?g3>&nY_->mFHvsqTBt8aNE}n<4 zEp3bvdBr}Kuj4be7)pNtB-=3G{WUG6>iafWp1C5ZZ6k8l*BSUle}-tg{upFD9(gH$ z2-PA?P2A849ebIdb`lbY;qY|h`Li85R3Be{t^muLMz+OA*dXu)N7_C322ys~9OZNW zO`Ru_sRda;Y={NaG;BA!j>UJi4rP$Yqi7ey8hHuY7Lhx6WJaXC3+7~`FV+vj#Ndz< zsJ&PvERfWVIxtm-q^ls%GJr?T2Qo=VPt37m4Td0kY=AE5z&->ZF5X;a^?>}??7rVcUKEXr+ zfl5WMHj%lv$iY2dYxsjElgJx5unttkuh@7(-mt7#UFAJ_<*HolyG`ZaD&6e8IZYLp zABo9D+X&AV%N*p(Ch;{KKXXK&_?76d#ZSu1NrauFWqpL~P}rWyIj_{EU?9$o(DsaG z&bnC#D0tMt;O+%@xU@Qh`~D$XvYqS@7Tji2orzidq95D;11E*m{DYGm#Q#4yY3N;Z zCI)@>zn|b<4Ss#Juh>Ty`y)^|ZZ4<^M`?$tfB%!&CSKP3cX5TT{EQierAsaad_D$) zvFfFgIsyiUuS@amFkqc18^U-znD|`bvWq?v&PF|`5d6v7XbnI%qfi>;br{B=PS#OfSw6YmzGGI$4AjOwl)`|I@dx zhDBYvH6lF9_%9KY3rIPmoI7CBL~;v>$;|MzWWr1+4MLY6k7l;IyQI((Joqb^Kd9ISx{#;m;il54!{3$`qg5@b5s?z6l)bz8l z6ZNwE?$h#8s|oO_7m)Ow%cxM|{2Gr<7sG0bT0AV-Adf8h?OY{3XIF zFVz7t&mSzPdhVbmI+*vFi-M)cX;0Bsn1Wprr8o%B$r6%t36M&GL76&Trs^aje^OGB z5I1-3t*K0|mH#n}S5wWRtcMhGv`cPC8ZQnKC|vvz5JGuy3a?%}B;~M8(>uUvyBC_4 zxIQsnQOW4pDWNP;MU5>}<<f#vQ^hpD#0>vRgx0dgqq#%r(+M5d7KQj{koIUe zXt6#gXn|>GArNWAo70I_a!}8PCIp4UEc!~Z*X_$*t`ClLTY!W+ov~F zD`h2>qT^~b8%l2tKZsmUE41jkS1_Vp+N}o@J=h zd!S2zWzMl$QbM-nG8xw8=xx;EHBUE+K}* z04cz^Vf-RQp``MlsM-QG*HEvLW_W!}2|c9{sKZ@CJP5z)5y1V- z$${*dcW4QGC`Id3>|w+?Q7&s!--ub@9#D9K6QYBHKpM8t)w%B=OE}Um;qhcMqTRc^ zxpZf;P^OhSpzLvTMk^RfU-%raxvN+cl$Y1Yas|nAwwS zkcHX#AWDlIaZAyihXTs8>S^1w6h+Aw|^cY;+}d8^h*rI z(>xq68LzC+Navrdx$QbV-jWEg=$uB<-WLsX&mVv1}`LuySKp*#)uf%G{zg-b2slgqqIr%F1z&Zl!00|A*b_ftZO#(dmt_SDewX#_Mr#^eRW7X89Xb$2RxJm28P*!6cR z$tI71B6jd=Hnugb{Ftt{@ilSOS&p5y=UZ(fTqqU_)EUJaqZ#E1u#epR4l*^vJf7Y{ zlIy>epIZ9CQuNgF1WnsLJC-6&8?JR z!Xr%BnC5t|QQ-p4gJZ|TWGbe0rwYIt$mu?B%=`X}fC3C5pOgA~V zU|m6oV<81b42iBTCtT*optUfXtOCD@jO515K)in#P39I%URzx0!+8q;enS=5#`^5# z5wCN2;5=Y|ghc7o7PyT8PnYa|oCXUURxks2I!-J((tr$Mkn0Am_hwoECn)GhDPU&U zG`MM(4H9W9m6_$viqO|3WgoFWCKcNJdFX8d8 z972)}gGhHOR2BWtMaX_uDsnqNKu>}Cj`C4DWKl>*{!9=u>k~>(O}0yJQEft9HT1&f*wX@8BmXpMuNi0`RgI zKv75|SA^@dbbmq^5_xJVU-^VF;BtV!!O0woQJlnB;&w7tBhRZe4;Cho&>xKEj2yXB z+lhNSBz_!OM!DU@@Qp|7nJ`HioJQ}vgdMr0~u2Zc=6_|C;IVM zn}_q-dvk}^EvH#Inn9O)To&yUKZG+X^(B=X7JJ7RuA}W9qhqv59*)W9s-MIz4_T@$ zA2m_f(xBW~gL0`8oJW-C<)7e7NomuSwg9d7y2{+5EpY$2{WcXAbFa(-{WnOPe~)2W zpo5yT6BTlU=rV9NJ8U$+b_{~?U zOeF^frm=kRT3*b7mED(OTG)~*$)PBRF#o}!TqM^;dK zOFuVP%y{ggvsVFBN7%%e3!s6!^>2So2fQmCmF#a==4;USmw1_edY!p$SWLf_&`SV3;d4<_D$j6Kaywa+B(t zj8Ym+H={vuEv2Rf&88rw`GxiLU^O4LpY?j*#VBF=SlYjCdte}#`F3~jC6Zcy zy||rvp2}!{oVLO>^4A`r{PvDxmbBRJRYRrJp|--Us4G>Gpnoq0i<`yBxKo2e|hy;>u$+#yob^ zN)9+{wn&M6VNX@-Pjhu7o58O;;gf&Mt0eEBM83#HIw*M9^?cIs(R{k@`|#nE5~v`* zn>0@|S0t-2%9=LexCO<}%6h@tVttE(f@Cr^t?BopL1s`C?$Hsw&ZvHIJF1quqQ3|5 zGI`TdwLxdi|FIvzxpr*%Fcp?3oniWiszk^9GJ5URMS&-UcjSi>-Ue2`h1spE1rDg^ z+v7uaPG@{C(6%F)g7*dsOC1q?^tjzE(Pm8)i7HvAW4(&T0*yEh^{L5iBF*RPgwit#+WVL+ps(z$v+F^fXq(7aQ5>Vy`mZMjWW2xm+FW>SP}+ z2OKD+IB-!YwT#QjYXGK8saqpc?B(!1v{$nF2hzv&>|Bh$HM%LZJQu86SOZjBmro_W zrLUBoE6T611!?aa|Qia-LiKT}9DU$POY$!9i zAj9*}Z62{=SqOZy-X5CUOPbl^Js%C~f(jox?Dp-v`u@9OVtJrQysjlHes;l%#9ZbU zl(QY{xOhDv+>T8`BIJ8RCK5?gUr>+)3i7tW2`aHqVABpmmB!&d-Jhzw`>+B3_h?b# zaiJ_kRUHwoBSBccXNMWDp&&5&K|vvH@fV%EBw_sf%L>X&{xpicIvcd9egY{I)iB{z z^Ibs%Rf3qj5Yov37BS=D3WxnpW#X#(*JM{o9+?$c<-@Z7<>{dBhqrR=8^?V$;MXdhFJQ)GG3n=o(J!1wy%;u{ueF}|`^;a8b zD|l=cvftKjceM(_GMyhdHO!KRjIw5MF5Ju*9e;}Xa&R*UGYYn4m3juM}t$vVS|Cvwd7L zD1IZ_TcA9XE^p1tRYAY)q<8q$ZvBQlBH@I;JSfP(5r#Xt!C6!-C|sC$>2t|Bk%xR+ zb>4*Y@sfLvZzHt1t2-4BpTv=vYw9BO1W$@=mBZx0;cbH;6)8=Gr?V_))8-$=@hdL; z2*wN?eF@H?kguQ|^?)Xy36oRgQ<_qvaUz)^DC*`e;-_EWp)t#elfw%ieCbFf6$2?aqER+Wi(eNLXj!IL2Wy8-k+|qRtu6na4 z0q(pS!p8vtTyr7TQ+}76jKPkt=}&QQzGTFhx3ZbkE=E-!%yvFS@LbL6$F#DyHHS8w zzRx7PU|m=X!LPlByHj} z(NW%PX*G2gme8Fc9&?vm%rIoJ7`Is96D!4@P549X!5k!&DlP?xA!bv?ze7I|-S}^A zYF40C{x&dtOes0A(-&G2W4~eY^c=M z=ARwS^VSFkyb>6pOKRkToFz0DlE_6>dN|iVQm8T?>krpX*X6MByT$UzFVhiZZ>anG zJ7F^_I~?>mD)5T&gw%4qDCJjm<71k(G)Dan)VuG^ft`A4>iTMv`L}gn4?7vx-y#o~ zHv$v0f&+rY!BSM#V&(S56e`Sj^m$9$fBw7B%F{uBE$)OoJ4a#Qe8f@W*mh%AUT*;a zhB-m>oU+d)@_L=)o-){`8Gd1ATrE$?<5Das>QIthI@mb<(3{bSb0HpV+j0)m2vV0^ zi*2zQASlTl_Qd;Cf<8ftm{h<0TNt)ngUjA#Zjx2#a{tO{sIK)pJ@=jHxep}E0x96x z!`Vw*RaM;UE+_~yrg%5tV4T&dGeBiEwx*J|s*lX{9ISM-ogJ)?dfSoHz`y!8Gw%*_=wDsi$f3&+k_zYbdT)x}>#_*j&RS-fzSuR<3wd z{hpBFO?x_PiXD8@5(^@?93aE7bG3%tJcWT!Ws$+_a1%nu!)x*@!dp{GzS1wz?>WNi z=}A%R^~?$^+4UgqQz>d#*7VzCXEejirDw0*4*c<8Y7aU(#~)ENMp4p$zV-Q~%_R^Bq1+bx8__^;1W)_7FA zUV4TrBL2;fdD6xht!UHA8YN*`&Qj((CiAQ+U{Su%t-slCEkXi338^&EY8>a{=+7wZ z1*E`XCh3Zg5|{PUs_)P|ghrD&B=k5Gij-a!U+=F7V6U=MLdOg%C5>^rUe?u2@72!d z60?W5V){Sg2%r{hBZRmUE`@I zaJ*F6dY_W4u#Cq#+XlE_YcBaT6A0s_cedY(;LaH`I!U*Tb>a7;Z9C(Da(Rha>@!!* zLdosI`L5q@tnBDRca%h?y}1SKz|xe(W!5MQ83HEvk#RZq_=eWs`5%KR?KSMHi`4o~ z{N+5Nx!pXL>$X3dvm91JSqkcBV9q~Hfj-m$hA=OQ>9NIwXgd4nH|Os4UGIxlh36 zF6-T0SHfX*O=o3~0t#}_;>ZSw8EVmv2T1BNi#sb1)58YB47_ronouOsy;u~^xXzow zP7_;Pk2eEU&=jg)%>b2C)>Sa=P(*)LP@ViKo@ZARw;9IJ!ms><<8{p%ekJoHbQWfq zj>3lXl3N?{T|Ykt#eV0@dD2mR6bX|AgeWs~{M-VnCiGFt_mWgaz7lX9g?*?#Ja_p* zm@hu^pO_LsTB7})u9QO~T%^62QJ#&p4yvou?s%xl(O%?WU&LQ-M=RC{$5?AN71qVN8r%*Q}fB)M;W8bV8mLwsny&Mc{FO5Iw2BR!Yh^s<7T;p_o0cmn_zBA>D@Pa zWYkGs%2jC^1}3)$RqQfdA8cgaUZ4qR^Vwi}J0!NYX203CUiHNIRp^D}>X|W?jc0K@ z*@JT@mG&tAY?8fdlH!E6V!zW)*WCk?bV?52SS{K#+8&Qvf>^M_C!09?r8#X;?6Qq? zO}y+;DbpnaTGIczq0ehVvtz}>-XwbTbwt4aB^pjxI?H>lnT>3ciKAfq$m!(eN%Qe` zl537V%Z6T@7+=}qUx3=4dHLsE6RB-0ADp+1%P608R_rKTiFI4tp7H^BGX5SUOG|bY@Vv|v^;A&n7+EX!J^>3| z94+CHiM=Y}mse1zZ^h+s_(nC^feC)9II|{Mlmt&v^3=j8@~n~5(P3n$P{+5ow-bqm zUmVO;DmB>Ooai1Mhp{fZ2qX4)vswj(jZo8_JKg0h*Cs(9TLtd~%}H@3QVx#LR3SAl>oEA4M5cAKI$ zO>kmTQ4G>CoFBr|C&BSZywRiWXJsszAg+t*+ljeXRHqB1??f#!WF-zmg}kAqC)2aMuU=TY)pMsHYHc;b-u1%l&YdU-=^b z7qj$EncJCn%T~h8f@$#b+IQbgV-El!dR2Q1XwbPHQOt4xI`SwaBImB$PdQFqiFZmt zO8Fv{V}g4ErArBk!m?n*PeDQN&?fV9qt1B9iDwj@dH!HLKe4q|p--xOg)i@Z?EknObj{&b*8ta~A#xPARG zMI%9yLQXh$^7gwas=KYSzAu1@ray<-Ex?u7#i8zC0 z^c6iGV3|QnTP&5zGNt@&&^A#uG#HX8>(#6DlkHNtH$F?tZvtyS#&SH<2Dmm>mc`q5 zM~%MtGG9uS&_LBY$HNo_S8XJPAt?&kra%Kt(FHxceUSW{Z>SD!q9j4S7EzAUozdDv zj%2Ky^O+@E?}+xGC`&C%Vj$!}q}ZtFSPZsGq$+%S*^5Ny*oX6xvuBjFTAVLxhq3*X zaWwam^l2SXJ@C4QC;#9alfZ7(YH*7Q=ty!BZZcD#Q0_R8PPix;v4b$W3Px=xji*#G zS=yK;Kr<;yMJT;ch&xoE+Jxrbb23-VtrQT~54=XD&Z35s6rkDT)$+*HK@NOjhrdzH z!#z`wGfwE0n>34!36qM<<{{s-Fl=5NwUUX*aWZwgPTa#c(?r6!C<8^75IRi1cd zE@Y}SxJ9`K>>1b4AyVtH(5xqncZUj*NEUN~iBH}8jgb!lI3^Vd`K8G!+p*F7+z1lB zKx)*HF@JsY_YC{$Rmn#O?1jottOxkC1Cv~X`YBWMrz+{StQxq9A`#B#1zuttUB&4-#xAHt=MAN`%>G)2m0%^)W2f9+o{5L-K4*M4NHzag zWNXK!q?m^({UDy#JrK!WN}J*he@Aq6*3PVi{17K$D{*lWt+`IHscLr3#E;wjZ%kvu zg%y6xKXvF=yr{*B11M_$2N6<6PwrPnX+bZ!3yzmyB!ATP4y+lnu@*Z0Ucp3`t0`F( z-EN}9YjC^H_)N9LaD+KRjkvOlt8%v4fW5N{HLvf@n>;^ zo7suAf|zk=S6_g2h0CGy61QDUG=pXo316Z<`wM%J>&Z#OO~(gznHlUP)uy`a`Hib7 zl>Kf+j3ZZx_AJ(FJM)|G{G#`-cVFa|d{!J#Rt&NtZWjvcKTk5e&lkDmRMr@8Hc~mE<}xd*lJ- zx!YKlz8}KU71(aGISg=;RGK}MqBe2rxaYe)$f(pW^8QnPO@)8au2&cB$E`xg?%!() z1VO%j-rgccMxIG*$b5u31(1>ReX=?f4Sg-|>)KJR2^YuW?!eZAohO_L|b zHneh`ei}OX_Hil&`H(z^83XGr)WgVCcq$P7XVhg`qbRh;I3^vo_A-al7t|DMM&s}c zX5NC7<*p^<<5;RS*TM3g^479H{E8A4ktNSBYZu{>^s#+)#h1X-!ub>4BZ1Sq_KeAO(ZspQSYf^k^b@nsc9+LEEoLrOuRdM5!;(OaOT8x9H3Elll)Sv83$ zGWfj^vkXmUI$|l(a|s-jB!!ZIW3*s&>Jo`%WYyibGalj18z|iujaXva^89q)WxukT z9;;3hhx6$0fID$=%6Q!R>{a)d3x`-FLaCHn&c1}PdB;d;cz8>qc><~SIn9n&uo$)8 zD`0PD%DL8)1aZ;yG-iOz0Ts!Vs@OT5DS^Vjg;WbL%40)h7(xmHud@aTjHJ?^!PJd% zWn5Jf={_KVv1pJEasnax)RSki%`jsp@MSGWCvv+xsj1~onZbYjn7^o^rdBwyOFNVf zfBW~H2x$+>655oS*|m+^?&g9jzA)NXcxu_L$~}+rakQw)L6mcTbI&r;cs3Ztj&Leg z!v#5ga|il}(q98&1U|y*Z54mxB47!k5qN1tWH zPjTCIkRnkPSkX{HSk9H#8WRr}+2C<5!7(jOkW2VJq!-bb&}u)r96LVb{Z}loj9iA- zXM*=H+R>)N`{_Ib7jg$1w;M4dqxt>S;S{V?22V32j}a~>X^quVuK7#}B$4!wiN6!$ z)vp>T|JB_AzB5Cc=tOA zm)S?T9K3A*v{RL^+Qrn=Wf+R_A+b3sHmf}HPfFioI6vf&t90srOQ4SR)9nM61(v?$ z$b7Nw*VRz;0-o$ACcZym;H-%4u@3OIp`{bMzCZ1@NRvoUxNWwUgl#F z2Y2_R&9h6Z1wUQS1CAeD3X6IIXO1k9H3Cwt$`fhOw;N^I@nl8Dv{P2pZivk1J;!J7 z;q2%@5_V2j%c+^-P#(Lh5KE%v$1`19f==||E3Bke82 z+S;Oa?RK|Nv{;cAEACL-p}4zCkWjoh1cw%PcXtWy4#kT*6xZOvT~FG*_bW%P?_B3w zf5NXd6XslF&h?CYJi`K0CbM>fM-$ewDEte4lc8n^1>1JZCwl5X&$*g3@|dZ|3U9s6 zx&7?)v?zMTgIrvU&JnJIJK^>- zu2uSzzc<_y40alQDJd`YTxtaP7~^Dc&1cB3C<-8R@~MKT5k}~*Ku(O+9t}V*sk$+d z_+_+aH3cIjXJS^MwE1NOGx$^V$LNnhW*cMj96l5o7_3!`(4C_!U`O)1jLM7}vtMfStbWJq|!{!x={r;Uzs5Anqp?;6hg^&`1g#>-W=?o$R2s7@15 zW0Sd&QU3JmhqAcZ&STlV#lAx4<|ow^|IzHsCprs_(>8cY0PZXpTR5~l@AmJ|QBG;` zxjm+xKDwn%;2Ah0!IL0egXCsS1!Oj-fN0Nx=NNsef)Zpji{Dl0@>W`l0hOdy6v^0K zGyFpA5#6|=LhcXk$yu~a+O{$C!ZiJT+22(KeIb;wL&rOh_Mtd1!h^+vM%qTl?Wp`T zMPiSg(PT(ipldWtT`zwgxN6<<79>7+a_OpD19`98+@$AjqsWk(2q*`}V?R8dCnBpu zw=<6Quk75$=1)7Do2S-%miUfr4DQ!iB~}8R|8Y&M3p(B^p*!n;80I82pnXRV7mg8; zqdFz(gETlaLM>T~JMiU=i#hhPnh0sa7K^M%aA?!d7m_onPW*xS7x@-Xl1i0edb5kS ziP&Mi;4-b9DKvDrxhf~J^zE7g5 zd1YXTJKpsOa{|A+n=Dn#|F(&@BN39$lb~flB9y%z9iA&EjteJ)bRJ57hoFK`_0HJj zAz1^6Xz?q@ST)G1<5spW_#6%*T7iaYwa}V8pvJ$QrlPgOi0xq9h2O^(TDp^y@X%3H zJ(i%^NErwq#>YC`$C*MWBEkTYV#AVT#3$0oQ;WH{P!jUzuU=Xnl_DRtwG2nAVt445 zM!*xlvJ7kbD05}dB$258Vjfrl6!YPOV)Qw65yl#I zi3s%zxK&F(xh(!F%Oheew4l_`aL~P#^Z6v6{*IoMq#Z0RKDjF*(;TE0FR3WsCZLP- zd-G~EX^e9ipAOLkmrZwn5hu||OhdUGXfk@kPaI!!Tu3kA(Y`r+9kU$?h;ny5xXK+v z`Kq$I9+Ja$9@cyGiN$u;zry+YAW5)td ztR1JFG<2C(#QXEf$?kKEE;dbVtcalmTvprPK;bL!`2u~{?#2sQ@>iVu8E+1bmx=iWk4?KUw=0r~@IUGyq;|M&PQ+7P z&_6`0W%6O`uGgmdEAVB??#lV@jO^o6O@w1JaFSnGcpIwpe#WONd*GW;lkUY5Y=30Z ziy@y)4e;ha5a1VZ{Ie9k@pwe%uUp*v#LW|>Bq^_AazkihIS9@ehK@oTM2eu<<4{aw z8D_dRJsOHS+RYriSSxAc)wZLVKFU}}dWYv^qq;p!mX$E=*6uQ-73d081Z3&lX_faUd>DlO1M{R_%SNMzS#Qt#lJu{SZKmtUZx^s72Ed%F zn#o6bxSBmLvM#I^X(@_=+#c$Y-)Qi&8&>%)byfVVJB3hD=HsgAia$Eo-XhzSTx?QJU=;tK7Xr8uyZ*!%wC+R zihjv~wpHeFS}e^@LCPcS5%YLnT`1v|U=#cP_p*?$nJR~u2dD#DHV}}k_fHngwx0ao zxZ7<*hKa@7>VzFBL(OmqN#5n{Xvh)PADKl%E#lF{a&TkBptPhpq->Vg)pnlu0(52? zeS_h92P;}>9`)7OdT;1hj!Zh;7P3n*?QC36PuqNm#F-w>`tw6x)@2CR>YKSL3&%Nf zs@E>1)fX%0eVK66Ao&hjnE4UUdhGv?al~})tr|sH_pIvb>1_B5gzeN%^c(k*^vYzN znyR^dtU8(sBU{&G(!xFO5)8p;xTf)?uORHj+9AR=*#O2INUJ!|bu_dHg)W-~6LBzY zBW3G_D5(%^is$J4cS`-a^SI_*TZkzj>c!#@j(M#M#Vgu<_}8|ox5@mg8QUFa$IB&z zBmsGP!Ip`H)XPtgRqIk^KD6>f-d2Ei=EM$r#IJ$|M?o;Rz$p#gPNt@1VT9rm9blk3bJJ-8}9J>H&oO&nWOHUkc(0^5GI zw_iRS0}FZ3TphYZ9(eR-H-^P>#qHZ90qyy_-?Oj&n(#MzqvCDkahRI%?)h;pPX2Ug|Rg|APw}&d04v$?#NoU1tZ^lNq2W> z>KG+H0MUEU+V@Vv0f2Z{G^VqjA*{bFC{V9#HyH^#UbgN8;6)H`7gG~O6$gjP%=xsSs;YC#ptxb88MfwuB!_h z`@=HKq`OnjY1^5<%XNOl2d?}WQjIqiTI5!12IVJ-@V0NpznZO*;p8=P&R;`Ajx|He$J#mb z(pwg~-CJ24#?vvxy_G=JJoQ$oAGi2;y_-J6pYw^%>EDC~QrF`ZBf6oWskB{4id)_ z&F*g1$66)a*Ksm?%|F8``|Fq8Ly|k`gFlROM8OhY-{=$pE+xcu=CH9;Aro`fA2)0Q zN&B$eK^n8S=S&hkR8-2|n@{kdc6RZ?Sg82y*9RYSfDY$0mIO2;YV9M)ZK#C|L>^Ae&#tyMrb-M>MxNP8G z=L6%@z}^Lxn0jz8xPHefm2E>z=q1bBl-q%Ce({EkQ!`wH>nTafW5gd~+v%<5t;kq4S98Adq_Afi6HC^uuHAWBL z{KL_i1=SC{s)(0SD*$MyQJ%$Q9w}J-o?oLgQ{N4dB2YqGe4ac8i-x+m5MnZBJdS~% z(p<|lTQE1|qK0m;m5M6QT6dQs-5?$gy0V_*lOKCofTasoxhPOMG4#>(fj!jagri$H zX?DW|ji(-|J5TJUM``As_|RChFMuP$-2Sj9$61kvUM?t&gR`XZ3%M(_RYrzYr&|`1 z?_0JOG|up|>AK!)U9Y52A2g+u+7%mJ!)i{j=Gw8eTFTFi?UabT;cb2+RqJk@Otmv* z6SJjLjBEkQGEI*|8{YPQ&oaO9C=rFlEBw?(S7~WPc2g=QS3#{t>!3qh=g617M3&fn z`n)$Y2V8f1pjdT+HCc*^XD(NMeR5KssvV=qx4R1q1KP2H`p+lHsU>x+D!W#zuwbEauI0y>&`t3Dk+q&-^Zol{fT9y*d*E?#YL4?Z1#)pV6P4=fFQ;eVE_iJ6#KWxzERRYJo3|h}p2O z_Ac?7uwm`9!?{kx5cj0U1~Hy3rAzDA(39xKM2wkcCcU-8*Bj_w;BWM(XneXd#Kw4tMoEeZasL#spDIj zS}6C#u%GI-e1P4z@k7PRd$Miso1Gn3r}U1(%$q zbbB8?6c(45%*x8jkZ2yw5H+MM|KQu?(0ZWa;cB)^GP+IO9{p035X%5_JNa?_0HFuM7m7p_AH=somR(9DdC#-1v}ck=LOYTssgL$ z>?I>v7#Y)-oi4M@$gL+l=5hU4MHPFPx`XK(MID)fW{O)W9&pEO%@^gMESc3`ZfUm0 zs6mchgWvCGo+(GI&0}$O<*}TN9h=bK&Rdio5DR`#UT6^h2+$o%q~!N*NK%j9jEqvL zDCf^#Y2WH(S+Y0n8pQG@;EsxsoobvT91EqCxX|8O2R9mZ50OscCM7YP;M zFFQ;b*|e{0ZtU)?KvvL)^fQR=VO3Dsn%RFQ_Jx@*C9EDp`)MK8yv+-xr1R=009{7T zJNdA;dFx87q_;dTE^h`#zpHO4n}rP2kX2EzfS9F_?aV7fi`l6o(q}d;G_l27BVU(s zyl-vI?qRRWV+!qU6DwoCWbUo}@cS_=`2gNjm|j{92_)W|&RM%&UR_ye{f0Jx$+>?E zeGpMdir9TXINzk8KMIaN6MQ_FpxoJQw{fed+rA2cwF|wT8==+Q@m|cJgjty5aXhTA zplM9puahWTZRj`|K8}U~0iR=2H*ddK1*(^Gt7|)*F?BeumB_hX!5d+2_>bm!-gV?& zEqXt%YBWv49KW30*Trq;LWo(Q4f;IIo2(H|?*5h4IdPdB9*>uEG|9bP@}8QiB?4ro ze0ZG=3{1zE`U0%}bSIYz#T#dUCvla7o;QWwWSlHq$e4k*-oz?^GFE-T01+z}n!dCex|qnYm>{7!#K?J~MJ=LT zXCw6s@>qgfv9mapFY>jw;RVa`?spDEW)jrnv`cLpLv5l=zU|m^6pgq)6a5)qbx`A7 z$6Q4t)8s{}et~}wMPa2dM(9jXuHUw~jecm10B+TmIY8DOV@TxXwh%0L^xm-vHpiOW zAU!eq?P6ZAz+)cFs>95;F2YmxcUaKaDvOjyD8wW(j&rndeQJ{5jY*aWf*cMI)&$6LAGvg*k3Wp+i9a>3jhj{s>$Na-z^bjc z9>(ZkO}fa`m=MiY)TZr0&-eLg-ja0HCv-~bvRb^LuGWh7yZxaN?=xK5eAA9wvw^}) zFP=w;D@`)ogJD8WEkov4^uJnjJ_I;;GZE-^W8Yll?$roB*GWp+JMZbYo#k0M2 z4qI+InaeD+ua=*eoNuox!Ry-_g&|! z-w50%nyMsJ!wE`hvNvOyjBf5zhZ8za;GbR2x5L|o8F&KQz3Y*(_nkRkm9>JXJqec| z9*bN5Drd%(KT76((5LyZOeyo89^=`B)2SY?tF?)#gG8d}CB$$X)KF&F3wsl=uEkE= z6Tc1${m$O}*hCX~vVhlC>9xhHLw{5IPwf6ySHULU9p*#p;5wi%PsN-5QK@-6;$b`3 zb$XgUH(zVO!au#HuNW{S?Zv!p5>6fL8CSi9ZI@X*b_rU?b4HYZhvzsUM|(+43L^kc zTR$d1p(Ix0MUK&uZsI}$D4}lVrXwEpzgL+CtyigVdo{1Q{%TQe+WhDx%$V0VA`5ZceAb-hPHdzehe`aC9$p>)hRF4v2jN9Z=v_~dVi7OmzUptli3YtYw};ci#; z@S^g}rZ$1~sT@0d{rY-Rk^??U4k=|`xoYU_nY6tSLlow&s5xhQJYux(3->0DZ_!q^QIj{so;8OKxzwl%!Tj6 z*TZp=KE^ER9DM%Tr2!>qrrUWjS!B8Foc>CU?KbCx%3Xb@#NRKriinfS_pjAW4?oRA zj3t2cbG;rOK^3e>V7kLJ3Hik^D_Ls~%veBlwIYK;8BqG{UJ6PX`yoJ#Tnrdor8qsM z8NHGhZ<7JLVid{ihCXK)A z9AhX$CoV*^DEwXvvYijvq187qjjvY~4{f7CGT%SaaR$`yKi{@&Vv>Ow-z1UPO~z1+ zIj;@9-lcoZ14iRORPedO)BhgSz|I?ITXIZ35#N7`>Q3D=&`g5_k<8ADU9 z8aq|9M^xE<;cXm$(plnBSvBg4S#PthUUi&1;anx4Reh&eMe#970n!gMdW63F_-x=? z$@~){?rW7B*NJKFAc4E?Z8WEos%9OwXWOt_bmY8pc(bS`W$ieB7EGD(mR?Tm0EZ&x>Ougi0iB|E}FSoT-*8^CkiG++CNx(f>V>+h2 zH@e;(*wg`o;Wn}Psqt4EDL4dbT4kT$P%o8#2!11YW?##gH?1=-YNB2p4$2<~nxU^# z=Wr<{Whz|cRgPm$a0zRvhsSh1kg{g(jo<;1ICl9HCIXXW%R@DXZ*ToQ5Jf6!dW!s! z>HTm0b?1gnfFYmuW^hU{zUGSi;3tO(G)W||XtrN)z@*qZ4ct@?D~qWDIZ4SNy^1-+ zo7>yHuZq%inL%T>mM?jG663u~%5kaNSztLgHIM6M=lu%#=zzhUawQuHEol)Fl+cM3 zu##{B-@ZK}IXKxMTJjkjCwI)jOb zY14$mk9(3Kqv+x8@}3+l+i4#!UkPT2(@I~7o!$5Mco_H{0AH*E5jajenMm}I1Cnln zvZBx-YVSp4`_N~MFW^=Dgj8^M^PS`>R$j3SS_lx*>%098XM9T$5AlGs)}lp41R&uQ z6Jp3*<*4kZLanMu3#xJS=|jc%f;Gcb-I1kK3xoXPtH}4*hGoK%s?{oVkCaUmg~T#= zHL*x>HfI3o*Juj8q&QB-x*CAaYMW1|vtL*L-mRSoy`Q!|pdW7Q^@Enh{h#rixDr(& zsXQ#XO$n~0|9p8EIY{9)=WK9vG)!x~`VECG%w}A=C#J*zQGc4QLOVQ2tW}I%ikfLo zK*?xc&9pdW7K{>03Ody%%JKJr2_?u;%IE=Ne8dp2UxgU`V9*Sxa&(IKCnU=SKQ39ZfUh)72^()Mq+l!4JK;HTxAoC0QoTjeAbv36QA%aUcE63J6ou$tOaWCX zim&p{`Sb?b?z|rtM6oK|o8AKJ=BaWyWTlu@Z9tz>9HCZ*YMrl-&0&14ou82V@jlb% zop(qq4(7F;$v(yB5(zk&xM*@Z@#;-2K>nMp4DDirAK^jyC9~wE8L)idns(vHNv01A zD+5kwy`|EpJ}zG+C8hsF_avQek%Z&WiY-YK9zM~Ze)ivc?TOU|(MC~hy-B!0rz6#2 zJbTwsU7PTe@B5?PT7DUMQdu7cM2 zyIww5+^V2vE?Rv$!$IdJX@gy?<)Js0p23YOg@@SmIpml!@I(tgtU!rM@H4=SCxp)P-j&b3U^@P|#{qFl9^lBy0x3u^ z>%5ho!FIKNVT6Rw)O)MG*ll>m4BK1$40KJMlEiotM^1hbrH9n~vxxrwxIt=b?#?zS z7K@dnm%|~BB`#9MhUPWm()!-yZ4IhS$&HXzf!TkEkmJ-r4L($uK~@-4+dchdGzU<+ zNoi*X&nEOR3O`d9;?XA>*9IV66}Nf*JGS3+(}dKQMWIhUTU$ zg(ooOlSqTb)Lqk=tx2o?>mXV3S%Jv=Z}-Wn*mTuos@ZpLNZ^L#%qKBg+=?v?MV-VZ zTef}in6yVIRn#jQ;p5jR8{jOgh3GjMPM0t!+elmFLdb@L9wbW_5V~Wg;ceu6e%EOK z$5n*2HZ;g10WCMqujOa#3V0`>QoN6FUcDO~7?OlGc+c`R)D3Vj6q>8rqs@%!%uG!0 z0rA2t(K?e>Cr=3cM6XY^S7YN_diEbTg#Do?@%cgxAlhA5S|ko737PGg%wuMWC<7;i zq#(ra$u&V$Yggh;P|>l_l>0MUXx5s-y3{JzLRYK969SO+n>0^DU0`S`j3Q}$8#TlD z8oWWhulsFUmOLR9zLD(sfST=~E7CnZ(q!wcx+aF~1-~ZA#9^~0}aLcE%vZ@qoyi0() zZm9sI^(x^2{-@^lp!%r95KxMVey(6g$j)j|J@6Q(C#KmCJJv!G%2*&YmxrQw8K1wz z5DF=8Rp-(w2>bW8zdt`Ozn;)=`cRfraEKZ*4SXG654AJ=E^VKg$f$a6k~v?hMC>TH z$X=V2!ZNv$85F?%3Q%y9yMk&_Ib;`56xMUbw+UtfL0C|RL|n@%$251F{#&m{MV*g# z;PP${6Ln9%gnA4>N{w*FTBi&>U&$cd&I&){nQaslOHiK*nRJ_gZ?!1 zL%4mqKgJ#N^mSLZu2Z$Xm^yWq?d~6Ig%Nt|r2mXt#9U5$J6Omvrnbskpd>ETFRt86 zqDFhKQ^q`PSCg8XbSMp}S1FGWW3Mh2-JO*0Ijfut-Bul`RS>1;ybFi%sv+HFAjT7( zaRKZqycRdXKW(rEhBNqi85pK4>fm3$R<)*QV3^r+Of(q__zzz$_5rmdzNi8E!y_eA z_x}BWgFKfy#*4Ws=4llkp@LRrIDmTHW1vg{fPc=sU5xEkPUrbD_R@>X$zVA&Ha#~Cm8TI$fmMuC$ z7o2`o8ruF=+J0X*A4)x);5NxHWGt5>7VOW8SxVGQ0ZgwUKtgIYHP-$o%U=?xxJ%$N zM<3DfAjlM8*pNr@_V_JL8%XE##GpmIq2~CXxLB;AJA3ABUvJ`ZYX(VJZUF}J@tQBh zz5kw{f4>vh#7A2h_gaZ#D_BC^gO99gH+~RW1?xs6xNi+U_x-mu;AfqW`mU`_ZI}tZ zhV4p~K?x>wv+2sjVfnH+XVXI4)y0gUPc4swdGz4)bI9FynhDh+m3;yIAkAuas%;Jn zSs9E_Hya|Qs{MGTSwY{3-|U7WW}qs8=}07e7?GPt!r?Y6LEeG zA0Z|=HN4r{Wj$k`uXw)F8&h!3xD-av_tgOikEc%-&m?{jc)o` zd_c%3JFHzqrk|mjw#jJfJN7Yub1fV`hF1{vep2aJ(m|e(0eUIbK&z%|5$JUzW)tJ2g);_;98N5)|cHswF12V2V%~&>lozNL!0IV zkP;N)jNPq|Q!J@eC5JGP4gGJ3xhb}xqyr0mjvfH`KZ{{qZq5tSnhjvcN#^UYO^ z*+S?1^ z?Ld2Jy&kz)p%(BC}&uV=h zf~kGV)D*q%%lNw638%sRC-;odaV+oBt)IPk9KXS!V->u(m! zuw`gm*1y5`+9~4h#tcp#BmFsu&7|Ume;anf$ zQ%?N{rjFX)9_0M3Gi9Ow)L<#PCsjv%9b#T)#LZMG$|m<939k4>-VhnbRUdlWC5Ty= z;B(a`xUvt#ep0#>zq?U2N+RW8WKR&mYH_m7gz34kR`DvnL zcr=Zsp5VN%Y4Y9wwSRyFM+C=vz&mnJh_WonBv**!40Uh9a3IWLTt88V7j;x4_ zi)c`=>NLTG=MOptS(`|`+Q6uXnp@-3&bQyqjQzR$;4q=qr_f2>M+ zh2!8wBKQi0GS&t-LoX(lkoJn#{uTr2lAWVD8aj)R|fnWotSm&&f<^#(s&qwGn!zLObGV$uWsyh`oW0&nR`jV zZPo(E_L=4gPdSuDn^r7QI=^UPjtS`aj$);kh_;O%+dcU}H)5vsh@v%8js2Ue9kN4q zB+cl1YAM|>5pYG$mamK9elMhJ-9c_M3o&|}xgFg-)&Ci}>$UGsKBgEUZuxk9HVc)= zeE+MUy&JLl{~ftwA^BgCJ7A%CMbmNXI9P8c;n1^W#mzx2;So-0YILd)R(bd-3*33W zs@--U=DElt$nMld22In^-ESo!ZT`MC(!~<`sJUfzYc|>y9(X9j(dO{8w8~Q!q4{G&E!p?7HA{EN;aNWE*WqfaE0|cx0V+$Jxz3x3Ow(7iD zMT9G^a5>btM!3u&JHgpJmUi27&#pGT^|4p8A8Nht(gz+%{fX2fOm-xQnrgR8Y6tc0 z*c;uCHk2;C@4x;^wS+z-o$TjGNrC2R0B)so=f`2K9pROnJF5zU9pRIy@MEbnobpRL zai=3#MjG}CL}}G$^HTs&;PO_qFRPf=WKEFO#_IZK=oGgrR@ zeYu;aRzYUQ%^M9qluq(rJ%YmBQnp-(8$_s*k|J|x)*4ZYVNCP{#t7vsy)ad1ZVv3wm!z?5%~6OLzI0kG2*s0D6>&B)h3t<;>ry@7`0ewj(N zDV24;v&s=e(UXGpqEYq4|x=X?&cCO^@RE19U+*$V~rca1NSW>F`uEGKd4uY zm_$#V`1vNhlg_(s*NJF$67SC*@Qn_BRa9T8r6Vt3>z#JsWuA5;w===_lv34mH+D9< zF@|Xw_n=f!5RpmF(hcqYD_nEzu>6m?Sw2o+K4_hPqbuuf)TNT}&%}dzjnKQCl@G^p zCsD=kh2WIpEfRkI5uv4##cYqe@R$D)?;tqU%0t#bu#|##%r@rU}0cO;nI!Yh?{QpDeakrOvc50wDG8{n;Y5u z09RhOIeokq?b+RSqVmcQ7r*{Y<6Qt_4NiCj+75Psptl~^-SUWNgQe$PCGO%}L&h`U zP<4mIM&2bzzkf(Ot;uX!vK+T~sNo&|r)fQpM%zP!eVedI&#Bmrj^~9MFQ>D;p`|PN zZV6SlkM27gbv~Uxt`wM(#w)6#t7FpYko9z$cq2_JT)n3VRonnfZArdUA*?tkw;J|{ z$1C4e5>d_Oen>bBGf}UP*vvgU*bYpow3C(2=Z)cz2Q=SwQnQkWWj-lWjh^FJf0lF= z+7D6HIR|ewnpQLZ(GFF(X5H)UwJL_T#O4nAtSenqcoiBR#?m8ZA8(M{9{5d2x z`ZR(uC8R?9n-UD_-cj_$p`=eAQ72>VLnUo6u`vf-bn7MW8mU81)vcg;`ONhh!pjv9!0E!N~sI9WS;A;NR zNc+|2pw01!W9gd@yrAHnxqEXj2_^wxP{HHz4{jX{hrw&!Thi~&9fHYo<&8TpFM)x> zfT&%U4@?5}bXtu?yBwg5EWjzD<;3OubwI6yhPz9ohRNGz)~;P93wW{qdMhkZAJZKL z+*-O7Vd2cGitDhAjP&_RF@*B!cZp|pc-CPySb7+QPLJtiI31kMM@!ckvTG^>TJ*+U zCPu0CWwb{OzQBOCXX5gn`{Qc|q_idvGw8)YY@vf}hQM_$BnQ-+^48<2{g*V_;RC7G z$q#;F`E4xs!>I1%ws0MU&}_%7)kQe@Lp8MP&c zS7&W`8UDVMf6%4|li}OrUudE*oH5#a>(v-4j&Sj?{5)goh0A6y@1`G%p)>zuEuI@_ zDhl^F+~%iEo*`No9_4U(X*U&;SpU%-2>CkmvLO3dV6J;>%$@!d-%~Gl1^XtGQce5v zz?-+?wepw|3yB%sXqK*>>swRUtJsR?PlB(VX5F5C>8*tKF$Ry&QpVWMO+n+6VLy$t z!s^+X@(SIgyL`(Cj%eGEA@ZLUg88GF3T&Vu&ue*eZ+SbTM10lT7S!vJBo$+EK#{qx z83O&3XenNdQ}uwOD-8nw~po7ytqvJ>a*I=~cLW6{wOMC$)-B>Tr9*EDyditI7TCUY^LU3C9 zzY&5YaS?qhtAc|o+VXeDT`vK5&Q8CG9OgtumeTf*_d&6~{$%}r&*6D%V=DbtX@fba zU9USHoJQ$ut6o-U>aKL$1ml``H?Uu-%4hiR=B6~jnxZsOfBy{#)+YRa0fLi{{{Vts z1GH{yep!i*UPs?0dC?RQy6)2r9<+brf`Fd;Pu*^Lh?z>`n6Gj`>) zIGSy-Eu)OM^m9yMZ|{6Dw)3^$ZCHIv@Dn4So(h$|Smyw|vKMaHmDOO5q3&r!1Bqv{ z+)EbpEAIVkptuzL@|i9&#qX@J`j+0?%aAjOn*lBFd|lUd&%Fi#RpG;(M+3F+*zs+; zzAE$~dKz;@el8V%A54kKi5*J{)%o@DG`c110sU|>bJLJ$7Q*~{_jvKb={3Kut(;P~ z6r8a-71PVS!*;H%CP$^0y3d~5!+mVSocJl=ni&ibFVcbEi z$G8%ET?KcLchDO6OZ`jik;DG3rgj<6cBpDB?AAYKdXkrXSR;~Oac0<@FLi7Wr?ZyX zmJ{8O< zQan42t0Hn+s9*inGoqp_UBu1nI&eSGWi0w7u*Dq(??SWW(-TiugWgIiLJiC}(WcgN3jv+}bkd=GblV@tZ13(9fzd$GZxoEXi=bqyW&ZtBF^Ff+Jc zSTn!297~I%i%hpthY(}cOG9Exu{H)}>C2(v1w70cGP<(yG7_8}g7=Scy2l-iP9NmZ z@af7Qho6Ip&KElzhrJRxCA(NZ%wE+u))gv1Wo~`>Y#%4uXqNgo8dhg%V49ZA*nHFd z2_1h0Z}J^}LschXaE>jteBQoF^yIiWDjv6-G*T!9d-dChzn|M8{OKSMf8*kPJa#7F zfKsKTT##mu75}h$m|NM5+BMkxm9l%DY!9jZY|ELprV+-_X&sX&y%sW%rd(1Bfcc=+ z#D#Ni<|mDBY%w*xzx&5-N%4RUHPYP9p@5k9QuHsMn~oNBxD0-Go?k^R*Cgx1KfgLN zPWKvr`(N0>V7OAhIGosS-d9UAsb`N0*rt{agLjt^8u=Fw0qKP?cYUsA^}WjbC)FF? z-aD+kbPVh=JXMSIcvzT=Z(@ez-I;1A*WHBDk!(2aX3kdYtrj!VS~(%2!Q%_lRwc>} zM{Z67t$E_#mjY7n6#(<6YXx$P&c`bbq={$?gRmk#3%$WH2|X>g(pcYR<$eN}yZ;Mz z5L88X5XlO2@i~~A9d1p#?S>t6Lz9&>MQhXz3+^t-g#U`LUiB0oO0C}YV+?;)5`GP# zWT53Ca$hX_0)>^fU8Ge<+aGx~9uWB&8+^4AMAix#VuNao}({>>Kt(ttc(tBhPAAUX=Yl1m`ZD@Gyjg{8$ z4CQas^mGw0P2)}MNpi2pBC!bNp8apF<*;%bJd-u_(&}B^iJUXod#*o3P3O^y4`mWO z8)}`I1McoJ&xtKCEQ(fxqUePq2nI+H-|`Fw16mIC17;&hVYYHS{4Gg!NMIh%#2py* zr=e_ebMmt<4enp}H@f;W4DSDTfKa69dquAYSIakcmgz{l&F^Wk!ZAD`fXFN7Hqzpx zWiCqD`>(v%Qjz%IpnQWO1dArsrb;L*&14 z0}mb$GF5G%dl$>@*F-eyj2=2GD}!GIqj&eP=JRLOU#dBbX}hV*p16qA*0O!e_*XLM zc4_Ih)BFmjo8NF+r=f5kB&u?^2skl`0Bwd*8&)FAmnhXjYP-n-_Fa7yj>($*;Oh-4YsNsK*EX0B9 zIDWdC-G=j!OlVXZv)Lhb>v9y`kw_wDGPF}DjeFkHkL2K%xb~c?0Wddcc%0}oby%x+ z@;onIv90Sq^i-~+U3)c#te~N}R^zUMkq?|r-W~jvvP3XesLoq!KT%33FvL!R4&#t_)o}H*S86AvjaTk%$aguN2=P<-| zXIpuy94Z?}R=P=O=NDI+a?QMhYN@NNTRCb-I^kK;K2}+Ax|IN-5gsxEQVeMP$8s1# zNX(di>|PI0*znBW3eOt-VZqdq+fcEIZBZzDF3*hmm4}E?YEZe<$Xrb`WSC5<#*j85 zz6F3>7xojoN>ziZ`&<@Gs1vRyxN3Rp09ynvin4Wx)6wNA_y(!>rq3Q6(kI=QTv8Oq zsH_Xs;BErj_qnGqI$lh+$!)JOO1Rb4XwzU2x6bC1@ytzVYy&L4wiK#S@5p<(o^3xJ zCRj80I~+GN1R^jm&ED&+BiXIqtUIW%oFi1F@i!UGR?_qnjxD?#IX*Pr>VODd%+uA( z9St$j(a~`~pNE)F&3=(|6#0B!o+Dp*zslr!BcdJcuOGbsWpJSiYuod3Mnm8FDHh=+ z+kZE?d-^1!w2+{{f$&mK3Dq?o($&eX`&~gWMd1EiKh#guK5;a^LhrUrQEJoHS0o?z z>F!)rewGHGMrTgW4YUhyn9nFu(ugjAAiD}#Z_jzthd@-RNsr5_f)j?vU_tVq1Y$PL ze9B$FZfX#Xo2@MJ6)awEgoaLzo#blS3K&5T ztIiX=N5gM26KM;}pSDMX;{%=A+Wc?GuVxwJ@v)j$fJGe9SKen#UbG2uwhV%mUQai@ zZ+f}C^)1b{Uhx03!8ayEC-b3~XaZ&`wP)UY#tkbP>Ivy{sLik2^LB0FQVu5C#UzxD zji9I`a44S7lm(TF)$0~W<$X}4x&-VsPGiUO^}H6Of~^+Yk&S-ZExMN2jmvQ9q4$}p zQO&$63&rvtNS!Yxe;MS<3&LgloLa7%ezn$}z(;H~QJuL26@%8mO`4#j|P0o<6AM1?!O8$?4Vv5M;LoAWS zj^>LO?1jVsn&vhC{9~He^jvYkOm4S#^G;Z$BkA@AR~G}egMz*DrcS zP~yj)TWMFI@q-^MJOBLS`F)3urtnxrGN<(jA9pT|m62~xq26J_L+2H&TJSU+1D~+K z?0)^(G|`utmW0OVaJ~CRv;S??Wl#9ihz(R$o&0>$_;8^-xmz@a*=-ELi3ja|^jgWvGTy#(+u8Z+n$Bu%B|yT(rG@2F5vSB%<`^FRMok0G!54 zB9a**Il(wJVaXE_)((Pe1NZyC2#Hdgzdk8GB~NtN8<~|nWp?l~GIudzr2Ws-A`UJM z((FC=4898>GBQE7g>F>H(%em@LJB!?$r8)JdY9GdO6D=wf5|O=LCs?<8@U6INm`{j zOWnqU<2t&B%PuhsfPoWza+v2|v9#J{GE>n$uv>kMF@YEvmQ=q#H1RyPlKz8J>EiiS zrc^A4m9Ufya-4EpLasC&f*7P70|TQoGekhIC@AM+(T&T;zj7jj&Jc+Bh>E`XAU$BX zD007!mZ1r%Ke3I=VNmoFmO=ZlKz_cuoM(RY6~t+^;I&er-Hqns&P8Cyc=r6KPys{(srIWf6uXJ?ddu%*nbu2 zKxYVyY}xicoyejiXhENUOT{9rvK#^|$EQcx`MKcSqHIH_uNrpZT_)2TcyMz`FP>`` zVJu$z;o&I_aWDF<2qO7g7pwJQy@wBF6*a}`i|XQcdc}k+5LigrKX#-fjSUdEnABjk zwtsk22EHkAM}X4i?4Vwq=j2$qUE)d;O*A;9+9t+$-|VGjL(_xz_6!m;rzk7 z0A1C9hL&LuWx|3yh|6EgmZg@LKRMgCX&>FS^^>#7E~bsQx)0N`TuE$01nYa#kL#(s zY2o%|NFO@2dLqWg#>!g6tjSl4f}jOoU`mRG0T)J4+_JQ^)T2`miiy5AG&C%;N>F1T`JIPI4fBicbg5cBAM2mKci7omN7k)4-{?c|~Gcu5Vt_;NS>1QN2H2Bg+LU9s5aW*{Y&xt{>pukvAohVT9`%^X^p zzk!bVpmYVhZGU`^&Rbn*yJJ08Ea$bpXQ<84D1`H}HG=W%$LR%1ZM-tG+(l7`#!^`< z{NrjTR|lk`$NuX6C3H-QVE*E4MB_&&AfGqP%Qhfn#Mnp=8!h2HghZo-8jqyj(MVK( zz*=`qA(Ofy#=1h!j_+s}q78OKMf0#Wyesg9N_z;QS-`2r+Gj5D@|^N@C$#ybvHEsq z)0;6kc_sbpUHCd;_Ymg(;_)$3EM%b8PZ|Bt8Wt*sUBQ8(CX63GI>uBZlu#UHEd^WK z;oL|14bJG1XKY@+kot=Nxqvkn8>2at1=Lb=xY`Biqa}7T3eBIBrL2%?M`d?J#lvY2 zt1_#W7(zP*dci)v-Vb(E^cYWxg)LmQ7Dwq8NL;SwB~Q|-i23vja2akV(o)4xcI}gb zNV_=`>3@R=g~N~z0PG>66c@vG&!A6v@!UxH57LY|MSiYOTgu{x5)~LNG1;6YH6b(H zk9p8EB_`$<-oKG)g_!6|%%EIuIf4R@er^JVTQgb`fM)r)HieK@`>V?VEo>Z(?cVZ$#wHfH)DGJEI?f$4K0V;;3g7!kV!hF2 zi>3Iv9$e{^sT8jzne`C1&HrD{2nI$to#)8YU{`tjw^bjYmRo}VO2vx|LzRi9N-wWw2ZzjGjB>fbshY>-XXyfVckq`4L|*`MXlXDMd9w2WolM zh-TgY=~6h;6P^uTr)P|4r7vVFeNU3Wh=XQJCA-STdz3|M5TW&DK-gAqBTU|jY%Fn7 zNtBep7R-9s`E#Uy=qfda$42Wy=1~cbGY__&*s+t9bOgfCadmBLreZK#SH7d3o}LFdb9rKqtv+tVnY~il(V$ zIj6QjZXfnG6d!47&!amZta!@tW<2G{g}! zQ2Vv;x6OqqKW4ptpq~b*UgN-c$<`r#QF4~k9=w5h{lzoK7%hDl*)zT|DYkiUl8 zqPDdL++xS~E!XGaOcCIb4HqkHvzF%2bg)^7pz z|GZ_aJi3B^VY4e!uu*qiGxAB#0M4NNjWGV51Se8(LDd=?K~y3iYA^q3woMNK)hm45 z`?mN#EamKel8-^k!mcV_a0aH?^!NMPkQU3@xA2Iq9}>L86ZiWgKc6a7>_Y#{DC<}T z=Pw*TG}wTmwmmvQk;S9_&^AbvFuC!cT0f zS4BSCVl2gyYE>cgcI!WL3tk!_xQpFC6R(lecmFOeMXQGPDoO+y((g7#|7(`6rOv)z`@{_svm2N;?X z-Aa|hZmkxMMc?K+b+pXfXt&k1Hxw;i_-}*Xr?&}wMwi$8<};V;yw+3Tva4ZKjd7@j z^+{WCW~o5AW15=+`4(EkeH$xM*$j^cu!M7`N`5ee^porBu^|)g`5WWBw=hEa?Sc&{ zj9B25=R1OX_I4NYXivANaol<`8d}g)^i_+h2t{b#k9GcL#z!|7u}7!-yAfBf4K_n! z)xg~UXs{+=8a$NAWkV3VuW~R8*fJGD3|0^@#<{RQtx$|rx)eA&fBw|($PJ5LeV!xt z{eU@(+$owohbzhHd^nqDY;7fp2nYIZmjI>Y&%sV}-k;JC>8mMaF>Hu_D;qnFJbuLH zliNj?{DHvyC3MshgTJHrn{{FO&jQ8a|I&NQ5MttnEOb2r|T z#`8IPtzH^F)WUs(KcBV1;-V@deamz28AH{dD4m0j0&n4O-{;D&V`reHVHN)7v$#{s zck{#VKtRoeORAJ`MjtYYYf{=xOTf)1CEevg*CP!R?=B#aBPJMIpDG~Dr5pEw&MRa+ z)0NhBMsaeGowZqLkecwNlyOeNPeKM6q*0ZAQZGViDWxyY$d(&{=vJQ&BMQJ=!JvZ0lZ&u=akmW z-B$G5x3YPC0V88_l8xs;Uzd}k2sPyW0Nk}3x-%x@HXCQo zunXhGARxaQPLh_9@ZTLpsB`Ts3T{PkK&KW-r0!ZD zk@xEkSbFx}wT!sVKg9=$y7(#|MJ5 z2aU6*e9ms2fc!J{&hNN%$FjSe21aU9(#^d%y2^nChtit*)qInX@|u=gPcdCPrl0d< zE(f6>bZ7spi#d8%gk5Fwkk8$le4(O{AO$O0w)a!;PS(RJxkY^`PC-4bZ6bq;c;;wh zkV8F3_}L2e_urs)t%Zq{91&Y8JaR9F7lSs#4UXUr?Oe6BZ;4*j15jT4<3=WfrQM)2 zutS@~EBe%VOL|Y-42Nw!xb^Dc0s>m?R{M-zcdVa{tp6zN*ivSg(Ku}XshMqXmh?4> z^7<;-9Hss3P0Zif#fGNWtA58aj()nD{jRh4w zTbc(OPZD4G{H2(1(*YXgfGFOWli9L8Bo78vy^Cy7%%YM*>T~NbD<0_S?p`=Fv?Sli zI6e-&;dOM8w9rPnbMWc`Wj8~n=7`-2Xe`szf;c&f7wiSLBaZ7Uk?s4z$YI>nZy5KwS< z(BjuR1nK^X76Qe@H&JtY-u?nsBHX{mOnIZ!UpT#P7{4aK1}6KiyX^n2EtMsh)1bNO zdRmIWd}df)68YI?_heE0Dn9O3tDzBMiFH~RzW9=rQYvUmzUpH0V!Idqc#R?6sIy9ONvfR?gF##R*x7abU8X+ z3b|vqI_rMwC-NKCSAjaOu8-V;%M2?l#-8mM*4?IS143U0J2^}Xa(PmnyJgY^8crW& z+vN~XNsAd@lx`OGlb5nd0)Rp;JH>$@NJ9+m$gL@nnMk_}^68Tsob@;Gcm?!9zsOZ}(-xYxPz=-GYK@JN68k;N?`Oi?*gf<(0I%w$8Ow z)i2R&%6Isn`-a#V>1=mHDea2uM%Z*08e(I&v6>j2DT2Do@!RxXJ(#%q@2&Jd=VPJ$pF zPyQQTYo}~GkWLqjtiL(MLK2F(2v#4n5Q91Jrb|t7XYzgss(cklMAtA@LJfwUO^>0D zm63UCsZMm$Opj=m>TNpd=ZLO3++YZOPglFV%SI8EF(N1L^A|p4{)U7`QM75G54^CE zJsoEGwj}2Tn0Of((pFYc(n41rr)*wEi2EJNh3_Z+=K>1Q$ZT}%k zp1~@vWK;%s%X@_4H8t;Wj^5rYOkmaI&sFM$e%IFDa};vl%YhD$uWSyV7!={-7w^C*h0Bsye4!r-%R$BQEGxePE%PF#?m` zdsojhVIb>lUOpU{-ZGvw-llIgUKUknuic~;9DBL^zWDm86iJVi_T)X_8IPfoBiAzJ zyJdZ|?L>8#Vw81nb$bSABfgrkb}&gpN9mNS^3EW+o5klY*0H!QbIUSPcVJ-UdqcdZ3r>z*Y;um-$o8J=Ne3=S~=lHFXl?EVvKl^Lw3r7}v&U=7$;vdf> z{bOr|MvAa_WTjrW?PeX(x>e7|Loo|9t3#%2O^g7I*RL+*erf)r7^QxqbtXYU41>{P>CaOJm^VQ3BR+d(Z5zY zt_9^|c>D~h^ZpFE+XH+-eDu}9nYpWSpW0lY3{y)wWN!&n#3&7d8ois(aTTeD z)d6q%(>RVt;haq<$4jbayoXB!1!ZH}a}dvAB71&#l7JVmtoOgW?b6(*#MhH%YevF{ zqb}T2cIx)p^uHwZx=Qh+ciul@3+|Ys zta+RK6ffSW?T>}{80$DHV@|6wA(#HgCdw z_h_17jT{g3K>U)wcx_1YJfwFgp7XGrX!5bS8nA~};R$5(*)44H4!R~Vw^;P`<<-vY zPifsT7m)1#$5rpJPk7zYEq>qO2Fs+yTT0()D}ySyX!(K!A=*aw@$r;Vt`kzFxL5S* z`5cSrIJ)Ay%DcFXNmU5!gAlsXcZZJ&{t!^w{dt4tu;;lDsKPG!I@G~g5ePP1Kru99 z-kZ`tuaFxQ*L;v6#TbhgV>|isvP;T-zh2$ubl>5Av-x6D#qKg-nZ@C#<7;SJCYAhLPyjF&jG>Eo zz+Ss5@(k{Wqiq+wnU7p#u&pH!iz4cEjcl{u&S~6Idz`7%rhTwmL7mE`=&yQkER4>$ z_KP{YZKHQj#FE-$^`LU}y?A*^ab_CJ*l0g{1|KK)Ee2+IcRO{HdFU>Q6)F{|RsK{w z+fQmPH&zGzJ*dIJkd!;15Qd01ZpY3uKUmerhK9$DY+V2wq|{KJ38U#DxyNl>j3(x6|*76?u96X?vpIhOe{M0Y2)F zfoc4yx9jd*Q%QG2kW5tC2M1(97~S$2vPuksQe)4kj zB|J*)drVnE0m>eF>5c7BJKr|@!|%GulWBXArtAu7zHvaJ zdV@kKz8XStj>lk)U!Qnox#V#+Rg@}ktb96rF5}aZ=1xNK{l(x5%33pH^=$8QE5E1Q z4QnL-4V?N;qPFiuy*(`=3b^+pndhw}McCrWVYHd7&Lu{(!G*`xEO-8=zoKQoVir<9 zwhT^dZr@o3IU&Zb4OlIn;gVU@Sl+=KC{EE2_!DRbzK%cdK|klbWI)9l7lq<)G<} zi>_y!YWYTeq|Kb^e&_mBe_37cdd60__EUBxx6Yyoq%OG&_;^>-AM%U#D+9;s3&178F%>5nwL|V%akAp^BlNS$<>uTl1q|e5!&UhsONgt9;g0Ln6AlP3B zg73>q5Ki2y*-|%bZ^D|q>I`<;US2uxHJT9gwRPGw3}kPwBB%x8j(JTQs7|A1&hlX^ zWaGa-BR=+gc)suI+U|txtDkXcFg2>~&(Kw^)D#G)58RkmDO9K-IyqJ#p7Xl?cPqm^ zG^Zfpi2M|QQl=sk$}NH_+z_g)$Q>hesH#L$I82<>z?7J+j!U6(rCI%Uvd8o75Em_` zYg9>c#>^kFK)kO0We)14{lKfvED5*I5YM6OkZy=TX}Ah*Ta4Y%CpxQ(HV!0@^4IxY7<0lo$L9o9@&vJ~iHFc&tlR&aVnZfW;TDyrB{ofiN2u z)h7XlNP#Nj0uXY0%9W9$6uFiKY9qTmAhRcF#D9r6H-8 z{s=52VukR~3ZBgBxHs3=GRcv$w&paMy%qn6$JWFH&VKC| zRL_jb_Wj`{Ej)=P-5kouAHQ907vJR6eOt&4;RS0S%8f>YmMhi8dr@hY{eNhAGdY1a z7hBh}&pljgv$$Zb8|N~syORM6RPcb|Q6!dwx3MN|g=`dQ-O!mf|!fzg&Z*%VKZ7Vvd zW17_62}BPj2@Xd+=RSPQ?mv5R>r))U^aX>ySO?Lk@l53Xw7)_q7EZc&@f9Y~e48zY zxmjdGPB$hj3TAEezxL|gf12wL7v-Y0i$kvh_)PU60dUHk6f)}7bn{aG9deRDSVEF@1 zZrAsv`vBd|Zlf8kF22roinXq0T9xvQ`CE>s!xueIp8)&W=uYr_F#zY{&0o9eGl|y$ zO0<2?v8Pu}y4FSz@;Z%6_+xZx-eE2sDr=;0mVz{ZiKxoCD>W zJSGMITDE6_`Tcge{B_@r=F(i+dvJ7{S!$_-1{ZEZ8pr_H_r1DN<7@5fWi11yqWgun z>3Z$8=c{td$}pjgPPhBO&xchCv<4suC z7tc@du_VsGH8IV2ehPBdR2l4R7HmEaZeg}RW` z+f7%^14`TIgCSOR+0^?*&MmK-J80ofYIey?57n(S%~jI|>^7l5(MDjr8h1Lsg ziL;}qRib$&QpEsr^mt2VbmYv9HC0#bKmh1(WCD&Khj04J!4P_Zn>`ZgDt>8umxm+5 zKW|s0PK10(Z*oP}4gB9AfdENbhrfQ)#k@oMT3ELN4ZE>@H5|w4a(tNYs1q$rz4Ax! zAkbYQIq63w!I9IlqMt9s=EP)iH5PatbL9qOSGo9m4zx#-VPhrw7*Aaqx0f+gY^6L4 zi8(^?&Dk#fjLIT_>!gokadY%(4dq6${0V1j_FkFMUYxIu&TiYBoNE`?Ss2`@WBC^` z(-@o7fUMP*k@$AOPs)6FN;f(hXs?vl(ZIixrNO z39%<+jV#;{!`o$qyg9pb+}De$vYTghzPo=AP>VH1R=g?-*bX<7seoAxH8D`BHNDlA zVP?twy{Qee==Wt7>3T25F1ECXNpqeiD%DGRbG-g0MB8if&9*l9JSrpA3p9YYuAQI- zPt>hiHf?WrP%pQ&))Y=+7$^K6za<>?k@rD*uQz5%2w=c12j8Ovs$*kcZ+us|!CE*M zPLwe{go$M!SozOA1MA0uj|K@z^w47nS!Z9qNG0i^fe#iIfZ*Wcmhn~ohelA!cH0-b zPhoN1Ox=EH8{(yiBja!4HKJk=_T1{zX1)H@UZ5%_PBlv%u`G%f|LO z>#nmvD*0!N#b1jk%!D@2!RB4=c3ND`I8`oq=+kj5E*BZWarhS~4WaLfe8I0d{cy8kIb7AJCW z4qs6{Dg#{LWCLeTf7sSzDQtV*u3OrCPB+TKp1gSVt3=EE+`q_4K!)LQ+mc8YXLZD3 z;TJqq#83e>SEg&UXvQ)yQISyHs$5-6hxy?p+6=`4pkf!A86>CwFvA3J)3(aqTtqnY z)Q$5tO}BkldB;(*#XboYE48h(Y5QIuViy8wU{06%wU+bl@kmwO^x5D-OS5fCGXAM4u_>*1m+NTdPh+oFa>VvA zig3p#8i)Dq61NapgWZVA+$f zzu+<_rZ!CM-r^C#kA+QT2sn3zSrds6taYd=2}ghu0!?*D8y5|x+oQX$hT@8gs(E^h z?DSucJ9%t}2291`V@vKFK6Dzh+!StQeHlYFa~q2&M0Jhiz#SVKrHKe&W9~ohKso6F zh|Tx^#b*+71!XAnCBL?59smAbcA9#mg+uCpE&A6pJnRY|KL6#X7VH>fyV@HVVWFdS z-5;wB)a>l4)l20IR*A%PbTX=uN>=(c4A7EIRvM57h>M%t@8S>`n7Ru6ZbDGoZ~lh~%UuoE;Imwu9KJeE< zM@!gG&3wCk_UMIj{)?6iQ^V)@!cDYd>~_yTJWzbfH3=@ezFcO?`or6!!bLHrx9V>e z>rG-kzMCl2CF_>|8E=@oH@)iUOd>VJ+i+^rZ}rA)1j9J3;0?9mdoc0rn^byzQqSPa zLn4HdAFMuc^CvcFRxp7uq3fX%p0Fyp4&d%^#G@N3B*v_Dlb8JkQ;N=v;l=|D6e{zY zyiw^J`=RvrM__t>T_&=H7<@b8kfp_Y8!3=OtoAFH0IvWiZb_XWO5eN=}3n zFlf5*LeE5lIlH?9Q{BWgzWTpP)&T7F;!XI1P6Sk+nqtb0%1-Pi*sK$=aNU`kj58Ji zOyVkQw`GeCfq;B15%C=EKl?R|Pz{L}1?~s*0FP;*M4S9sJZ~Y2t7gQLlvz8G;8C~4 z;V<;lz~3J|{Q8TNr%6!zK0t$o#xXoQ!6hAh@goIiI-et$8TtYO0-m&4)lqyL2ezqR zD3zhBgO}ZvNCWxbc9meV^r^$`-zI3U zwREnh!(8(4b}SVb79fK*b`YuRgBH1t95;BBBK-NK0wCXj+DiKeDO3awOZ}BHk9iVZe|6CRUXkAKZ zZH5cc@#OU0#KlQLuR6k`K@16B8r$S#6^{$D3r#v9QoJ`N; zi+?$z4=&zRzc(HF^8vEexZhM??=6&0mdh51DQ+cZ3KA*T!D~0OtEzt!QvS5#4zX7~?E8D#5cboM(aCSZqe6LbS)>~1 z2(s@OJ3F+nSf#R3RuN0O)0AGyMf3uG!`7DEdTGdhkdZOY-<_1pp@Q3c|5j+Y?7+8K zwH!o`FyU>g%akf(YHEt?R`#a`?60=CgoK2+xV)v)1*^u!p~S{7Scg!Qsl;jVGI0n{ z<`$ob^oj0(R%Krb&wz3iYowAqOfFnB@oUo2J*}?*=M49>P&K|;q^n}9r#S-bct=6* zBs@M)`z5%}g18t@x9(3X{$4r1uV$VRm~prjJe}2mF7q~#0Wt};Z&X_OV~EYBtUQnu z11CeGkD@%GRS<$i2QDT_kQ0-Hdf)Jl2Bk2dSVDJU4f^u|Y ztKp?K46^OwJ-)YEq)b62!4os3Ro-8;^vxOeM;CiiQ|sUhEyyoqGR$ zDj1kE@+oi8s|E}_7|`+u#9oFI%AisUamLbbbTm}7MHZZNqH&KhLhn{}a~$aK3^LV+ zYMGXynvegv<^`>A*V;sCm`cOMk9sJZpYX=@yz~Tm)=^8#iLojhPsMwn8IrB;EC0B= zs>E(QR@VJ9^yEZ9js_I@?=4^y^h@?_F3ugkmcPD%u~QeO7sIgF_RQ}>5r4&;Jo#Gq zVDv04mU=Fpx)CZRZ`wJsEBh}N@#h97h>d6XUaq7)VEOkiv&1=L!S3>9|7?czenQH= z@qFA$lG;Q}yo(|u#YJZ0+-1!on#R4&AW3X--9kpPll-4YfZ||{b=dD~b;|s5gzBHsieM0arysVj1H&|&i$j0amMju zxyE8MeBE!wsID4G`D!bLl8@E=;c};h^zX0y(#n^32n!=@4By5rbqdVk05_)$I&jSc zJSe-gN*>D9m{rWI)%X}N6`B^@XSLR<6JC|rG`>{_d9*@rFTn&&7_O+`3m-ryB(&An z)YL3hDwR5%6otOBf36&kQY-K16s)mA4j6DAIzx?C>ukp1yiwg2_GkHV5h7TO*znyO z=USL(QDOR>4J@eFnHYmgj*f=rY3&V&su`XAU)D)sY~H!qI<=Es;`?!1fPhBVB(q9> zTsb*ce&38igBe!9?>jI>{u@)MlBYlCMfUzTIR9xR=7IU?^=6G0GkKn%h$sSO=>K?qz-}u4!e~M@rKdlEvsuop?&-nAA~iWajjVVbogu3k zZCwNkp({!w2iUmZje0Udr4EUIyUo3U`s6&sO_=rR9+*L=yl2)f=MsdV%iB~|GjSEQ zi)^Ajhw>09bkUU-Ph0)#tFwq}z}aa$@S)AJSEvl(`#>8rZlp-LYW}}tA%rK|CC9X~ zw#!ZPOJBt&yJ0mnVYH(xwID|3*GBH!(0>#)KhjbSi}-7<{Xx!z$W%P60NLpm;nO-6 z?(CLn7SF^Pc#HdKYgd0hjr)Iry$6aB}4@Z(`bn+}KudMm5XX#2wh>V?H;AZ9ysP2!pJa%$+2`aKb)LQl_bYPn-gkG^g=k>d>NLog zDEUnFHBBVu6G4oBs7+`;4x7|p?t8|*O^?gR0je?N~!J?SvJvOMLC9US+ zcuZjY58P|lswWd?-cADE4I6t3#8U3iVxI`Q6R2)7~xW#(n;h&pN zSW7FIIS1R@9FN{2tR7Y`5VXK|k)$k_e;b%ixy-*M;uDj2`tPc024OSG}0tq}(w zYAs;WLsIv`-p>j~P;VfIOW-xi9}4+84&p#J7$_4ZXKH=dZ=oV!{wMUiWjRivxph(A z;QJO(@mOo{L(8vtlMi#i{967+*O2sNIE6NT?TF9Im=!BySWw$Bv}B=nVvT%&^Qz(d z-tl^dQ=u7y?9ZP@YvlfO)(3;EzS+$TS%T_1W{QfHdg>S>=<(e|n5F~CvLe<@Ey0MI z1Fhf1Zz4o0RXHVPY^|Zj=a;1Pd4~`D%!z=5S4|beFsrOtfp7XRZO1x3uPcZYI(H%i zgOn5$7901chBt1`4!Ewn3m*QPtvrFBK0mTr*hlT9j*iK~cH1!ShnN2s*_cEtjnx*8 zuWf0GI7)L6*Y#i!1m418g#L(~Z7S3=_I|vbIrCF0TPVv%1KIhH#XK%%VvE+!__wUX;`$ax>yv@}AL%4s!P1r53F5;w#_f}&% z_+!>{P{4jfA_y6=@gv0AcE$VOh=%Lwg#ciS|4?32!R>L#Mw}2QeRZBWvXBK>{#aeT z?7Zq=TJ5Qy>hj!pFDQSm`}$Nqc0(X8DtE?ynpoV%hFZ-%OSUzUcGXjhFvRv9(0Sz+ zObNz=p2H|NU!-!+4JPSRo`^w^%O2J)_qy_7u;^Ea*|ne=X3)m&d1(}Y@(MX7hCt)=kkvfi?{hK*_$p?#)z$fB#d-EyH959r;Mhu zjum;5UYNDZYstPI)oOb1z7WUjvGU0pvrb!}i`l~9-n|O{P$$2Q$?dE;p-!T*a!13= z)I>*j@gAqkmihg76^O|Dl&W_YP@R#8Z%cqS+j2O-n{-%G8Mw59=hf5eNw^_tQT%bs z!$yVIPw58K>m9s}JbH;hmNKJ;kFtMTLX!A5(1>jssv)I2a)Hf6H_W&D_N_K=Rd2|FLD~(HBuMY>6lt#oqcrH0;4dIOy9S>?+=~29m^3`rsmf)gQKtpK8n!mlK_ z*&54I<>ez`(8XaLFgfO{*XjSPFES-yInw#m$l)|r&dDW;h(r5iHM-ZdtZJg9rIqLW z0?k+)2LrPg55l1}#J~%fi!qX?E|!&h57D;J?JXjBbELdMWA4AC1L;?`_$~um7h|(B?tlEl?e0&MyOo|N;RJE3m(&7%U4jn_Ob4E-|miFuD!-Dvzw;f^jBBvzRK7D%>_r>$k#f0!eGcX%#Pe*BqCX8Gp zeVR?i1)e$^BNyPRWvuSt&}6mR=yp<~h>BQSF7Z5iwqQrM`qF(;?Vs zgw~U593j**tz5_oQu!I88>!1&d8= z_-7SD!)aVZmiD}KArq0^=#j#o4Yca4qOjtZ4$V(pBC$}-pB7Nx{awct^t}3)`=F`ItM#>&eeRh=*9{=P_r^x zY84uRH}nUbf(3iuDFv^Io>n)jy_vY_lYl690C_~J?#|Q_mx>8Oh{#e=1SZ|fQZiUj z$>cbGGlQqZn2w~Vq7hO5$>d9}CeYhq+y6?pFK<@=#pQh99nl7-F~6bYTr&M|NYhKc zSob5XBWaMp<6yqOaw}t=IckN6&mj6mzz^+~+eIHn6<3@($uIoQqXhiOcx7rg`dal% zRcIG(ag-CjHVOz^2Y?^gENj^M*l zQlTrL$xGy9ekxoI9+@%k)EluV(iT@zQ?#cHc8YOBRYbnh%Un4d_j~nEn$~|w6GvDk z&FHn)w~%0`vlF>@12)uuCV@n88Q?(tGjfiep5--5!8l-Dm(X>{Pnij8Jl};!W(oK@ zUr3eoeC2VhAnI)gRehZ{C~fpg8GSw0c#*Vhdhb2;2flds;V*m*X?y%#^J9M6ptXm z*+)0Ye<6lyw?7br2-icO91-_HAc>b?`rK*L{Leh4HAj0mp@%8`E;)#sbskzfv}_#9 zVPx_L#AYf_SA1$`87$t1R&Ed|JbZqcj9h(#JDql@J$t-SEa+ikPAuw_aU862+=kse zvCt{DISd5!`hqf>3Y$Kkt?3LeErg`EyIC?_s1_)|YtG)(6G>o+fy2+;<~qLzbm><- zv&wJa6n|24!Qs~9GQ~#0Z@6DWcQT`noI09tU0r*AW}Z}B&zO0V!KtvU&n`czC?{)a zh5s)KzBirfC0A62lUg@an#+(TMTbkQ(#u<+Nf(T=E6L z`25Ofc^f$rMVn^2EuzpUvfPyWO+pyOped z^7vfwd??F1AgyCJFKad749Pu5w1+M4#;$%r~>gx*Sz`PHLi+#|q- zB{I$-UXk?w0}N>$sNLVta_ds#@MW{!^~-L7by|8(n#7Gn>&n%bvCRIK#^u z7=8a>`|jhGGbEG1=wa$!8XGYn0F!7cg)}z|e8>oTrMXyjkdmch=)a7I>)Xj15K#1xj%#ijNh48?0w{*7-;7-acbPO8qeXNp@tMGtHIOq zH6}q>j1a#1CluWCkv3ztXNx!1bNkb;!ag-UU7gj8Za~3DOkNZ$85>M@ws7l6y3#4t zE3Z`A(aLyhiUzh86H|*BnFrt6nX~GBzupY|Q{m^y4YYr2_ldHlgsNOgVCASWa+vyS z=sD&4R9VA+qr@90!@S0>hsESo#YA3ACpaAalLJV}+$1~7?r!K+O@&T40NJeN+XZ&Z zpOC8d*Rd`6y$pL`8!w6!7r$+U1jdX??@v$dY~H80?tEPP zSjFsgt_6tJ_psfVqVkBaGS_vUNKsF65v;MCYtn6Z0ershv_z0MWALTDDejx{X6m8> znQNRiGSWl9pi1rL^YvCL)?(pd!>z@GXP@<}sp!p<8PYtS_n%X_HEAMZf`yLGo8y_mR01u)2ir|J z4BP}q3wL2G+^G*dA+K5%V6ubeM#`(Tc%TEe`4`;~qICA>CH*;QMf}x_!&*i?ZEC$_ z%O)|}KvDA%Lo(fsON+*ewoKs#>Rn-bXvZE5xgzZze_1S%NNL@l0(Ywx#Yy{OU^u-B znTQmUnn8($;Q*XO$_O2^ejU^Cu`yQNqJss3RvELrnNNAwUYICKa3`d|1|RTVQlF9Feq-ajk+vh=!ljs&3u zDEc8q9<%O;s6(F?er(MB*A9;vsxQ$PX^@F~4E|R}c8)Fz67!J4wf^KR$(Z?fgRZZR zz{|*Ii0dLckm)I-@Y?Ql+nJeJQGkQ(51w(W{vSMJRh;ENbOu^0=&}GBGWPDMsxcBj z3^iGp!dy>{?0gL3*a>T35S2ReKVmIEUuX2ToP?l2l3L@<9DH3*2V6I#&o}-TurZ@K z71Ct+Mfe(?+pFbQ0jKkL$#x5q4oQ1ntC|Wt@5bW^qCcaI57d1)`T$rCvmBwVixNl$xN@Yt3MHFJ}-�KM6= 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 Glm8Eh)%8XI diff --git a/ios/libs/Sqlite/Documentation/Resources/playground@2x.png b/ios/libs/Sqlite/Documentation/Resources/playground@2x.png deleted file mode 100644 index 32646d6aa411b7b5a7163fc692c7252fe8ee8cce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 124729 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

lbErWo0fYUhNnO45# z$`$7QX77Wt6ZWl~iU*xbsEqs~%a&q74RYMj0RH1XJ+g?fgNiDl3|U-nNE3;kYZLce z#y#0FOYHYkH7{=sTzYI~lAP`6;@fKEN7+O|_wsGjB(EVyokJ1EFv2;DzVT__rv3>5 zHYp?9zW0&q8Wb@7{u`dKNX7ox_Pz#~94Wr*WJz$whuiD}I!(_{MpOEG zTXe*4RuG2-e*PDSRm#$u=y>!mI2Yg|RrJ0t3TAvP37ql?>Ug)|Cx`1B%uAS~zvFq}H+B-PsX= zzRs%y0A7;!Qb=LXjBECC_&MEty*a<8Nk=j4@i0yv)+Ai_lO1;SGlpk)B=?{jsnRqo z7f{rb{@eK+E}6O7#nzR}0f)~;kN`LkhuI5Lm|_mTVO*Te0pordK4T68VPk`= zb`{Hh-boa{f-u62dT>)7VZ@gU7i0SE&)XB3AD?;)d%_}dO~7&R{3R5Run(32waa{N`IM1J=fPPTIURmz{@ovjaO{WMXY6WN1hL> zs2sQp#2)CQ!tBcQ6UIt2k{Z(|?BnedyDhGtqIu=HiEyb_P zpIM8NtF^UgXrkn+`W+a~6Mq)AKxfd91^&Q5)pSk^`(Ktp+FV2{Ub(WqAvrb^j&FMiX0 z!$P@QjK=3+BtA_L3D~HTu~P_xrh{NW!hDf!)5jD+x$3T6GrW&B(K{8H{M6Da*snW9 z6yOBB7MWC(bRO*bh(oXgW=G)(~TrEAjJkm6PlC*PdIg2K*8tQR9 zkXe*rt$lco!#|bNXfuoHY|}>1b?x0J{P-Frt?T|4^GW`7t<3(Z%eAZcD>sCIzkai@ zI(+1L!u8JK^^VGP{!6+21^W)7SHM^UM;Jnzi>0RI5r$)=nqJ(KBHDc?@1_0%&d zY9GH=ghD3L^_?N!fAn%`)-wYmh?eiZ+1SOV1ZxS1Hg8>N)4635_yySiO7Yafp|KEz z@^s&KqAbRGqre{Yf}{Nxyd_J%`Q^*eZCeiz_x#Yy_4%%1894DqM(Rr(yFW!`?j+CCq2$a2uKU&le zn=NQTWiVHXOqw91>>c|YMP$oVpP-i>U&O1=c#e7Pe^-%c3HW+pJ%MbSAz+@+?0b<(x}`sMki;D|VGn`Srm=lEWwy zWzIhVSKL2dmz_w`IL}fv?xWIX$Mmj=a7l{|G?D1KOSAf+Tt0C@0x8GEPjwUv@p8-Q z=GjkeK0$u2`fgI?G4U|aaOJY{jzjn-s)_Chc~DmdE|U%8NLvdpG?LfyPcb)e3x{T{ z4vOeGvYIu2TEp?|Sr@7kM}wxQ{t2(q@L`C~A{`pP5%s9}V3a3YH@(b^&KDIDjUMY| zmd8(*S{@XwI4d+zK~qQmD1!G_8Ss|B&TAhjdC%k2 z4HsUy=?e&V4Ux7RJby&?E_UmiP^I7jhe;wKo!>xX-&r8TEw3k4^4=0|yCUY?!Z>9Y zR^Pm>i~bpKq8L}xiUxeDd#XCS^R_;|Ct2`lGu?|zUitR3p-*Ox=7Bd|Y2!1jPn+?U z`*UB@r73LV<$kleOV{+8OFLOqr&^vaR1=olz|ldG#S z(S?nipkcRNk1)+4qAqj-0}4h=n=|3gw>|V_NX}knoXW?lgq@9amk8jcUnW^9x0z2{ z_ib__YNVIFI&|vb@nMdbbIpd&suxec&zq*-K}Ei%3uwGCVN!%yP#>rb%)<;urE&VU za;3YHqwXo_Ne@x<(}p-_A1Gxt3&Vn=dA_L!!hj_^RO32}H=mTvoIQ_7fL5IPm`lY z09yH7ta)!|_Dp#th=Tz1+7@ZzIwK2ESA08F{B_UB;oHf{fV!v~qyCTjYf7}X#xm|< z+bL7C$#NA>(_60{kYY;*@=xXI?QUY*43~3^`Zv5&9XZq87w7d8Gm<@qVWcJG+0dk# zYFGyA;qFD+13D$*ln>t}`DCUi{k6g}n%07-M6@$N+ULeWMx)|$}(IV(k;#) z7O!q}Zaq_Z-x?`E=iy#y(Ll}@`H{;*%p7;c+}}53?`C_R-99|}P7b`D%t#o@!*(#j zqN|s)aZ4TRJk%9`b#$roe49p4&Q;Reb|2+-y^!ee)A8jIBad0V6+AyYUj9-(EIAp2 zC@-F}eUP+vzU5i=tPCg}KV^|SUi9dUno=k&PXk4bzd-8fa@ge4&#-yn{Kp9Wnk(ea zk=XSOIyvp-hIB)7aELfeTqmsrwbjhI-s2zqeKA0)neTAvoYu44*%SN&;c!Y*Hg?V%CXSVfe``yr*lY6h(5%7YTuYfnL z@k-h0MJ^5vlL&^;Gdba=3SxWJzCSi_#?{38-RH4V4r2wkMe2ELs8=(Z=$qJx zR}oUtboyShJfIx+ESPp+jV+!q%lVT-EMflnGnd9}jsY)v4HHa~t>eJ9p`+8YOueTI z^jB0uqIq_O?*w@EMC{rRte|z0+5vZ$Z@|I{iA@FTs>Ala@JwmmWftX7xszto+1b_l z+hY@iRG8+k>4M&Tb<-SX19Z{wH-l?euZ{$2O#y=?lqJmHu9ZVAknXHI!~tF5UpZ7e zVC%icKz7gm(sB?`I4+6wp(jVt*+_Z+*wFoR zrS*c)H5QMm-)^gS8uKYT%)aWMd@Ta^HFX;-M0x|wWJxYcI>C;MA&~c_R(_Aava(BT z+m&UWV=vO2OVQce8RlSI_~d5MxAksi+0wg-`ULa-m@fO8Z+(mZzyE(QZdmoroQy@H+b$1n#GJ7ux=kNoHrK z17h6k800PM5*`F?s!h04-XCD+qdZI57IBR>K`uwT*M|l_;;Y)v7eS~thDumKi*1*F zHw+>}Zm(YGJ-`ieEzIa5Q6&R4&V?&`7?U6|1-GRSrEn|Mht+1O-)w@_`;DWl9J0yP zFl2i3E{|hFX=ws|`fEvLuEimRHx@+BLPVNFb+_(hP5rhG(zywbb}nX;CGTSWtM0je z)y#WIb*d`jwt;Tg^r>#5G6alLp$*fRw zpF%H%y(jSum8f7~t@`=9Aq;C|Z`dvnU+r(3t($-m5H~uJ@eb3W>m8C@YhG4i*#e%c zYY2^7UleYGjh?b~KJpUO~1j#5)3*)J@5+CM}g zz^N7w@t^TB6DK(8B&7~g&61;^jLfo}Prh#-RXSPs;l7SE<&A+coL0Z>d-$6RR68jI zdIq!i(9P=ilJnm;C3n9(D-srr&PSV(lD!;;`kA-71c@ih*xd*$tcL7YLD!!2GdBgG zO3|~L^O=szx(AE98U3QR=6Ni-j{46&Pz4MAIF2(=*U>Kko#EO_87StFu~Zj8B{Y`? z$~EwAgd3=b0Ui-O`=9ChnWmSir+9irMwqOx@%jxvc%ib9JFPosSIp69Omh1b&Rd0N zz(r7ZhWZrt!aU5}gD+C=nNEXL*?w7iiCCc7t~6n)mLl{y(AIRFi9?~r z@#IkYWy1Sf%0pmrjr_`|@S+NXv2u8BI(lZhbZ0#^PoAwHi_KJ5D~ zxugdw18G=+pneMSBTG>l>FBX)LO1jFT9)_gCc)-XZ$pmU{%~IX*eNpO&CdL;Av*Lz z#M^D)&c{>weS(LQ66mvZmiZgZEZ2|nHu4=)A-Hu8vr41FqV>>bLL55RfV#^y(NK32^B~O z(*)Dmt0R9ONUezN7XPK^JT-O4nS|~T5KJR>J{Ty+pRjHtuqeF|*S7tg%^~kn zwpXNUP?2V|?Y8U$8C+#uF@UO8)6!l9eN_8-S^=akj#7i*dAXL?)`_Z#5B@}Afa2^E zCleBu>pJp@T861euA`lxFBP@d$89HW2K1(R$27q=KA7toCujqdaBvwz+~kJF%h4>% zYL!dO6OqZlLnE}zegKD4z6wwC?-J~5+u@A-UZ{V%>^hP!5ooYh(3t9ibM#bq3;*g}Tm!dNdb=ZP zyKoVg`srO0;*(mhTq|I{u6K817PXr&d)Z?ByK{3to9$s)sVv-cmw!W@SinTA3iwJ2 z0(7OnxV&LHt`AqNgH$9&JaVKtw}&B{oha(tr20}=`X`_>%&TUF=s6}$)n04W1JLE} zCueJ5I3W>l;-6##MFrX(WvdJ9ydh!F0|v@knUq^An+qGSgN*AJ8#PT7SO$thO|I|M zgN|nHNi4R7nZ=KRTy^TzKT6yg@7DGVn@xLB(JwwsyrwSZ6O1rYS*{Qd4C3U|!9@pZh0>26bo^KS>98#F(mZ&p_(NVwNuxhp&1_&txKEA1#L&U3KKc=jxAAgyeA7%^*E z!x2D9ErYAK)HD^DaPB=Rn|QFcu<1!?-;}8MJiktdvgngsww>%#fp$yN$$3%~sslU_ zow6U}JP+o3hA&(15+Jxk`OhM%GNsWl@K#k}tjMb+*#p)R4XPEe_%E^_>u!06SFOl$4{$O?YCy$>XVl zMxzn_^YN|m^KCC)Yu-i0#7+~eT3_rck!EG?>iV?apM73b`gH^cP)qIn#WMY|_^tu3 zoNY$;b)(vLq(Oa^Q2L>oPykRDF zcyj1k)IXtzmA#Bhs{)R=(xFk?jOBZ5frq$iYB<7U?`Hv1QvhQLS?@4;(>>t)Ixj*t zE1ZcRFco8!)>O^*q+w^tzQ459hNxv(O^at6O4cpr$(^n7Mgt_P>- z|J%?~GbvP0ugyd+#ehr_ChsT38}N1y8Nxj?36CP^fPS3IW0mUuCRDGX`^GzcbAuZM zhZPupqazJ99hBQc-lvdsIphR-ag+XosOAA-(;v5o>y=9d??Sr;@91l4!VS%+kpZL? z16$ziESR=B$qyOTyfd`Uj*JQ$gVK#^<7ee^>L=Zc$#%pK;sP}T&BbnoO)zp=&%wDK zN`kzv=^HR?0#9@LvZ=d?CGl2v1~bileC?8C6j+N&W3i9 z*pGB!*J`NaGaQIB^JoJb@vFWm;fIGpGN%0A`zqOC=oLR_v5FR_8z+($29av1W18O7 zAWV;-MMK^7#QZeLYQo{K#98A&RL#9WlhUD8O?s2uIh$2lFu1>OdLv*-1KRcRcJD{g zBhI7*2FvS_Lq~U~;v9N#!+E$_2XmfEFdACZ*wUcv5+9Kzy758VkW_%s%!S&QOa;F# zN7*dJqkN`h{Ghuj#wf@7;acbZsHo+hP5l)f);I;VN-dj(&zk2PpIfFqhu)(eM^;Cr z*Q`8$3E^Po7N`Red@GYKo!#A-|Sd`Xgj0pf-Kp zW-@C-V*h(Dq2pPZqsjhb?K?f+S0SOa@3cxxYEQA^k_uTo@17V~+M4vn`@ek`=l&e8 zZnpVOUtfQG=EiBqKEd7Q*);ke9 zHvqGj=s8YLO{11ATG<5=$=(uoYi}8{nZqB8kaQv$P_9v-!So#)5?&p2_CFeWpc0Uy zF__DQL_%boAZxDIo1E59- zi-5ZY?uN{na(MUky)9!CB|YRg{P_rNpQg-0yuOf^A$-1JpU;B3P80|3pHFsrTOd5iyg0 zm2#(DWA|EKs?QE~DPKx^(JSuCOVvFhn72Lha_1&h`$pWFLd+W@VB{*>ivkrcafYR) z`&ToRs5CVAfUZsuh@pu|%BDEWKrVisZbwL3+Hik=zvl@s`eEo!Pz}t%e${hjelGEj z0+ZUAnpNyvH@(ATt%Z#5ZB_&E=ivSF?aUgvNc`ky6>S3+4i0C+QWrM*ay6@D#Ur|a ze>m-|vLDc?gcsMi2<_OvgOsz(_rAbsZov!wqZ{z^*_SIKsL4x(>?iDVrnl8zk3~rZ zM9ghtPrrX>mG%+7fvf++>;bcH%TsgnbPuiDO`SHbTy26+-OO?Oc53Vb-sNf$H7*yn zG8=#K6qQ5J!0d%cDvF{_dirUyMEr<`#`d#>4^Ss&(EGguCe!X z@B$q!7o)~(wru!Hab?f1nd1a28afHN7EHR4wgoR2Q@uP$BGaa7cVNhX<(e|8qORpf zrAyZ43hT3`%QuA(exBCB^RFTQVW0Z@ly-sat@OvaWl&xr#%di4qUz?si_SKbY@6g4 zfYr^i@Z6d2_{$_em<8mWMmEne!!&2J>?&jJ-n6^U?p8ai8mU#NbQI6BQulv<#Y1(K zR;D|A)>YYA0o2Et|CE=X-tr4-widMcoa(e2M(`n7FO4GJAF=7r>wicybSvfR{(y{G zq3VkN6uMj3-@I6c$w%NCrp2RAv#j6Kq!OT3nrLh7A?qaf_1LdyfY>k= z5tE?WkbxEMOg3$c58}AXF&3V$atrU4m1M5}tTE=sng8Owu@j4>`obQC+umEZd9>Kk zEXD_P2fsM?NYw}{&`09 zYqcJ<)833c-N~>Ux=56vS&&XkOB2(M3;h>2+Nm6L8#|7$F)DhE0fCK;zQ%|4^i6Sy zV^7(B-wUY1c}IZT);={b{QeelF^%nkP8(GoLNkYl4Osu(aEfB89csUl5+w0me1q0M z_5vh`;O7YmTc|qSzRS;tzV^Fu&(!Z&%chl=Nh@1GK7D|m=bl)K@emRc!dHOb0|0=V zQ8|@wgsHh^-@Yl+vxt4)w--^NxYwIHI6CV3`!{rSbS(V2AN?t@Jf@*mYCh})8Qw0y zbd7zek5lj+WErj%r6W-Fk4$Mk=Cpo-maDh{_U__~(nj^K9 zlxV^mhzA746^dDxwK7W)zPXJ_K*#Us>*?L$=MM{AvdzuS#ecSZLrY8hAu%zr0&c~% z+B94V*?HTA_TP2DL~*dnxZfiGn?&4Zeq?&<`PxF@xZxd^MR?tsX!1eQ1=)=7s-LtiTJS+&$qcM-HwJXeQIlhf8w}0d+iz_VaAcSl(I+C_VdQb zqtTYggr*uTT$Q(7>mCC=2VjsT1aqhM$U4mb$B!TQM&HWTD2@~=UkJM;M>CQQf*PzC z*j(Agptk%hZtLIwhQN&s?liLEIKe`we`=YlTs-DMZcP2JA{~_%y`Acgspb+nxj=2XgIgji%|nFA!Cx^+wu0XUDokF^rX`R)m@|@e1dM8%s{=2>m1IjMP{tO+QT%WXdCS6RV zZG_BBbZNCszCK@*jmaDuFQ2{B0FkJ#z^b}ft<0;Lsi_acsk|czMeb<|)+`B{DtsaB*; zm2pO#ziCK%ti5~n&b>8i_C=_ikBu(L-!jTPzC|-GtR320gGC%suv{aY6`jrsUqmiC zO+d(KI^iTvu0KD>s7l{_mD4|(g`)j(9PPbnQQX2lxP?a6Nkr`J?Uk2w{6Xi%i^L1j z*&FBC_aPQgS=sGFDvXq`=ac)$5ULS8pYBuhwO7s&o`yJL^iE+>!*M3CXyDfGcmGez-)M(hJT^ZvyRVg{ zA(W_i1-H$uXeIi^r#@}3E*4ejYULTSS7mp>i?qpy2J4H(!a&4pLNQDhDxb*2=;g-xKe!qpoAo<~`cMp@loJ?irz?W@j~7E5yz zm87e_M-OA5D7u4|Bn1-@_%e5-pWdi!?-?DwRRUlv=?E+Jj;!_a)ne za+yK2&>kz9kq(}eUD`Rq3~akO!j<8=n^FodQt|YepNxycgPct$2*K+oC&-WH7EV<< zZGf7yi@U3U82qv~_!<7$YRFmq-2ub#Z2PUC$nn-wEk)$_EegK4fFB5@vb&qvAa5U) zR%Uuf)<1Ra%|P&=^ey5!c~=F#(iP$GRB4zoKNk_4#$v~{;(!(I7)ySsBjU{-!Q;xG zNy+6&)M*wsySmO&)i%N6%L+hsTl{KZi`>EWmuv>&vXkpbAe(P#T1B?iziJ*@HlxZY z;fBY?9X#?|JwE3GU6#27lugZ1-8}!4Jjyt!Mh4@x9Qqdgv*41VL)*>D2znD{F<5^z z4mw{rl$SBN{GJIxU=Rd*A}a|l_1v1@fP+2luYZ1NfsKmQ9QcV}vfY%8q>a;L+born zus2JN8h8}l?z=%Qmn0CCN0}aHkn3dqDna9_beBRKWC&zk0=bS2wr+LvxVXI^A2&PI z@E6`5O36bd_k6>mQ|T&AR)|CqVhkP{9o6ykgPgX1_zS=E+aKwTkPEno*R}IpMQyny zsoG<-HF*X>O!`Bd)(a48;!gj^O`*rz)Uo0{s)N)<47F9ZvR@67D*gDlv&o%YFvp?^ zN0GV#7Y(e7jky_?yi>KA&_v+qkRNZJQy_1t@*y020ch5TwuPsjZCRP*;1Xppl}Ztr zyuKI!A+%oExUHw~_~z`tl?Y`F=oTQrs?tz{zaW@VPAsd{Zh|aSqH4ouMlwJdC4B2O z+Z_QrFPV)_AZf1mc`C5xB8q9Hl~#f3+h4XLQ_zD0KS-C+428;#qW5RGSCV@S?cQih_jOt^ukE|=oz-Xs8rw0euOUPV{_xyNK zPW}XG6w(B=HPa2!^z#qf<_{D*Z3x-DFb>ZtmAYtjoH7eBIiTxhVpE@{L2hjgqZhJG zv(ilsdnO%srH6N{OU=$T>>2aC4V%XlVhSd=SqiT6-zPI-t(uGwBz`xa4O|27@!dvA zT6{-zP+$R&j$o+Xs{kz>QP)Jv^c!@mew{79w-mPivZxHsq0b9pmku2z zFB5I`9R=S~Y2~D}gZ)}Z+3I8-vKtmps)&h{SctWHrnI}BSIjSty;wpQy6B%=MHjE| z*AU5)i5?oW6ch(+zBjh57k5heu5d&*Z;i5OKY`7+-#M?^^Eur{smie8P>%=)4ztY=Rsg zE23|$cgvc3x3mQw9`8Ez7{D-OnIJKo7lZEeo%I8akmvC~s}!A` zVD)ic%ss&+=65S!yUw3qI?54Utkz8Kl4R z?!#W2An_iSk%Qhjxrl$94fAvH1GA86_Y0?5u|Xf5jxPSSr4FV04xcEaL3b#ufv&7x ztV!4FS8UVfl5x;XrI(44dm128XWvVR^;3J3|B69klvkZ&KNKoN@qWZ`6Y15hI+o2Y z`6T$nmIqaI3Mo18Ovl|MkNBo#BoDWjgnf5EHo7y9%tv&D-sfVU=x8-B3xL>Nj&EU8 z!TI`lE*cO*AU_&PIFoh;5H48>X@d{_i`)VXOLERzmDuLC#v|pE!x!6k_53s%ycLtR zB%_6$VUf?S5yg3uK9>h>g;1a)OayjYXv5d~O1Lj}(ao__c<86Ha=Vpdv$zG<*fT6i zyWcim35UX36tFOmBNvIho4NOOGbi3Bg8>t*WY2ia7f6JvidDZz6~Qn;L9=y|R>=gV z5HqY6}Rt>GweBx&SzD4K~0M5Sl?i0X=k0Y^>AI&GCf;Nw22DgXX9(YZ^)-)(bZ$S)w%49CF)s-^-UL+ z;08T0YA1l5o7r~kGkqQub*d8A@;a>()6^@_60^-H60?EXG=g9581#}5zchq~NhJF0 zg57#CUx8p*cMFvl^L4k_Bek^(2a|^5-PE#k)`_eg!JlEN0 z47%q#^E0pR8YRi7q9=c*i8|Ohe8W0w+8sjSDIXfUymPJ6=5^WnE1gzn|6_};F#VNN zu^p}Yy?H`>q9IB(H@)-gyp%Hj8TeP&)ao*=ALJ9^Lm~!{XI)hYA*txRMj}@CA4Zzr zhayNqwiT0$Gq}Ev353|)j}azY?jTn^h8o8C2u&L-)~Zjwbv7g^Ty)b$EMyZ5Gw4mq z^(m_5dg}SLYkqz`&X|G9$(7I^pVhH;A!qvqlhr96@RBT?J@-fxu!6^@ulVZx=u|ko;LM`G{b#^PVZMQ;}BYn`* z54%Hd(o4U{SqXM-Da7Uo-nAXsX87r5Fr&Nhp6;vc-rKiGjCM4X`iyNXbZ4@arNfYO zSebex(_&idTcoQ#M{U|wD!;#oM9G%B~YCR7kjS-uJpqO%niqax+o$*G8)>4it<-!Hmh2vYc5<68fH7UVQA zF88YCD$U{(9jlzivBee3@D+ADwB; z#$Ct}GhGB8IDsN9;wx$gDL7}3dRkG=ua==5MPhU9S|?jm^~rvRt%mAaMr83sLGzF2 zZTliAHXpZ}E$a(5y5%h5!z~&;buC$q83OjNWZ7j!nCcL`n3C!4eisVYmts{zS^Oq# zGXBXPjP}C;|M^}8P-|9@G;idse*CD(f;_7Rdk|xG_iN$8Ed>SowRQp@G~wU3S$`F zQ`_2T_WeX!eKT+OO=Mtw=iYP~%9@$Fx_UG&1+RW^cLU1QlRetZz}e!v%%8TgZF1xd z>k*}z8ICqIw<2zG|ePBxa&+x3fq zw*LM&{qlsJAGHa$C2{G_mKiMt8d=IW*%y@87JDep$~NrxP9+nyy^mA4DV5H=J#KYs zCl7wWj{7kA7qj>6fv7pfM#n0diB*TUf>{K_|C+2tjqhW9e0gm=g3AwvX03faL>!mM z-lkzWO0<9PP~IlO@5?-6N8+}zPU*F?b&6rDUD)@9f0?#o3U*y}MOc+FYZ+Mbp@?oEzzlkw^#yCW~f9lve%j9(5<3#di{?p#5L1l9r0_L;zg!_5G za8KXNHOD|h@>J{qU4;C}!4s~50Oj4gnzp4&XQon>ROcjDFQ>4`BUB0M&4YQf1D;bO zjlw}lvgY$!lY9iPvksW2#sxUE>W-(J!D4k|`_`vEu4)@Q{wv++tZjipBwXUpwf^HP zj!Ac1u6*Zp>>vUMKk*JdVSS(5Au1${A;+XtHQAkWq!W@Dl4Szxm5$mNFHE);eKld)(M=^sp@VN!wg{IoIAFzqnyna=zabhi0dZtar!0bG}CpnG$X42>o+L*PZU~JOg@9^UY58CcJ*T3Oa6d zxMsoU10;Kfb=fF}Rw$=gUdBfSAW7UmW@nh!X4L!W>L(8--re{Ot6qc~m}g@ouC@o< zH(7&a7s9Dj)C!Oa&TD5Zcc`iHwH}wsb2UhgYqND`ukDhXN3juBl?^e5)3()pLpkjy z?MxAkiwtDU5~?DU=nQS8?j>`FSS86Ec9#+zWFVMuqK0@#e+VZA(`Ow2ne-3l|1rwbIwx2%2Sg7yPJA_p5Aqq~2Lb6A~0elpT zIiNP(ZQP4`oxfkDjKBYFvtjrE?p*CM1#))NzWIB;`S-2bVNicX`$fu63bFraK3W)? z_8DFjfA_X=+9A;j_PJO6&EsTfS_TORQ*;z_UG(MmBeL;)lZM&@v!m_EK-a$O?JN!^ zCTk~79HRF7JD<5`7pv%Ie?yi^J#^M$^eMTvY{^xP%)keFRMRvR_iKs1{kj@T<`q>X zPkEK&I9XH%U!_4#MxIus3$UHol+jviz1{d~Bgb{GQgvJ3TNW)+Fwwl%G17aqF%_qt z_tv%<0)3al<@YIF;H2uKuCSCn=02ykJyC-yWFW(r{%&tJb|?5Co?$eYKanvN??z4R zbvSL7Uc{&erd=9ue52jM)5e+h`&KNIJ^35|qfS&Ckv^aVEhGdcT3VQn?`as2Z(@O& zU+s^L<8wJKQhRMJZ=G~F@ei6c8PUpR?u;sd!YVQhml`wkQ;U`__u_ zl-`av^OL;l)vCtvpgXxaE^fnzpn-zv=lQKc+sf?w_vLAtY+3x>&O0rTqQTOr5F_iE zMN1Xd-g6Q!l)8y}HzWNHn|au8Gxd?A!OG3LCx4r8E=-WOT>ezK<&BKDUBgh#EdR^i z-rx-Z-h5A6Mey)tMd7>i*&WBE8sZv4rit;r8@;!m9zEH}jbK-|r632nD;5|S)|h@V zbnJYhUaDF0QG`pvx4U8QMLZ6L+NSloDM}kC zbNMQ#1dqCe;q)^}6(H!E`Zj1V^G)ODxqK`7zIurbEO)Zy@93RRr`m*mBYtfWduvjs zOpgMW6Lja&o2WI&Oenx7Kkisjvq>6AI~9cvoV;)8q~w#bPK7+-*$KYeHGT{ zQHwTzbZ{sm-`@kyXEDp7$IS0(-j=JVH7L+qxZx&GC`($rHZ&lDIyCy;4PeZ9IoJs{ z?vUvPjoOHCK&KersaI;N|4_U<&(9Al;LZyO7r-4JOSlmga=b{O+n&3#$XPEl#NOt=s0apI&ABq7R)_e;;$JlFLV zQ!jc}^qc$9#6z6LR6e`X?wC9o@Keb?paCGiJ5f-#$$L0kBjJCw8WMQ*jl)EgPIPND zOAI(8ss`un2L?YWKl>CNc19LwJv#8AU)9IC!&s|!ktpHJJE|!dg|f&*L7~ok#(Jz_ z`@O^M6bYf(bhGjtiGvF193A&7)+2~M<;oqWuFXuJnSX?Q$-B^z6PCwbW&N1^5ko)J zLmaRY^}t3jmBV5|`Yg;+7I=sWeS~{E`>?VRF@o#*-zHPSMoJV5c~oqJh&=1CG_ zr}813E~6W<;&dNzeKJ|tHF5hnyPu?}ae$w@!aWjs_bT3ExDcBE9vO)*9(^#mvY@t? zMR41!7rhXF(%Zy0bHPhQ52ld4X?_1o#aWeosXNjK|60%WTQRFEkNzSn$@q1Fn(Wn{ z@G(X(Kbj-X+Jj(0G*_IxT9PnY(MS2l=Lki_nOwf|xopI9>I!C`jq8_kToxHRe$j5! zDj6rGqbl#kR$x_p5ko6$iLk;VDS2uHZdMsDrOE<~`U%TaJmL=OvBYiM_+_uTs4){) z<~i)_%a?qk4xL+v%GhYD^TY@r5qXP>R* zRYmjNjNs!?Kz6qcH%q7VE0)mg_otLw7~fVTy0(_;x3t=J){!8VmDcanvMfSx7p^+d zxkgIi>3*?z(ur{4yBgA=*OYh6Rfd97_oH*_x)Ci5(WoD{s(uH#bHu2v^EZznzHEHP zvYRyapOFydvCfLhYD-d^qWjzNI%TOcY0{A4@6F0?_puH$&X3}!=6^JI)s7}Wmo}d! zEHAX+h2dnPeH}uRMcsIe%QfCDGmTXwIlLP<7Fyi<(@U6Zo4@MpdcKUBNG0p!>aH*> z+?qPS__C4W%;=B`Y-l8vFDpOqrJSV*g6_uip=+Fod$on!pRb`7h%d>QZw(CBUJ@#! zz1__IsK;+WZvQPw8-LLaR$#3r-oC6?eIUYR^;_@`KQaOFMW{djTC8;aRQr&wqLQ^N2^`6?r?nqFW-wftKM#V z^7dWvYn$ssb;ba4Yt@SSseMG@REx!DR)fRV=zHbe(hY>dv{~(*9RF41$%B)PcMYs1!RTJUc|XWo)$rjVGh{`BAY*dI}YUzZ`OR$ znl$d1l&T~=%Dio~ts-5#X=3#(>zLXR>TiL+fXI4dR>WN(>J~O~$>TS-jY1MsTRjH3 zh-R)0i7H`M11QeXCI;-fHJK(DMl@i|6xNOdk;=VyPzRI2t_qIiYxb0jYa{PWT&N$M z+wOXcXLTAXS|&8+Umo$znlbiKJN1*Gx#@shBaVsni3SFY{<$d}?i(L* zDF$y=;_s5>yRiYZ*rmL4`btW7+8;;#Cah#ntGIvE`I-8rV7J;E7sIY*xFhLBJ`we z_@^hj+;;NJ;13J`)t%nhiJaBGv75^~U1=jLoY}U1=U>&EC*!g7&Pxg%Xp(6lgPTUj zmFpXdT6pl`yc4|SR!Zo%7z>&BmYB*5J7{XCsJM&vwDQ`IOmfE?SH>cbETrBZ%or|BHNGr%csd~XK1(xPZn*JP80!^Z zh2eHI?^2nuNbJL51=)dliHV{EqK8c%>qs`qiHJkr`EHHO#8Cy6JFr?`&lYhxdfL%F zXZLT6NIxz2vX)N{b&f+Fxemzc{{f!(XoVzcl4Dy*`o!)qc*;-mv2f#y^Fl*AaaxM| zP_t$4_qSnXm~asjduw$q`&DeRzas&2(VSozvv5roCZ*wt((u*v&YK8xW1*>!vF_8d z>Mx0vgh}c%{NRNq4K0;4c@##}0?as{$$~*>o?-I2;b2CN8Gl8EH0D~1tiH{|d?~>- zKLUcVQ5ByJ+F+@GeA;^H{h*GZS6-VJqsnDSt0XDh4iNc{gbmj5v~B!jyH&3 z7*lXcj$vH}25C3>4(Zgrf?xTkeOcyR`_G(hAvnDzK4pt8cB!ggHA4tagsH_~loeBW z6V=A`Pwd$?CwZMp^A&nh3>7kUPfF`~(ht+cn^Bsk_cD6=l749@4$ie*4%S-shD_vt zYhb>;TnVr^-5Pe@El6&8=|xh)mR!EX47wnfvwZ}Xv9r%eb2lAT9tribQg|PaQ3Dme zNg2wT;a^8(JBTH+y^znM|D|;3UGmknF8Ou^<9er`y>R==blBl!M8xV5>87MA+J{Pg z=k3sl+k0VFsFCWd?;g(l^%>UnS+nt{z8`NEMvU2Aqzw!1mTGQff9EYWqd(c3n{q$7 z9%(i$^F1^4h;JoHm0{0;2cL{6sM9KAm+$7OM>c7B_0Cgpz&zii<EV-KE=$cf1&!&I zoeW{igD~mm8g+icFO6m7ZHW)67=jdb?Yc zl@I@Xx>1%U;(T2{xwT|6tPqojKan}s8N()I-$ zHBUBQ3OZ6Zz2GpGA4pWh6mupTadL#N)Vhq43+9TCI4k6EZ5GttUuhkl#XoI|j7ddy zBqWX+`b*c>a0!Q`wc_s?(hqV_EVe2{U(3h%o@A#hGSSg##M>;+$)^EY7FR(%fd#Uoe{Fl^zbYpHc|#flTb>wANvKLJsCu+1_$oM%Gyl}-V9_yeh8epLqE&T;DB5#Y0k-u2FpFr{|P5g&nQ2o~RQmIU>_ z*@e*JcFr9!ggxgX;=(O|lp5mTMsa0M77-E_^LZK{b-O9oQzm{rxw1vz(Ic{8AvW8E=-M%`r>>2GJ5*JCiTA{Lq; ze!cLdvi$|t3-6!@G5WRX^Fsn1Fqhi8W3o8I=CAplb?<^-hpLxIDInJK)$PFDAddr0 zzY?j4m(jm^gIgrVm47Dp*ALy%R`)Zh*P6@saO*cq6y-ma{C-w&lF{mHF?kBVIq;(s zr7k_J#KIiv;P3*s>6aBo{)8=4434X1_?jdV;{@s`k&^;lvr_GC{U)-id&FR3ovUGZ z6{b2@0mRQ8Ue}*X_3_i+9HV_0N^fLK3l5pCFRwYv{-z`X2F2BdtxDds_jWeJLt|pQ z`&8B9Vsl?t6xz|@j#1Ojl!IJ%V(?Bb_UGbXKcXEd{nh*V3A%hdy%L_h@8crmsZM)4 zFOw<%P_fxJSCz!f>GfsCb+^~Kl0wUudi|xm*>I)`y zTFVRdM)UV`cPqHZ^a~1ydxBn)^2v;(X}yH=VGXr8U%66%xrm;)!B0Ks3%ShtxM9wwI4MlGY@ zK7=*Lpn|uNtTkPhSO6s7Q(TO>f%K%I?RI-^!nX8q<;(hp=t@%bR+srN29bgUl1*?g zLC!Vp-+nUYiYonTr@;~HnTsLMXEOn+xa&OHZM2w7wEI>kWBy#~JfyPDfP+VrG=nXu z2ZVF*$2N(WP5Z^~PU27`Q^4bm+y%JJ-P!XKUg(L*5tZ%Idx--CtJb@$ zUXHaoLfD4%EHe&C0gZNv88_gF{DdTQeG_^+Vof=p?A$jp|6M-xdiFIpPb`M<=(V37 z5rf-NwsCbixYDP_JiR`qj*)tr=J}VASzd}lq*P%`)*_iaHGB1abodiLDdVSFqT8F= z?$BhwR1@PYpU`BHDc&5_9f#cIpdB&nkqkJLDiR;(i$SjBGbX)S^Zk8VZGMS)xk6EI zO`9=YW{cHJsI^DP6lXgDQ|;8fUNf;$KE#3MKaL8GD&=zud+xL3&%6^ptL>wuS08k$ z>*Jz%spOPZgCcreQryr$YO$OukbyoKJRP$6bv0W%f3G=bLC>S?bRjq9>db<8m#u+B z1$7M#zwJud_e}V2TFFFxbqA6;C^SIV7Yhz%rVO%XilF`tke6_Nyj#nbX&JZm%pgujjlIs4*B=4Or9a9`HNx`*NQv*)CuPEdJ4s6R! z1i;;t{cD`F&ex5%?G>q2$R3v=s$g?E97;DHs=vd0Kv2Ga>RsPmy{YSOB0IJ#qE*VT ztIfE`8W`X-Jq_TzUcAZ-o)eq!alhxMVOAT1efIqJ!r|h@_NEgJ-UQG-kcZ2oQC-;6 z%E`T;_;2=rMrFUQiSN|Xv5=~2Ii<50^CCog!_var@Bh|ZPpc%wNgD9lp@9dByHtB^D>X`+Cr{T`v-JRQS1s=UEIhDC=2p4WD!E~%t_HrYrSRG5t~G6b`P>?z5H~#TpA_}C2Tw}mj?1RArpb`T zr4M6rlaIXLZq0r9%4#@OiiQ3kSIa6(+A1!KAOvz!6;MO|r4njnOJ{ za;vI}|1n+WcneJq9%rD;KW^9^><`cr;r7LGYxc@XJx$;o~V|Lu#fFq7ssuulV=ntii;)!aVN(RFngIF)%9uw97QkD4X+~jVqK$bGzf?z79G-4xnF2d*0|9pKat57RQPkc6X zn;94bbo(@l-mjFQm6-IO3lxgE|A8T;IiHM|6h%(3`wFk7jhvYKpVv4uD!bvS@U<-m z1G~y<_+RoTxT(1FiT{)O7@Y4FvF4VV=FxOaA%te-;HVzeJh@h4dy4Rwe-hR&Cs`IH z*?OCy!NxG}Y&lcoq`+kdot7TO_?7v0_-M>$@0(9BrKe~5Dqd~5kjP?+7H|B1}MDB?D6z>3#GX#D)aONn0=uNq1F4?<*> zyTg;jMd%`O9uR?082<4a8dVr}162g=_?xwfF+$vbFTP^i2fDCawqFEtJo+-*N9JlF z@2_6}lWDb}*s~bj@C5rx?v!=e+*QkdL19xrxXizoslR`AT-%gL@g>ZKmK6|ZPSC4= z-bhyY)4c5Gw-34eBcWk^{fyaz*dPYLI*W330&Mp6Xcz-l)c%gVj&*SGY zdJeC76#vO~oXhN<_+P4lk=Q6FW5xdzT=5B9Fyh&H3S;&I>)~wSXN#-wJTD9;JY z;!(+GPx`Lliae(Oymic&s!Es!EH!cfFd&+stNlS8%J=; zvs4wrxEbHj8;9VzGyd~=<}Sryw69-K{_9U@RF!WZ{>yg;vr^%#WUyMO2Fg77bubj>(c7Iz3KoX_dJ8n%5o&hY3Jew?!Ar;Q-RuIfsq!GQpbf#eG$7w6ODET(198&V9VlB z7xpx)^|0N*8JH`!>&EGS>nRB2lbh?mXM-L*8(*8&F-eq9WY%*pA4%m^*aEh?cMo~G z#le9-oDl^fr)jXKa2tOw$Wa`|*9vc3a8AefzCPKk1zH~^hRwBx0myST3e*tFy$T?R zeL?AR<%!3!>FNx=0wUyTUPB*vL&{n<7W6QEkzwhvsabyF}qz4A@N6 z*#NNiT2*3*9hzw5GjU-N17Mzy`m;IyCD(XOU^OSB>8uDr?&YbDMDRM1{UXcZRL%yO zqRVeXAk^hfL)v@o%kZ2GhkUoq5TF|;4cipyRcdI00X0{En#BoTjo@gXtqtAT(2c{L zqT!>#@x)zivzcbTK4?AM07k9FvQ&Pjex369FSCf3r5dQHNH~)aqzm+~5ovL8x$3b> zz$6;MwShzytCoA9-LL72bp6AgClkXV?mwO3VP>!EOwhw$8GGj7QPw1_0yvhb7Fox(r+JfAUl9+Z8Wew*cM+@p zq2fXe)TphlySXz4T%XSwaGk7$In*=$zzq%bqpE4HpL=hnIkc;hsM8Rz8|r4fvMo;c zSoR_sI3DEa=-Z#Go3=$O=qyR%LXixo_G78UbTfi@yIC)_G{`Hw!kGAhyt_GMM%p<( zUu>|24%{4eaHR1&XsZzy$S0~t#{w%Rf4ugKE%6z5vs$GBfH)!M`9Nvncb+KU6><2Z zneqX@!?Izic7@HgH!fW`OlrwtrQJwsIu{vRi3P2Io&%{~Q5%4J+T)!mf0j7E_u~`F z$&7(R36y`?GcSSNNa%=Y@1grwOg;>sZr=As6Kn>JeSrO{Y;Oey(tR>p_B~Z{BeiVk za_9dzo1H#ftW#d4S!4Puu!0S!wl*vPyWq5%fpUkhmI+`Yx!G7MNnqa^ttaU>yx$^j zfT)d%oc4 zm=g2#BVgo8E63@pM{O&cr3DY%vU;~=HNFb{n78L&bPVFLp6G7yuAP4+dUs`J0oEmv z1M?E%opS=&a_nAPR_N79Ph-wMZM11PtTbp+ zo}*Kj{5cZKP7K@nDX3qj&E|DBE>qWyb?%W{l`~3}LB|)#@?AOs6Q=$|#`ia9EGZkn zwndLxJ-)zwkj|E+<2S5j~FChte4JGQKVL5JDrSB;Or^iR7J!e(s>%Od!_nph|YHp-X8zxnqo9N}L|ek7X2x8V-31#iG|O{I}F z1>9ZB*tvt7!tdHu(+)$tl0E{p5D}qo^8iX?9SN)IXk%hx+PimJ?@1w_tTY0hHy@(9 zeH{f(QrJ~eR>n%7{7%56-VJhE>vp~AIQofRcw=h2)Z+H81HRDYQ`L^JnMB6L#kBz* zH}n!14Y)fZ;&rm|Lli*cx@)Q^rSWNPH?M`W{5;^d7Q+HsC%~W z0?hez&H4k4oCf%!7z@Ck=6T%TA#GMrP_aA*6PWUr4=0OM`f8&o#Ejt@rJ77`k^TX| zgqvkRL(}|Kij*_jG>Vk9s+=l%P7@i`#3A=x*kZ-7Ao$L@c7=Yy#WnJBB@zCmCHexs z;L~Kckd#y2BFyMg3}XVKhxu*5a`(UE22}hMutLN(hDP%O2vD#fa28uM=$bB@He2yrkBUJ) z8~qJTjk9n3zAZ3!R33PWMa;vv*6s$I(Yg`6Ty&wzI+q}eSdo}5df)XG7tXm@*D!f3 zqQ=+SQC3%$^_hhKk9zKU(lrSWPRGlMp{gjJb6dJ7^A2@IG`HTTKX&wzh6n7gZ{w?75k^x64g9N8cc=MeB=GtPaSdE!^Ez{>f zje8om8SOPbacmMJs%16}0wtF1%_v6C#{-}@ravqo{df}vTR59K6Npg?qKSZbuI*|q zqVzV$lG=*z=JHSn8lG|+go>?g8w$kPDmH}zmKu5XAoqPjPG%Qi8X^}En)BWuI#DSS z2H9H`Pqs%n0En%+^(xMBpe*W8q;!4^fusG9fDF;=n>Kg&d}+n&Rx&k-52JoJ7jjvm ze$<)hx0k|wV#7imt=a7AZdM|2pqx(~GDq_0I|oRLU|2m=zKHivLkC3=(PK3QT7jTkLdGJ%vc9&3lH9=r8emxnrDvm{{&l74#oRSTC zZ5T#laE&8CfK7U^-4E$^+@Zu>0ztCbpHNT-fC;%c$2a2?uJfvrCOM-&mvM=rYlw(2 zBO9%|?LZ9^hx>~RW^+|%h-gOq1D)?WIRWduy9GyQTwM#G^VX&UA`(6H3Z>fM9b2E zMJ~QMH?Ce0aa-mqw1$`+OOPsW7iD_O+qYkD1*(2YFmddAzz;2rd@7)QjC9!=QXAn8 z;$F$(Pn?7bL zJZk|-zbC?CPRFL^BlUA^xB2}oNRSroz&VI*nPLAxBJg4Su>O=x*0_fu}_cm`~@&Qts#G4*gHVk#GB`aut8>m><;nb?GZ==DbY z9`9p}&=ct!i4@KQv(Hde3g36Tb3YF}QwT0CTN}-bAZ`>ttZLDR|MX2_%_o&mOcI=YxQQ7{-Ak?1>doM-_JYQlp zD84Co68cZ9s3B`gfP>euBg=^vLoDENt}pZr7_BHHCcY8W_2387!w`%>v!6qHPh?O@ zWgpa4OC-|hGIn2fKK$wy_51N_gH!a+L^H&}G{oFc-f!2Ky||6#y7#yvQgFrb?Bz54 z*N*m*;#JouMf$J5A+Z>i0Sq&lE=B+IVvV6-Y~zKe7Qrakb&I%EfwEz;*>~@`^$jtk ztI&f}4u}O@DFsj<@3>v>&b-j>%eE25$pphe$uhX48l-}&_ezF|=(>Q8-ydE7=Q3sV z*V84}#~`xS-!J&XzYwEQd8db2F4p;oPVw$PR#TKdRtsYES|^Uy)3TaR!W}lB5qll` zs1c)v%(n6i3T%BTg{E!H+`B3ihT5GZoZ#T z>@~SKYw*?nng6=$en`xh1{$iT#J^-PC94=RJ;fnkaR_0@Tr3B}?son5KE1?>TjEnp zGyOfMo<}ZZxzbJ?y)G076y8QNk{#Ou4{e!DA7wfPLCn@Z-H8gTd_Tu9LuFV8{gq-1 z0@cglZYH24pvA=hw)!aK{}J}qVNti=+Be-@0@5O7fiy@DAt2q|(hMox-3TH`$0|E#0AXh%`9xTyx*Q{qDV=<2~NjzvK{RM!r|9b*|4k7l#6heDZOWgvKojgip!? zjf9hQ7_}eUW+M`fHwHEPHAy-j^aE1>3wN<6ra~p&YIxt(S`*>2TB1ggVi`ifWtol< z-BjakEE6|+H%BMIwL+&94!0=dc&-9IHg*n{IuWthY4QhLCrZeJP8w^hUiq9aujB_J z(Le9tIOo+wVj#Bk#c094}btg3fc_|M9<3+8ky%t=o5grI699>2C ziM>5jyhAIbP?96LiioL&`16m?gEk}qILQr$|!%I4F57h)zo?|FASIt*fFIJPXh|%Gyo9|8X;gYW~5A(fr+`BkCC%A%P>5(Vh@3U8wbyHlWiHA^$|JYn*IEAKrmK zLb|cLr~&vxAf&3&hzqDxMm*Xw6N70DJ1%U#?b|dX^^Kx=<%f4Og9lNtSNnlZ98~cvq|f zMzH=)7w_K$GpBJV#)7CME%%bw+O&1|o1QM5H9F6N8LnZ+tZ@s`MErXxBxN~0q^}CY za-&HckQ>yPk6%#VO#`y8zhEIJqg_=MNf_dL8Dx8FnNG{ zPSUoWVgyV9LTuAaTzH(2dX9VcbVT)Xg)}OMf-3!iIF=|WzO%5he%qOh23`}JukCYH zPv)GC^a}PABpPLXtA5$q*<0&+A` zSCJ(amNVE~xA2$esnGR|M7J0$p}u4)dmzFLs^dhlBu0^hQP@DEndsRtM9aft1Nj04 zI}PGff>&`~GfpQ-<4uCJSW$S6XMtf4y8A8MtR_i?yhO7c4WhL!5>~)RYKPAviz#bx z@qI|;)KgAzCDwg!yWDn{O-G-e^dExw1UPNc$;DWz9};m8DzW=S(=y!x7QHz2UZgPe6`;Dkb0d*{KEcb(GK7~hJvr{=)bJ&ZG!0vt z8Ad%GsTYLfAV#x*53}M(j-&*Bqv^tqghY_fr{$8P;(}EV?IK;DsPQIS2vCdl&~b+L zpvo8C-g0TfA;v4vLgs^P!|kKQ$wX+zZeSV?1YV+d8Ufv(uUCpO%!jx@F1ybY0%Vh1 zYdGn@9Hc;+aUl7+6Fj}vUbPH?i&H;GTtQ>7&eg4~$z)*)>T&Q_Ph~~zew<&4eFGaiiAg$M{?|Vg);6nYw)&qK__>JH>+5tHaNY1<0 z@3Z|!r6@%D(Btz`b_J**S1nUjUVU%=Eibu|#Rs#ps*HD={=QD49V$JTuP^sasIwA5 zaM?@&5zn|iGE8N(G?JPGuh1{lk`kkOlu|L6PfjM%-Gm8^ygO`RXYCWM(2wK^iY%T4 z&gs_u#pcgs`wafSrOp^&3O!RDG(s+XdGd+~j5TZ`SqLw()=@-4Ko!>`Y_Uq<1jJo3 z%$lkd(;!6AbWZmLRyBU%4`t>SREOfskQQl-Vr`F>7KJ_eoj{a$ik)X;`-7X|$s%@Q0vU4+_5HTC*bj;JKQNmi)Ev!CQpTUJw15%TSi zryY`@5+`QZ=HUup~u^@(rx?6O*ice(ZGc52kzMded zSzFh&n~i0Pb9DvA2AyN`o1^98JWFFEu`4tI3L>$5>{LPN${GCeDdo~ZMbUbhiov)W z`fyWdKm8j8AWlpK+=8+sX5Y0*yKhlkU{8Qd+&cwKr@p^eC)$MqgVS|(n*A5|ODuz; zi0CI*fV%(S=TD~Wd!EsI^)2FgQ^(JzFKh(=4eZ)=1Tfs%wWPU8H10h!$zBT_@Kdo} z_T8)Oq;||^Evu#>Z3L#(!%#Xlso@Nsp5qJA|LckJjJzd!7fNYX><=8cC-;E32k(Fe z(u_OEvN#z*eV-3Kjk3h(w@3%li$u<$`$p2{s%KYc}baz!SQtG4GjlfVi>jeid?Hw2pE&7==W=qKWWs*P+gq>LO)=o=S6jx<8Q< ziohnMEi{qwI9TZjYT1^Y?0?d@NT#>PZ&IVFs&XA_;zA%`D@eEq3K>s;)}kxoCu!V6 z6?KQLlv7jdxe}k1}fJun?l`qsvs5g04Yr2nzRmW>r zt^))Z-8#v>l&MtQ&St~wX26aBjfE0M#FMWWcC<57o#%`A^ZnUtlF!^acIE`B_1rOi zJBYrWS>h}t+)nm#jGZLEID}rR5Q&3cn^uq0egE%;;&94Z$r$u^+^s!Ql#0CJ)JpQj zXH5Aa=0_NP^1&3FDQxLqZ^Zf&w){@X>)d}w28QrZAK=_a0Tm==K_9ZwcIta57;iSN zYog<2xx59ZhdlqEIzsA4l$Q#0FieFCr%>BC=r)JKD=1t`==tjJPGYO*6sV(=N3XIg zj$U*j5WBP86fxs+^h{;L7-xiRRy#vNE>^d@hy#Q$nZjAx*+&xU!&V{4ud{*9k0AIZ zhsOiyHpizDB*%p0bf?74T_|uy&Rs$uTMWw%Ek~V@mfb`WGdf=_LdSYsqt3oUohSEv zwsP1()$0rV^K!Aogbz3 z^J%yjjv{qO@(Ag#03gB@f(nGbNyi+jah^gzv>*C42jt-_HVn3!CO@fB=;>rh=!nyR zzec)2xKEQR^_zi(ky(x9Ibo_j3od5U=F3zzPEa8P3bUT^qkU2*qO6{9f_VJ=zBawt zvLAu>oa4Pdx9J7x$v2w6f;`E_3foEmRc-n9$T5p-$A}xEKAbvs4E$NfdGZUM0OIiN zgqOS=S@-|ZC=Pd;boQfSjBOt&KbFZ4>Eq6W43NsKRz0EUU<87js*r1 zSn{L`k0DrTyXoz zgVB$*OX)D(i5fR|ds($=tIIpKsgQ-&MQR=XO~`#y+4HH;4^m28bsQ($6f)^L9s?Ql zl0vq{cxNHiwb@J&Pq>>`7ipu3NEf)gD= zAK-aLv@mj;Nk(q`Mkr8LilKP%*kP)EXQP@!aa zjzzW%4QXZYH@vhC&>`{s&7qO@p?B%ZKAMKlMlR|W_b$qa-K1FW3*}Nt3KF{GP9apb z&r*2-yJaP5l6dSQkSDXez1%on(SN#yXcM9%{T?0GQa6%5jIdRW--_<*&WPaAt-iUZ zT(LiC*MT3A^-FdavczciOk_cZ!^1BG6q>YTFT>h=PT+o6eFpxCTjX`@^B6OP=4j*5 zHcn<2|0p2CW~MkaO@^QMz&R2EB{`)HB^bXZjn)48X+$c?1t_7%O+&ySN55F8Dx9M1& zvAK)#9UV-!T0<0)+&y?k)@Cx5$RKvD;l-ycW=WMuCAvK+I&NXa`;DNzSlP=A*Z>c% zg)oBPUJgC5t%oyS%Mgkewfl!;kVGA|gw2M_&^U`DMQW0XE*I)06(6xt?tQ$TK8jv~ zM|TRX*yjJ{(cZm-hB}+*u9k;w9WK_xY42fT;q@YWuO<%E<*bFg&UU91StW0J0xRmC z&_(sRcjF5Cp4xf_G^w;oQuNclhr+v?shl#$NF_Y4aj?Z6j0>?Co`ptG4qS%RGPD_oZ#Off%xN+chyHqOjk~X;Qw-;^~{0s6_YwS-&DnE#nqv3b3dfjq^GZ zbdE<*tCH3iB{g!rkS2goP+g}|UFO8Ucb=wXq37|z9L0=I_E<>YZ+KI21!#*Yclz8N zSOC?QSieZd@5tBFh?|RYT<%)Oppp&07nWxRr$@Wq9r8%TnKeIG{`&IP@sCr+PE;u_ zjzI|`sGa$i_{^l~qF{+N_M-P^efXtv_dall{d_0W4m#IYw~YGN&7Z%@NY2KjD@~bb z!9ri-`M@D3)W2WhnL!`yj<3?Dx2gj!SYo;l(QgSbC!$axJdy5f7SqCX;u*h^>U29f z#JhK5()2oa2t1;x6fA8hqf7NkjWO>_g+pLwjk!o6BSF(kbAb7wDIe+AW3`SLJQ#!| zB6NUL1Yz~tw|9Tj;_og#rNL$Q@2VENz$(fnZ*$yN3b3GW{-*q zTX;-b^mRovxHUw4fG*tFZV4hXwX%JmQCH#@)iyd9uph@c|FA~M`*{Cgh2~N%I)zSQ zVQSU)Xz&V`As_e(uOn>j;why0NMUrzAMiN8)!dRYv%U_lMcMP}Vveu#RCsBNv2*-e zxU(nWyqEExtI_GWmE^yTo zp^v=|7xiV0Sum-lnY-teRzcvd=J1eI+6^nZrmw|G0XwEcZ>0(p`0XvwCM1FY)xkxJ zm+}M9g9FQ}b7nxD=c?yoduX=g@Spc&o+JK;sZ+*}i+ zdvX>DoDcNg*bZgz*h@$&jG&TEf@=HwTf_}=CV^Iqc8;6&4?uDFfb(nJCPzS8!EqKi zW0NtaIMbwnAqD@%yDOacY;=pf)jR1VKd7Qwz6igPm~c>y9(`ecjvwfB9#nc!;rNnj zSrzYC!j0C#wa^|Yr~#a!w3}Z7ZYE7z<7Ny!O`KQ0i0yAh;NRP{m3kgQFY5ITpo;Gf zESE|vFj5q^???MW3N=n;0%(yTaK#+_V zNvFq%IgB@hl5ue zMEVu+J4|Z@Nwxc){R9+P!tNyi4wa^>O`kC&$pawe;~_JvyZ2heJu7gdxb+YUDgf?6 zkGYMJ1RbCk&5r>%v^!n-2)w#w1XTGy{ZUrvNMN%6vFR71^vC+J-Uh(fh%db+*)Rz> z(=O90(^$k!1_m_m0uk4owWHs_Z=s+8kfk~%zB>;ypIgTo`R)`kkA4Qh%g$JSSc}dB z65=-p^A8{CR3w9_a{z!T&mPFdN5dUS?lXsOp%Vjdl=qBqaqQHigHdY#mPV|>{dty2Keo;m8s>U z5q`Jk#9@pXH(Ss4Mg$bVxaC{|7SIfcn~-X{{;ML$z{fXnZ^iGlKz>Q zy;(tg@uKGj71djySL|Tkp}Gi#Mn1f?Wa}qS!oSOtj9$4*QGxEW?Klg~3-6j(y_Xn? zbiyoe7G0xW04P||zil-XKTRkWM-H;c6iYhd5?vgC$W8x4<>}7`EMrmTOtYz?6!k%sc4ua{Psei36Vu*M2+p~_p7A=fl9KIzp z@AAXqs#5KnW+Q(>D!VPndRKivntc*spR6CAb13;L1yJiHfcz{MWj*XO8UR-Y% zC=MaBJTeBCFIP664B7W3w;@_qTF7z_C@z~I*$ku?4q#1rdwlIV?pL9Xr)L~H@qaC% z;wR0)UHb$MdW|-3S6WhQZ#}TcxM!ca~mffZG0X zfbL3K=QyVU*R6K;Wyrp(pE1#_CY>tC*&9cZ(vnAc0*V>M0~Xx4BQ&yJrB#Nh7h3 z0104u$9RSN%V_$VDh><|N7kDYBz?tGC6_>J|2z^aB?-x)`V#VxIUHhz4bUV>+&1|p z#4tra{U5y^tm#lf1?hE?!r6rerz`_vY^H;8fS6X8$Rx{Pm~k66I%_-BRv0yF$R0`6 z0b;FwUVPK(f&1a=$oSvIaNe^PpRQ%9t31uOL}2RBHDH zd|PCt%me73j+?{QU49mJ)QM5&*&3-z{+QFcz3EELl>Dt+zbZv3{QN)Q|E=X9Hx1WT zlJ&J8O9b-~bbf`2(ScUTSPD+q^jt_ZNgEY0>}jpUa{rc|i#w=6C@P3SSA%1_+crNq zq+R0GL^6r@w-^D|O8p=Rc|?KMWoeTK`vm=x1YJDQRuRKY^sFpO{572ZE}-{OiykXX z8=@q(O?+U}7qD}Fon_!Zr17XUrd<8v?KcUVI`62)Iozr|>$_IXj$OCs0(E|M& z0p7l6bx#HpkE9uU14;qGZoe-tF_~(UjP@6dM$oJ_N7ri{BS=#!p=dwuyIz`yQdBPx7Bk0}wT@0_eSUzFwWO;*~@ETpC5eXjb{95~%Zj)NA@l(kl8DOurs? zhbg%BgL%C=Cx#b+7XH0LAp`!l3$}seLhU6BG(Rk?7yb<(k}tc+v%SWqU&2Nao3+2c zun*m(nD|NiZ-N-*_dl`vYip%XzXLU*@772;Ru|wvB|k0Nx6J@#l4ej3!i*3*n?t8F z=>%%!1#bb^ASUc6lm;m2WV@@AJuTr-m|44&5c+C70T!pEDY!ogj$|Io#H!=4bTNI} z4I>s;8~J4$tbp22+(%wgCY04WQW>A%A+LFi6+(qZl-ZSRgUoSGfID!Q@0M)!#kO zrgWo>^2msogree!ES<=qv0ZGdmr)OvaHa#pPL9BG(;o2`Dhmzyh9L#YsTkA0!@rRd zIAZ4Yc%e++ga%`-df=PfeG0m}MP)w)z8Ak*_NtUFgtOJ5e`UsQffdEO&(t5=ND|i+ z1kh&)c(A17NKaFjTHidvzPCTzWU>s`E>CkOath@?XZpBj%R`7ke=15BCLWR2mf{=$ z%*NctbxMgR8|U=UyD+whsh+XCy8`$usw+W&MAHi>)y2+_eh(wb4r#Ic!~}>#URURM z%pNZ~k(V+F)Sv-M-7h2baTwXTL7PV_;8+TIL|8?Y5*GJyBTp3HGe#V?FfizSbn4SrCMJhwfj7}mtykN9 z>K^}tdZ8v4&bEl?9JwqyqHkKs%x6zCa{Wq~c-TH}Q6zz}@C<_==hZa>Ljq#`Ixp~g zC)r_iora2B0=go#gsBR{k>$JaYPGC4_Uq+k4VQ?&PqL1TvwocS)gw!3#aj*Yn|;UR zG%vU}v&3A&uV0y6Qrv- zd}aPJ?zTgZ6x3sBcIAG{FsdjDS#qP_-wRpeXBkf?xvu*|dZ z*d!FRx6bTOLLabT-}Q8n4duL9F6$+Zc8or32KeXHP4r~2C4Qm}#1^a_TRNex)tXRp zhD6oR-=u>T)auX&!))2>o+O4nKv9>4R=}2BouIT`nK)bJiD*&*Ok^WCbhgm6F0a+( zFn5yioM<}G;_&ekAh6r>bBE?y8y6Y4+YUOMpbz|PdE|C)GvcA4MsY>9aAjG+lJu;Q% zzDbXY8r$SOmdQmf-f6sWOU5%4S4N_jPT0{6QXRV!MM|^$=rVI9G|`Gb8mjlOx+!jn z6GuD>9GycNy7bWV2`t&JU%-sbt)0-x%vT#AydUiV$1lhGZr`Xq&w(abexzbVsr?KgVY0R z2nOn`1MBfP&KJfFhIw?B(Rdo($qOk+_}FZt%ZkU%LNmK0#(0YNbxWw!(wYzsp0Aj- z=tlefQQq25@;H(i)ELLLRs(P0&g0J8dn7H;ppa6=r;3va$M_bHdgYC<=ZVo6`lyuS zJAJ>{T0*2?Z7N^`nAJ;Qpp%jYJTth#^v0T4f56rt*(B30lNQd+Z{CgJb92z>lypD; zFx9KyUJ$6ziRV4y)ZdwGH=d2eog=Z_#lm}^4wD;O$AJ6?TtdUFE*Qc0{t zA-1a?4q3}v%&EubK(usMBzbh{rKL1`AZZtQ4`g2BVo47bv z_r&SjT$I0cy}zN;icWu{xuR{rN~CGj?>@fYPJ{u54^|?xAqk)ZB9{Nm={HJGT-X?F z86^5=HvPjF=m!7QyReY*K>m}}{pVKE9|*@m2u_d(rlUUOE{B0Uie}JfwG-7PhV0?w z7RV>$TSl)>cM6tW7Mp6{fFNy0T-5)v<{|`}K`jqVY1BtBmSuzfH2gH{jlP8RD$v>x z6JpuuIQRDOGf+zTdLE|&j?qulbN6QeNEh3|4eeD~g^V%}{TO_=ndP@0fxbr(Ev%nM<*~t|KF<meWK>}i}B=8#$zZkpstxf7| z)guF_z(5r79&wO*)oX1&R7%GfaoH~c<<~#Og@qW`w;oc6 z@YQ>I1g525DFTqV_g$)tnkT=2wvSVB(6_M5e|-j;sT_E>&M3vWZg9HMjJatf$jk{tw3d%)D6cF+L&U9F_n9$ysE6@$11ouMILtfsxT z_jHY1Wmjh%s@ny29b!E4>O^%!LF_g?3rcBkyHvO%Hv;@~KYZ9lY7`p+Z~kO;4u~yP zz3LroX#Q&R`KDE*^_ml8P9V<~bk6LMLO*t39{xM8pxL1_FR;KvX1utr>T~e|4@$C4@wqI=q7<+A3&^nO%Q8$2 zCqy*O!)^=DI4V^saVDzja*NKM6l_{gcE{7|*96)W*G5ciz$Q)>$B1YE%p-temmB&3 zMv{;}BiyrZNvJVz-X~7YYoi>ABQfM5XYjO;UQ8f=O~(`XgWz&bemMsE+NtTybCFCo^&QfG~QO88!@4JQk$9w z1{l0O!_#k{SBXUj40k@hTW$FIL56l{vwz6rK@Br~N@$uV?U189A0Dg| zmmK8znEcUhC~^0msmzEgyo%(&gmA3hkQ`gZUw7^S*+yR$dlyH)tz;&=m%yKX#~MQ& zQ)GhTEH=8wjD#oNQ=&)q#4Z^|&$tzih z&T>N{6^RqQ>e)szjCv#4B08I|PumVX-@yOfKDnB{rHDEbuG2b zgZv-P>)C582i$DCwfHGdIa(Q%5>ir~&r0;xHZL)`)6J9#O(Zl6W@`BoOG=+X63~!f zF65FalpsK8!ndZ2iG`R`Dy*wrJ)7ub=&vPIAsI$xky{T~DaZM*2D<$!F?UbVCx{y4Hy0te-64G%pFOd+cHLds> z%|jKyCG>&rW3}budNNtM;ed%ly@PbI-Ly|#UZH#8IZUl6hgW?RmCkj|?^ZCJ&8OHt zS!DlvlZ0Cl0yX*NsY-TQnlruR1K(lxiuXlbzW#bEaHD274bV*ZivoX{smaVqj)V*I zJ!xSOrqHyqByJSXL7{jOsSp!)k2wujX;>h+vZ|aq995g#-nslHZ$Dq`@-ft^i|37 zS6XEQ<#56-)TmP{x&A7XAmY$amG4pfWc+ud%Q>A3T1R(`cMKFTg<=9ig`S7%Eb1`a zUtF(ZVH)F-OBzeCmmjnsf_7t)6WT1W=EYT^MJP4E51n*>rp`OMa!PaB^(x(ym@ zZ2vY}#`M*wEW!gy95^d2-_B?5u5acK_VVzN4x6({9q6`ugqoh@?(lOwR+pRxS6Asx z_*vj!cukTijJR?;V;;;%EdBK~+`UrEvW&2{l-}C$zGS`4tJ7tob-}0-zk@?h-yoNg z8&Ro+@p_Z^fCT#|Wh*oD>4)O7!prw$i~9;TzfAf~-T%_7L0v*DVs|+E@#?Z$D6rYu zKBi2Voxiv(==1gwE&b~@%Lke_EK3(MEgNsTLNU+F(Nqz`yYdIWo$`5a1k>f{j2G{CW z?x}rlC%s<_Iv0lVxst@MZBtZc?E*a9_?P`=+u5|kia(E-I2-z`ygy!UJiIMS9Q6pV zbvB=Hl|A`n$H);6Zt9OYM;bRu>`|VMV@76~;*o6YXbQu3?}ut--QS5^kIC)7ysKGO z%_KQL{;o7NgLkZT{08`WFZkHk=PjKlcn)%w%-RcT3pU$JA)R*-Oc7jgqv&KjmtR5f z4W_9T+`|hCN0KTOWsCCk39;oUS0fz17cEtIzKdF$?jya&N>b?y_dYyQT`=y-;MzDd zC+=uY=52qb5g<`08n_hryIk@NhhYQ88?%yYaYZsQnEWw?~Db}I#w<+}u{FN76g1m(H1?n2XFe`fPe41kK zkhJqGc!r0YBKs3yUTYU-p#8a&@@L`8)K3Cmv`E+B29yM>yf%}*Bd*Lad`j(KpwY|U z(6zw62(;tR2JE0Iw0mhw+8dQC_PX9oRVz*_J(*f8IY9JDw;ddE7>&hz1wq+Y9W#46 zs-lN3YM9|G0Tw+~Rx@)hK@aD34sQb2?72oW4?OX+xSX^T@^yURO=@cS7wu^50jpBl z{Kzf{xuksDJG~pz;O#fc7X`Z?yf>azTxh!H<2}awK0gC@1Odp*fvbFf2~upVY5#Os zu!0X;Axz}@R`+aOTPWhnua%>NTP*iBlMSG|7db6xO`an^zbITFl1DD5_GUrvW;=sc{(h7F zY0Yi1;)Ndlw70T{BXq6!W{&&Z2i~7<^!M4@@(lv;1cMhjzOtcsJv}6!xn^ydPmRd8 zpMncWPL?cs!j@eas3k;p)>U@xZ>i-^oXWao*vn7LUg!M8g^?@0H*$MfNWUD#7-&0R z@9=)|r2MPqXs+170M9ULp(09vn^Cn?B@O>w%Jc^4<0A@?=oKX`ArHorse20lHgT>+ znOKl+G52Y&s&yXzNV_4Cnumq#oJ}btkqd)wnvd}Zs3O_Vtkj!mca{ud*4s|udggFX zHmND`xqO$^6;3Jb)?p`EYSX4ot!?X4CaJHU9PmlN9VRaNeH?Mmq{c}PvB{+fnPRnH z**5U*(1n)F$ZVc*Y~%nqXsgNuAep1<|AsgQ*y`sVFo~N-r`J`9HL( zI@z_e4;i;wOW60ouLg@%a_qzG65he;Okc^X2eNBb8O`0QOk#6sVV3EnU3W&QZ0`x} zz_TTv5PjVKQy|??T=UD08UCZ_nVZtlz33~>I1M>QHtt<^~85?_3iZg^-+CjSQ zVHd1!?({}1^RQN=;y7dbtOYK9;U}Sc)Zw_GZ-N}*8hn?8r(nij0F|BW);bBpRNsSx zzSDkxunu2}Rb}z2PdNov_WtGA*1Rl9g)a+N7(IG2oRl{7LRBPl&0D4%5=lgFzm-l} zZ{U%y1jJ^?-y9<27548PHBcTQ4FCu`+SorlobnNf8yqgDaCvMiVc)h5+ohF9Ey$XA z`7UAkijn?}F}s=eSFYvr@^!c)`7omBc#G9O^&Uj3K$J5GnElGl|Fy3g_bBfKWh=@{ zu>`4zwYR0R#?KcU+}s~yx~`~BvOQJKG!UF|8xcLXxJp<7#Qk6c^C=b{97992d%?MN zcw}wUAhd-lJ5waGZzB=a95Y!qK%&{QicA0RW8)US!-fGidR>YJ+m78Z%vzP;FYL#R9Innqy8<}A)th@B=uY|a4s8Tf^;we4OlaOnm{1oI z50*w0uFz$f({-G-cw~=%9e%=b{X2d0LaV7V;L$b7JLzuagE-h1#)-A_Fq5DcAL4i! zZdy6QY>NxmYTaPoHX%kvrrSta4J5D+rIOoWMNMPHTMa4Zo_^L;c}o8 zPZck~^yU!MXrI;@btTS|oCDSK!j`&+=4BhycYTJ4(Rz*t2SQ^ z->W((Jlb-I%4!XJ5NA#*h0=-}rG3ZM+XmvSr-XDzE9Anm(h)~*_^4n6wV zEK1qEi_U!Y`@&goLmjo?COKO(G?=rE`uXV(Ge9`ZF$U)bFW$o zp=NR&U&8mMfj&Ct%_gl5{Y9xu%hSI04wsEEmD>#T0-*{EVk^YNv{2f2r7)FF7|%zq(O4(jVvP5`9z7l{Yy(=JHf-22bxs z{y@ia3$CHJ3fDEPx7Yq@xt+$T={QyqC+hrArtF3+w68!I zcgLxx{FE5yac{iyMpk$;MZWAIwr;;58Bx3lwd>AM{1gwPi6fXYo#9ys*Tou#Q_xJq z5A|>Ri4X9;Ec!=g&fYU`W1P6UFRdMD@ERdj16}JbJ$i&O0ukLn#Dd#OkjubgL#HbZ7s!JQRCAit9)?V7=O=8lCW-2&L~owB<$28fB{Xq9)i511`VpQCgKB5btIS^<3Z)NtYVKLn zyFgAn;TCG_cV`UFpm=!&h>!quiGw&`(J{{?f1}43J=Qe+TwC0}f@@6OI!%z^)de*? z-OYEYWxMdrCyzxBr;r}|9)q+CO`stiH0e+m?=m}C9*AO=&mUcPMvB`e6Z7?*-e|Jd z0|N|8(>(DC7_o@$(2fkLNMdXtjP;=>{`@c=gxowH1aCSl zd0pF7FOD*m=~wE-PN{v9_FVAVvD&E)WE$_Z39mtaJlkIsP4z_64?UVe4%;ro^si69 zjJwL6@a&%LT!iHY0iO?=CFI)ED4O91s^g8QDkIMLksl(bbj3%+W_woui@#56M^8Gq z`QwjE;kps;oDa>~O|*F&hHU==$1|}%A(6@*chAp6#dL#o(ZFKl5XWH(c~P87i?}}f zeD`s$_dS<)=;oqggvy7~ZYVH@I4_Lm`g@A&p?$N>n$s<=UEU1O(%SBgN0X^np1{S- zu^I!-((76W=$;b>>@5^jyH}nQoZsl*ESfL4wWMl@xR#x1-G7FeBa&H7P9-u2Pct0Z_Lpa0)K>G;lL0DXxm|5)sl@)B0hm%ky0*eUJr;X9XYzn8<3la4fC9udtQJh znZHPAsLj>w=hmLz4zKRBAKNIytn$m-Llob@xwNH1R3^)>t%1(0&R)XnLqNC=cki~{ zF_^qa4aLxY+)Dlfs8tP9rg;2X30s8fZm*m?rUbM*-qg9AUe`%@E^2+NxG0#`wN%}! zw%0p)5s)a(x@rY8c=V%#yiQ{2c4CF%xX(sC2^h4ArN(UdfeYinayLvKtg)U4zE4E@ zwuMhy?MAYNQ-pV(dpc@22|CU5-Q2v|PYB+9H0AE@XZbSF=pK^OrFH z0Jf3AwW}3U)`7202oEUVdg;YzwRf}xOOy`?meoFLsSed`H*tD>An$~ofQlf@O1Lm( z3o6;#JyHY<3+1bflw)fx-(9oPd4-)6-go@Brd2;o*TZ{$OGjQ~pR}Gn)X+0w zS#8ju%E7Jd09G2zqU)U=@0hQ#`RJ=CO+S$hA8l=t%&YJ8#@-&!yp+O>-f?~-A)FEbx=<(VRmC}$Cp00hJi|_mS zrBuav*?AZjo||i^!ik8T_@e~F9KF#-;ZToH8f(p=k0R1xsc-Bpi@luTv?p0%kH{%* zA9d>1$4J-vlbyGe#p;*`FW(1d6N=XtAu0`fthHzi2&Y2wGm$>lldeb*tk4gmm(CPy zl%l2j`$%w(jkj>>4PI>2o>wOtU*}X=!Y`VN>{TLK@e)Djq1N_m{x>i#b5FYI%fYY5 zY`PufZmw;klgGwEO18IR^nO!Rd{Z6wdV~VYU}`|7qStnDXthrqaXgBHwK2v@_v_O0 z*3o;saCZ;fI$3EgiMnS3haVs|Q=H_0&gic=M4|Y~cTPMWIj1y{OSo&AP-2JbtwL_Oif~YIJu7~gU zJv$bpzOO$?Lfln;TVqBoyt}|*a*szLlXTs>Cy6GT-w+IkX-q|DMUl?sd&S##lvS4v zt>Bt%t%HC4N`uM@lz^}fc^oEk(~DO6y2s0ZwnZaI7$!o&Alr}BO~A_KK)3!t_Po>y zHqTKG9~(}>My?=~;7c4P5ERFTfE*wbxQ8sfI2qz?h+uxMbaG~Q*bfHy%}=iYRp7Ie z4>EQ}K}n`YzLz8q4|G*h6L=cAFE};U@;u+KY+QbhR1N@o^Z7&qd89Z}{PP3BtURrv zC@3^zZ9eWNAPAjrNRR~c%PQ=U_LE2ePe3jb6q&w`SQo+Nwe#2{ehCNXOaabp|2XsN z2>BAhC}b$X@f@1P@u0^bV3q{O7!Vk9IQnBPo(=+N!D(9MItdB?yw{zKK2p&7_fPN` z2m=1=3ltnejw)OqIV!j!(Gim$)@=a9$eh`ge#rilhlsFov2VpmO|dI)hO+0h}OaNXk`vcs06SN?hKlslt{2PAJECz~3(QYL$ zqRIp=r-y0PL4biicR*H-0O3MIf(lFp&5&)pe(fJWnnn3k`TN}=6>L!0Y(R6XnNF3F9q383N)%eh z`2pNVKLeX4a07y3pOfJjI+0K(;A}^*Y(D6!xZh)N`^LNpV3oK<-4ifi{bXyjF{yI5 z4CIbk;9AYFOcd^Wvqa&BL;#ERKiizIHy*mQ9Y{p+1p7>Hjsu3{8M0Uvu1Aot9&>;32ERlQ7E5MP{HvNgA4cMgCE_+{)z7y?%i?02d zAQob4&p8va?2E6}PMEK<9!%o_v~AtHg!zW54~~Gqv)P}mJ--G)x^suh2fhLSt6%SJ zz=sm_+pm>Z+)Eo2P_zzW6K!})uLQ1R&lhXqb_eJf82<#zVmVHr#juBhK^Z zuSe)U16#SdgEyei+g~X+*^~{82d@C-Is`ud{udFDqrL)X%t6N3tPrryI`Doaw|~PP zf9yXZyfusB25jgslK*QNR7tMMq%g8x1-`-LeEclhU3B~`H28?Jx7qaHBUGa~O~KqJ zCU`*+lGZo50&0iJ^sZ*0fU_L-jPaTQ^#NPnTXP z*D8C9xCNWc-lfs*M_;5=AX4)2J>Soq6qq(jL=wAKU~l<%1kKx(%w1hl3T=Rpc=ye*7mNzr97i~ayl*7@o3bb>RJsbb3tl*CNemCGxO)U(TY`l@=NYw!l0$n*c`|u-_Vs)P|2~p3MUc z+v$C^aqBde3LZ11mocE4&i(LEv?EG8RVf3Jb?Zv16CEb3@kOsHTGg)NP!_}@Fi3Su zhQ)U9j=uPzbL4|A5W$V-3!x0es{zJ^ufsm$lC#a?@eR9|z}u0TSS){p*gTfO3~;xY z0es@u+cvZks~2~FPc{M0UOz+0w_DHXHEZ6`{py`Z%XTxRFBggCM|VJp&fYx2n7kF* ztN84=po$2qJjfanDQZn1I~aA0FH+W|giAv(qwO{43*?DK<$|tv*bVD1fn4)}cSPtx zW&altvO7|ip-qBj;^jl$h$1`&ZPNK_Qwd(r-O18Cb;;5Imid`^FFdLGYPoo7b97&A zj(ghF8_fW+Y=CJp*DMQy>rwz)^}kL(8F2auYj5qqppdn!0yE{Vxs|)yHw$0XrDE_W zvl~|e7j#lh+y)*B1Rn>6dV)+yz+cO=BvhheBk#xGu7j$hwdV*{RSlOZMJeva@F@%HHcTlD$`%;eMXI zdw;(7@1OfPe)k{uU!Uvv9G~OepwoH2&gXbM9?!=!CtY&U6|(=pJozSds|dM!x1{D+ zn64GRE*Esc8*U>`A>>m-CNBro_Q#nI@-Q~!%D>KoA{ zm4Xbv|5_$XD~hNez`GC61$}}L=P~T`y!ohwHHSOebOsbADo{)=Y@%<20Fuvb4{ZMO zX|e)2&(fUE(#4FYWYp2MB`u~BY0$L%Pl(Ap5>52=310Olsa)$Dd8Tv64TAhv<&!n?$OaVURGMfRgEPlC$zS#XDZ&2A4{%}ntJ)uHz<(PK{K+CpMGd4 z+H=wBpE`|*B^uh!`!^TmpJ%9~X4o&lMezRg=v(Si!eWLiU(gyjpuU@A-OjKEw$vT8 zwvYNAK`h_M!q-s`Z5gPF&0ch4F3Lk6o!b*Fin)raI|xoGPL85i&%X71DTK3VwEKoT z+}hW=`(Sd=zx`XE?rfSv2`XtXGCTjBLX?T-^-;4*p{yKTKFqCk0j*4pOPw}a*@lc5 zS;b04X`heVvaD6_4XdJ_U;gKKdd0AL9a)Rv`~}e$JnC9P)3-+_Kmi`G6E}4d?f30& zlojvB!@UenR2y&9i)&0I-bv)*5^1AfFf^|R4H|!Z@muTz6Z5GDyZA47T_gP7EQB_j z=?+bzV#u29@m#~$cjiybOs<+n(Ua-EaPEmEW3aoa8?;vo;Ik#lWeT?@pIZv!;XEW%R%lxp6LY$ z{=LAjmxz&wd0Or1OZ@2XjLm8F_jh9~d(4|^PSbTXQkPjg5AWFt6*3hX~3Qbfo@>B!z zse_1b6k)l^g{v#q`F1))j#)9avkXe&KX>;B36o`1r*A8*e*y2jdo@r;UakZ21e=EM`h`oBIWl;nKSzmvF2WNvv^K&Y(ub?rT&po_c2u{xH zt>Vl5e#dQw#K4JzcV+szcCxNH5beAgky_M%Jl~4OpS+?LXB{Xummy7Kk0++kgIA}| z9#KKqF%=he?ZMK-}k`f?@j1tjN2aKcKY1|$e}3hhF2iB>d*b3 zcRzsWG&?Di^Y^E<%X{-i2L(nnoUYR+{N-_s<=a1O;H9qJE#s_}IU#ZV^hpxLM}2Px zames}9A%Xc#*0(%5rs@m$c1+3c+6vzRC-u~E?JQxHy&8UAx})tFq7K?YG#*Q z6hZUbH<6dV&qSfeYYhf^w)cmUgCun)epwEFuy~+sNxy{>5d-b^`^xE7vH7dJnDJU$ zN#%f3B~@!a$5{X*c|sNS&y6NRDr9z2#5^03#{PK_llkw&MR%!xRN~~mX%K;T zVZ!{HP8AA+OyqR2`O&)2Wv&q<2ii-7ofon;ufhM|Eq8EX99y{sf$M(x>PoH zV3}eIrSQIP+j7YKzyoU9#3Mhx1x|zY zM!(%%+NvuiW!K!GC&9HJ`RC>YYaW5ums){C zVam@^;5*C9z@cUF7s%)a=L*4=m@utjn!tJbI61j8lyxn@;Y4rU(@64;CFH>zjSwHY zJq=$B!ZgB0CIZ%C$1-0xfG^19H5`~UmV`baHv(~=xn5PVc}JaA0>>5<7~xf;FcfFY z+@#dT8l{b5P199F^moVlF!Kq!TtBV4(gHkMz#%_>{pOtLbZacV%LqK@QC}69t-NDd zQLmQ{aW4l@agH9f9~r|)l&eptA?7BOH==3r$&8=n<7IWSHrAvv}>G9 z%HzY}lcHd5kP?kHPTO9hF6B6)nUE3|ji7{`L61M5lJEbe>6LnO6_AHQ3@)lK7t$co zd32cBq-#vn#W1=N=zX= z(qVZ_(X60aj7UdoOFuN+6+F*LDfwa4ri3*WPg>REyn0a=xqCbfZ=cn|6e3q=m?P*L zr(jaDgdi9CdQi(aJN}vc;yiTc?K$D~DZQGviZ}(xPB6t3Z5qN@qIG+QIy%=NF@7V2 z*uE$h6PjX0&ro0KHyij6<(!-U-XnEW;P2}=q4Cs;Lpy~`L2{cNI+9y4gjYGVN8EE+ zTKDef?haGwhBc4IuX z>Pq$q7+KT5IH69r3T*!1MkHQ(J-UX^0GgI!+y%}p_5Rbg`?oM^s?kC%z9INviX^8r zWZoy60YsNh8i`TT+(o6`F+rA3XQ!B(sWBxM5=B8Yt}cBjnkPvAI;IafjeqU;taUP9 zig?%uBT#QVkSXBHI{2M2hdz`|5GqT%iC#YLGqF_6NppJ{Ri%xagos_TZZfwQ(f9&E zUc6YKw^5ltm~%Kl0H&2~x0K}#UL)HY^J+HCOZN7`otj(%u?-owU&)ODKZW~|t7SIC z)enCR@ea&;{=vnVJkn3rebS&XPS|Q63NZdq{xexU6@-}z!+kAk;pQV!ATzi`9@0`BKpdLs)l#rODc;`}?)QR**&B_LkuuBACfQ*(`N41Frd+HT6O; zdV3I{DgwEVk>JCJg=Q_*MTvuJ_#f(_wU%dMnus*8&upuHY3cbOQuD&`f6osI6d?+F zV8l$xOyiWXlLaCk?PB)R;*@GtZ#lvC9APAo7&$B^_&+vxU_2HBf}FFBcwMnwzvl&&_+FyM0t+ zlql`<-u5{hs$nSI21!|O;i%0Bpu@K8$x)kt3|8u}`BY^Nvm;oUO{imQA;F}u-o_nsEz#k(KF$xw|MIvPe z!=ulq(!c>g)M%83ODh6Q3VLCny3??)59*d^_=8BO83{^7mOaYQZ!1GVgW%!=-~Ro< zCPWbd=q`+)w`{GBw}AUs3pk0y{cKwV^ezp0k~Gk9P6f+QeH+~2(JO9Nj^O)Hs(`~h}6ec)R|h#W*xIpG8hCs^^B6jU=G?2aBpfmx!Q4VSkE40@gW z&aO4S3|h*KDZzyWbV3xR$`JxEGq$*G?_4ogCk+rHo;jpKL@fcWw-@`os z$-{fwxY+3=-Ak(&TqfQi25V`M56RPITw4-Ix9D@iUR^ z-+unybS?Dr*M1@>8`8uru3QVN`*=p}Mu)E}-kUsxX&E7OU^|McxVwMq*+KxtDl7&+ zWJXGQh#e;W%38$?eG{{=``@-A4+jB?T@E^QGaJa@IB>Y#_N;-0K*hIbC3hE00Lw5% zs4m!*bUxAwg+1knI+;QK^{!Ol?ExLF^;U)#o4JRY_~LcoD;Nubf+0+! zv+7}wNlQ*44=flFMr1aTfG}gHXNthw0k`(;N;GuIZOA4t(JaH})DTs%Z?KJ?#oi4V z@HChVs?-S<1lT>>BdES}RUX%h$l|rE!`V^Kt|78h_$*vRAfgEX#W<)X&r(zOpIm~a zqXKZtE2|ilSW`-VjRDSY3V$w&>oa&93B9uHuy*3eu`4n64%dL>G`%Xv^*4-LeYPGh z7ql#!3Y!PhQ_<-doHA57#7_(t&olZ&AoiQF^J{=~zb5CB#R=`hQFSs@Xb~J$D#*-qkK3Lh8X=AlNR9FIFE=3w3!gqT%zRXnyO@bq?=WZ7$C zLV?(_?V!@Vq!=OTu@eEj(0~hHRkv<2IFj?;$k}SZ{p*FG2k3 z5oWy+PJ3)*z+!!2;)uUQh@S3Z(W!B#gR@Soz<+PzB?2hm69IpY`0 z-`TKnXKn+~&u{gA&-zW0i|P#ijNZ7o*)dB%w^f>dGia|;~sW|$JDE&2_Gu^`;rYlq3c<^fGb?W*=KL3`+;It8+$ z4pl;P*6bOc)Fg`$riivvJU0L%D_Q4r-9s>BZbJcu`CWKLBftehHY^j9J>_>bF#GP) z9~X;>`JHUE{<%#=;#VLh(m{~pO|ofd^`JZ3a?Ay&%iG*~dH0^`fbeZ7UbAN$@zpGP z4@kmP{K4;sTE%J*qmN^3c>t$Fh#m?imgit@gPx)L_aYGtK@XO_L5FRW6t)OV={dJ* z`1+#MH<2ABD_7iOhbN{2afL7k`aD6X)%hVELe_Wd8Z1VutCsCC$*@h0XZF`NwC-4%c}P>%-)A1e?x{B$ zwQ3T--chcDA(G|ve)rCF6z7YE0Q!e%#` z9>a0?Z{P+@!v|LQqD|=j`T1`ywLhcziUVrCC=_FeNQvd*5mfU!L?*R~PT(bLcVTaq zK60OSB4DBRK{0b0nFkL5G|M=DtpzT`X5(?4;4r#v}y-X3clpVg=)qdc}Kz;|9;P z#74DTL`Xnk|Mx{XhcM!zK9-gibAnC_cfmF&sq$_O1g6`=O8{;{Bc}Rlg>Fx8P*JF;obkGOFtUcM8NAW%X8cf-azkLyxh{QY zcqy<)nZzH@L9ns;B#c?-cu)h2IF*B#B*4=OYd!fsT-OJW*UY{4vd#(1mD``kOGEA{ zXlU|9OEyg!ivxeZrVP^oo1njm>)y1?ajgV8ko^P7D{pfE&$PHFb!rL#KIPV4r5*oOOU* zP{ln~SAFd87bz@r%bXT<*8$xfP;YCQPA5{!cE@~-Zh760Fl8~1>d&EWjUdsKP&en1 z(%v3~KLO|a&;lqB*qR`AxpckP5x{}WerG?1SfwRs7KFe(c4E(-$yK!>TB8&}udEz9@bi5jX%rmh8kf=wWrin)AP$bi*zt3w;=IQ2Vw8 zqw3b4iIki%;61u!cq?Z2i{T&TPpHx>>ag&mr3Uu9w=bFf2UP+9ufzz*g^1p^^z)6G zjt_2>#kDN~B7Ggao?{}Vo_KbzA>}9qqgXeBTZroL7Wv%(W@)X>Y&lz4jidcD(Fd(&_I^{%^RH?3IG*5zlSx?(Hjy4r})F2h}#mOaBO`9`Ig% zWm-R7erzl56|UyNAFS@It;^3?>7yqsK9W-(Ccha6ZU@rYDhTUNPlW%WbcpZ-O62!B z;dOGnm~cji_FJN(hWKaxC2=p)zUQdLOQOb-rHfzy%?Pn07#(qGG`r-D3#L;!waQ1_-0XR;fxB8*n%vetE z^2K0kM_3Fa4*u3BH-!Mu_#z8Q3|o}UOu_^V-y2GOYTqHao5jzRvULSGitT^eKG}`N z7DiaXgqMGL6_os>>I?{tfIi;*_L5Q*EGF40Zc=^#q5*-BD{6uGXL{g3gf)$_7*Ui$ zU9uKif5Vx_AmQrJ%}?S2b?Ii+6YGp{RibnBd>iw9y!gp%{2k3-Q_;3^7&FT!h=72? z`QKP0Pjrm>0%FP(DduQ-&rQBay4(E)l)Aa10Dr51+2>-6KU5+mhh983{LJU9hi!xn zZlSbPl(Sla!MTSHtJw8BHuDT?Fd}-?V`D6Z)VRe z);TBC)CJ7T#aJ#>Phyl`hZ;DPCq3H)rbBM<&Xp$mn|S;hqQZf(R==xyAI#q%;w{CX zOcNj4o}j-MT;K!so>`#8#@%(`5~HGR%D*AYOP4%owq~mFcJmM*2LKyfbhkSAJuQV5 zNnFWfzkm3vd*u8lTZw|(>}_;d8XD-%F(7DRkPTpF0Euzr%3Biw z=I=K3Wn)$E#PX2WmQ;SW9K5%3nwc7@Y*IGxueX3nS5jDJw$7 zb1PZ6kVZo}`#cTHK9t(UG-goo3c^@LS?qjvLITTJ8=~mas&!l(>}h3of%hTmiy!Tk zz276-ld>4S?VC8ddJTFlSxqIw7VL~8s0DmCw(@D*VKAz3X5Io85OyzuXoK3aDT=)4 zrU&#!7sA1Wl59kqJE#hMDAKxVp#R>g_ZihZBh1Illbxv0l##-3345IXT%MOcaL-OB zp`WdwJO?RCQvAdOgz;wRr(u(^M>9PACHh8}JxDWC5Wq?{A=9aA+>*CW)yJ=om^MNu zbevl=T3Hq;FJlSqnR+ETvBKA{4o*Qx_Z#Ysfbne8dc&aloIdE~K@o>-2KT%-t5_YN zTyPU_GZ=IG zKrh3%gZo^3dk@-Y{tZ{K>M|pwxmpY{J9eXr`L}>_Z<*OpPN&S83e^X9iU}v{9`l98 z2ZMR|^E*h_F{G6>*>89D?>oW|JyE|xhBUGz{5sMtL#JGhE!u&^8x3)4XT-?3#Uee{ ztQxAR+J+%0Ly(I6SR_~ep_HkH?s@qS{f)IyK=|%6AR)1Q4@zsZpMn<34aN8OpcHF{ zNos2tAV@Z3vY?k3)o=SL5MP6CMjA#B^Xiw;J z2p!79X=JrPgVx^!nlo#@ZBXpo9+t=I2sWe;E49eeaut(URp#+W-zT_tdiEGu-$N98 z(NOIA>@egn+QGV`2LI|b=r;OAQOF+Fb!a}QcdF~lc@Wz)4ukR!lw62vj2HjzYU5qh zaXp`yk%EYE0_9c4h|W9onI}Yl69{Q`VGqzyA#~_P{uMArJ$l z6}3LQ-Otv8EjVHXmy67x(36&;B^crWJ`%du>F!)cExsA2tDeNyqB)bAceSf7N9?C& zvK*xV>`g~Fhe&8ZZWDjJdw%*n*T||p%-RgPTu>7kJJJPxhNilDa3_vyVO=sFe=4{1 z$LreZJ~1)8Iu9zz&g2<1F_Ek?zOpt}tzQA>*^x|>y#C#z8MFk0_dr4X=Tq?N?0X_M zY6oCc>fdqFfEO#bX3yQLn1C;@W3~BUq>o?*XxF(SWvnnNq7HAp?n{VF+so0)ifTgR z;t}$GtPN`LD?$tNV7V!}R64G~)Ry1lo4=@D^}!H{lS6^A%N;1MQm}NCwP~>Wv;!}k zJa!z$;(CO;|F)rC%1HqEn~fzR+O&)zGB^z-ni=$`bvvQ=lwtE!Bayul-FQG!kG zFz+oC(|sd?JbQ0O647d6UqcGfWslfgFR9sUA&o`MF{`qJA3@K7I+Qd{d79=lX-fls zS_1Hm7SMYv+m}5cytM zZ+#_wLJHryMjEVJBfeZI@DQUNmD{O=(-wl%@o^#<=uuQj+l_T)9H4N^?YU*}$T#di zlF;@OU@)(c@;t0`r4#@QzB_g^$oL97z zWU$MB_}v6A)=3hK*N?qs;+x(6QzIDP_kFkqeek#K{YtV^aLDCqu{5lhanx~J`t$lB z?AP*MH&n}zFHpF4(-7haSm?%PIRF7Bb`{_80}r@8ssy;1l_G@*d}jj7s|2)elA@Hlp$Hp1TiuF? zcEM}+i?>vk;%(cl^mYxbVO8a!`w$OQ;MARw%o)rRBOi3Uu@VIZRd>EjXzV{%MihJ; zpb94Og}hHmHe5s<`i=wNWBX8?+Bpo)qkcT)?3@W`XO|YiK57?6q~XT_HZssRT=V1! z4ulX92m6~f)ti`vGxTde=lg=rzI*hUG#DD@A{?9VEMO{u%@rAbM)U1_;HcOW0}bmN zrFIboAL%P|AE`gk>jQ&TxA!}OF);me_CUz0(a^l`+3$k9RS?h?ip5ny+ZizQX$I`U98oU_H!$FoQG8A7Gyhb2;WG9$^EMq1FJCa;K}-x^Db)t zn^sOEukZ$R@m3dBpR{a?9H1_+3GeYU@UY_u9p2wLj0(^A>A+%PB{YlSa`7#w3p)d&4P5XWUl>l-V zxBk~(`WrNko*}df>bM#f*<u5UhLZrJhQix#UY41ak3(&8z$ z>}h<*Ya}__@U!{^CLeF9*m8UxJB#=7gp@pL@h>Fo_4|*G)yE=#Q4RKN+lE)nrRTA` zYxsmRjn0GU`Z|#4Ms@MpD;+>ZXPAO!;yR<4LmoGOSE^H3l-n|(&q2C5XLBu^=Ahz{ zj|A=L()IBRLX{db(d3wH{Il+P1QG@49s8y?%XYMS3hF|?p&S53Iv2Hh%O+0a7V;b9 z3_ua}u~e$73^$#@;t0)e;*m^C)_EE|i*stAkyZiHlC4Bgi^kk_^!T@8BggKrGH|7S zLm;2V9GlJ7<+fSW_7n5{_e?PZST;JE0uK|ybWOXxk8OIalP>zJCUsP@8dl4MP=TjJ zMr@*fj^9|RJ^ZH<*M({HkKX||@6wfON#6vSc{Es!QAg2sp(2C;%pp9pf0z&XO@3I* zZx9VYhXIPU9T;+KI}N?;m3aVZ_>fG}%^#4Muy=MIu;Vit zX2M?C6%%P_)%!lb#|5x#r_P|{-cm&TgpHne1SM2D^-$_O@ENb7c+oU<C4n?U;uD}qox(gquV)L?|*4o;8U$Qm-`q^{{wUK z!l28|)dUx2nw25DPn4)8nlOO0S_~mFS$&GD*;}+N#^3q)mXoduqRoB6P0JBkOlGDl zCkR;+(F+XkzNx1YYW9Ee>Sd>L^5=rMy4C@7cfM2rET&Pa(R>Ea3Q@dI+I!ui#+)q9 zRbI^zayTWO)HeQ>^6V3_^d43R#!3a37 ze1BglPbE5Wa(92l*WL2adrq06N0@ddaqW~onBHhcWLI&na~yh(v#E;-b0g?Xyfc)> z0`PP`loTcwQ?js$FLFW?HeO5 zLom*H2hNTz;j+L0Hjz)`P&~0jk*-QNDP~bbaN3X#V-;0_Ag26)t>_HxW*V3Rqq#jK~37pH54J0qER{OkYjCFKkuZT8F^Jk5mV}o5_REkzxvEqJHcB`kzAm}N8@E8WStVqEi>xG!W0R{vz zJQ}pWuQ>g`pT23S)SeTR?C#8R`Ig z3?H3rPb~S<4{_ulPWuD__L_ptM%;x71^G}&y;;t*&xN}rw1uAUV~ix8g06G;;(=)J zJy(DDyPsRfGHS)9XailKGQ^5xl79l#Y80^ABTKpcD=3^D#GgKd>zrJz5 z`#UZe%!~jOcQEpnR%H*qofdH4vZG(4@p*P06M&!zQ;-M+ki3#HpS1#VSV<=jnhkbY zl_Et9S|>Fu&vG+UD8O==1OE(drCl`evs3>aFg8LkZ#+Y`42eKfMEbyCp=nrJ{4O(-nioG5tEpFzXI@HtD;xZn~NSA)& z7m>&$8>n2r442@S(7&SVc$f1Rf#X!N+OPg`hj5di$!*=2V_@~17elaMlE!{=U{V{) znIi8ov6Px!b?nz}QeB>euDoE(pt|F(Iwp581b_bStnOiYQS znUgRpOGGsBarDBG;8*{H*+v{bO+>EArG;6H1xytghV%Zn^Co(L0)W7a5d|Pk3&0Hh zCz0=id>)*m`FGw7ekBd{#-HCt{*UGQf3)KN{iFZhjsMfx(0r{zG!YMRe*iWbh)%{6 zfI9pmB1gt~p|@?;c^GRN1(J@RZ3j@4nt|!*#tsacgqIMeLC;yT;T zoZ;fPjnwhfF@96^;<_l#@M0b3Tk(oJuzlR3?=$PKEV18``#~*cI+eY9jIF})ew40z zYO!4p)*goiGe53S#7iWZ$eJ}5Hl`U|-rjwCCs|k3C2hT?WH?6kjZap~+8(hVgJ{mT z{4Tag{?g4+`%5vMg&_v7soT3MhaWR`Pt0$h6?N*oc%VS9yUj?!u)Xv$gg~;Z?b*(4NZ9WB-C9uud679FACU>+}MT< z?db1~H>XC8q1Cn=wd~6o#?q@oc2|YT77o~g6b9@=@b2!Dqa_{LQuUhi&J_l~^(5P# z3)1#p^;X4kauKEX}RRWgYgaT=e6I(jSlp` z;36lZ<6AmYvt>rySmmrwy^1&4^$bzox%`u5weB|e{v+EP^jvY#57uo8-{Z11pWaZl zAbeeo@0UMZL{?XxlRNm}S6VdT80)G)>~Q!McPq@M#b`5+3ohlrZehkkC64Z%<}N-x zgZ&MT_WHnwPZztUBPKJ+81dYl_+f1up{5JG<>z&6345YOqhqZ0l5hNNzRnIc1Af_;7)K}+-rD#ZWs zoc$AlbTs$89k*(k)9}S;r|1WJP9eVwnp32|4wJE&{thYyB=FX}M6 znjmvtt3)Z#nvIs%Z$a$A+i#;frqhxtms<<&><_W2IVndgw&e@h#aL)$`t$HQ1%+Bi z%D$d>yw635{d1x^$^P6FSjgmISOe4<%}v-nq~TcUs|UBk6h<}X)@rJBpUpTuG$L?F0L7ldVf@|)~CwEbg*(SKWa=qC~S?&&$-IGnm9U9f%5A$Y%8%-HHlS95PjJB+G+GQ>D&r@B05_$5{WzEJ> zrEf{9I)YrBOSV^S2salWZIxDhymrwdUVeZ0Q;%w-32Mw_O1a!!oL~1fZF$+KasO!N z7lzL2S2A(#Eti#gBPL?iS~_zw4GJE1*t%5E(?ku6*DH4EQqa9ZerWbdWou$K{(fsA z4rDdWOLmXi_C}G*%dkL1i1gH6x;5cpSj64O?47?nD@J#FG8ck*Hp{q*dTrHioSK-) zTw1y2re)x{(=6_;d=#hPDcQ{Ex;U8oZQ;vQUL|cbCdJOsfSbBhB59nzf#LDqE}@Zb zsl<~~;?~y8w}rtkzBSazJOsul>j4wRXs5@y&mOeZ?}hw%7P0s215zg2!vtxP$(!d!=d|l-D63)EivwKzjP36 zaWkg<{QchnP}u}RpsctqYp2JT_d$-rZ`FI%@!WctG0!z4kiW2jCIJ;*;V{bvP(fe~ z6Bi8FDsIn1qs2p5M~fu3QG{;SMy+sn8fnE(^G<57^ z^Hkqun5sSeeiVc`-KImikX*hEN>L&hHG`_W+wb5yKp#n(oSc_woA%7#QewIfm=|;W4&HGANm@79R$LY3BHe29CjW01ho9 zEXQMf3D>k)Hon2Xq5yAUDzxh*KV!V7Ke^I1$i>3+viP`*%D1c8uV1}FO;g4&167gM z%h-T}JkV24x}$vbSLNwI6NcPf0AHFw4bro7UoU~uu9{+U{X+LRcQ@{4X$eO!%{+w& z6Zk{CniVOMc{CyZJPhnWkO1zj24#vThDyX_=R4HhY35s zMeyJH)`!}<_71(6Xp42o=*jSvIp6Kj`1;r7?HQ%44;B;ZA5|3Z&Gd;X4IQ}tnwe1T zpW+s78d$$PP})`Hd8N&KZTrL$EnfQzPpaP~{l2bgL7nQ4SH(9XC+bX9EZ;p=%zo{} zp{K8=6*?8b{zg=ZyTG(WLG>V2!B_nD+Ju8*mRk(I;OEpT*IJL7)+3SIRdKmQn}pHk zwKl;JYOa}g^@3-#+p-5N!-iidYp};_MpYDt=5B0xWa|XRUH`VjxFr0%5tA&Tc-Haj z{)MGBdHJEHHa)Yq*={QK4^zH=+Vn}+;O}lrO<{PM#o7G!+KT53QJVQayT;Y7D9gj> zNtr0sh4{GMsFLn^J3l_zb}3a>dEl2t2+CAGlj>>)254fsBO0( zcXZEyw(&msm}^M<=<2Aj>yXk2Y;EaYEHz0Ipn5Al!6Nok<|)vjj!84c&4J7A1 z^MQg?M4Gz1*B)7EJ1W`3;YX$Hz~?GMMlN<+LfonYW$t}q#_k#w)}bCzq^>fijI^%? zd_Oc#L-GDZ-Pt4Z5e>(mKF!5?1>b`eSI3B@Zj!YFY?bDV_ZSZlK0UMn`l7GE16`nc zv7DGJ<}i~`C+mIGsltHrpKby~cQVCEa zKMdK&=k|f00gc_*UQ$(_3h0$Y@6{3&RaGXQVJLy+1wtLzquY4~`MhqQ%1DAf?Kmr{ zieI>BKRI+S3^c~YU#1GABb?@?#m5~lobH97u_LY~W z8BY4E7jx{l)|WBv$^#^i@tWB)rH#pY)I8>QbW6hvwP@`=HC}k^)=^)R4M+FH;dtjC zua5NX?%q&SAh2AQe6nBZYV-afXbHNj4{g~WC7!igUMFluPFAN6PbZB84NUgLCB9%h zdQx5`zci4{px1+*dw`#8v!<=F#mr^m_NJBE0lVCJt;g{t4J`$Y?T?mf4hQnqocigy z&~N+J&8>WNGv8FWdnNqD&!TVT+0`MR#&`*n9YVsR%R{MV=e80-hpF=0R{8rG9$FKTj*bUKV2cz_f*y-ve54%Z!cEO9;>4|6FuVVQ(7U?Vq zd}E_$n}nk#^AB!kj2V?Q2Wk*HD~2~2I#Wzfj2;Nnd`)h8arpjZBJBl@qG1k?^?g0I z{(~%0Mc;+zgt}bVPk9N&@Qq+MtwF!VoMa?|10rLXeE&VH!Jbv+ni?w^t zsut!SKj|YWmmG_&JIPc){B}mj_xmB%b7I0BZ(cn)((&z;s=Gr0Vjwi9H==MWou`fj z-I$#^T^aG+<75<|1WqA;4#qm~@ih6>UQ~uh7@ch# zI+H?ZOIW>RXjsI2;TUHP(#H-w(cnnC<%zKA> zj`_ldswM#KvU!rljuX!Hz})x38(2m!UBp;?MQrJme@Y7D%20-7ou}X8^Uc6%(j#@> zhNU!3+{W&HS~se6MpX%IaHG{&*>BR{AC>NDNVxU_Nf z6dF_K%jZltPW zuwnHJV~m@fs{9vm>5nkaD7OEILo_#Kg07+3M@Yu}wFhOcpQWue^Fq2vSb)&c%ia_l z&PubQEcyiMkIdC4pW)>eqMa!M1;-0XjqE;7lLRt**H`=M*00~MFm^K@<$-y`g~1}F zD$)%F_d`Sk=BM}hGzNv7TVQ`mR#ShPNVPw&rH@-YuUm->`BdNJmV%08w9Oj>GUd*q z=LU0_M;UWj_Za-MlHO~no)B~QE)Qk6Uo>;ts&C@!BTaXrbE+qb3zUZOkn}%Y^gG3v#TGqZM4p+yw;esFTc>+!SgFie3GhfSAOz`w~m?4?-vSjo}VtC89m11 z{aHOasFIqMme&gDebk&@hqC2#t@qHgHT6bLtS`6BP3I|SonsJ=H_O^lrMa1-pPTvm zPMfmZC)Gl7X5)iXD*HQnA^J?8(hc|JLsTk;N=oq4PuPcr0@Qz5yj|Q?o|Bkt%2o>B z9a==?zmxG_rVWhx;aSClWqiw<&U0?*&UW#g+3B}Z+;gI6BA0JHy($$0DVyU|7CL=P zk43c91i3^m$_qX2`LU*Qwr~FppO?}2DZ||1`>ND8bB1QBt8@$`B=2m5bvZV=tSW2@ zo!czZp~UzHm)UuyKWJsw;L8=*-{>}f%!Yi*tFC!nEDuP0{urcIc#V3mR!4{43+}S1 zCx`_os_2gTo+5E5ch)+VWI`I7c$9zT#!(*iSn8|jr^dHlls$Cz_BxVy4A0v>5U8qj zq4e12j9O{C?*^IAzmqeT&Me3^6rEa0SZ6XmVo3Js`h5{`wT#mOc%PFF=h{#COv{j5 z>Se}glOCx)dRuaP;!Mr_>tg8_*Tf#@=fsWj$kC6NbtL))T2c@m-ZVWs$dK3tI${o> zv)=)&En&S&AvVG%%Y=9Ir!u8z*aQdSj4{(w_gT96h`Al^(tqk=`>>`@>wUzTVMEF& zR83)(LARsgKIQyRkbJ8xHr>6laAD>vnfLtB(11n1X+B@U+qX{^U#L6huwzmq{jl`0 z^JztKx=?v%l_PAWd*B>F(X@YVY0>99(bxs)Q{I?386!3kS;qw!6TsUX7xGeW-9E(1 z;%h5=n=WUQVd>P^`C_hKG8yqCgGw$cc;UK1q7skpx3Jdp7Cx%U_xZ|*l=O)<7Rt6) zwMRbPVSBJn#q!BTRhq;rzl|+LrlEM+mF3+Rx0{aFIqRNDJpM8CeC3ppd#$T0Rn4pE z&rYBAUliY>zrdjQ&E-;RgUE&>L(|dkdAW3irn^QlT&K_`{kGoI3Y7R$&8uevaW_Ru zEMV^~+RJYPQIY)^<=t3@sGYU@-KFXUsnER&)|0Zq7L_N^hsOPQ&7YuSl4A3huLx>e ziwsU7`&FmOy+h-SVDyzMp+CGrcoqSl_tGA zXF@9YhQm;m8V$vxrQ6q)65Z)YwI)_xb#IGjD_I?pquRDk!;l2~tj~AW=+ybA&H z$3{l}dbZiKIhW%Ptn_~BismRD=DRuuAeQ374)P+ikx?{37KI;8|*;}Uo+nfew zJ(V90<{D|tBk#6Hy1PW*RWAKqdEua>2NZ&p z9`R|^zDGzMH0ZI<8$X>nw5IZcZH#WzfQJU?Yuwqw<}B?XOD)s zw+KFDuzEUpn9wfJOx(tMk|kjyhe}TT9LBzSeOf)W|7mAj;zuc;FQ*E;5|d}}la>Z;Zb`It? zwLzt=*HCnu#{mBhCuO&t=Dpiej=fA{w&79d@en=kqFZ#0=V(^Er%aZeJJ0rdXGs3q z`~>@KcOysSkEv&}36c-rC}4_(+^=e!mtf*BYAeKVD@mNg7Q2RoeJ>8EXy)w38n&^9 zD$d(~Em}5dRX)tKESgcaztOIl>KgtBNMfg>V0mR@lA*dv@=4(w4P{1(!s}}%sPWo- zC3L>8WXVzvtxqPbcaP4K{LsP7P{tN|iQ?7Ig;1ld6HZgm7{~FwKkIw(y06AB-$eC8 z%T3}AANd}Q%$EWEM&r+_z9#&HPWm>QhU7kl=JYX{(R1sElgPg?Q((z5CZv5d`X#BA zFW2DcjbBPGdysx|Czcj8`qW3vS@bM+v?b)4H#g^#-x9*bjGSlrE~Y(VZdM~bI(W)! zTb$G%`*29=&mmii9~&~9(HESWxHa>1<@BwW*HXl#aSTm&pD~`kE;>zSqIx6wbkiAP z%?lZ;WP}r+)Lqx#ck>e)*ebNl(&ymb<{#W2mA^A@b#3a4Z0cp{x|D>1Gcsweq|GCC zhSH&ofya||`7S|k#4zq`@SYdHaBTsfD^$DkF=LQ~;sg`bmm5X=O1I)(l7v0U=k)K7^@v}L0GVJr`q_;J*-paHn9F5%_e9-KWwIH#;q)Ss^);T%bns2$v&{^bo z_%YEdOO;PW@I!amsBo4!y-F)$xPNW_6@E4B%dk}YN|pt8YP^yHhmmwR>Tt5@?hyO7 zg|$D0YcEgsd9m@5Pl+Z`6m-UKoT@JL#6HB)0Gv!45bI687j&OBgDQNh{yr`_2g?(6guE}0J>kyVCb1spX*muG^ zXog+Bp-3v@sw^1?Cnw)Dz3<9#Qr|rNBFoS@k-X^_P|>DKdRnj>cAb zjZN@f<-$ApQyJb&rAkO@s&M^$X6ob`*%+1Y`kF7Rpu}i}lr#1NGp7#UiTioj5b8=E z;-~kF+4)y6uO^SJ3;A;PPjB@3(lH629CsSu=dgGIo$nK0oEvLtoq8T!@hKXHh)wF_ z&&1Kn7pQOL`LJHF{jxm{9$O|+fAjJZM~02E zC6&Q=M6Ii{_8C%~^2O=Ow{J~`j$T_GA+E}KNbfBp(t0Q}UuD(hDY@1ME?;TVW+?oq z3wZ0pkG*we?l*(80uGg)O&cyod?ojGFH;r0{M?v{i)uEw|0bx~uFYt(aaW7uty+p4 z$)*d93_4CM3+SOlkLA-JM-rum!?gvzX;a_kC@B#S(ta( z6!tSlb!S>@*JyL3H$ej|I_YYNR$&rN%oM$G?Wg5Hg`>jq+ubtipVN6d-7Bf}C)1qB z>SPQ3BW+MP>!qP|h2;_~|1XbC+8-y0gtOC|7D%Gr_nT{cqWt8lO&{HyvxpfP8;R?> z-CG`)Zi3rfS^7z$=oi9|WlUPT`@ z-jX_MW+T+*$nRUPjHe7BcwqQ_=lhQ}K&c1_YLMb3irJTz7mw)lr=O~>fuR$80WzME z>FQa#m_aJ@^(oPrpoWt<8J3?{azRq65`r@;ZB>ZdWv$b=aXIr#|LEasgM67D;`)EU znEHI5#&7oqi9*9UXmW5jEwP$6UUa1K!LSJRa=2V+boawsrGxc-)7qAc>*;M)mahU= zpTxV1I?nc7(wYhi(t1i!m$%(yyYHu287zKdXc{#}>p%Wb5TkSKl3$7n(JNNr0LxPG zrFP6EeT}A67A}cved9^INv8cuP8LoA=8BX>1Cj^e3||EG-#?V2A{_X;Q7Wpht9 zaBPlUof7oJ@P3xaLSbfK_S?WHmbzFY+#)K%D7R-gp7qbOeiu_EMBrWB4MXwShg0J;o$tDx zwqY-KpZCqwFk!;ZJG<&g;2uMW2yI>Ata?+n1?<|-P&z!W@6k7FP&Bol|Nhat??b5T z+vL~)CH>_CTB-ww}}gP~UR zRpY$$$_0_tSR)b+S8fm>i?JTqI|8$OIw)AN!nmhK$OXJ`=KYo6Djnjn;@iM#b46c^ zuY8%lZ;~R5D1HmPopS~}lX=7F8@9y(jQuY14#C2VJ;KL`<*k#kb}Qduh--`!jAojP zsxm?k|@zu`o`yl8cPd#*$EUi^SY4&-E3M!h43MS(9UBM`J=`^mjq)gxz;42+&PWNK1)55B9^D zm3UH=iASoAYx0SCO!`EE^Cn+LEIN>uI40EM^=0#Xd-K`&ixH1Pu)X=L!r{A5hZ&pq znYe^v7MUtKzhW~-P?xgsFFuv>-psu9w92zCU-t!TfI_47Pvf8&^?{4nE}K)m!=kTl z*a<3VI+ci1M~q^v^11@QUxJ=bBfHcmQ_WhmH(g=qR8aJprK-B!T`wH6BO9I3j zc2A@$S3s|6)Oou-qs9c@WX=UsS* zxOAF=K~E>R?XwYrgu-2iPON=;{TY_5341Q1Ul3hv7RzHq8+Lo?>xmJMpN;$SINh^p zJeZxkn7GeC{5D0CxmaZ0B-Z-P9Mn*9e+%E%v91)A%BtHl$vYFG)>74JjwrvSU+FLz zp3L|oVPq{0uTWZ3m*d+9blvhiu?KnCZ9~H~c`yaLkyxWbAKAcoUwO_h$Cm!k?dg5z zUoQvk?4CN~C%)JwEGNEd963Hl9-lX95mC-RInkQUts0X%ohP7M{Ih~Cd6 zS{ou^y89R%{+$>Y6U(e zHyw$tqJVO1`TYqLE{7Mu2!^IcALc6O7(XKM?kRm-c8lHNxffSN!W9j9VTQf&kQ1@M z0NrGR4X*C(o6u_AI_Bwqd{-WXg^I$s<0lDT7?k)vg$jl#*D->FJ0I!e6dBOTmc3=C zO=j1p_3KBv-}beq?z#b8BJf~l7%%jkleEY>T^Aa9YrBs2Rm5-k5#>sAXWsoyvFZgd zJ}N|koL0~J$;+yO{s5A^pre{wHybvXQ1F-B&l=jw$4N4+V}$ihFSjs}6EnBTm`qje88`LNU?= zc5SHDVnQDzIY=)&l4?J4Oy|gC4&HK7GG=KfAYnob;Wex?QCvS~Y(o+zdj(^+U+2aXge@4v{k^Y83shqU zT&$nG4B<`q453RP!e1dS$PnkMnBUEzR}>h=$=rX;rduZcj4v_#p&{Q&;Y4UP!oT$- z;N_pk`)i}mqj#^1q8evQ-bhPs88<}oXBm(ag=Y?xX&jHZdZl={J3le!B7{JI@2Tox z@paqB+YD~tRVQPt@r?WKq-+M>H39&!6;CA}pFzX5!T8mMM-O)*RH-YTnlk^&I=puu zr_QiSzZ)gs@CWp`i%6}JOLT+#+iB~Yc5jc{Zy61yWgiY7V9S(MH9WOi*_k4I-P{JvX!)xYTMwB*ygEp>phMqAZt z(_Gdg)we4-#&-Tu^r^Y2FKg?~BbB{gk*_nrg{avkXO|L2Zjr=R=6dACoijwO#Qazw zxl&%@kVL=aX=L1Pe&Ax;Wbq6>#o~{=@G9GZ*gl&*e5Y~ETH9vn+8Ub?=ZB5<{@u*Y z0%zunRlg&No1hvP>-mU6- ze#bxAepg!TfQhQ;;HR3er7FnEpw_>UEg*(ASY+68BTQl|u#@in?dAD4KFTwsjVR)~ z_?Gu!%J7z(h*v;W#VM%YbFMwYxP=^6-gg~)4ymag=ksI%bAErVS^q2dl6J>Xaa@1# zD#rQZ+*TDHtMJBh=wl$eA%-@}wsgPw)*li=biAaG$zfvt^^J(U`6uoC23U{&1fwmn z71HtTwiJ8$iNVa(0%)w2`#yMJ*y*Lp6&Ji@{G-2YA+exS)Ffuxi_PP?#eZ;11uso> z6K0vsPYvj#Zz#sT!#ZUiM=>lj`<|%P47Fr$f9c16{Lwm#y$n)X`m@ne*+;+FY=}CO zFqNS)Oyl5F)`2i17APNL5J9}6kb+pEfIIW zKeT+A@D+$jj4`kI5$d zNan^>?fB5Je5QDaW>jc(i{D8<^Yme)J2o2jJ$WpFJ(rH=4eyOD8#(F9&?tV(2iE%^ zqFM5%qTf+8kTMF+6d^h*U9o>=n6TT_d+Bno_YWs}_h*DEC$A(HY3&x?jz@^!=)0Sv z{f$z0oNpc^iaVXCcZoPhm`ruoh*n&ujI+cms>em0%*{2PtFXGZxQ7~>1tbdO=1A8O zFWi~VlGouPw`xE0cVO^!IvP>>=D=09miv&2!#PTGr~1H`U}(xR#L)8tF5T9GpF!r2 zCA@3%@7n+Dbf^R~>6_Uy<0|ESX7SxwDL7Z1Ka=>F@AhcawYF0EbWz?V_xW#x_Is~G zl~L0bE#sq+_m<|tI5~<^F{*8e3HvR=^Om3gy)}QTf2Fyfmhl;ZWw%a=FJi{dkkQW@ zW+*g}8lW%-wC5lSPiBo}G>I%uzjxxOkND`=_el6o2AV#E%D#UU|7ov|myi#y<;#P! zuY3<$K?)YS`uSUU1hiV2Qq%876E1f<@ZdT1-q&HfftVC~#@L`4b{|y)sxAHOzP}bA z8u|qN8(vS(T$nxgn_Pqo$t584#SQf3ukCKlIG@lk`wu`zCcDQ|cLDtRIe-6FKFaK` zZf%u^Vwi#N-lFq#U;6d(-gvQ0_zaaCQCw8;^0l#5kwWTk^a(7oAKVFYVBdpasOpyr zwG2H6Ma<57M=?~M3d(T`%9L%MKiARxi+ht>M!(>TCV*$Ggzt~B%HpXI%D|R#FTd;K zYe`PiiXu1pUMVsM&k-5o_>jII)~GaS`3&W0xW6)*Ip23{_=9K-;X&F?;FsB2RNJ=g zZ+W+%`l|H;ZwC+e7AYE&VzGbd>$1n=C`%YOKm zhxev}n=uu4EXeSk2Hpu)}P=2l2fxxzIpuJ!b zuQfbb+bO|h8ZVORq9vpG*^NL!^0Kb8TLTEZ?!yL{d_8qk$$M0=9%Z3vUu~-zX}Ts` z;utLD8x~tzcg%+pD>*aUlv!jdyC=4{#4Jcmjz{~+F$0|ZqNBt z#yGdS6JYZ0@d?<)cBPfoPbQ2$NPRiUNX&q#8UFh}=W zPKBF&-r_jz*=7FSyx}t)*UV>m-3d4knMo!w;)`d_>&7w=mbgM{h09Tjh3((Jza98p z_;uP&{@Er%xtv0^+9iqI+D&o2Un{@TNb8`vYnO2M zm*;eh$N9!)jlx}Jw9$mKvrsRY0ZyGAU^S*&wUZ4UwQ=y}MqF2AN_}D~dcQ4En`(99 zSN4urmJ^J%sbtYJRExgFBD*1j#uHL~-oG6bB&xEJ>dHnPt-t*F8=p~aYDr6J`kfIW zG_C$(S6~TJyE0v4QSn;%{!z?<4TbYr^i{IFPh~!^B&%4d1RXl|gVH7)@;dd8v>G*0YuBfd_ODgl5Ntb4v&??Mml`krZPngR4 zq;8gBB60^kjrBFoC#x&Dh8QP2jA~v>6XmZ?*-e$shkBHS z^7RJix0FiT$A;Y#LB@ACueUQ!%WQf1Wc3`gPp%s~1rYn}9leT7v?W8taR$!!twjAs zao{>M_`c?(6-kCFYfd-h&MUFOG9N-=>#*>mbdTJKAaAGc) zw+0XPX=VK2&%IyqV5EYK#uIKT%Sl z$pcgjW9gkEC$kTOXv57(>Qvcl_>~BvoD(J^u=54@Dz*OQNrzClL@DH90${= zZa=#uC%hn09VC3g!<(*vGav`4C#a3d&IFsUaIADScpf_GeqOsXO^-24x#UgtAn4s} z8Qa-|hJnyyk84fgPJ~Z!lC;s71asRIH2qeeLHYb>b+Ve11bRBl`ZuG!QFhtf&mK2T zmJtRK+kND4|C@_E_?zJ_3uD`j8pcX?8~asPDvSiA(p_&7aEaw#2SJN!3!&rcuoNb{ zzo9le>cd5Y>ll~5E=9;1KApqtW)+a@#gOBUpnXQZ6p4+mNQqy%pkaInvhBX)F=`E< zqIj3O4Qjr01~PVQs>Pt)_q_Mm_ZT*wAv>Nqg`iC}r~Df@rj@lrVr0c@kFh>gtB&aq zPu`s(tly*VgJ=gppH$J%xREDicc1T}&jN(72=o$=12cG+X*dT_|K<&(bAeQVa$sN} z@mcWS4nsh|Mf4cIym+OKiAe@Ng9_bL-gAgal=hB5N}TH(;4J?DJqAkmrMUm|&zJRs z_4of3!~Xp|uq=uU;jj7cmthNh#Q%OZ`(1@Wi~oB0VqTa0pCA9%f6z%lB>&$peD1s4 zS8)}0#3dv;0L)sO?UTF-`W9IVvcw%#U6@Py#%=Jp4h5my%kJYQwq*Luk!Dq6ztE`}}@6R+b%$o1Y zw9ESETR^`Ce@>do8@{ALfUqG4=YJQL{)6-j$@Z2p%bbJM<};)5lYmnEty~zbLoWa}6d6GUlB=RU5%Z&4%NjOvosz{+?0m-Pu!@ zhNE7lf#P_R4ijv8Z=JGnreL*rD&?ncK38o2Gv-lX*-uy3H1FFLk8#E$>Z!XZ_{5vV zGJcukR}LY4M2g5iPeJiMa_dA~ZA!-#!Xg*YAbxDcbXR6PMTzzQ>G%Vw=tc2QCXeZg z&g0;ClRD*?(*)j3b4~x(Hl5{bG(XEGsMabI=3`802t+r8aOmg!#br|KawvN9L2fWR z$2?f1=6wCTS3%(9#1KtZZ_SKd{c6p8?`+hoLmnC+Ma*H3rJ~71+isJoe z6&)j286DBV=1id{*kxz{Z86;H$LmhgU~~#jv%!Ulj{{0|{XL&CT7V(E7=9o}x-cm$bJ$%!@Yyi8i1FqeT=dkHNEdXQDh%+}SI z)T4~}#d7ZErcAC06{+VvJ6cw&uM;D;-Ylrtvts>cvq=ZQ1jI@|2-Z!Z+y-AKB~VbL z?N32fW;)yKySf7dXEaE&QlAOy$tp^ycqzqDxGqx?M1aGjCJaK5dwB`8LwZN=k4^Cj zCQ&ue?=od?gjHjD0SXt%4NVkqQ9{=9KLlc6l2}i2X&yim^OxuZy5`wduAOwa91nXh62+ zQSQ2%#;EA=?+rJdIjNxkoV#>aFv;fWJ@H};Hi?_}wY+B{Yx0h(@UPPP6wU{PgkY>(pmkmYaCjH9$0f2^)I@kcpcYi8cP1~O zXx8Sh2lEWksN~M~o7T~OLm7Y;(w$F89r+tbI7DqP&RhukVIW5SWN#(C`6-yI1V=Hb zO8X+wo++d}Z@w4M5{ z;YJF$2HhA%Els+%auF}*sc#yQr)jUbCs8)vfjiDie)V@Y{oU$0ETr^0i7tEB41zI% z9i#U(0_W+3uQbkI1UNaBN(P3G%x7l(89dzn<#-lGXginwv_E!#Y2oA0+K-rFE&HD26eMsMzUkm@sq$Vn z$@0?ybK*|N>w&Y|KFDWo^%`mBQF2izzj3*Zyh(+?OmXStZFNyWV6D%!r0CwNl$sRe zz{2v0!M$6*`L=B|&n9WEZruB0s^558%hJDpYZKpZD;#+|;9L_@xlE0~HcWH6QVnxA zM_p)F>aTwXEV1sn#RwuAeN!N{qy&nis~iY)*lPLLe#FKS5(H6#q9!8%eF29UVi{#s z43H+DBF3>*L;0OHWXpOL6%_}8I=x>CfE1-lD_sY{W{De~&boE1Do(EcR&0R2CK!jY zsplx~0JRkf1~fUH;sOUyn^kVIhbbRCQ150c76*LAj{bxuhC4mWJKzaJn4ewA`)~%g z0MCxt!Zoyv<1igwL-na((Ql|jN86r+(t0GEM~Ddp%UftT1CGwZ&T{Vqob_s_SO9IR z&@>0@OSLM*{CQsCW3LH%dZe6m*>R+hnq!Xk2o;G_tjWU7$oSl1vD=4hDs;0UjWZ)_4=hv4JGLX^@mcd^!ca+- zN&=MS6A6xOQYBQ)51dCBQm|u=_FL`h_hA0ge#NyERB{#cj7yed#%u98_BqZj?t?MTUps)u8)hrZ zmfUkZ-Z6zkQa(-LHax^Lw(cCWqnA%ml9xO@L^4z0|FbnqzYsqlP$*u0ojnXAc{#HR zAGQVziZxUu{m~@^dhG&!fZc&Y0Vw>M)gknz|0PPG=9C%1Gd!XN@X^Mj>G@b!U;h4hBsJtr;RT7(LZuH=@4~Kr=!?Y zGd4S6*RFeqvBJ+Yrk-{A%EZgYFHHMSuid*tAw-PB-LRvQhi=0DXBENxqOp(5BUBS5 z8jT{=!1Lp>#^Gedf7Y(}JOy&`B7h;m5Cy=Pc;e8ZBHIP&{ZfD?GO*p~V~|wYzshjM z19Ls_b1$dtBZG|=IMe08=lY#^rJD_mkw{-yRSz1l`g6scWr*oeR*AN z%e6NueuT=qAzeH7Vw5tH_~u>1mx0YS1}Czc-^}mksJ953tg&{Tp@v%vQZOn%Yt25U zCV|1bT!M0k|fpFQ2W@!$K|-+)>=i_Pi&;+xh$x^OHadLRX) zuBwNW?`ldTjGV15HN8WfD{QH`%D`GowE(Oi^Y1Es+-?0Ov+sEy3C6Y3FI`tfpZ zC)Z6p%vs0ZlbQ}WCM7e!TD#U>WBG!Jb4vGTrCkb5{Y*v2@L~GMdMxA4u%=vS64v@D zJ=y`*`AUNhBAc@(G~wN|skIM>3RO0Ps`((Q@wCp>{zhm%LK#+pdu;EgI-T-55-ajj&q3Bu!9T}&n_(K)({a-MmnhBj(bI&Hg?jb0p!PrN4R27BFj~&Kk z-8_V{8pCnIkjQZK6NPI3YC`sBhA@|#pLG85V2H!^v#vf3J>~k*W>^&QL)BzAtpY{y#!yM3Rv?Zd`vj5wyxWLmp*)5MLE6J``77fLUI~Frky|d5Bpq9P6y^XD5b) zhN`LhHW+9O0U3i1bqibLKCDOhNWGBvK6xuLg3sK zjlw5vdkFTJ7l1?ZnU;Ust!WYcmO_h4=7p|f_Xnk2vJ+#DK!NEWET#9V{O?Sav{T8M z^JZwdWXT>km0z@TY1T~V73@~mU;dz4(tUiVbJL4cNFFJ3S-%T{2tHs`fS>dQkR|fAt7Z_76c8b?pAY- zeeJ|{R2wsmGn;eZT!PF3RAnqIED+Y5#&nuqcKpN&9p-F)F>*PbnUhUF7Z~G7dE)J# z+%>FsfnnH}#g-&|8QoJG1~z9*Gc$_3ZX%Ht^%jFmx(PaAc)Yfvk;R;o1aHGC?0^*D z8c)Vajb5#PI`-=0GU4T+*lFIhk(%KHotg(b6Sk3O6&zcKwils{Y0Tjh9e42mll^_9 zfW&){_n~a7Ksefc_BsYXJuc^);cW`}mJ=12D_l6;M0WR#oYnP_u@hCw668w+hn*qdGL+?3m__n+*L$srROu>|l z-pUG=`KSeV2Z?ds?=1$jv)v4-f@z$%((hDcC*qynVGpQi)R2?}qA^Zxxv+a>R~L&z zLVwKXrnp;gHnP4R+;&N@U%5v)fn7E6YomGNiOsQAx7P}P9a3oYVPdLMl?mDA|M%-V z1(K9Nx@g-f5QcXDvDG9UjH%19=^H_!I`SqX+p|?64`|p?aNzmv5u+`Jq{=DYTH&2! zSoBNeb3h=e$J?XFw@-1rjV`{^g$3@j?XAL2V?oa7pOD4irkxDJq&(8e!)Fb?HCp79 zdre4CJ8Y`<89zfK@Fd9f%lhU44h!U7BnW2pJPk^iqfu#uH<+t5aWm95K+}!|rxpNQ zvWmEUjwplcXqzAjdhZRfva`Gd+RP7HE|;*bs9Ui~{i{)Iqpe>%OKxlb?>=!gC1#H~ ze}=A|(^u{V)L;S5RvI_#*Ldn*8Oj;>Og6?|b|lEeOrbs^P-zZdGNzWHxf}_5oHjYD zuOuUjNA#kNe@ZwkWl#m>ixWxRUexI=q1cz7UfJF83wOStOp*9bJ^CC&bt0{RU$?&S zZ3~%BoB80WWdi9wI;B(1v{~4wWkJPI#uIYg_|bZzC%sTOL|M})68x9Y3;7f-)_73i zpo#$=r|QB>j6(D7%a>nCKZ1TDh$49;8y$n-Zw}T879nX2_=+7)3!Mb29s$)PimEP0 zTZTWO5sWlJL8KL#^(Ei>aea*&9E%9J(;{}j#3Bml@vW$z(5Ar?<7!Ib4Df{s48Y=4 z6dj-LGsAUkasfi&I%I@u0#=2$n)!6v&ccusK6HKDrw=liRIn9Zd+TMvyg_64yTD`P@()mpc5GPR#|CUJkPJZY1T z`SG}=74RJ#`_FUyL2#U zJG~y zD3*S-`2ax-?j^5RCMpXNW8zl=T<+lt83icb@P$Mp4t?5P#5qu!H~o!<44 zWHe#+MicO%z!NM0>A-3^j>Yc=G)ZI?h(PE;od*DeRq28pYN8cxJ$5^=AjmKhk}RV} z@EaQ$4ZG<;`3HlPhfP)QG@87a!&)??%;F7awsu7?l`t!Jj=9A9un|T+$m7^KYz@ke z7$m>FaQ$MJ=g!ZdMm*{$UBOhNQ@!e$T&^w4;2u)6I@sW=tha1_FH$oGSyFr*Aa_xn zTw|%7RU-Dc3s>z>94nqLlQ$J*Fg3GA!Z9sCq2_pYNFzs^ z+VHz(x{uf=xeuSXEEYTK!E!YTb)r* zN~?a_uekzBokEl&!JMx6l!>w{hr11bXNG-CVnwT_=a-yXQHXS8Iso$$QbXn>n;wLA zRmt`9lbz!@(t5j@{T4-=5e=<`_T zlVR1kPNZx(sT$h?PWNovu&ZlqOEq1wi_zoVrr*CDU3abdnZ>@hb|Ktj#GQ&aOdrQd zb52;>Qch7bz4^0IE`l{ixt>D!A?h9EEjaZFK(nDH=lV&LmvhLY$Nfxjuy6l*G~1}o zZN#?tK3=PNZCL*BKex4FHsKRITtyB1?)2KbHy!^8 zTQ40Fum5v%A=kqHp~(ROej0v`Zf(UM=+(%6nfFLB1P%Zm85uLwMoo?Xsb%9%-Gtwx z7$pAmsWjN7Mw}o0?YaDOFb7yYB=w2@XUYAaf8YOoQ{`{J?4P%xvq1iN|MgNFV}rKY zf4%hApiALReq@B07d8~NZX_aw@*9zvzxZ+J2QiZck&)Fb^AsM2-;>i{ ztdAS~;U@pSJdi%J09gJakt)l7?EovJ#CWiHd#+tZRyM?>Cw~9ajqv4Gy=vP`eCYfj zp~~Ww57AD5$~H-h9lTJ1em~N6^YUO+h80kiJ;deM00d%LzJf>Q>MRRRRD%*%c>f34 zMg=lsjQhG!s4}+UOWNrd!PV@gr`^s=QFa>1x`J( zvu=$aCQcgblIYLigQOi~0m^@u^v!Kb=SR)$kgex-8d==__x?-U^M-0Hei>BOyI`1` z8R^W1D5E@K6?JF<_PdHHM{)ij5-c(DT*U&5kj)!YbdOaLyh49g+hx^sqw`v6|9z{p z2_iTe(24!jyOa1U!BvS9FhU~SXy>#xJR%jUt~g|5`JN!`5B?ys$LhoS1}sHGFq0%P}D}&@rsKH5rS)f`fu0An{3?<B;U&0qb?7=xQ9~3T z4PUKNzB(9Cs=UPg^BQ%+uVLH>lBex3MpZ+lQwx3jv~(hYUAvKN?+tbbtkT8K2T5f)Tv?5k>;mz`+^5HYNn&Rqpt`;^)ai z9$MuvI{w=;mXo0HYAh{!rE#xF8SdiUKa8g3|nrF^o~_- zO@kIOJ2W_B9J9qfZK_B(icV1!5dC=-9uPR=!8{_;vxhZjj*RUdr8}@Y%73 ztb)KGrR}uM^X>UhLV5hKb~gs?ioE!Tj}#V6qYy!Q=2EuIX64*3p}GTy*N9zUGAscpT2q;U);dcHsJWSf^6~6qlPCw4(*<` zK*All34~W=OQ7;&rdY&_hAu~at&q_EeI$BnJXP#rbMdy1fPXcB%kNCgNtQrdmru;Iyy)C$I4 zT4zsV;U^@so3`m3ca|1lUuAQPYtNnisCRR6V9ILS{z$xbXVv9Fzu6o>b-(CQ6zLJ_ ze!b`ZgGj90X=PBtgZ*FFx`-oM;mqLRyYognrLi7NcMHF*7K=MGafeZJSXDo?sva`# z_@%|s#vJ$iQ@4%G-O&gxtBysjtr@d}Dr*1N9V=Q}6lNP$D1y)F*1j)k?bP1g>rZ`L z82-A+i%~-7w(HCmfySQw7K_=(S|4$LDu zGMJ-2*nqVFEM|lBs3xp2OM*YP5pw z2Vke4=Ryrqku)bjYZ2AE1UIzyrCnsxP#-$YdT`Y3pTgF)m6@(>T!0Pf3JdRC2(@As zB+-%ku3~-|13fQFXHK1P$^D51o6GD6}(;l>9vaD;&muTWG{6@!f#Kv3?t>myR3rZ8e%P9E!T5rUaGNA zAKV-q8lg1Lmc9Q9T4XiC)44WN&}kfY0FR=6c%$4UX!Z}BEc7I(3)?S;H^7#Ln(m~~ zObgiACNA#-{5{u-gwH;E8th*iPl+lj8y%7#y^1gw)(-=$Uak;aRpMc{%2?s(@7;84 zbHg51(}2yCSpdH~^#WWBj@*;4p`b5A&-?c2ag*Dv#n?v`)(}q)yY%a83js?^NPiC2 zv?~-kJcQa_l&-)#-a2u9IrQbj%>Fk=Df0zdqTLYX1+^~lNVkG8`tH79<0wDm9|os-k{EQW)PvK3v!NS zPilCfh~4MxpO}s2NUVbIAuk7_s_ z@uPs)!RBxw);RQ*Wgn*{?GW#?AP*!bIyd2u5{ZR(Xalvp$K1snE`XTPP=Xw63{zr{d0$}A}4AM)&P1h_#5{h zUbYKg%vP)+oiR_(^EdtI`oea`lI{Oj~VzJK)bNmi8c8CP`i`Bzl&WmYutwSVT*{TR%rJ1BXr z$n;_;RO`}I%qBwyp$cT61-Z#ez#-M!*W&G1u>iDO7$Uh3}7NVtpM*6hPxGIpe?5yGq|z>?#vhhHqlasMr`+|H(a{+pnfx17ExKF9Ai|aI!wr*r+WWtC|*q zp^LIv$f8b@!O;f(wHpO04ZnPD>o_*S=GFBZht)YnFs-g*<2wZggi_X*06yHPP>y0w z?^A6HthfYyK)G=!Z<}t9-p5n&u<2d+${p18pmsE7dY=nC3wrt-L0nMVjbr+r?zWh^ zH|?p*bAj#mx*q!@8y7H+LzZJEJ1;_EHN>$Y^{7XVb$jXdZeu&ZkS6Ry+Ar# zt(P7ssxPhCsjwj2It>&w&%uh7Wk0#INP)3&Pq23POBc!#Xf<#NPr*A$3UMxd)c7y9nt94s~L zG&{kjow;}#T#?qH-Rp1|?Tg^cW@5G+1&{Li)i0|}ppUQslXR((Ob~7Vgus3=xfZHE zQ`qRH_;j`Du$rV|M&%w)&2tcz74(ut2Xn+lMQ3BgfDhHM=?C!#FrTOKKb(#{~*;%lsm7b9{>(!)7Byrh@d^Y703S)FVld%2XStdJGiHwS&fG$}Oj0 zxmLpANlH>o49t|De{lv6ok{kspFb4KBIAstS<2jtBtZv>(Ny?HHV4eWeI_bKUr?0o{6OGpjI4;DAhI8Bt#a%3v zGjY-Pl0ijeOBCHH`D1e!uC$*(R@F~@mF+0KUNuf1{jS0cf}8?(uAnC>OV5TU?nvxeTs_Rea&A-_U}^j}OS%43!EsprlUi zKp%|1EOg~Zqt~Sm60fUKz__(v_lc2l9_X=jdSANV{`q53`3Leqmhu7)iL%Xx-W!}Z zBXVSFM!=V)US9KgN0cfXr|4tTgl`2<1P%DT0HH{5hKD3g7wxnQu0TU4Rp_~1Kl|1~ zrY#oBu4ZGs+aZf8Yt*p~*rio1bhgS-ugMYBY867q(WX@3H(4#rNPJ@+tuC+wdxu7y zN&__;mmj?F!JLl8H-1O_bxX4k#IeI`@L8jxcw4?73Hd+%u~n0G}RlGN(_?765n zZZzX~MLQ&jysB2?JReqD*$n01&{!3OpvtUr1Ef+By%!&wtoW$=a0EvO_Jus0Xh}JM}!jCle>#&_E|9s{SXq&sF7x zyan0F0mG1JFQmiYdz&Dbt2xIUoHU-Exj3j)QlDpJ>@l10O_E7-36F9h;2-_esgjbD zcXhq;U`F{%9LH0xXCF&$8I7tQc>fr2V`Ti^M@=Z9EA6-FeKM4Cp|a}IlRICj8pozs zhOJl)lcrPKL4r3s+d`)FOs(nej9a@|)GM@2!`Hi1k{%tHE89T#jo;Dy@o)pu8ZC8~ z=;ji6$Y`6mX5SDqZFz3z4qi&mJpH?;YsUx6A0AKB73N*5&s|8^hP?YucyJq|3y z_wCQ(xI1^0xQ8K7(0Qtk;5aXk%oKVpq@Hq~emvN`D5?B(2k2_aJDxA?QG`d6Ii7I& z+cKF79`EWc1oQw<{eY# z;F7th^L2U|tr^<*A)WPz5=m9;cMeK%eGJz});f={r2G%m?d;lq7|#ghvYfiazk7t| zE&M57`!QnoVdr`vA}Qc-Dw|tQvpnt3j7I19aK-XtGX}doq;a4&$F=Y$m~;MPgKUzk z8n`g7E%qXCS~-ba`G`5t{N@iFxk?bm=fvnX zBPeV?6GgAAgBtAjK)Ky7E0lS?aZ^(2lOHA2w6t<42}WEFQZCQ3s_yWRJM?A_@kUq? znJ=>`(wdHitEL&wMi3csd=!5xiitu;Osvr2AqDW|DIE75aGH;HuJ?%`PL@xCV~Jjw zxOvb^PvOn7=8Pc;V}%&UCqGl=C09ZR#A)i>qxsk@L%#E4eCwAgmZgR57yF9CnI^6L ztYvZy-H*zQ@z=$ugyYfID*V!JryKGaSE`GBeWk&J8HxD(YV0`USEOI&9SWQ<={jSl z-+{C>2NG9{G*-`8UZeGAues1H%&%FoUCFuc>*x7H;iGvBL3cmfTaki)SfS8Fd6e^MTb6iI7uM(k0YN8*?2iH;bE2{zB(dQP~BlJk#P3-{yKnz7k$Ly zDk2pV({n0}6)QQB-fxy;MNKH3KKs0qOa%2$i=Z{I!R{Eep%)a*(f3p>_l~AV&7LtB`)kICH-67t8t;I;Z^@#} zfE?Mgnv!}D4Q>Q&fK?;)d2)@9)+1I;fmJj`e}BG7hSxKK4&E<4bD%<4i)A%sZ(7M` zKD?54#RSpReqT4WP?j9!sNrl!=5b8irn{606jt*3PdL3U+z&PER;cj!FO?XEs}c8K z2y~t(^gn4rHRYf?qFa?!;{LRVGpOI^l*ph>tJnWX)znnr_*~L|GchC!l&>3`P&*Au z8FII5GBwR#)2H}*0N}_<(5#E$tF-S;ckGa*@I8-+BT+64R?=*@f?5X)PFAlg%DThF zYtQ_kf~B~q$ZIT}CrSn)ahB+hmK(;UdQ`L9J0n!g>PuLnxpG_!PCFfM-Be5C(YG)D zu;?HoZntm&XyR{ST>klsk+QU6%#oWxDr=?IOXYfLdy*6nix+sac)Ul8Mb zGrd_8@=t9-zl?`UO!Xc)Dw^I&I3|k9o?~&x`<;?!(NM&qsP_5x} z9F|J+N@UeN9aiNr33+{UURU2Os~retEwj`8Y;=FWyPB-xuEW*W0w`5njAlJ0=5 z6ie?`|Lf?H>~0BDOg~H;4LuHeT9m}Ho>e;attUzCP2Dt#Uq!A;GLQEELKl@}D^mEl z6wFsLBH{_lvMSHU!5%zZz8!!Ua+Z!`oV$94R?4}8pK1A=d9XdxInF}I*1DReY2mK+ zJ>Hcx+D3Vrbrbxhmxu*I2mbUK9i<Z#q`%cFDhi!6}%Z0kb_=;bv2d*VTRW{qnp@c%#jSr zbnwgLb=zt})m`!}=^Zvy{XxpNDlnwlv&tsAw&_~<>xe3i{>H+;1~ zp4Z{UtL(=P9PLdMZg*d@Wt1 zp>=eArh!zQyc!CD>I=NY1lgp88ZBK-MEuaRtCD25>r<}Xi8Jw4$tdakVMc!BF}l6i zPHho7cs~VPO|baIm0~)@V6&QT|5P)-Jll#Upr0-#5pu6eAd!jV>C_q(u;@J68V*&@ zvQ>Hmj|}CW`;|d6?!c1%k+{5Fy{nSKm&R;Yh(?Z;en=3eQKITQ&!WU6Wf}zdgb_c` zYAO1Hcl6Y^qvf#r(5Fpa{?T06a}fB( z44$glpELB$R1(Ll64~&zjTeHVeX`t6h(xK0YdyUr%i&_JGWVJ~vDPD=GJ6T-+Hz|6 zVRe4RADhG<5>rb?eWTI0a+j2OQK zbjKg7oraiBPT=TTbzFSbFWu=Un`uX>Si~~@Mungn_8iuFqg7Mt_lj|I#>egP6?R*{ znl^Y%XR?PFiO{tWEzeDJVo6?b=0?C(s9hJkn!W^ zr7%h+ow7bCxP2tLDz6&mV9Rc*@ z6?bX-X$h&f&WfiQztq`|=!Ax{Yodm1+R2tK7_Q_TNX-ZWJDO?31Zl0OTcm24JD&G= z#(ikru5OmU>(pKG^8of`{vQqsy85l=+hU~-h)yS8>m`E3fkUsT^*YurXS)iQPOaT$ zzfQUGq&&pZOTKmqhjufDwn6Kt7(G||%)|U{I2|wBl)VS~MDn}a#+X)qd8|9ZVW^#k zaP)-T5hc-N)q`2UmodQc$fVNK7%>&_*q;`@b?-MfpgPj#)H)3{CL4agsLZVDTO&W? zI&~fu4+rM|FY?|qs_8ZA9t>*aiXs+@fD{|jQJRuaL_koa_YPtNfq<0Io1mbgfYL-d zNDHAi=^`RZM@WE#0D`mtp@$O6Jn>%N|Ex71W@gQr`7-$=Ci%5I<(z%?+53WV_zCti zwdP#)`#hw;_f2K?-D*0Yb=S69b#p_*3JVqj*cewlzMfY7B(5Fqbq;z_j`2eL2}Tyd zS_k-oATmy|jE?vUt&p4S_KI2%`C~`J>i#Q~TWUk-lGvu$88F`Z@_Bc5vEmut`yem}>?qPxA5ac~;W>t`RA0OVH?qrtI z=5Qc6^7tGh8zxdSMXy=2e>L-@fkIS#7|)5x8P!73sgD;Jur`=Z<*p5Mz`$-)YS^0r z?IGB~)%)+q!>nY1(T951o++k5Q@bAG(9MVCJT zS6SUa7mH87$Ed(y@f8)8=9+8EEqw%mUVLaEtE!g`sS8_=qa}RnQZO-HuBYkZK@qWS zF0w(LQb)=UMKk0$%o>QD3tnGSK&K47GpJmKAUb9b<3tBGUoVlObvzBrNKQ{q5czn*P9fuUR-P!_0zzdKaLd@Dl3lhXg z`qON&3zKXmfg{s&Lr2NWP}#1!>IaiTek6AMNr7O8Do?-wK!^-?%~c-WRMF9FB#(OZ zYmi;8mEV;-Q9v^(CA$o1=d!pqKGR7m-hQXjJO&_)D-D)Dfkw}`u6A(=GT7&*9w|TA zFjG+)A=TfH3mY1E@;TF~4)pBA+s{<)*`)<|u3YbXl3q&p+XMdt?H!q;=eaW)12V>8 zg@f&$37-q7``kXiPXp_UwO2Du_p>bxAMOdN^EIs~H)+Inzep6e1OhXX4V+2N72H};T9%^^Imn5HzHx2*vEw# zyON!6|bVYI{>70)02ylISSETh)9!?Y=kOw~MI23N~lfa~Qn>xEnyPCdgBuoKI_g)n7 zPrk5z&dzzPf`w}_RbE1uOG`dNAiiCD>DSCjw6jr}(0ER_RNPb22Z|oM6PQ?a9Zruy z%bn}h#N1mL(UaN`^Wr|&{(0&qlQ(}pS_ZAMuksu zBqwAV<`PTHxql^vsg_@fkpC-qFYxjE&#%VeI&lpjCv#;SP|oP{Afhoh((>okM7|M^ zY&Xl9`dyx--(xG0^p*Z{r8(DBDP8+3nAJp|S6)-P%FH_$r9*dgjKxOZ2sCq!lgE5! zQh<~PQO6In#0b^eYvrCBpi^+#1_1d?Way|FHM@2jH2u`R)`1RviL|QyvvBmwK|VhofUYWEDdv{SGn#rb)!cjA_L3fXtRoefaPAKf}m*;Vmq9y_V^5T}&}5q1vf9d+8#A5uTHaYbqk@7-jpkBdGw|t`n3PKl z%sTe*ufw*AJK;Oo36`Y&r-hNm7BW`2k_-;=a_xMPyCMWdo^y|VnG>80EApU;+{WmU zVgb+{e*AJ?j9$uQZJ8;d=p+JlUhuFAmvSbrB4V*F@2oR0St**-cxsIBcQ^nMp~_|= zDb^s|$w}2Pv!}nel7oCV#ot#8wUB>8sygye9bN${i7m~GR760JmTR}`;u>>kYm9r) z9D_HaRlxB!-AP24VE-+`+{}}E;Z+7)=A`67J4a5b^O+$d?E~6vA49ZA-V8ASH9XXk zIsR&Cp;&al1RZfgKc1m6-^t*r$7}s*v>)m9o9xfYFvqy3cu<^8IQFrVj?o4U`xqP( zX;#}3n_q6`9{L!rAC=k8Egbdl>VuBrc;^OK=%T!tNP{~i;$KmLLK0f+G7dt5?JP#- zzsd|fbb|3n#=Dpd0c>+nhe-9Oljdoq7+>AfYoiEL&1R=7jQwm$i`i2Q*IvL1CK;P8 zMrYJBDH_Q4Rq7iz5;KfDsC5@dJq4HZmIAw&aw$eA)wFDJBfe3Z_cetoWP4Z1Xa45w z`2j!2CJ#~cV!zis29@n)AoqZA^ZG5WqX|Azt&cI$NcW&g%)<2yuFQkn@5|{CZc=`-fMk zKbcc|?k#`9P)%Ip5m&q|7WPWoR#Mfc427Q0IJWv=N}()Wa}}WWsUubT0Ig&)kQjY( z?8kcyP5I@Q8$w;*jzdu0Xh~2lPbgs$)%oytiWX@>&#ns3f-;{&|1Qb6rk8zE6V;9@ zwrbic4N1z3#49&jQ#{_yCmYVhHH9>y^`yfOIdho) z?5RfkX55!cv1`AkvF|uUgTb9G3TJw>ZewIggX#sgk-=aIAeWys9vv~4%6Hn$xpBYJ}3{tSDw3?)gdn}m1Fja|+ zTRO|$LcH#v^73hQMTx~IckE)^9w(E*+OAr5iW(Nsa27S*&*CK|E__D za&y%EWvbYA=073fyF!dZhqf-5cErGPv$oD7;%DzUG(_=y6OoQlF|vs$sudIZqrw;pVMYvps8Mb*phZ^T+T}&iQ|Faf`yoprE<;9< z3V|3ThQ(t`-qX5hkAFC#n%29S3bxntwP9A+VUbEJ&LFRfrY1n`Q%%)iI_$9@>pXpwLv!+Yf+ zw=^=gtEA{t%g#%kp8~zRv*N5$PQO9D-vJb2pZXCEj4Y<6HIJOqbPsaaInwpG7G&)S z1{i@W;JlEJ;s2hP1L%_Vfnep)S-$&ES_F13urz>z#1H^e6IRXBhF0ylf%ukWco(gh zXl|Vz015tZ+ud3-RdyHwa~Oqny*)pWp+sK?BG8d}$k*K9hP3HBYYL-o9U{yO;55-s zG5<`z9Wb{t`Ozr(e5U-2tmu58VKTzxm?fK^!h&o4jBX9~-mh&_S8hl1D;iGN$DltU z%i%$*dFg}a)FkrnjeJj8A+@(^Am6qZ5qv712>iGogC2q`PR;vktODM#F)>QNcm;sO zvIl$g2MJvzPoTS3gb;nq(F)3^MC)9s#w+==OYC8;pJlo}FH{F^k_(CXtUcLJz>5wUB#6Ig+ zpYuyK$~{;8$}gvuM^jnt62YQWw%Nkn<|o>>cEyTWaXA|Da0{TXajzklY0nxG2Oc&A zl6R;{^`Beu0e^1$jGWb~%IPCajylh2IWJI|#V`djq&Dvmg53IU-+F zqIoU<_qz2Ej8b5Xj0C*GN>HyHAcAZufZ@OI8irqlpsN90ZV0q*0D>K=oQBD?JI}~% zj@XX*uf5?y4d{4&rlWr{u1yBDS^7F)#6GeIYNpQ*3D7uv!+@6fD?}xn%hR}$7zK=v zzJ811agmXc@oZ%=(%+$UzQ5iQ34W0-g%Z+0=}9h_F%T&z1dyI5s9EEIk-F6df;fN& zsoo>0+4%IBm>MUIp(z|4dDVeeL^k0)(=#07p)F<5;Rg^QtvjC zWZZLT6>Q3Szm{rk3Si(j5j|=Cedi^Wrzr#%uML9~N-2=A`b|o9hC-pthHu#{y_@4+ zc5k3Xb^Ig&JF%JvbbQ&z4H-gz1p-5|2?B@%L19bY9XUoT`7#Ag46;N4F+)gB@Mpih@T1CnY(&Y^v@9>4w7NkP{@E9r~y{eun1yLdwb@s zSN!Go+$mBnqsd?RuY%!UZs9rHO8gyiT(soaS-v5_hg%AXVz>v~RNjTqFkY}Oy-@+b zzxE|;vDKL8kPSV<#XEpjCh+Xua<0POk5T_M4Nx{pP6~Gij>gWB-;I5Id?+Bj9|lSj zk7+Yy!}#fa=m01LQF}KntDF+|mVyq10v9BNLBqjdZ-yrzp*{wlb&LUG0n;FZu%*qn zJ)reKsT}&qn;Eu)zN!Q`KVEAGHJP_!rpw2a0 zT)+CN0W_CUfM4_w2$W|mn*iotyQq;cU8r~J0iawJy+)k?(x>E*v!K1>RbA@zO@Hu^ ziRV9nDswf+Kx!jhxj;PyAM4xDeix;(p^R7uW4bP>-JDRYxksC;`mD+AhNwG)Y*^;@ zcl{t{X6?iRaz19GMkj#?Xbl$2)_{=X3=m#YO>hSd*CB=Hx&b=I16QsDyHuZVi%IRv zVnN#xewu_LTQM*-Y-T+*)8vT(sqF?Ec3`e~HHQI(1_ck!evv_C|3o2Ux9LQ?Z^*+Q zyC@8}_usEcTYz-rLR&00$V37$bL0lr1iS-W zv~59Qm0Q~cIM^Gr!G06^Kcnz-hwhBoHpB<5`uuq`>%w}Y{RJ*$_P_q_m8qd$$ZIN%*J3 zy4Tj$l&pflN>?XC2w|5FKkxS9`27*@$u~v)`YpG<>E>c6Q<(B@!Ajwj9(}vwb`{0A zYk0e^zMLLL-ROsau0olJ5Q{feHMvGIRse2ydh)3NQ?Kd}t?NY0eRb%|d~O!F-lv*i znv?#jEPJ5uy!y-wTz}wEf#{s^&_fL*kIm*JUX;EN@2L~hv!#dF89oz1zUWM@Em>3I z+5kcYfVJ2!0*Ah5eul00v0?Vs9;a0uiYE8+vLYD*QefW!ImOJ&iq4NGSZ^5Ggl0~r ziRd0@cqTLb-qyTk`uA^T-J+LU;zrBrCbl-@hE2;lAhST+ecCSA@i9_J?K%=KS+~2| zVewfA9Zu~Wk8LMqmp?y4yu0tmEPSJq$$_b*`)%I5gDk@- zDrESqmh3N*_BrT2v$cLwwmV#{`8M<&%Pa|`i;ETgnufWWT!WE9-&2#4=0j?BFxC*Y z4QoJTY>i^k-UF)%26RkjoDAl}>XBOXNd$}G=jMTHe* zRVgaoSq$Qvhd>N-JLP`TZpc7WRKVQh#{skiigWM2LXL z#R+6|%cF_}{WQ5ofDVXtKIA1o;daUx>EpTyD}aWpE1ijW)Mv1{bUD9h1d>A4-jT8h zX#xIp-VE{ebs5l4?A5{ietErywj-fCzJ@ z`Iv~&Od;&ehHqi6^=AO_&xAlpvI=t_V@4=BXOgw8@6d6`OuV>cZumarxUT}T4)!B% zF9)f|7jeUX>q#9D@*oBv>Pa^Rs5)G`9N%=<1!0;DBZBYGs5d*J#?t`bL-Zd^Hw5~T zxn9SPLPH?R9zVzrw1>0w8U*w$M;(BD(t@4;+!FxBF!My*@6e=sjA$1yPKTiv1QrWO zPY)U4<)MYl*1ij+Z6n&R0L{jI-hr@gk+-M!`C_6CM}nvYshb|F1pQEvf@gw;8EhKd zV7{g^yn|`aYnQq=hg&K8Snk5`h%~~Auorw%=%fMdXO=baW9FRIx;#u#WA3B^FpLzk z1&A_;8XT6NUpp6xvupjiqQ6}b_)Ry(=o>l&(SCHG^+al!Cu+^36N?kN=|@w0th8V- zB>C$Ohg*1LNpAzUOLw-`+4FA_N(-yzcn-G02}hSQBShU$x9Q{q?l@Ts_4nYe>n-av zn_>Y}A6>S|Y#cT7PF>WMkh9bQz)F)`&6HOO7AUL%x$YhiR#0FT)}YkZ=@Y7ye{NfD zj@1adAiU>qJnw!C^=;ZA33=B8+WW-ggNYXYieBLv9?9nZBza>`~!?(Q9Yo0GOo6IH6i6A(zsK3w7$3PJ{Yu6qt zkX@xd%mL6BZ7-X|#K4-eju3WzP>o|&)3$Sa@?9Sq#H`#a&tITNEe^h2n>JVec0e{i zOTqKg%?3@b9fEURVaLv@K8|5JKg)_*tZAgxb~|OC6l`!ySuyhA2L-4MGjm@_1ZlQ$ z`h(*=VIy9H4wiFzs?}jTXQ6(QBPoY8NS|=h^c{aPjY-qy3n@YjzjuNwdLG39E8H<` z9PeW2p}U#mxnT>;X$E}l>pD5+C7?0*v84*Kpi1EVj}Okn0uq{ZEYMTf3q0@>#UXYK z!Y{=eB+qB&X7KOTyO3s?UM1Z9c>gxEwZaM(^dS71KCgMRQJl*{O@ea`-#h1{4{K5N zm=oXiH#Lwi#4pB4W%Ir`#H#397~;*abx)i<`bULooQ~1iyV8es5g8ds7LVh{Z}VkJ zYq#BLz61R_u|hS%&Ff}3DJ#%tw_DDGIuCmWnAXo5(9!-OLUP~Zeb*Ub4Q-6u_81YyM z2`T2l52k6&VGcv`62H?j8iVo8f7qiDV@!U35~&1#og>XHrusJN4z+s}f`#fQ*yqs1 z%c-!=xZ%v#QO4~dz1KWB+9jO=KU+goi#48y)cG!zEZpfULA@LuWMb!pTV+vf0To>| z{o}$%>k{6So^|)b=o2iE*VzlAh<<)E<)?f)SF1x#W|lD?y`s$3%yHC^Yk}jP)-d9S z_H-7At&a#K@x@b26j`C^u{IOc7Fmp;)La%+YtVQH%Ix(gQp=WH|g9YIl&DZ0!>TP6VvR_|@K2dIt zF4>-qHTWHBk1k+1rD{^7b2m5g>LqMI{|c^(KlGaP7JvIXV^XNZJr*6KtO+rUwzcGF z^v@N3s!WO}oPpumj=1LfHpjjs_#lvG6Dq1^C{x)U20V4Br$JG^_N|d1v2RI6CUj5I zSn@Hm50!~k+0+Iy;h2IXDmo;w-BTZ)v6Oos_iw8CqV*K!7R%I3y>71vM#3o8Aj9dy z(63WiI*i#l)K}^Sx&92Nx@#QVWWZB(U5mYvnQ@Bc+VQMg$*_E>3j30n8z96m(Z>;S}uGraKCylT5aZF1r^imE9={)$_mV6diWiz^ zAp*a_;6iE{=LXi_mnh8D^h4nsy+0e{yT@f8D9ZnH z#$1e8Mg{2fh;OsCjxaQx#rQ=?RX=?|tQ<#F+2gpBkN0g6lY)ApuiW0~!cem8`D6m8 zOTCV{)@0w4oS*~hSV#7GL3Gg_6{YD{ky;BX(21Gv26Y(})5If<-8)S*ZM1|k{cC1Q zp$=+#P^*pYTHdey&zTVcjbUmhvsQ7}>K&?E4oxTeSC#onMP(jZZ12`H%YqV_)#3Q>cO8R4BTVUY5L<7l5=`rX)?cb(=Tz80}< z;_*x8n7UQt^E!9uLm$lCRyPF6qQxmblezd5G0p%>Cq7f3WyHrG^@^1C1)V3i*z?d4 zrF7ptI;4JzElZNT#dV1{pb?k*qCYUm=gV*N>c;+gmhA6W+D+W|9U7IaG~3+_k5-H+ zASOW-P|97L{X>GTd%xh5>3s5$YCR=CLF=U1wNNGBHr-$?I@}QCVNO~hq<*@?Agm^& zi=)i=hR!X0wjleh@e&`kfTVQF)kOCz!=C7Re3gFFAS&Z|*o@&d3#Cp{&T(dD|H0Oy z441!IdPH}_{(X?80RAwD2KBpmRg*QXu&&|^3?qW`4YyqFO-CgY-a2w^0cVjuJLAgq zRiTKGAO`O(;ZrD#U`fvFV~8Yv<1CrtiI)j`v)jR+LHEnM6*~uRA;f7pkcx<^>$}eg zP}P*kb2&BDk^>Wf7&tN?5Faa!23m~zk4*UCMZ$tX3c2|_eAk9yEPo@piC|94=luyf35goiLQOLGP&a5cRb+dyMHt(k4oRc|Os;$x-1HKz;u+mY z#9rQ|5ihk|Q~EE{zZg~%rQr)DO4-<9kB;u13-R}cAAYgR5afURB1AKgyRu!_$OW|Z zyd7A{%MTQ4QAfntTiy~8idtxUg(=X{Uj9bk_aIy_0LT%VvkP?GZ;1{=paMbWJ5^@U zj?qs!-4&I8!M(*&&v031z%X0~qOoYbTpzVlE@kvFt z#Ksjz82ek_6x69kCI%KS0W66u4TK=7i))P)*~s?)AQ*j$#tTEL5{v$YH^#A<{{*9d zFcqS0RL>quQXm1q_DK*u6Sot9*Ie^2tc0vNWZzDSB$?xSqiBjVoYU8(sr)+WmlO9^ zIs(%9i9G|S3Vn;Mmo=AwPlMl()S&rf*&7Z?`|(txocA8&k>Ndqt4(2}uT_<9(z1I- zx}+0LVm9uQzMwAY&aML^%LCqz(fmyG>ozelM{mMvtn=`;Z;@>>|INY+tOoL=e|nyY zT~esFl?7O^}Jrp8m#uB-WLx=U9XehPkn|97U_&}RC8 zKyLEHzGm{x>mKsTI;!a*rxY0;Y{?V?^rgCYBh_a*v7+jSm$1+!8mf>TUocsQxfKqR zlJYV*huWg@hV|&)-ITzZ6#NpPkw|nq85AQ<`swP>Hp6C9l?4y|{L;SW) zm=wn99Aj=?Cud>t_0pTMHqU2JSoJ?KRs4g1B%Ff0AUZJl^)<8&3SU7!m4>SJUA zJ!66Zj0v>0&iA?x(2t@+R$)CInN=Y9=keMEsM)$M+lj3;`Gw3gI(2hB8)aLNv_n=u zj$i>!&^L3Hb2kX^G$O)JG5yIstQeQ(<`DyFT*bn>Bat>rALi=}Tgn_H>AHN*#qkrW zK%`b_#bIi=s9b;CI%JHKV+Wq{-?sFHR_5ntEY9i71myGDnv@Wei%d z;396DQui$vdP7(Qh-LkIG}MFG1UduMq0g9O*P3s|wE|4k;z145JA@DvqIVYNIN^bIx4{Z>XKUe^dNUz&WCj=y{F9!bSQ_W zKJv{WHjWQ{E)m^kDTA~=H>q4J@iUdGEEYz385u5Ed4W%oo(snCjR8H2q@vm!89J#1 zD-0NU#69fubG5U)-m)lREcfM(YEB`eB9Dy*%r696sCX&ZQkM)9#_|M2kVs; z*7PQOZ7Cz1+ig*6$h^)*97)LBvNU>Pq?8a*#%CLT*Km7hr}(&pO<+>F3K3vjLlt4tv0sVpGlXUK~LrU$hu;hhr$}@y(#P0gmXr^aah+r6}FlM_PEMJH%X8{;Db&q)sd#DvA=`G z!!+9=de>B*K14>y8!4(RhK>b7&xIsj;czf~dIhzLcG71RyxKHMLsG>BSxVj{{4jX? zQv|-)6j=}%cSwOFQhVyjY(_XMk1e!VGBy*(q`Sw8pcBmdHSc0Vm7+G}r!T6k7R$;mR%$WqsO}BdLKKm~kttzwhGF@U zxs3`epPA*@#5%N}+NZcM3<-Lpkw#SXl5W7@?5EkSk1%E@KBSrc*!+hZx?^%^FT5Cn zf)30Vb+AB8k;+|wQ`kh$Jv*+xC*?auKSd}Z|NI$ZB~uq5$MkL5Z)=BR#Gk~@WjkF& z$qQb}0Mb{YLdq#4rJxgvVQ@JAa{}y88eqfTsK^iT1zBdq@sh2DyNrqFk|*ysA4UyT zISzKCyoDl~nM!j`S~C{so-{#;3Xb3KS$$aDc!;}QTR;3`$P0#Z4%7$X2YT8M0fOL6 zWx@3B+XtXL9Teh9K>$=dF=)4%$gl&N1W`rhR#WL09I@AnG!38<1E-5N8IGP~_SVgb z44cqvD=4#wMWRn!4%i3%T=q0YiR1r#yv@~$H$)!yY;fTtF~4cmi%mi`RP-xu)C!GN7N5bSC- z!J(um(&I7{H-`3E34_L+6Dd4sGhZfb7lPqrSp=RF@{ep z5vP~7a`f6dlz?J^dAiP1eW+@zT;61HaFi&&cKk=4z#*pa#MjD;I*0*mY@jtuRW$>j z&_DT*(y;IPo+**)=b*iSLgB;q&soGhp;PEz2?kf=R?a8GONANE00eDb@OvS}F!5vU zbA+-3CpI2klqZ6f$*3}AcR{DgClw1bjL!vlTzElIMWCfkkZGe5!qM;N?1Zl6d`64k zm(t2()gAILKFqWw4a@~DDBa)z84<2m928(bfeD<(BRzJEkUko+v3 zYIa@6@RpFO8f~$6^4{n*7;zZ|o6{MI{oT19AXHqRyT$vizVm;~&|`PS+Z?xtx!F;6 zre2g1I0R@5*=_}KU)CxoWQ#1k^<3O?fsjcg`X!5A%HWyvIU+29H(MU=ff~`Vgzzp- zgFcTUhm-s$l3>S$n=Xd3r14~hpvDf8Hs4*Rwga%vF2(0hN@H#Ku!;p2jv7e&E?HB; zVAU)TonGaXnwO(Wi5jG6!$<)1_r&XIIK|$8-0fM5z<5=oxo3vw5$17G4wDBROJ& z(D|&=d^jb6fpn#ADRE$BHN8_kE{n%hFDf9wfVZsva3+g^QAY$GY2lP^9dqafi-~2s z_TYB+vTRg~t^YFUy$Y-nhhyc@DFZcGuhkk>l(7L8yu{5kUBeitwdAhqv{fL+32VCght_QwLJI8-|3 zEVM$Jbx-8Q+8<7c7Uj`hS-T6HBHiNZ%e4=e!sQ}2%`<1z8~H=VFVKBoMjYVi-V3^F?G9oDVS|HYrR1zg>quk#{5aB8{pImpBI76*&dXr(O1 z;{_LPN^NFLPY+y+Kf?PjJQ6H&7+ek{TDnW(hUFRf&~w>25%Y>!Lv#Q%VKF4%*DIrD!t`w}Qv z>>!YfeR(>U09jEC`X2+p>6e4f|El;yGH?GMi~RrH(2EnaEByO<`{!`~{lzQ(_daO< zp&a)AfKl+@5&wUBG8F%z&lsR`!~Ac}9XyO%NB-cK|2>xfb4JGh*UyjlQdiOquOJ|` zsb~Yv9sIxl>1Y4%kxBl)zI598Ufkz;1$p7p@@lH;kwGICi67v&QLOsZ>6crAScOV~ zv~f$0nb~}@(_dx_B={6SCO)|>mg}_*4_YN67-8)@dr10MAI*Oc@3Nm=Y+jjMByKiJ zIS&8C%t_+{qAaU=HYe;frfFn?{;!H<^F8ZYghA+V;EimH2@D zE$ewt67jmDzk^b)R$0c3taAsMnl%+`Ts121V;yZF-LOm+eX|g2TlY;^OQUU}7SUu+ zyy|&};+$hqH`6aAoo9AQ^YVW`8R%q};ng9>clvaso`d7aJk$`8?_FraT-ELiW+r=@ zjD>d#MBKNq7?g^a;gm_>@1<0`{_wQ(|HyN@WbxfE2fZKIRBm|tzOQzl^lxYWQrxTI zYWfh+tiRPSv5*DWY)zhGzNGzq&rU9$*qw?UjR^9Bu~?Uo7-?8DXe)xtqgS!Yu^{Yj zePC#zXl=E#5;x<2>l?&6LhUp)u<|*8& zK$OP3F)?qs0=#1jj{QFBDu=}Mu+ z4tjb1-5^^>+{MAh0PEDf+KWJ;vY}})z+8^H{$Z}_3B|Oazao1PHtkJtt;;-RIVw(F zYAJW>s{K|)JO&>o3AhX!9auVS3*9homKH(QHPhqCRA&~i<3{xdPrJC+UWy##M@l(- zuxl!EvR~|(L)N8~*d|}lT|@plzJzBwjx*`s3v#i5?K>OFBYP}Hy&MPMHT>hdEi zC)zGe%kSstzE8_^nMHNCo9}tsHZrlwT6HM>RYU2j;ThVzeyJ75S%I8`{Ql5NnOZ);*S`1Knwrj+o|?X; zBfK;Gi0c~G)Ze``$A{kCXsAAOgY~t4)9?1@#VKC6vy_(JOA800v*#r4tokN-QI8}A z^pGa(3~LS!9*tSRT3JU1TTiBXyss2y$-`SKj7fB``XdbIBUq}e@lh)C$TD)lnA64p z3vRlEt59k3%N~z-!N9&5u9(uY9Cc5&(z&OB_Kd};t2j0$ot^&8=Vr0WB~Q8z9uYof zQunAHBG_OgvC`|;!NC++0lvn`S-a`Xjte)CUVPEN@b10cCg-SxB&3Ftl&~;zAxLav zH<>C{TE4_2?_Q9iTjKZ9hrh{x-(lXZQz{#`=d|NdXFIe)Nps<;z62Y{MgE<1`aZO= z?O;dfuG_3E@*~?1Zy#SsaVY;aTs0ZmRK1W^jg&)%KliBkZ{!Vs^vPy_$=Y?U&_0SXPmI#YTt|ux~;Mf zh1&&MH?hda!5z>6y}1n=`$urOlHy9oRL3>vKrCyZeY})QQG>57 z9KMY&%4SmS5BYLnH++Z3U)a24)m)M ztNgT2Aug_eX=;~s;=UVT@1WYW6I&^WVR|#aXP>3T;ZV#XPY{Ot-@<=`r#b1Rksape zu@Y2N4woMZOWw{Z4jAg5kF%X0tou^#DH(P-YNk}Ld|+Xw>KSC=3!S9QD`3GO|GH;7}#DT1a*#{g?F$3^lC;oH@j zAvT^zaW#hF5tMRd9kz0(WqOFSCBaOwK$JqIgPYkB@PVJ)>qX2fMsdPK>ne-;;|{i* z^J_nU;2KN0E6NX&`o5+TmMS%d-!cUv8hpuyvCx{I(~-M@{V-@3X3)tTMkZ0N58{I`PGa<^@EE;{fh@X=bggO zyT0cdDSQ}jv%EHl{I0%5fo^0C;bFL%rMtLcVo!O!Z8+XB=4^fa4^2vVARGx?b#R&r z8xCwIGO{#~lK+IW{(y{&z>J~DsO_Ut#k%}W5WnxPf%>KeZs|rxm{v4+c zOup6d#7O3hdr)bs6|&ZBsebQOXjGD9IXBx<*_<=3xN4m`HsLb+%@9Ye>S|Uk?mKA~ z-py0fm;1P=UGKci1JuGY=OeuPAVq9t!7iq4c)6pyOsTfIyeOB5Tywi2Mjcai;S21* zDlqrd-9&t|i|3r9>_3{<^YIy-hLwuCAa`pef@&>pHq16lYUh-BY z!p?sW^;OZ}->ZW_GTT6LIY+vxjCJt_ls9RqaD04~+0gJ=>F?g;H}Fcq-Gg^$uFmf8 zG>*yIJ^T(+RDUEYO{jLAEjwCQiGF9qCHZ)e7%8J(ec_Sq>Ox)OLDdDnvgsO1oU074mkc_un%>8j=hbFyG-T@R*Vc4k;p;nL%&CgPqA~$ zs+*m!nSv@5i7*z{?&=}D_sYqe&%|r&ZK~4WIwRzp=LReS? z(=PJcbZIrk`#NKjue5Fkn3rqTNw+Ftip;frQ$kwRyA%kSdL6SjDjv5cXe?4J7S=PV z3c{9i`_lF`K4YVMQ1zTdm0ZLxB-KX*_8MA8&p#tFw8A zNUnT5U)E@Kwme10_)+Fr3LCdL0AulVd;ot8tgIf9|dWG`%<-^gQqk1{HDvLP{luafi> za=E=N3@YuquqW*~a+7oOYllkt#iFvoRDOS1XUv-b-<&DK*2Qi!mwDW8)=?bc+X%Lb zLe)?TbT+RZm1Y*}5UJW}SgqCP+ zQ1QmOC)HhMDOTPih6JbOUlJ`>8FTXWMUac16G#b#qV+thGN^exPQ|O3dxt3rwt3a8(YHnf2ss$i z8|96)h<;jop|QyW?+;X14y0y!bFMmVe-T^QRt+;TB*rW@U?oNVK5cXqi2UVA(q(*x z*6Qx=BIlBR2>F`VA!1(rxUJr&W&4d_rqW!WzLAxS|Je7G$mxsW@`^Xfy!kM&bIjW? z>VrcM%jmtL`i4bpG4f?@6}$HfsfHP-S@t43HAh3Bz7_u~HQ)xlh*H%RgF>dUe$qhz z`gnBFxs4AEHyzf>7E?K_8~mg@>w6VA?Lsv<*t}d59CHYd;m#+~p7Lv+oGah;Jm=QG z(9>3$FJ^b;oF+uBns|1WCmkM*!n^t@aBQx@n1aTpEpZ*hG`XE4^FF@@bc++OJ6Sni zb6T4WQ0=N>SMn6v&fJk(=zxj$PFT(v=G03`3sSS(oYz;p zoYSU96nZ@c>f>+;p8r-dKnJtPsbFQ9$B6J`xe`1QRhaYRxyt-t@nSdk^VUG2e@t?b zdlMJ*=B4oK)t=wyaKE*oKZrvt}i^Gmj}_{>j0lgu7zcg^9I$j7Zyzk&X;gj3w z*}c5xL^xU@{6E7)tRS6tZF{1O;s3n3ZuZsfdnvdg3pkq3uoFnGerf^`gO=mo!omW& z&b?-Bv9%~koIPms3ooHuy-_5s>6^pgk7`C-uc@<ff$?ot)hRuIwDu`rP|ta+KHpn}N;Favwz}EFT3G1lsLD1nAU-Qlq1~4LV$k5!^rKxD9{_u#1Ml<`BD-sG zkN3+o4(|!1SC-DYC??aI2G{+|Zm3Vl9ItV4jW-Dyyz*}g(%)X3x&EVqI{Pl|51s5~ z;2&A96%u6IOr?ABuTMo2FSp^P1n_B|i|;JOa*3MLIQ+_^B%;%J!S(bK zN6^*)pMq3NVD?{Z7NE12#d&o^N!284LPfp{*XBqoep<3}0YASu?`2hSqj9&@iD*t; z&mAKy5p?(d*R64YugQP#sJIk4+T-a!_{o77ti+=@O>*~`%Eqt)Pa@`xoJS^r!4tU^)yt z5B~Z4uJ&1Qu;)Xcwl4WC&To+SPf{0cH2D9gB`cWYC2e=s^+UF+k}Vb2QmcBFICTFa zG!TdsGo4y&xj%Jj;0Hw`bvn?=CY+}s7oo@h_xKPgR`7{}rLjQV=)O%>T@yj4%`|-B z5X0YP43d7dKT($U#?%yJEjFr_3o|A&qx~<5m-e37Ir0CHbJ}13FCfnON?<^t%bvR{l%)j~*qJT;?84iH zH}Sb_R8!^-;!TKQ$U?J(DrOGa`N2#7B2Yg2T${!^{4*`69FKBjlZ&zPj{iMmXz^k2 zlgF=mth!TkRMUGYdt11tJ-6{Y$Ky@=eTFR3Op9=j626Kv29;I#9tGi2?DMvKU@?aK z0T$#C0np6G_KB*++DQI=v-mF@7^`sm_^r=nZE2-m zNFS+FJBsW+zCjrngz>=|z5*<=|~>O@ltQ8EXio^vz(NYVn2 zaBhEwr~Z<({;c3b;-&=h=e(6k)_7@tx_fX>(XliO86?9gCWTV%{ex&A$|n6A0AzSn zp)(Pkl4H$60oJKc#;ZG)JPf>t`14{!M$ z{W=(vAe37E2upXiaJ2HMR_xlEd&JYYiK*NqpL_=&M-GiBR1$@4W+B1B51DL5a_b*T;7eoh~|LOQTpk{@@39Vi3` z6^)!2z93L)3)Goj7V5voXI17CGd$3&i%r=g3i{YQIfu#&W+~gFQlT$ST{?2?<$~+v zeow>ZNI=ZU(_Ap z{A)$8LVI@Zs zBPV+a#mcFaXqJE@JRb8e5EYQI-7HLzxL?_#ll^02@+;q)(WpPOCvvgvx2y%jKZ z4`Wh(RLE#Ql7-Xj(t^&tw{oO2T(IK%J?!zm`(1+lq=+^u|5fmn z*#~#7_4Vb_KibL9X)^N-F;SzrLad+p{u(BBlnpt4&>gXU#j2HNTsk{jXh8 ze!tqv6f^eo$e9VT-J@E>@vH;2PLmpzg9R$RnPGSHXUIm#;<@@#iUQM?24qee%ERvWa@v^S}c^yrn2~Hu(=%#d^B{BP!Zpa<=a(71itk*|$Wbtg_hwTK zshaRD`}jR~++@dn>k!&juv^!dt@VC%lW9-ucjDf4+uywY@@|K42QEjaHFfHO|ttczaVV|8_nIcinSRWm)W_K>+V z%klUaiPoMuO3m;ekIv0ypp|NOAZCoP+#|Sde_aZ{aFAqXK81sD5BHY@MJ*K)ne(%H ztOF$0+Pk`yxVc! ze1b+!ZpBOEybwLz>zYzY?{b`)T;8X}h@4x{U{_df99jpKUEiaob2)$k5bpOnTkLd| z4)?k?Sm287m$Iel?GmW;&{Q_;gL2Kn2V;w>ee|e|CHmgPhl}^`Xrf9}{9ky0yCbRJ z$k$?j(hU2x@8cD7x3agVCCt4YMTG#ey3e3Bs%yWZa+H$l#(h-ojIp%DSe1sWsB+6U zRtb!Fs_)?VL*VQDz!Iq32v4&QX>)jpv8OD9c za|Rb_p|$&+PbPc@`YKG_>#+eRQs6W>XY<)=#9OoBf*b5vdDfek`W#a>qw{x6*`mXZ z18Q8NlZ`?{I45_LWteH=ZQEfiD9GULoz~CgGh}V7eNhRj;Q9EiGrtqQPFwmthUZ0J zKJ9n~&R!L^Qm-QvE%~>j{Vs_iD@#HhLHe&elfJ@3)Gg=-e8b2_iw6he1LktXFcHU8 zdH2(`E7K-j?3wC-X|tPD3LOOl@fwRs>hu=M1V|pO?MM9Wr(mqqc?&-d7uuB5T5@^{ z__Tm~12^}2#|&~3x#I=c?&8b}dHxWws6|&>`DkI-deGLru4$HGRwmiheTTqr7q#8) z#HUNIqd}(c|9G1x-;mB|?>G%`bav9PrS^`D$w|UWCgbn*Kuc;8P+09XM1#*NZ7COh zgRc`5q*7DNYRryKPhw`>>?a`pWO2eODJewHr&K)J+@nz34O&O&J3EA+vb4Tu$ShXQ zYu9Z`7rU!UX=`?2#HGdw&-6G|SZg64QN15?Aka{Rw-piDDKRAQ!b+%6h9vBrFzKzK z%Bo3N>6w<*Ns~r9b`N)8&T!s8vZken2^#@LGu5bjc%#Hl44>axd8B%=|P$Ajup>&w7z}OI=eNy`^50Y z<$AI6{eu-ZEZ&o3__}o}>`x1fk0#2jGRrQ-uN0VPA5c6iGHUx)5=#%oNAV#qX0_yN z9S#K3azP?JQ0IGPIkiQ?ot^RfNx*z^P)Eg%y)(LEtTWL8qX;R^f<5v=2~~L>p^*v& z9b81HVuqcUTSA5Ak3ol{>$VRiv))(>8zd`euY@Xfj7-~S9!azj(5!P!Tip;gue2gx zN4d7%MW92o*9QvWAirpE6oNMTUY*brueZ4J0U3jW78KF%U}8E|C@(LorM6^om7I1w zQ~x}1l{sfL*ra+tq%^0^s_9O+t5hN7pYT5wNovFr3+Zq76K*Zx1&XA&(x^NdaIL?K zZmVzFG!s?cfGb~3_IWisx)YENx^}013LeTS7m!@P)iql^R)>+}C~STd=>aX5uub@2 zxox-j=nfSS;{$FF2;nu27FLYF;j=nhLIXn<^!qrWYd*>r822FiFH@x0t$`FLeaK)i zqzu7iC35UFwebN_A5CAZW)T9r!3$G*FCctt@11P>G253+H~L>0DqXNRX^qTe z0j?G$>nmnhy9I^0>c2vFdo-AGOQgO#R?;VWJcDPd7d!-dNE-Css7rhnIK9F2KV?d^ zHRLomPY@!JFezRDQ6+IvDIFwZ`e&*sT~-P zxK1o6A%H*OvP4yEn!CG@QnBx=RCM1UQzv12-iLihUf|jaTXPn{);(J1o68=jD)^IN z;#p;RyV2LT^k+oJGT4^-ubvELrzoTk)rZTSR9jrKV^Tp}bkdBQj$hGEps>AnQ0^Hp zCq*Ne&5tZp{9c)F(`PQ^vB1T@@Fan6+QIkuO@h}_XL*>bBoGD(_mmFj_`F7eRh}cP zz&_o?I+?H&PlOZ5K8gW}wWZ>q`vZBB=pWxVpCO9`8hS7Nn8l8W?pIO9 zum(FLR_=b3-ldl5xZhblx>I$&t=se3q8(G;NCd+Hq{U}*1k#4^^~P4(5#zzj{=~*w zEPaZd3v+y_d&m$h$$rPKCGOq&E8Uy3zL^siaxZqY_q}7v{#ti-Z^e4;!K&dxsI?GT z1FTKI;DF-9fvS?c({j8$Yo}iJvPQiqwYcla2BO>&=Ha;1qonIS!pLjh2y!XsIe6hR z^8nZyp_%JVdo`G~2C0J8;Ge~$_msL0)nK)R`FJ=%k6nPk@0u3mgH=UJZeGdq)2Op& z$(aQnD{wJ8gp1PM6K@QbVdxPXX6dpL0yV6qswQYLqi`Ot7br9D5yRUNwJN4_u|k?{ zK`V{NfgZt+ANYqa)p7vHTWf{lDrz<8=6rcQsK)2HHM`MqWr1}@bW?h_x?T1){3%=w zOB!!u?Jru!1mQeWxj4})n=3qK)EQ7P5hN$s%WMjQ`KwNloZKUxM`1W!9bL>oxEbhl z!u-%)BFH~37k}+G*726QmA6)aN&$~efxjs~hCVY>BnC6P899355&&#GTsQG^)XRES zLpcB$?tj>HuUn4{KJ9+|eeqs6t4w|MTJ`9^n)z2g>^3}(1g}1o~+W2w7ntNiD8b>rM0DIs3vI0^Qo~ z3V(bEK?Dv4&gS81vMYXR!GZNKzAR68Bc4QE_;*R%ybzHe3gXaPoWVd|htcLz;o=2c z`h*`0+Nc(`^FwEMT7tkEeF0{!9K76plBg?7N+z@@I(9l5RPG%>Mz)#?#Ae>U=eRnG=xd`UV zS68{!Bx#6TbdN6r>ErL($v)k@3eDwd@#ha7P9!T#*;J7v!sBySpnwsgML^8vYa?11 zBv<<&*3I>ieZDc~f<}Fing``ol|89qUHuJD6k!Oxz+`XaSATQ0MZ5-D6@NgQuKI@w zqfGaCH^^&6W;t1Wm4kk2xC@56!7iA4$4s-)Jfu+u;|8N@p|^45xS_xP&N@s~sk8f@ zQQSx(ZNOZ<4)#;a+E3v^Zm|5hv{JFWGDD=X%Wltv>EZ=xdb|kCa`DXXyB^XE1c}=z zU&&1$1(AhfT(4-$7$&O#K5#?E3U2TK0YE~(JLnVKW#;?kZ38b;|AxpgLbnBLe>^=1 zM#w|$v`p!O`5W%M;@E|JIrr0$aoik+$Y&~eE2-#)I^3!EbAWu&f?IzxH8{{ z(TY6}?RSV|*OJy$2iJwhBq>jKnPpPBoJ={5y67Ckb<>?W1MRl>gz+MZ?afQ|^yNAj zFWI6U&r8E`nLQ0VpE8)v0=ykP~G~`~WO?l*Le?a@inmK5zQg z3Cy4K+w8Q3Lh znQTsk#BM^}KkwAjZm#Ui+cy+#9?B}1ilfvzZ=e~u-WE8HagQZ`i<%v6dd8ZB?#;fg zn630N$>6xSG0%&pG*H+$uC6uFdQ{^fh*v0f9DT3~8O2qb-4Le#itITL5(dRz;qb4z z^DRC*_l$_smUE$m&GC8tuEh%>P)a?f*K&KVtd>@(oTMYjeVPc`kglD2_hANXy6kbM z1-ax-+Ra4zG`*zIVE^UwX52yDt@bKix>1VAa$sdZWM&5B_~(`087&Q??P%uNOFZeU z1+go#_I{@{RNR zBdY3ms5a%i7i!h|l>AamK)sS{L9XyYL7eAX;_6}#E%UTaQqq;qa za{bR4T_03acT@2(=Wc|vp(DK1b#{t?sUa}zP3sP)f;8XBu+BCe$H9j> z2=XkAkkTD2rSj*tb5oV!-*ZX%*XxTT+8sqz_J$KkXcr9 zg?Bf6ez(T-8vNc++9Z$J9%}uu<4k+Ha)WT}VUCom4Y&S=9!buDEfDTM;c!CARMX)4 zh!8SjQ^RyE$J||u4#)~)w@NEWb6JG&NIGlHt`jMGnfE1|nv%(!e62};E!?azv|)}K z_-a`+b6#pA&=C!dvk!@pKXJ^%wl4pK(1tJ2_OfL1cY$QC2I1o~X1Ie9Qi~MD5Wgx+ zn?tD(do6{5u+?lt0>ajKN3OTyznvs4q)&464Ok_~U?$z&IxMz7oU>{w+0JdY1e^m7 z!)37NbJO=btfD5cxpPa8xlwWQ+KWgV>H;(75YI7iLpceox5>wpB0tRWlc*72c2;hb zTCb4lbeJ&x!NC;x-w3Z46c)+LKQ_N9%V*&wbf;Y)D(dYaV^Grem(e}Em0qmQETWS} zB*~e6#Yh_KAC!p4(Uv!nv%lC-N+{pDhRwgkQ8b#H#o;>npq(&%p*^QYB{GKX@-5fv zc32RsTOowHNmux&@clVO^rLclVsq47cYHzTHvmXm1Q&-3q(S(thC*God?yft8bu%| zsP4)l1mAt62)V>tPVa;h1%*=j)8cuEtC6#5#$b)9}cGMz8tOg~D7 z)f`TzT=I=ei8334J6w3@0X>!NA+EPI{6 z>8Ts-_ZfddYWp(;Cy=0T9Np$Ya^e2oofPHdeGrj^#R7lBJ^@SU=`h%Bl{NsdVxyH< z!jPavHEI*|YrqHZhlcxyFnGu9eO0rBvb83(I-!3x+_r=W&n{t7B%yXvZ(jYgLdcW( zDKpU56DtRB%xn3C*DQvsu{S~4t|FbIZ)97%}3XHQqY{nskt{ z8*%^2+!#y(UzsK=T{sEz5KgnOgHp#U>O&V@k^We#RdVwOX0$PoI!NoJY<}SY2NIRO zi0=O{s15zB zqOe;Yk;+Lm)UN3Is%B#XFS&?lcoh(|)aadTD&3i0Y$Y@9)1lAeY;qFB(d)bLp)&>B z(dgS~=&V*=J*ET3M)-(O?aht;HSNt{Rsl4q`-xYAhwBp4G_si&uQh83Q2|9C+J}7I zMX8OQ+PTzXjj%nnePJ=Yt$y_4Ry*L%`~kB zX+Vn3R$aHCJs{l+PV44$?@HJ3s>%`Sc+=Qg$l(dRUPRV=ng6h1KVY|aGAP;8f;KXX z6;g?^z7G$QA%>-$Ywe+|-fmP^DU|NDC|ToY&?xMJDbU{q_sC(H{vtkdz5vAv;MBqo90hjx)c|Wo!ORgLw&LZ0w=p|B1pOFSS zxu?0Dwpkd~+x=>H`upNr)V5@j5HzQ3M*8MrEw6ah@O~wgB7&B(!fo|# zUIH1ab;!8<|J7Cx-#-J>GO@}x2Gx_Jk|bwkN4UYB8b(?45uAHk4 zJ_JWmXk+_#%r?n}+w*b9pf zjiSugB1IICCkJ-?aSNc=;J@AtI^V1W8=#jH%_PeRWa zH7jirwP#ZLQU4lN7b}OdwV$ij)9UuprOoMZw~yAXCJ^It(xsmvp!bv*a0p)7Gs&pS zc5w3&o4cez0zq7tD^x?RqoNR#Oh*D$KI5>PX=&YSX2N4+dNJ_aCffzvW!^`^wuv|$ z^>Umu(MApo$Qz6jYWwv(dAg3!mT_`Vc1{TfCD_Shu+43@%3`4ysj@t$cV!7w5DEjr z^7-LNJrHYiz0VF#kd)ZqoQ_ZnHV=B{t6L|0va2X)X4YIns?-5R+~FJrx^Wnz5rbx+O~ zR^V;rjHm5bU_aI41v{Egab2nSX~FAIXOrw<*Tr#a4T{BDp=2b)e*DSRaiW8zyz@n= zV?IRv(SsE&OF~#$nlxY5*1j%2EjAC6fym>Y^nvlOigUWXM@^u36vbhYdsKQPWG%T! zCg1O@qPrdzkWGz_l|BDHLH$+CjixMPdckJ_EJ-=?6HUm_fJC4Zh~nByt{tj-ZAp&T zGgadj4rJ)cqJ*9=}q5K4% zOFv~W=LNT=y>%;l?`hxt-mxokk?%lQ*{~^*%4rKY7qRSvwN7lZ;XgV2+}yEJ^o`S< zw5~nG^Wwd{ROLwMqP^b?@dx3v$x}_w2h9lyGCGuJG^XwAa&nl{`yf)CM#LIXx+VQ;^o-%LrV zl1pH;H((<;G;wP^{2h{1Y%1{srKe^0S2uxpMXYaho(Uy>uoxry#~UFY+=&QYrCJQW zQLPOx;U3&D1h|I>f*UuKJd=!XM-L4>(tY<)NOo(AGE1C4DOm%6rBTYlO+V-Vju@Qi ztDgYZT7=?}GBj0(O^jsCS2~hQ)5p?7@*DdpGGT)Rw_0@6?lvGRUa;nEbd?U67yvvZ>|bmI;> zq!^#uJNf)go-iB1v>L}F*nexPN$=4%&{g4I!%@vQvV~&h0$n6)_Oi%vib5_x9Xt*a zq0ypi84xnnQyo@Hn@oeZrIXi`pPs(Pt|;PEc9l_f1Ylnjr_+$kRi!=hyWXsL^{3iPg36DlVu;w?lP zH`CzH8KStiMGAF-S-BjPMqSF9g^A^_XF87NJF`!Sp3qO&`=T`w=HCf{uib#1*6;k} zY#n?JDXnxJMeLk*4cC~}6}E(aS7Wxl@P}aOTG_>0R)xlLkhi8HoaFs`zt35pp9c>L zVRDWJBmX{!>jnDtM;?&_1?ZMv2k)UzT44Sbcp{tT5j<<}z6(EZ+zr;Q6Ax~M_NlUt zg5jbX?fRts4%H4?$}j6dg}#VgVs5B?wB^V3x&<8zC!-`6w$hSFMfB|nmrX5J@S8@^ z-&sa)256GKy;QB0sut6DB_{7@>zVn--uM(NRg2W z?>Q3a6g~SI(eNM>r^G(%@)8|XHQ~#ViFyw{@5}J|1I{J5oWnunyL_Ds+Me=K?hkbu z{Iu(-8N%(yTHw_AjnY6Fl_rg>+WcQ2U>S24^IY6H&QOkp9HiZwJKUF`^GL0k?NXt} zEq5^8)5b@EJ7&dS0d4uqMJsfV5g_dqeIyr#LD`xk%l@XDTigF~?r23lc5yNaLl1?3 zSp@j`0OZ`2RZOat#q;ondA68%pfp$b@xY+t!;OG7I_c_6#fsu3Ohh$WB28D6M^Sb> zH(%5s`X`-3Idrd&ZqnsLPUYhaR?yy@{Cp!y)#t#vEXU5za=L0g8JX zy0k7?ElippmteA@BED7BVe0E37+KlyMdIJsyyfxU9ysZ1%A-6C9H+eu2QFcAOZ!Q% zqRc#;%`gSDvRA^WprC+4+^O{vXPL()o9J3s(XI$E$)MKDBX6*r4+-KQc)`0ief@fg zi00k~5TEP~yvljxODpVm0=yD>Z;Pp6SUR290<{$MxFoL4{UX!gZdZi)lvy? zU2x&8)uR9bh+EST0_Ngf@wsoD;?*Pt7*KS|x9@cX7cQ8(%hn|em-9;>MhDuqaRdWi zXI5!z1E<1D3ZgBJFmtDK*xytkx{`9+9u(uXuCKlpx==x{&H|aI2MHY?WYyaY;E$=m z?L(N$Rczo{$)Jy&@nFZkDO9pbay3etmd_ps+N3KY4Rr)z#wb&jOFd^lR4ZWfJ5vQCo(8&Y_+SZ#0EIp(->FV6 zYdeNF@w#98V#|^@fJ``<^(2YXF+~x^iYWISn-y{zXTmlPRok# zynLdwJlRBDwBFuEGn^M|#3v<{nA(FmUQ1y4!DJKDc3%u^lSQo6C`R~RnJ?f?;a_ z_K=<4BpjyW{Kk87YyNfuGWG^N0@ns6o^xDPnWLgMIF}$ICyuP1LKuV_7sR*L!{3(w z@`@rqL6;MtoPKK?Ban3~&^z&?bV1nXrJ;5!uoC0)C{~^>eQH^xHGLb zYVGUk%et|K-H&(5^wv5;8R^K9Lt`#q)6UV5FyFF##RL`?#01Jof;%5N4SuI1&QZ~i z3bjebYWsez)&e!9#x*<{p}z(sjNsBX5|8}vu3yA`Pb1scFyjwqV&>-zDYZ(5omc+e zt&I3|QM^n{vKMgCELf(VxeZn37ww;z@w(=-|4LE>vTMLFSnrE1#|-U30yKq5nI7^y zQW%G~eQamrtdk@iAJez%OCFZTM@P%l3HPx^_d7`8a~?6&_}JN9HpfWis)IRQ!E zcka(9tCL1zV9k_E4*eH@slw*wW_{~I%pa0&3J58J#)msfpaAjxl&;;8Ylc@0L8Uq~ z%^KX5_M7|Vkcq#wcVv3SHaw$*oE2AoI`WhZ%*rucz(^5%nt<^S)m7U=-G2?p>@T70|pKubYwh7R?zpF?w=k>hCrXER2+8MCW zaQFPnW-Uy*aPI-0_pVys{4BTRY9soQ85$-f>R|HL%*DIrs4hSc;~?~1TcJxTDE?A| zN9K)p-xl6jQ9OrX-!xa3Tv%H=vUXLxWDe1mkgz(w5N2?Pf-oY?nI@W+0!5LM+V~TT zFPWUUU^U{ZGhe$%tWHb}zwS=nZwN)!djB#Bi@|vC3o+uKJdU6v5;gc3 zF~kjN?q@RrDu+AmQg|QWnC0Y7%q%8gRk&a6gm*rn>#R^i>8kMB1V6e2*&3(JO7XSSaiOJ&>{2wWse^UDA&o@-q%E5&05VdOiX=h|HTD! z!rjqHIX^wKy+S2>~y!vVX0%-NDKaAp#{Qw&Eq(_v*k>^&QJ ziN3x?!Vr^ldiT&}`EHxep=$;7`zpFZ+e_~jBhFjg+FSOZV&Wx8+RuP=TTdpD$wUSj z5&sd*$IA3$cerNb+cqmSa=kJ72+QKXyMJ9=*YBf(^9pA8t~M({N?3L$Q67n_j;qIS zHGnPJL(y7F{sql=mtwjTY7Au?p-JKZXDHCUx#KSSV> zPfp^$Ci=%p!BRTTcIC&6-}e>(OKm;~y-MHr8AAv*-mm5MxKz6C|3ph!phggA?$FPF zT!|8=%?+Z)X7;e$Xb)XpxDhz0r&#izeDO?NwA*}qoYCX5e~qgZ_&GG1iMrQvT8uqM%fj$bphco2S4j*(*@AA-dBUey@?z*49x}YoduR=Ze5*Yx z*PG-tO7j~zoFb3cCkbq$m=_f#*2EruDA@~M0*Y9M(df%Hq|ukSf9)B1xTi4nh5XYP zu_RE$dgour+w}isvHb%A|6UOW|DF1u2SVwBze@b~=D%YtHq?K==RZ@146*&l|BosE zKfELtEDQ)#d%rk79vLJ4XLbMgsvZ9yty+vUd6eDm{r$x*%#cv|Gv~WgFJh+Y)|vS1 z%;UbIAt1yLfejRwJ*v?3SUpJ@E*O7eg zxIRhMs8O!YeCK#~@7$y?rmuDUFoU0j!K$v;p%Z4CdB~tf$23Ii;`^)Lq}2mq-6^{+ z{eOSuKf|F*&NuVnz0&RlR)-DNJ8w|^M6DTj*7(eyhp{b{?|#5BeIc{86KJcAuKnk*hNP&hNTrZ|!2bZk CF|3yW diff --git a/ios/libs/Sqlite/LICENSE.txt b/ios/libs/Sqlite/LICENSE.txt deleted file mode 100644 index 13303c1..0000000 --- a/ios/libs/Sqlite/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -(The MIT License) - -Copyright (c) 2014-2015 Stephen Celis () - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/ios/libs/Sqlite/Makefile b/ios/libs/Sqlite/Makefile deleted file mode 100644 index 50d0714..0000000 --- a/ios/libs/Sqlite/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -BUILD_TOOL = xcodebuild -BUILD_SCHEME = SQLite Mac -IOS_SIMULATOR = iPhone XS -IOS_VERSION = 12.2 -ifeq ($(BUILD_SCHEME),SQLite iOS) - BUILD_ARGUMENTS = -scheme "$(BUILD_SCHEME)" -destination "platform=iOS Simulator,name=$(IOS_SIMULATOR),OS=$(IOS_VERSION)" -else - BUILD_ARGUMENTS = -scheme "$(BUILD_SCHEME)" -endif - -XCPRETTY := $(shell command -v xcpretty) -SWIFTCOV := $(shell command -v swiftcov) -GCOVR := $(shell command -v gcovr) -TEST_ACTIONS := clean build build-for-testing test-without-building - -default: test - -build: - $(BUILD_TOOL) $(BUILD_ARGUMENTS) - -test: -ifdef XCPRETTY - @set -o pipefail && $(BUILD_TOOL) $(BUILD_ARGUMENTS) $(TEST_ACTIONS) | $(XCPRETTY) -c -else - $(BUILD_TOOL) $(BUILD_ARGUMENTS) $(TEST_ACTIONS) -endif - -coverage: -ifdef SWIFTCOV - $(SWIFTCOV) generate --output coverage \ - $(BUILD_TOOL) $(BUILD_ARGUMENTS) -configuration Release test \ - -- ./SQLite/*.swift -ifdef GCOVR - $(GCOVR) \ - --root . \ - --use-gcov-files \ - --html \ - --html-details \ - --output coverage/index.html \ - --keep -else - @echo gcovr must be installed for HTML output: https://github.com/gcovr/gcovr -endif -else - @echo swiftcov must be installed for coverage: https://github.com/realm/SwiftCov - @exit 1 -endif - -clean: - $(BUILD_TOOL) $(BUILD_ARGUMENTS) clean - rm -r coverage - -repl: - @$(BUILD_TOOL) $(BUILD_ARGUMENTS) -derivedDataPath $(TMPDIR)/SQLite.swift > /dev/null && \ - swift -F '$(TMPDIR)/SQLite.swift/Build/Products/Debug' - -sloc: - @zsh -c "grep -vE '^ *//|^$$' SQLite/*/*.{swift,h,m} | wc -l" - -.PHONY: test coverage clean repl sloc diff --git a/ios/libs/Sqlite/Package.swift b/ios/libs/Sqlite/Package.swift deleted file mode 100644 index 430ae6f..0000000 --- a/ios/libs/Sqlite/Package.swift +++ /dev/null @@ -1,24 +0,0 @@ -// swift-tools-version:4.0 -import PackageDescription - -let package = Package( - name: "SQLite.swift", - products: [.library(name: "SQLite", targets: ["SQLite"])], - targets: [ - .target(name: "SQLite", dependencies: ["SQLiteObjc"]), - .target(name: "SQLiteObjc"), - .testTarget(name: "SQLiteTests", dependencies: ["SQLite"], path: "Tests/SQLiteTests") - ], - swiftLanguageVersions: [4, 5] -) - -#if os(Linux) - package.dependencies = [.package(url: "https://github.com/stephencelis/CSQLite.git", from: "0.0.3")] - package.targets = [ - .target(name: "SQLite", exclude: ["Extensions/FTS4.swift", "Extensions/FTS5.swift"]), - .testTarget(name: "SQLiteTests", dependencies: ["SQLite"], path: "Tests/SQLiteTests", exclude: [ - "FTS4Tests.swift", - "FTS5Tests.swift" - ]) - ] -#endif diff --git a/ios/libs/Sqlite/README.md b/ios/libs/Sqlite/README.md deleted file mode 100644 index b7a18e0..0000000 --- a/ios/libs/Sqlite/README.md +++ /dev/null @@ -1,293 +0,0 @@ -# SQLite.swift - -[![Build Status][TravisBadge]][TravisLink] [![CocoaPods Version][CocoaPodsVersionBadge]][CocoaPodsVersionLink] [![Swift5 compatible][Swift5Badge]][Swift5Link] [![Platform][PlatformBadge]][PlatformLink] [![Carthage compatible][CartagheBadge]][CarthageLink] [![Join the chat at https://gitter.im/stephencelis/SQLite.swift][GitterBadge]][GitterLink] - -A type-safe, [Swift][]-language layer over [SQLite3][]. - -[SQLite.swift][] provides compile-time confidence in SQL statement -syntax _and_ intent. - -## Features - - - A pure-Swift interface - - A type-safe, optional-aware SQL expression builder - - A flexible, chainable, lazy-executing query layer - - Automatically-typed data access - - A lightweight, uncomplicated query and parameter binding interface - - Developer-friendly error handling and debugging - - [Full-text search][] support - - [Well-documented][See Documentation] - - Extensively tested - - [SQLCipher][] support via CocoaPods - - Active support at - [StackOverflow](http://stackoverflow.com/questions/tagged/sqlite.swift), - and [Gitter Chat Room](https://gitter.im/stephencelis/SQLite.swift) - (_experimental_) - -[SQLCipher]: https://www.zetetic.net/sqlcipher/ -[Full-text search]: Documentation/Index.md#full-text-search -[See Documentation]: Documentation/Index.md#sqliteswift-documentation - - -## Usage - -```swift -import SQLite - -let db = try Connection("path/to/db.sqlite3") - -let users = Table("users") -let id = Expression("id") -let name = Expression("name") -let email = Expression("email") - -try db.run(users.create { t in - t.column(id, primaryKey: true) - t.column(name) - t.column(email, unique: true) -}) -// CREATE TABLE "users" ( -// "id" INTEGER PRIMARY KEY NOT NULL, -// "name" TEXT, -// "email" TEXT NOT NULL UNIQUE -// ) - -let insert = users.insert(name <- "Alice", email <- "alice@mac.com") -let rowid = try db.run(insert) -// INSERT INTO "users" ("name", "email") VALUES ('Alice', 'alice@mac.com') - -for user in try db.prepare(users) { - print("id: \(user[id]), name: \(user[name]), email: \(user[email])") - // id: 1, name: Optional("Alice"), email: alice@mac.com -} -// SELECT * FROM "users" - -let alice = users.filter(id == rowid) - -try db.run(alice.update(email <- email.replace("mac.com", with: "me.com"))) -// UPDATE "users" SET "email" = replace("email", 'mac.com', 'me.com') -// WHERE ("id" = 1) - -try db.run(alice.delete()) -// DELETE FROM "users" WHERE ("id" = 1) - -try db.scalar(users.count) // 0 -// SELECT count(*) FROM "users" -``` - -SQLite.swift also works as a lightweight, Swift-friendly wrapper over the C -API. - -```swift -let stmt = try db.prepare("INSERT INTO users (email) VALUES (?)") -for email in ["betty@icloud.com", "cathy@icloud.com"] { - try stmt.run(email) -} - -db.totalChanges // 3 -db.changes // 1 -db.lastInsertRowid // 3 - -for row in try db.prepare("SELECT id, email FROM users") { - print("id: \(row[0]), email: \(row[1])") - // id: Optional(2), email: Optional("betty@icloud.com") - // id: Optional(3), email: Optional("cathy@icloud.com") -} - -try db.scalar("SELECT count(*) FROM users") // 2 -``` - -[Read the documentation][See Documentation] or explore more, -interactively, from the Xcode project’s playground. - -![SQLite.playground Screen Shot](Documentation/Resources/playground@2x.png) - -For a more comprehensive example, see -[this article][Create a Data Access Layer with SQLite.swift and Swift 2] -and the [companion repository][SQLiteDataAccessLayer2]. - - -[Create a Data Access Layer with SQLite.swift and Swift 2]: http://masteringswift.blogspot.com/2015/09/create-data-access-layer-with.html -[SQLiteDataAccessLayer2]: https://github.com/hoffmanjon/SQLiteDataAccessLayer2/tree/master - -## Installation - -> _Note:_ Version 0.12 requires Swift 5 (and [Xcode](https://developer.apple.com/xcode/downloads/) 10.2) or greater. Version 0.11.6 requires Swift 4.2 (and [Xcode](https://developer.apple.com/xcode/downloads/) 10.1) or greater. - -### Carthage - -[Carthage][] is a simple, decentralized dependency manager for Cocoa. To -install SQLite.swift with Carthage: - - 1. Make sure Carthage is [installed][Carthage Installation]. - - 2. Update your Cartfile to include the following: - - ```ruby - github "stephencelis/SQLite.swift" ~> 0.12.0 - ``` - - 3. Run `carthage update` and - [add the appropriate framework][Carthage Usage]. - - -[Carthage]: https://github.com/Carthage/Carthage -[Carthage Installation]: https://github.com/Carthage/Carthage#installing-carthage -[Carthage Usage]: https://github.com/Carthage/Carthage#adding-frameworks-to-an-application - - -### CocoaPods - -[CocoaPods][] is a dependency manager for Cocoa projects. To install -SQLite.swift with CocoaPods: - - 1. Make sure CocoaPods is [installed][CocoaPods Installation]. (SQLite.swift - requires version 1.6.1 or greater.) - - ```sh - # Using the default Ruby install will require you to use sudo when - # installing and updating gems. - [sudo] gem install cocoapods - ``` - - 2. Update your Podfile to include the following: - - ```ruby - use_frameworks! - - target 'YourAppTargetName' do - pod 'SQLite.swift', '~> 0.12.0' - end - ``` - - 3. Run `pod install --repo-update`. - -[CocoaPods]: https://cocoapods.org -[CocoaPods Installation]: https://guides.cocoapods.org/using/getting-started.html#getting-started - -### Swift Package Manager - -The [Swift Package Manager][] is a tool for managing the distribution of -Swift code. - -1. Add the following to your `Package.swift` file: - - ```swift - dependencies: [ - .package(url: "https://github.com/stephencelis/SQLite.swift.git", from: "0.12.0") - ] - ``` - -2. Build your project: - - ```sh - $ swift build - ``` - -[Swift Package Manager]: https://swift.org/package-manager - -### Manual - -To install SQLite.swift as an Xcode sub-project: - - 1. Drag the **SQLite.xcodeproj** file into your own project. - ([Submodule][], clone, or [download][] the project first.) - - ![Installation Screen Shot](Documentation/Resources/installation@2x.png) - - 2. In your target’s **General** tab, click the **+** button under **Linked - Frameworks and Libraries**. - - 3. Select the appropriate **SQLite.framework** for your platform. - - 4. **Add**. - -Some additional steps are required to install the application on an actual -device: - - 5. In the **General** tab, click the **+** button under **Embedded - Binaries**. - - 6. Select the appropriate **SQLite.framework** for your platform. - - 7. **Add**. - - -[Xcode]: https://developer.apple.com/xcode/downloads/ -[Submodule]: http://git-scm.com/book/en/Git-Tools-Submodules -[download]: https://github.com/stephencelis/SQLite.swift/archive/master.zip - - -## Communication - -[See the planning document] for a roadmap and existing feature requests. - -[Read the contributing guidelines][]. The _TL;DR_ (but please; _R_): - - - Need **help** or have a **general question**? [Ask on Stack - Overflow][] (tag `sqlite.swift`). - - Found a **bug** or have a **feature request**? [Open an issue][]. - - Want to **contribute**? [Submit a pull request][]. - -[See the planning document]: /Documentation/Planning.md -[Read the contributing guidelines]: ./CONTRIBUTING.md#contributing -[Ask on Stack Overflow]: http://stackoverflow.com/questions/tagged/sqlite.swift -[Open an issue]: https://github.com/stephencelis/SQLite.swift/issues/new -[Submit a pull request]: https://github.com/stephencelis/SQLite.swift/fork - - -## Author - - - [Stephen Celis](mailto:stephen@stephencelis.com) - ([@stephencelis](https://twitter.com/stephencelis)) - - -## License - -SQLite.swift is available under the MIT license. See [the LICENSE -file](./LICENSE.txt) for more information. - -## Related - -These projects enhance or use SQLite.swift: - - - [SQLiteMigrationManager.swift][] (inspired by - [FMDBMigrationManager][]) - - -## Alternatives - -Looking for something else? Try another Swift wrapper (or [FMDB][]): - - - [Camembert](https://github.com/remirobert/Camembert) - - [GRDB](https://github.com/groue/GRDB.swift) - - [SQLiteDB](https://github.com/FahimF/SQLiteDB) - - [Squeal](https://github.com/nerdyc/Squeal) - - [SwiftData](https://github.com/ryanfowler/SwiftData) - - [SwiftSQLite](https://github.com/chrismsimpson/SwiftSQLite) - -[Swift]: https://swift.org/ -[SQLite3]: http://www.sqlite.org -[SQLite.swift]: https://github.com/stephencelis/SQLite.swift - -[TravisBadge]: https://img.shields.io/travis/stephencelis/SQLite.swift/master.svg?style=flat -[TravisLink]: https://travis-ci.org/stephencelis/SQLite.swift - -[CocoaPodsVersionBadge]: https://cocoapod-badges.herokuapp.com/v/SQLite.swift/badge.png -[CocoaPodsVersionLink]: http://cocoadocs.org/docsets/SQLite.swift - -[PlatformBadge]: https://cocoapod-badges.herokuapp.com/p/SQLite.swift/badge.png -[PlatformLink]: http://cocoadocs.org/docsets/SQLite.swift - -[CartagheBadge]: https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat -[CarthageLink]: https://github.com/Carthage/Carthage - -[GitterBadge]: https://badges.gitter.im/stephencelis/SQLite.swift.svg -[GitterLink]: https://gitter.im/stephencelis/SQLite.swift - -[Swift5Badge]: https://img.shields.io/badge/swift-5-orange.svg?style=flat -[Swift5Link]: https://developer.apple.com/swift/ - -[SQLiteMigrationManager.swift]: https://github.com/garriguv/SQLiteMigrationManager.swift -[FMDB]: https://github.com/ccgus/fmdb -[FMDBMigrationManager]: https://github.com/layerhq/FMDBMigrationManager diff --git a/ios/libs/Sqlite/SQLite.playground/Contents.swift b/ios/libs/Sqlite/SQLite.playground/Contents.swift deleted file mode 100644 index 11e1313..0000000 --- a/ios/libs/Sqlite/SQLite.playground/Contents.swift +++ /dev/null @@ -1,43 +0,0 @@ -import SQLite - -let db = try! Connection() - -db.trace { print($0) } - -let users = Table("users") - -let id = Expression("id") -let email = Expression("email") -let name = Expression("name") - -try! db.run(users.create { t in - t.column(id, primaryKey: true) - t.column(email, unique: true, check: email.like("%@%")) - t.column(name) -}) - -let rowid = try! db.run(users.insert(email <- "alice@mac.com")) -let alice = users.filter(id == rowid) - -for user in try! db.prepare(users) { - print("id: \(user[id]), email: \(user[email])") -} - -let emails = VirtualTable("emails") - -let subject = Expression("subject") -let body = Expression("body") - -try! db.run(emails.create(.FTS4(subject, body))) - -try! db.run(emails.insert( - subject <- "Hello, world!", - body <- "This is a hello world message." -)) - -let row = try! db.pluck(emails.match("hello")) - -let query = try! db.prepare(emails.match("hello")) -for row in query { - print(row[subject]) -} diff --git a/ios/libs/Sqlite/SQLite.playground/contents.xcplayground b/ios/libs/Sqlite/SQLite.playground/contents.xcplayground deleted file mode 100644 index fd676d5..0000000 --- a/ios/libs/Sqlite/SQLite.playground/contents.xcplayground +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/ios/libs/Sqlite/SQLite.swift.podspec b/ios/libs/Sqlite/SQLite.swift.podspec deleted file mode 100644 index 57eda40..0000000 --- a/ios/libs/Sqlite/SQLite.swift.podspec +++ /dev/null @@ -1,69 +0,0 @@ -Pod::Spec.new do |s| - s.name = "SQLite.swift" - s.version = "0.12.0" - s.summary = "A type-safe, Swift-language layer over SQLite3 for iOS and macOS." - - s.description = <<-DESC - SQLite.swift provides compile-time confidence in SQL statement syntax and - intent. - DESC - - s.homepage = "https://github.com/stephencelis/SQLite.swift" - s.license = 'MIT' - s.author = { "Stephen Celis" => "stephen@stephencelis.com" } - s.source = { :git => "https://github.com/stephencelis/SQLite.swift.git", :tag => s.version.to_s } - s.social_media_url = 'https://twitter.com/stephencelis' - - s.module_name = 'SQLite' - s.ios.deployment_target = "8.0" - s.tvos.deployment_target = "9.1" - s.osx.deployment_target = "10.10" - s.watchos.deployment_target = "2.2" - s.default_subspec = 'standard' - s.pod_target_xcconfig = { - 'SWIFT_VERSION' => '5', - } - - s.subspec 'standard' do |ss| - ss.source_files = 'Sources/{SQLite,SQLiteObjc}/**/*.{c,h,m,swift}' - ss.exclude_files = 'Sources/**/Cipher.swift' - ss.private_header_files = 'Sources/SQLiteObjc/*.h' - ss.library = 'sqlite3' - - ss.test_spec 'tests' do |test_spec| - test_spec.resources = 'Tests/SQLiteTests/fixtures/*' - test_spec.source_files = 'Tests/SQLiteTests/*.swift' - end - end - - s.subspec 'standalone' do |ss| - ss.source_files = 'Sources/{SQLite,SQLiteObjc}/**/*.{c,h,m,swift}' - ss.exclude_files = 'Sources/**/Cipher.swift' - ss.private_header_files = 'Sources/SQLiteObjc/*.h' - - ss.xcconfig = { - 'OTHER_SWIFT_FLAGS' => '$(inherited) -DSQLITE_SWIFT_STANDALONE' - } - ss.dependency 'sqlite3' - - ss.test_spec 'tests' do |test_spec| - test_spec.resources = 'Tests/SQLiteTests/fixtures/*' - test_spec.source_files = 'Tests/SQLiteTests/*.swift' - end - end - - s.subspec 'SQLCipher' do |ss| - ss.source_files = 'Sources/{SQLite,SQLiteObjc}/**/*.{c,h,m,swift}' - ss.private_header_files = 'Sources/SQLiteObjc/*.h' - ss.xcconfig = { - 'OTHER_SWIFT_FLAGS' => '$(inherited) -DSQLITE_SWIFT_SQLCIPHER', - 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SQLITE_HAS_CODEC=1' - } - ss.dependency 'SQLCipher', '>= 3.4.0' - - ss.test_spec 'tests' do |test_spec| - test_spec.resources = 'Tests/SQLiteTests/fixtures/*' - test_spec.source_files = 'Tests/SQLiteTests/*.swift' - end - end -end diff --git a/ios/libs/Sqlite/SQLite.xcodeproj/project.pbxproj b/ios/libs/Sqlite/SQLite.xcodeproj/project.pbxproj deleted file mode 100644 index 9d38dbc..0000000 --- a/ios/libs/Sqlite/SQLite.xcodeproj/project.pbxproj +++ /dev/null @@ -1,1461 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 03A65E641C6BB0F60062603F /* SQLite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03A65E5A1C6BB0F50062603F /* SQLite.framework */; }; - 03A65E721C6BB2D30062603F /* SQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AD61C3F04ED00AE3E12 /* SQLite.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 03A65E731C6BB2D80062603F /* Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF71C3F06E900AE3E12 /* Foundation.swift */; }; - 03A65E741C6BB2DA0062603F /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF81C3F06E900AE3E12 /* Helpers.swift */; }; - 03A65E751C6BB2DF0062603F /* SQLite-Bridging.h in Headers */ = {isa = PBXBuildFile; fileRef = EE91808D1C46E5230038162A /* SQLite-Bridging.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 03A65E761C6BB2E60062603F /* Blob.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEE1C3F06E900AE3E12 /* Blob.swift */; }; - 03A65E771C6BB2E60062603F /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEF1C3F06E900AE3E12 /* Connection.swift */; }; - 03A65E781C6BB2EA0062603F /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AF01C3F06E900AE3E12 /* fts3_tokenizer.h */; }; - 03A65E791C6BB2EF0062603F /* SQLite-Bridging.m in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF11C3F06E900AE3E12 /* SQLite-Bridging.m */; }; - 03A65E7A1C6BB2F70062603F /* Statement.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF21C3F06E900AE3E12 /* Statement.swift */; }; - 03A65E7B1C6BB2F70062603F /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF31C3F06E900AE3E12 /* Value.swift */; }; - 03A65E7C1C6BB2F70062603F /* FTS4.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF51C3F06E900AE3E12 /* FTS4.swift */; }; - 03A65E7D1C6BB2F70062603F /* RTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF61C3F06E900AE3E12 /* RTree.swift */; }; - 03A65E7E1C6BB2FB0062603F /* AggregateFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFA1C3F06E900AE3E12 /* AggregateFunctions.swift */; }; - 03A65E7F1C6BB2FB0062603F /* Collation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFB1C3F06E900AE3E12 /* Collation.swift */; }; - 03A65E801C6BB2FB0062603F /* CoreFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFC1C3F06E900AE3E12 /* CoreFunctions.swift */; }; - 03A65E811C6BB2FB0062603F /* CustomFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFD1C3F06E900AE3E12 /* CustomFunctions.swift */; }; - 03A65E821C6BB2FB0062603F /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFE1C3F06E900AE3E12 /* Expression.swift */; }; - 03A65E831C6BB2FB0062603F /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFF1C3F06E900AE3E12 /* Operators.swift */; }; - 03A65E841C6BB2FB0062603F /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B001C3F06E900AE3E12 /* Query.swift */; }; - 03A65E851C6BB2FB0062603F /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B011C3F06E900AE3E12 /* Schema.swift */; }; - 03A65E861C6BB2FB0062603F /* Setter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B021C3F06E900AE3E12 /* Setter.swift */; }; - 03A65E871C6BB3030062603F /* AggregateFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1A1C3F137700AE3E12 /* AggregateFunctionsTests.swift */; }; - 03A65E881C6BB3030062603F /* BlobTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1B1C3F137700AE3E12 /* BlobTests.swift */; }; - 03A65E891C6BB3030062603F /* ConnectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1D1C3F137700AE3E12 /* ConnectionTests.swift */; }; - 03A65E8A1C6BB3030062603F /* CoreFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1E1C3F137700AE3E12 /* CoreFunctionsTests.swift */; }; - 03A65E8B1C6BB3030062603F /* CustomFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1F1C3F137700AE3E12 /* CustomFunctionsTests.swift */; }; - 03A65E8C1C6BB3030062603F /* ExpressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B201C3F137700AE3E12 /* ExpressionTests.swift */; }; - 03A65E8D1C6BB3030062603F /* FTS4Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B211C3F137700AE3E12 /* FTS4Tests.swift */; }; - 03A65E8E1C6BB3030062603F /* OperatorsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2A1C3F141E00AE3E12 /* OperatorsTests.swift */; }; - 03A65E8F1C6BB3030062603F /* QueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2B1C3F141E00AE3E12 /* QueryTests.swift */; }; - 03A65E901C6BB3030062603F /* RTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2C1C3F141E00AE3E12 /* RTreeTests.swift */; }; - 03A65E911C6BB3030062603F /* SchemaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2D1C3F141E00AE3E12 /* SchemaTests.swift */; }; - 03A65E921C6BB3030062603F /* SetterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B181C3F134A00AE3E12 /* SetterTests.swift */; }; - 03A65E931C6BB3030062603F /* StatementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B321C3F142E00AE3E12 /* StatementTests.swift */; }; - 03A65E941C6BB3030062603F /* ValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B331C3F142E00AE3E12 /* ValueTests.swift */; }; - 03A65E951C6BB3030062603F /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B161C3F127200AE3E12 /* TestHelpers.swift */; }; - 03A65E971C6BB3210062603F /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 03A65E961C6BB3210062603F /* libsqlite3.tbd */; }; - 19A1709C3E7A406E62293B2A /* Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17B93B48B5560E6E51791 /* Fixtures.swift */; }; - 19A17152E32A9585831E3FE0 /* DateAndTimeFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17BA55DABB480F9020C8A /* DateAndTimeFunctions.swift */; }; - 19A1717B10CC941ACB5533D6 /* FTS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1730E4390C775C25677D1 /* FTS5.swift */; }; - 19A171967CC511C4F6F773C9 /* RowTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A175C1F9CB3BBAB8FCEC7B /* RowTests.swift */; }; - 19A171E6FA242F72A308C594 /* FTS5Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1721B8984686B9963B45D /* FTS5Tests.swift */; }; - 19A171F12AB8B07F2FD7201A /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A178A39ACA9667A62663CC /* Cipher.swift */; }; - 19A1720B67ED13E6150C6A3D /* RowTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A175C1F9CB3BBAB8FCEC7B /* RowTests.swift */; }; - 19A17254FBA7894891F7297B /* FTS5Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1721B8984686B9963B45D /* FTS5Tests.swift */; }; - 19A172EB202970561E5C4245 /* DateAndTimeFunctionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1729B75C33F9A0B9A89C1 /* DateAndTimeFunctionTests.swift */; }; - 19A173668D948AD4DF1F5352 /* DateAndTimeFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17BA55DABB480F9020C8A /* DateAndTimeFunctions.swift */; }; - 19A1737286A74F3CF7412906 /* DateAndTimeFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17BA55DABB480F9020C8A /* DateAndTimeFunctions.swift */; }; - 19A17408007B182F884E3A53 /* Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17B93B48B5560E6E51791 /* Fixtures.swift */; }; - 19A17490543609FCED53CACC /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1710E73A46D5AC721CDA9 /* Errors.swift */; }; - 19A174D78559CD30679BCCCB /* FTS5Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1721B8984686B9963B45D /* FTS5Tests.swift */; }; - 19A1750CEE9B05267995CF3D /* FTS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1730E4390C775C25677D1 /* FTS5.swift */; }; - 19A175DFF47B84757E547C62 /* fixtures in Resources */ = {isa = PBXBuildFile; fileRef = 19A17E2695737FAB5D6086E3 /* fixtures */; }; - 19A1769C1F3A7542BECF50FF /* DateAndTimeFunctionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1729B75C33F9A0B9A89C1 /* DateAndTimeFunctionTests.swift */; }; - 19A177CC33F2E6A24AF90B02 /* CipherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17399EA9E61235D5D77BF /* CipherTests.swift */; }; - 19A178072B371489E6A1E839 /* FoundationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1794CC4D7827E997E32A7 /* FoundationTests.swift */; }; - 19A17835FD5886FDC5A3228F /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A178A39ACA9667A62663CC /* Cipher.swift */; }; - 19A1785195182AF8731A8BDA /* RowTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A175C1F9CB3BBAB8FCEC7B /* RowTests.swift */; }; - 19A1792C0520D4E83C2EB075 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1710E73A46D5AC721CDA9 /* Errors.swift */; }; - 19A179A0C45377CB09BB358C /* CipherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17399EA9E61235D5D77BF /* CipherTests.swift */; }; - 19A179CCF9671E345E5A9811 /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A178A39ACA9667A62663CC /* Cipher.swift */; }; - 19A179E76EA6207669B60C1B /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A178A39ACA9667A62663CC /* Cipher.swift */; }; - 19A17C4B951CB054EE48AB1C /* CipherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17399EA9E61235D5D77BF /* CipherTests.swift */; }; - 19A17C80076860CF7751A056 /* DateAndTimeFunctionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1729B75C33F9A0B9A89C1 /* DateAndTimeFunctionTests.swift */; }; - 19A17DC282E36C4F41AA440B /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1710E73A46D5AC721CDA9 /* Errors.swift */; }; - 19A17E04C4C0956715C5676A /* FoundationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1794CC4D7827E997E32A7 /* FoundationTests.swift */; }; - 19A17E29278A12BC4F542506 /* DateAndTimeFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17BA55DABB480F9020C8A /* DateAndTimeFunctions.swift */; }; - 19A17EC0D68BA8C03288ADF7 /* FTS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1730E4390C775C25677D1 /* FTS5.swift */; }; - 19A17F3E1F7ACA33BD43E138 /* fixtures in Resources */ = {isa = PBXBuildFile; fileRef = 19A17E2695737FAB5D6086E3 /* fixtures */; }; - 19A17F60B685636D1F83C2DD /* Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17B93B48B5560E6E51791 /* Fixtures.swift */; }; - 19A17FB80B94E882050AA908 /* FoundationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1794CC4D7827E997E32A7 /* FoundationTests.swift */; }; - 19A17FDA323BAFDEC627E76F /* fixtures in Resources */ = {isa = PBXBuildFile; fileRef = 19A17E2695737FAB5D6086E3 /* fixtures */; }; - 19A17FF4A10B44D3937C8CAC /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1710E73A46D5AC721CDA9 /* Errors.swift */; }; - 3D67B3E61DB2469200A4F4C6 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D67B3E51DB2469200A4F4C6 /* libsqlite3.tbd */; }; - 3D67B3E71DB246BA00A4F4C6 /* Blob.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEE1C3F06E900AE3E12 /* Blob.swift */; }; - 3D67B3E81DB246BA00A4F4C6 /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEF1C3F06E900AE3E12 /* Connection.swift */; }; - 3D67B3E91DB246D100A4F4C6 /* Statement.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF21C3F06E900AE3E12 /* Statement.swift */; }; - 3D67B3EA1DB246D100A4F4C6 /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF31C3F06E900AE3E12 /* Value.swift */; }; - 3D67B3EB1DB246D100A4F4C6 /* FTS4.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF51C3F06E900AE3E12 /* FTS4.swift */; }; - 3D67B3EC1DB246D100A4F4C6 /* RTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF61C3F06E900AE3E12 /* RTree.swift */; }; - 3D67B3ED1DB246D100A4F4C6 /* FTS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1730E4390C775C25677D1 /* FTS5.swift */; }; - 3D67B3EE1DB246D100A4F4C6 /* AggregateFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFA1C3F06E900AE3E12 /* AggregateFunctions.swift */; }; - 3D67B3EF1DB246D100A4F4C6 /* Collation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFB1C3F06E900AE3E12 /* Collation.swift */; }; - 3D67B3F01DB246D100A4F4C6 /* CoreFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFC1C3F06E900AE3E12 /* CoreFunctions.swift */; }; - 3D67B3F11DB246D100A4F4C6 /* CustomFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFD1C3F06E900AE3E12 /* CustomFunctions.swift */; }; - 3D67B3F21DB246D100A4F4C6 /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFE1C3F06E900AE3E12 /* Expression.swift */; }; - 3D67B3F31DB246D100A4F4C6 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFF1C3F06E900AE3E12 /* Operators.swift */; }; - 3D67B3F41DB246D100A4F4C6 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B001C3F06E900AE3E12 /* Query.swift */; }; - 3D67B3F51DB246D100A4F4C6 /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B011C3F06E900AE3E12 /* Schema.swift */; }; - 3D67B3F61DB246D100A4F4C6 /* Setter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B021C3F06E900AE3E12 /* Setter.swift */; }; - 3D67B3F71DB246D700A4F4C6 /* Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF71C3F06E900AE3E12 /* Foundation.swift */; }; - 3D67B3F81DB246D700A4F4C6 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF81C3F06E900AE3E12 /* Helpers.swift */; }; - 3D67B3F91DB246E700A4F4C6 /* SQLite-Bridging.m in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF11C3F06E900AE3E12 /* SQLite-Bridging.m */; }; - 3D67B3FB1DB2470600A4F4C6 /* SQLite-Bridging.h in Headers */ = {isa = PBXBuildFile; fileRef = EE91808D1C46E5230038162A /* SQLite-Bridging.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3D67B3FC1DB2471B00A4F4C6 /* SQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AD61C3F04ED00AE3E12 /* SQLite.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3D67B3FD1DB2472D00A4F4C6 /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AF01C3F06E900AE3E12 /* fts3_tokenizer.h */; }; - 49EB68C41F7B3CB400D89D40 /* Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49EB68C31F7B3CB400D89D40 /* Coding.swift */; }; - 49EB68C51F7B3CB400D89D40 /* Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49EB68C31F7B3CB400D89D40 /* Coding.swift */; }; - 49EB68C61F7B3CB400D89D40 /* Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49EB68C31F7B3CB400D89D40 /* Coding.swift */; }; - 49EB68C71F7B3CB400D89D40 /* Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49EB68C31F7B3CB400D89D40 /* Coding.swift */; }; - EE247AD71C3F04ED00AE3E12 /* SQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AD61C3F04ED00AE3E12 /* SQLite.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EE247ADE1C3F04ED00AE3E12 /* SQLite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EE247AD31C3F04ED00AE3E12 /* SQLite.framework */; }; - EE247B031C3F06E900AE3E12 /* Blob.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEE1C3F06E900AE3E12 /* Blob.swift */; }; - EE247B041C3F06E900AE3E12 /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEF1C3F06E900AE3E12 /* Connection.swift */; }; - EE247B051C3F06E900AE3E12 /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AF01C3F06E900AE3E12 /* fts3_tokenizer.h */; }; - EE247B061C3F06E900AE3E12 /* SQLite-Bridging.m in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF11C3F06E900AE3E12 /* SQLite-Bridging.m */; }; - EE247B071C3F06E900AE3E12 /* Statement.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF21C3F06E900AE3E12 /* Statement.swift */; }; - EE247B081C3F06E900AE3E12 /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF31C3F06E900AE3E12 /* Value.swift */; }; - EE247B091C3F06E900AE3E12 /* FTS4.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF51C3F06E900AE3E12 /* FTS4.swift */; }; - EE247B0A1C3F06E900AE3E12 /* RTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF61C3F06E900AE3E12 /* RTree.swift */; }; - EE247B0B1C3F06E900AE3E12 /* Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF71C3F06E900AE3E12 /* Foundation.swift */; }; - EE247B0C1C3F06E900AE3E12 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF81C3F06E900AE3E12 /* Helpers.swift */; }; - EE247B0D1C3F06E900AE3E12 /* AggregateFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFA1C3F06E900AE3E12 /* AggregateFunctions.swift */; }; - EE247B0E1C3F06E900AE3E12 /* Collation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFB1C3F06E900AE3E12 /* Collation.swift */; }; - EE247B0F1C3F06E900AE3E12 /* CoreFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFC1C3F06E900AE3E12 /* CoreFunctions.swift */; }; - EE247B101C3F06E900AE3E12 /* CustomFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFD1C3F06E900AE3E12 /* CustomFunctions.swift */; }; - EE247B111C3F06E900AE3E12 /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFE1C3F06E900AE3E12 /* Expression.swift */; }; - EE247B121C3F06E900AE3E12 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFF1C3F06E900AE3E12 /* Operators.swift */; }; - EE247B131C3F06E900AE3E12 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B001C3F06E900AE3E12 /* Query.swift */; }; - EE247B141C3F06E900AE3E12 /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B011C3F06E900AE3E12 /* Schema.swift */; }; - EE247B151C3F06E900AE3E12 /* Setter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B021C3F06E900AE3E12 /* Setter.swift */; }; - EE247B171C3F127200AE3E12 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B161C3F127200AE3E12 /* TestHelpers.swift */; }; - EE247B191C3F134A00AE3E12 /* SetterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B181C3F134A00AE3E12 /* SetterTests.swift */; }; - EE247B221C3F137700AE3E12 /* AggregateFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1A1C3F137700AE3E12 /* AggregateFunctionsTests.swift */; }; - EE247B231C3F137700AE3E12 /* BlobTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1B1C3F137700AE3E12 /* BlobTests.swift */; }; - EE247B251C3F137700AE3E12 /* ConnectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1D1C3F137700AE3E12 /* ConnectionTests.swift */; }; - EE247B261C3F137700AE3E12 /* CoreFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1E1C3F137700AE3E12 /* CoreFunctionsTests.swift */; }; - EE247B271C3F137700AE3E12 /* CustomFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1F1C3F137700AE3E12 /* CustomFunctionsTests.swift */; }; - EE247B281C3F137700AE3E12 /* ExpressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B201C3F137700AE3E12 /* ExpressionTests.swift */; }; - EE247B291C3F137700AE3E12 /* FTS4Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B211C3F137700AE3E12 /* FTS4Tests.swift */; }; - EE247B2E1C3F141E00AE3E12 /* OperatorsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2A1C3F141E00AE3E12 /* OperatorsTests.swift */; }; - EE247B2F1C3F141E00AE3E12 /* QueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2B1C3F141E00AE3E12 /* QueryTests.swift */; }; - EE247B301C3F141E00AE3E12 /* RTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2C1C3F141E00AE3E12 /* RTreeTests.swift */; }; - EE247B311C3F141E00AE3E12 /* SchemaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2D1C3F141E00AE3E12 /* SchemaTests.swift */; }; - EE247B341C3F142E00AE3E12 /* StatementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B321C3F142E00AE3E12 /* StatementTests.swift */; }; - EE247B351C3F142E00AE3E12 /* ValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B331C3F142E00AE3E12 /* ValueTests.swift */; }; - EE247B461C3F3ED000AE3E12 /* SQLite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EE247B3C1C3F3ED000AE3E12 /* SQLite.framework */; }; - EE247B531C3F3FC700AE3E12 /* AggregateFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1A1C3F137700AE3E12 /* AggregateFunctionsTests.swift */; }; - EE247B541C3F3FC700AE3E12 /* BlobTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1B1C3F137700AE3E12 /* BlobTests.swift */; }; - EE247B551C3F3FC700AE3E12 /* ConnectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1D1C3F137700AE3E12 /* ConnectionTests.swift */; }; - EE247B561C3F3FC700AE3E12 /* CoreFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1E1C3F137700AE3E12 /* CoreFunctionsTests.swift */; }; - EE247B571C3F3FC700AE3E12 /* CustomFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B1F1C3F137700AE3E12 /* CustomFunctionsTests.swift */; }; - EE247B581C3F3FC700AE3E12 /* ExpressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B201C3F137700AE3E12 /* ExpressionTests.swift */; }; - EE247B591C3F3FC700AE3E12 /* FTS4Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B211C3F137700AE3E12 /* FTS4Tests.swift */; }; - EE247B5A1C3F3FC700AE3E12 /* OperatorsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2A1C3F141E00AE3E12 /* OperatorsTests.swift */; }; - EE247B5B1C3F3FC700AE3E12 /* QueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2B1C3F141E00AE3E12 /* QueryTests.swift */; }; - EE247B5C1C3F3FC700AE3E12 /* RTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2C1C3F141E00AE3E12 /* RTreeTests.swift */; }; - EE247B5D1C3F3FC700AE3E12 /* SchemaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B2D1C3F141E00AE3E12 /* SchemaTests.swift */; }; - EE247B5E1C3F3FC700AE3E12 /* SetterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B181C3F134A00AE3E12 /* SetterTests.swift */; }; - EE247B5F1C3F3FC700AE3E12 /* StatementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B321C3F142E00AE3E12 /* StatementTests.swift */; }; - EE247B601C3F3FC700AE3E12 /* ValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B331C3F142E00AE3E12 /* ValueTests.swift */; }; - EE247B611C3F3FC700AE3E12 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B161C3F127200AE3E12 /* TestHelpers.swift */; }; - EE247B621C3F3FDB00AE3E12 /* SQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AD61C3F04ED00AE3E12 /* SQLite.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EE247B631C3F3FDB00AE3E12 /* Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF71C3F06E900AE3E12 /* Foundation.swift */; }; - EE247B641C3F3FDB00AE3E12 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF81C3F06E900AE3E12 /* Helpers.swift */; }; - EE247B651C3F3FEC00AE3E12 /* Blob.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEE1C3F06E900AE3E12 /* Blob.swift */; }; - EE247B661C3F3FEC00AE3E12 /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEF1C3F06E900AE3E12 /* Connection.swift */; }; - EE247B671C3F3FEC00AE3E12 /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AF01C3F06E900AE3E12 /* fts3_tokenizer.h */; }; - EE247B681C3F3FEC00AE3E12 /* SQLite-Bridging.m in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF11C3F06E900AE3E12 /* SQLite-Bridging.m */; }; - EE247B691C3F3FEC00AE3E12 /* Statement.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF21C3F06E900AE3E12 /* Statement.swift */; }; - EE247B6A1C3F3FEC00AE3E12 /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF31C3F06E900AE3E12 /* Value.swift */; }; - EE247B6B1C3F3FEC00AE3E12 /* FTS4.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF51C3F06E900AE3E12 /* FTS4.swift */; }; - EE247B6C1C3F3FEC00AE3E12 /* RTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF61C3F06E900AE3E12 /* RTree.swift */; }; - EE247B6D1C3F3FEC00AE3E12 /* AggregateFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFA1C3F06E900AE3E12 /* AggregateFunctions.swift */; }; - EE247B6E1C3F3FEC00AE3E12 /* Collation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFB1C3F06E900AE3E12 /* Collation.swift */; }; - EE247B6F1C3F3FEC00AE3E12 /* CoreFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFC1C3F06E900AE3E12 /* CoreFunctions.swift */; }; - EE247B701C3F3FEC00AE3E12 /* CustomFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFD1C3F06E900AE3E12 /* CustomFunctions.swift */; }; - EE247B711C3F3FEC00AE3E12 /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFE1C3F06E900AE3E12 /* Expression.swift */; }; - EE247B721C3F3FEC00AE3E12 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFF1C3F06E900AE3E12 /* Operators.swift */; }; - EE247B731C3F3FEC00AE3E12 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B001C3F06E900AE3E12 /* Query.swift */; }; - EE247B741C3F3FEC00AE3E12 /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B011C3F06E900AE3E12 /* Schema.swift */; }; - EE247B751C3F3FEC00AE3E12 /* Setter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B021C3F06E900AE3E12 /* Setter.swift */; }; - EE91808E1C46E5230038162A /* SQLite-Bridging.h in Headers */ = {isa = PBXBuildFile; fileRef = EE91808D1C46E5230038162A /* SQLite-Bridging.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EE91808F1C46E76D0038162A /* SQLite-Bridging.h in Headers */ = {isa = PBXBuildFile; fileRef = EE91808D1C46E5230038162A /* SQLite-Bridging.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EE9180941C46EA210038162A /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = EE9180931C46EA210038162A /* libsqlite3.tbd */; }; - EE9180951C46EBCC0038162A /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = EE9180911C46E9D30038162A /* libsqlite3.tbd */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 03A65E651C6BB0F60062603F /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = EE247ACA1C3F04ED00AE3E12 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 03A65E591C6BB0F50062603F; - remoteInfo = "SQLite tvOS"; - }; - EE247ADF1C3F04ED00AE3E12 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = EE247ACA1C3F04ED00AE3E12 /* Project object */; - proxyType = 1; - remoteGlobalIDString = EE247AD21C3F04ED00AE3E12; - remoteInfo = SQLite; - }; - EE247B471C3F3ED000AE3E12 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = EE247ACA1C3F04ED00AE3E12 /* Project object */; - proxyType = 1; - remoteGlobalIDString = EE247B3B1C3F3ED000AE3E12; - remoteInfo = SQLite; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 03A65E5A1C6BB0F50062603F /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLite.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 03A65E631C6BB0F60062603F /* SQLiteTests tvOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SQLiteTests tvOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 03A65E961C6BB3210062603F /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk/usr/lib/libsqlite3.tbd; sourceTree = DEVELOPER_DIR; }; - 19A1710E73A46D5AC721CDA9 /* Errors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Errors.swift; sourceTree = ""; }; - 19A1721B8984686B9963B45D /* FTS5Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FTS5Tests.swift; sourceTree = ""; }; - 19A1729B75C33F9A0B9A89C1 /* DateAndTimeFunctionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateAndTimeFunctionTests.swift; sourceTree = ""; }; - 19A1730E4390C775C25677D1 /* FTS5.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FTS5.swift; sourceTree = ""; }; - 19A17399EA9E61235D5D77BF /* CipherTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CipherTests.swift; sourceTree = ""; }; - 19A175C1F9CB3BBAB8FCEC7B /* RowTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowTests.swift; sourceTree = ""; }; - 19A178A39ACA9667A62663CC /* Cipher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cipher.swift; sourceTree = ""; }; - 19A1794CC4D7827E997E32A7 /* FoundationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FoundationTests.swift; sourceTree = ""; }; - 19A17B93B48B5560E6E51791 /* Fixtures.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fixtures.swift; sourceTree = ""; }; - 19A17BA55DABB480F9020C8A /* DateAndTimeFunctions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateAndTimeFunctions.swift; sourceTree = ""; }; - 19A17E2695737FAB5D6086E3 /* fixtures */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; path = fixtures; sourceTree = ""; }; - 3D67B3E51DB2469200A4F4C6 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS3.0.sdk/usr/lib/libsqlite3.tbd; sourceTree = DEVELOPER_DIR; }; - 49EB68C31F7B3CB400D89D40 /* Coding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coding.swift; sourceTree = ""; }; - A121AC451CA35C79005A31D1 /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLite.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - EE247AD31C3F04ED00AE3E12 /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLite.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - EE247AD61C3F04ED00AE3E12 /* SQLite.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SQLite.h; sourceTree = ""; }; - EE247AD81C3F04ED00AE3E12 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - EE247ADD1C3F04ED00AE3E12 /* SQLiteTests iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SQLiteTests iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - EE247AE41C3F04ED00AE3E12 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - EE247AEE1C3F06E900AE3E12 /* Blob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Blob.swift; sourceTree = ""; }; - EE247AEF1C3F06E900AE3E12 /* Connection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Connection.swift; sourceTree = ""; }; - EE247AF01C3F06E900AE3E12 /* fts3_tokenizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fts3_tokenizer.h; path = ../../SQLiteObjc/fts3_tokenizer.h; sourceTree = ""; }; - EE247AF11C3F06E900AE3E12 /* SQLite-Bridging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "SQLite-Bridging.m"; path = "../../SQLiteObjc/SQLite-Bridging.m"; sourceTree = ""; }; - EE247AF21C3F06E900AE3E12 /* Statement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Statement.swift; sourceTree = ""; }; - EE247AF31C3F06E900AE3E12 /* Value.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Value.swift; sourceTree = ""; }; - EE247AF51C3F06E900AE3E12 /* FTS4.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FTS4.swift; sourceTree = ""; }; - EE247AF61C3F06E900AE3E12 /* RTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RTree.swift; sourceTree = ""; }; - EE247AF71C3F06E900AE3E12 /* Foundation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Foundation.swift; sourceTree = ""; }; - EE247AF81C3F06E900AE3E12 /* Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = ""; }; - EE247AFA1C3F06E900AE3E12 /* AggregateFunctions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AggregateFunctions.swift; sourceTree = ""; }; - EE247AFB1C3F06E900AE3E12 /* Collation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Collation.swift; sourceTree = ""; }; - EE247AFC1C3F06E900AE3E12 /* CoreFunctions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreFunctions.swift; sourceTree = ""; }; - EE247AFD1C3F06E900AE3E12 /* CustomFunctions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomFunctions.swift; sourceTree = ""; }; - EE247AFE1C3F06E900AE3E12 /* Expression.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Expression.swift; sourceTree = ""; }; - EE247AFF1C3F06E900AE3E12 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = ""; }; - EE247B001C3F06E900AE3E12 /* Query.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Query.swift; sourceTree = ""; }; - EE247B011C3F06E900AE3E12 /* Schema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Schema.swift; sourceTree = ""; }; - EE247B021C3F06E900AE3E12 /* Setter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Setter.swift; sourceTree = ""; }; - EE247B161C3F127200AE3E12 /* TestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestHelpers.swift; sourceTree = ""; }; - EE247B181C3F134A00AE3E12 /* SetterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetterTests.swift; sourceTree = ""; }; - EE247B1A1C3F137700AE3E12 /* AggregateFunctionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AggregateFunctionsTests.swift; sourceTree = ""; }; - EE247B1B1C3F137700AE3E12 /* BlobTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlobTests.swift; sourceTree = ""; }; - EE247B1D1C3F137700AE3E12 /* ConnectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionTests.swift; sourceTree = ""; }; - EE247B1E1C3F137700AE3E12 /* CoreFunctionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreFunctionsTests.swift; sourceTree = ""; }; - EE247B1F1C3F137700AE3E12 /* CustomFunctionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomFunctionsTests.swift; sourceTree = ""; }; - EE247B201C3F137700AE3E12 /* ExpressionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExpressionTests.swift; sourceTree = ""; }; - EE247B211C3F137700AE3E12 /* FTS4Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FTS4Tests.swift; sourceTree = ""; }; - EE247B2A1C3F141E00AE3E12 /* OperatorsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperatorsTests.swift; sourceTree = ""; }; - EE247B2B1C3F141E00AE3E12 /* QueryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryTests.swift; sourceTree = ""; }; - EE247B2C1C3F141E00AE3E12 /* RTreeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RTreeTests.swift; sourceTree = ""; }; - EE247B2D1C3F141E00AE3E12 /* SchemaTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaTests.swift; sourceTree = ""; }; - EE247B321C3F142E00AE3E12 /* StatementTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatementTests.swift; sourceTree = ""; }; - EE247B331C3F142E00AE3E12 /* ValueTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValueTests.swift; sourceTree = ""; }; - EE247B3C1C3F3ED000AE3E12 /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLite.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - EE247B451C3F3ED000AE3E12 /* SQLiteTests Mac.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SQLiteTests Mac.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - EE247B771C3F40D700AE3E12 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; - EE247B8B1C3F820300AE3E12 /* CONTRIBUTING.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CONTRIBUTING.md; sourceTree = ""; }; - EE247B8C1C3F821200AE3E12 /* .travis.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .travis.yml; sourceTree = ""; }; - EE247B8D1C3F821200AE3E12 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; - EE247B8F1C3F822500AE3E12 /* Index.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Index.md; sourceTree = ""; }; - EE247B911C3F822500AE3E12 /* installation@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "installation@2x.png"; sourceTree = ""; }; - EE247B921C3F822600AE3E12 /* playground@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "playground@2x.png"; sourceTree = ""; }; - EE247B931C3F826100AE3E12 /* SQLite.swift.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = SQLite.swift.podspec; sourceTree = ""; }; - EE91808D1C46E5230038162A /* SQLite-Bridging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SQLite-Bridging.h"; path = "../../SQLiteObjc/include/SQLite-Bridging.h"; sourceTree = ""; }; - EE9180911C46E9D30038162A /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/lib/libsqlite3.tbd; sourceTree = DEVELOPER_DIR; }; - EE9180931C46EA210038162A /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 03A65E561C6BB0F50062603F /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 03A65E971C6BB3210062603F /* libsqlite3.tbd in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03A65E601C6BB0F60062603F /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 03A65E641C6BB0F60062603F /* SQLite.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - A121AC411CA35C79005A31D1 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 3D67B3E61DB2469200A4F4C6 /* libsqlite3.tbd in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EE247ACF1C3F04ED00AE3E12 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - EE9180941C46EA210038162A /* libsqlite3.tbd in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EE247ADA1C3F04ED00AE3E12 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - EE247ADE1C3F04ED00AE3E12 /* SQLite.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EE247B381C3F3ED000AE3E12 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - EE9180951C46EBCC0038162A /* libsqlite3.tbd in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EE247B421C3F3ED000AE3E12 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - EE247B461C3F3ED000AE3E12 /* SQLite.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 3D67B3E41DB2469200A4F4C6 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 3D67B3E51DB2469200A4F4C6 /* libsqlite3.tbd */, - ); - name = Frameworks; - sourceTree = ""; - }; - EE247AC91C3F04ED00AE3E12 = { - isa = PBXGroup; - children = ( - EE247AD51C3F04ED00AE3E12 /* SQLite */, - EE247AE11C3F04ED00AE3E12 /* SQLiteTests */, - EE247B8A1C3F81D000AE3E12 /* Metadata */, - EE247AD41C3F04ED00AE3E12 /* Products */, - 3D67B3E41DB2469200A4F4C6 /* Frameworks */, - ); - indentWidth = 4; - sourceTree = ""; - tabWidth = 4; - }; - EE247AD41C3F04ED00AE3E12 /* Products */ = { - isa = PBXGroup; - children = ( - EE247AD31C3F04ED00AE3E12 /* SQLite.framework */, - EE247ADD1C3F04ED00AE3E12 /* SQLiteTests iOS.xctest */, - EE247B3C1C3F3ED000AE3E12 /* SQLite.framework */, - EE247B451C3F3ED000AE3E12 /* SQLiteTests Mac.xctest */, - 03A65E5A1C6BB0F50062603F /* SQLite.framework */, - 03A65E631C6BB0F60062603F /* SQLiteTests tvOS.xctest */, - A121AC451CA35C79005A31D1 /* SQLite.framework */, - ); - name = Products; - sourceTree = ""; - }; - EE247AD51C3F04ED00AE3E12 /* SQLite */ = { - isa = PBXGroup; - children = ( - EE247AD61C3F04ED00AE3E12 /* SQLite.h */, - EE247AF71C3F06E900AE3E12 /* Foundation.swift */, - EE247AF81C3F06E900AE3E12 /* Helpers.swift */, - EE247AD81C3F04ED00AE3E12 /* Info.plist */, - EE247AED1C3F06E900AE3E12 /* Core */, - EE247AF41C3F06E900AE3E12 /* Extensions */, - EE247AF91C3F06E900AE3E12 /* Typed */, - ); - name = SQLite; - path = Sources/SQLite; - sourceTree = ""; - }; - EE247AE11C3F04ED00AE3E12 /* SQLiteTests */ = { - isa = PBXGroup; - children = ( - 19A17E2695737FAB5D6086E3 /* fixtures */, - EE247B1A1C3F137700AE3E12 /* AggregateFunctionsTests.swift */, - EE247B1B1C3F137700AE3E12 /* BlobTests.swift */, - EE247B1D1C3F137700AE3E12 /* ConnectionTests.swift */, - EE247B1E1C3F137700AE3E12 /* CoreFunctionsTests.swift */, - EE247B1F1C3F137700AE3E12 /* CustomFunctionsTests.swift */, - EE247B201C3F137700AE3E12 /* ExpressionTests.swift */, - EE247B211C3F137700AE3E12 /* FTS4Tests.swift */, - EE247B2A1C3F141E00AE3E12 /* OperatorsTests.swift */, - EE247B2B1C3F141E00AE3E12 /* QueryTests.swift */, - EE247B2C1C3F141E00AE3E12 /* RTreeTests.swift */, - EE247B2D1C3F141E00AE3E12 /* SchemaTests.swift */, - EE247B181C3F134A00AE3E12 /* SetterTests.swift */, - EE247B321C3F142E00AE3E12 /* StatementTests.swift */, - EE247B331C3F142E00AE3E12 /* ValueTests.swift */, - EE247B161C3F127200AE3E12 /* TestHelpers.swift */, - EE247AE41C3F04ED00AE3E12 /* Info.plist */, - 19A1721B8984686B9963B45D /* FTS5Tests.swift */, - 19A1794CC4D7827E997E32A7 /* FoundationTests.swift */, - 19A17399EA9E61235D5D77BF /* CipherTests.swift */, - 19A17B93B48B5560E6E51791 /* Fixtures.swift */, - 19A175C1F9CB3BBAB8FCEC7B /* RowTests.swift */, - 19A1729B75C33F9A0B9A89C1 /* DateAndTimeFunctionTests.swift */, - ); - name = SQLiteTests; - path = Tests/SQLiteTests; - sourceTree = ""; - }; - EE247AED1C3F06E900AE3E12 /* Core */ = { - isa = PBXGroup; - children = ( - EE91808D1C46E5230038162A /* SQLite-Bridging.h */, - EE247AEE1C3F06E900AE3E12 /* Blob.swift */, - EE247AEF1C3F06E900AE3E12 /* Connection.swift */, - EE247AF01C3F06E900AE3E12 /* fts3_tokenizer.h */, - EE247AF11C3F06E900AE3E12 /* SQLite-Bridging.m */, - EE247AF21C3F06E900AE3E12 /* Statement.swift */, - EE247AF31C3F06E900AE3E12 /* Value.swift */, - 19A1710E73A46D5AC721CDA9 /* Errors.swift */, - ); - path = Core; - sourceTree = ""; - }; - EE247AF41C3F06E900AE3E12 /* Extensions */ = { - isa = PBXGroup; - children = ( - EE247AF51C3F06E900AE3E12 /* FTS4.swift */, - EE247AF61C3F06E900AE3E12 /* RTree.swift */, - 19A1730E4390C775C25677D1 /* FTS5.swift */, - 19A178A39ACA9667A62663CC /* Cipher.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - EE247AF91C3F06E900AE3E12 /* Typed */ = { - isa = PBXGroup; - children = ( - EE247AFA1C3F06E900AE3E12 /* AggregateFunctions.swift */, - EE247AFB1C3F06E900AE3E12 /* Collation.swift */, - EE247AFC1C3F06E900AE3E12 /* CoreFunctions.swift */, - EE247AFD1C3F06E900AE3E12 /* CustomFunctions.swift */, - EE247AFE1C3F06E900AE3E12 /* Expression.swift */, - EE247AFF1C3F06E900AE3E12 /* Operators.swift */, - EE247B001C3F06E900AE3E12 /* Query.swift */, - EE247B011C3F06E900AE3E12 /* Schema.swift */, - EE247B021C3F06E900AE3E12 /* Setter.swift */, - 49EB68C31F7B3CB400D89D40 /* Coding.swift */, - 19A17BA55DABB480F9020C8A /* DateAndTimeFunctions.swift */, - ); - path = Typed; - sourceTree = ""; - }; - EE247B8A1C3F81D000AE3E12 /* Metadata */ = { - isa = PBXGroup; - children = ( - EE247B771C3F40D700AE3E12 /* README.md */, - EE247B8B1C3F820300AE3E12 /* CONTRIBUTING.md */, - EE247B931C3F826100AE3E12 /* SQLite.swift.podspec */, - EE247B8C1C3F821200AE3E12 /* .travis.yml */, - EE247B8D1C3F821200AE3E12 /* Makefile */, - EE9180931C46EA210038162A /* libsqlite3.tbd */, - EE9180911C46E9D30038162A /* libsqlite3.tbd */, - 03A65E961C6BB3210062603F /* libsqlite3.tbd */, - EE247B8E1C3F822500AE3E12 /* Documentation */, - ); - name = Metadata; - sourceTree = ""; - }; - EE247B8E1C3F822500AE3E12 /* Documentation */ = { - isa = PBXGroup; - children = ( - EE247B8F1C3F822500AE3E12 /* Index.md */, - EE247B901C3F822500AE3E12 /* Resources */, - ); - path = Documentation; - sourceTree = ""; - }; - EE247B901C3F822500AE3E12 /* Resources */ = { - isa = PBXGroup; - children = ( - EE247B911C3F822500AE3E12 /* installation@2x.png */, - EE247B921C3F822600AE3E12 /* playground@2x.png */, - ); - path = Resources; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 03A65E571C6BB0F50062603F /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 03A65E781C6BB2EA0062603F /* fts3_tokenizer.h in Headers */, - 03A65E751C6BB2DF0062603F /* SQLite-Bridging.h in Headers */, - 03A65E721C6BB2D30062603F /* SQLite.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - A121AC421CA35C79005A31D1 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 3D67B3FB1DB2470600A4F4C6 /* SQLite-Bridging.h in Headers */, - 3D67B3FC1DB2471B00A4F4C6 /* SQLite.h in Headers */, - 3D67B3FD1DB2472D00A4F4C6 /* fts3_tokenizer.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EE247AD01C3F04ED00AE3E12 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - EE91808E1C46E5230038162A /* SQLite-Bridging.h in Headers */, - EE247B051C3F06E900AE3E12 /* fts3_tokenizer.h in Headers */, - EE247AD71C3F04ED00AE3E12 /* SQLite.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EE247B391C3F3ED000AE3E12 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - EE247B671C3F3FEC00AE3E12 /* fts3_tokenizer.h in Headers */, - EE247B621C3F3FDB00AE3E12 /* SQLite.h in Headers */, - EE91808F1C46E76D0038162A /* SQLite-Bridging.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 03A65E591C6BB0F50062603F /* SQLite tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 03A65E6F1C6BB0F60062603F /* Build configuration list for PBXNativeTarget "SQLite tvOS" */; - buildPhases = ( - 03A65E551C6BB0F50062603F /* Sources */, - 03A65E561C6BB0F50062603F /* Frameworks */, - 03A65E571C6BB0F50062603F /* Headers */, - 03A65E581C6BB0F50062603F /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "SQLite tvOS"; - productName = "SQLite tvOS"; - productReference = 03A65E5A1C6BB0F50062603F /* SQLite.framework */; - productType = "com.apple.product-type.framework"; - }; - 03A65E621C6BB0F60062603F /* SQLiteTests tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 03A65E701C6BB0F60062603F /* Build configuration list for PBXNativeTarget "SQLiteTests tvOS" */; - buildPhases = ( - 03A65E5F1C6BB0F60062603F /* Sources */, - 03A65E601C6BB0F60062603F /* Frameworks */, - 03A65E611C6BB0F60062603F /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 03A65E661C6BB0F60062603F /* PBXTargetDependency */, - ); - name = "SQLiteTests tvOS"; - productName = "SQLite tvOSTests"; - productReference = 03A65E631C6BB0F60062603F /* SQLiteTests tvOS.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - A121AC441CA35C79005A31D1 /* SQLite watchOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = A121AC4C1CA35C79005A31D1 /* Build configuration list for PBXNativeTarget "SQLite watchOS" */; - buildPhases = ( - A121AC401CA35C79005A31D1 /* Sources */, - A121AC411CA35C79005A31D1 /* Frameworks */, - A121AC421CA35C79005A31D1 /* Headers */, - A121AC431CA35C79005A31D1 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "SQLite watchOS"; - productName = "SQLite watchOS"; - productReference = A121AC451CA35C79005A31D1 /* SQLite.framework */; - productType = "com.apple.product-type.framework"; - }; - EE247AD21C3F04ED00AE3E12 /* SQLite iOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = EE247AE71C3F04ED00AE3E12 /* Build configuration list for PBXNativeTarget "SQLite iOS" */; - buildPhases = ( - EE247ACE1C3F04ED00AE3E12 /* Sources */, - EE247ACF1C3F04ED00AE3E12 /* Frameworks */, - EE247AD01C3F04ED00AE3E12 /* Headers */, - EE247AD11C3F04ED00AE3E12 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "SQLite iOS"; - productName = SQLite; - productReference = EE247AD31C3F04ED00AE3E12 /* SQLite.framework */; - productType = "com.apple.product-type.framework"; - }; - EE247ADC1C3F04ED00AE3E12 /* SQLiteTests iOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = EE247AEA1C3F04ED00AE3E12 /* Build configuration list for PBXNativeTarget "SQLiteTests iOS" */; - buildPhases = ( - EE247AD91C3F04ED00AE3E12 /* Sources */, - EE247ADA1C3F04ED00AE3E12 /* Frameworks */, - EE247ADB1C3F04ED00AE3E12 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - EE247AE01C3F04ED00AE3E12 /* PBXTargetDependency */, - ); - name = "SQLiteTests iOS"; - productName = SQLiteTests; - productReference = EE247ADD1C3F04ED00AE3E12 /* SQLiteTests iOS.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - EE247B3B1C3F3ED000AE3E12 /* SQLite Mac */ = { - isa = PBXNativeTarget; - buildConfigurationList = EE247B511C3F3ED000AE3E12 /* Build configuration list for PBXNativeTarget "SQLite Mac" */; - buildPhases = ( - EE247B371C3F3ED000AE3E12 /* Sources */, - EE247B381C3F3ED000AE3E12 /* Frameworks */, - EE247B391C3F3ED000AE3E12 /* Headers */, - EE247B3A1C3F3ED000AE3E12 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "SQLite Mac"; - productName = SQLite; - productReference = EE247B3C1C3F3ED000AE3E12 /* SQLite.framework */; - productType = "com.apple.product-type.framework"; - }; - EE247B441C3F3ED000AE3E12 /* SQLiteTests Mac */ = { - isa = PBXNativeTarget; - buildConfigurationList = EE247B521C3F3ED000AE3E12 /* Build configuration list for PBXNativeTarget "SQLiteTests Mac" */; - buildPhases = ( - EE247B411C3F3ED000AE3E12 /* Sources */, - EE247B421C3F3ED000AE3E12 /* Frameworks */, - EE247B431C3F3ED000AE3E12 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - EE247B481C3F3ED000AE3E12 /* PBXTargetDependency */, - ); - name = "SQLiteTests Mac"; - productName = SQLiteTests; - productReference = EE247B451C3F3ED000AE3E12 /* SQLiteTests Mac.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - EE247ACA1C3F04ED00AE3E12 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 1020; - TargetAttributes = { - 03A65E591C6BB0F50062603F = { - CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0900; - }; - 03A65E621C6BB0F60062603F = { - CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0900; - }; - A121AC441CA35C79005A31D1 = { - CreatedOnToolsVersion = 7.3; - LastSwiftMigration = 0900; - }; - EE247AD21C3F04ED00AE3E12 = { - CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0900; - }; - EE247ADC1C3F04ED00AE3E12 = { - CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 1020; - }; - EE247B3B1C3F3ED000AE3E12 = { - CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0900; - }; - EE247B441C3F3ED000AE3E12 = { - CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0900; - }; - }; - }; - buildConfigurationList = EE247ACD1C3F04ED00AE3E12 /* Build configuration list for PBXProject "SQLite" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = EE247AC91C3F04ED00AE3E12; - productRefGroup = EE247AD41C3F04ED00AE3E12 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - EE247AD21C3F04ED00AE3E12 /* SQLite iOS */, - EE247ADC1C3F04ED00AE3E12 /* SQLiteTests iOS */, - EE247B3B1C3F3ED000AE3E12 /* SQLite Mac */, - EE247B441C3F3ED000AE3E12 /* SQLiteTests Mac */, - 03A65E591C6BB0F50062603F /* SQLite tvOS */, - 03A65E621C6BB0F60062603F /* SQLiteTests tvOS */, - A121AC441CA35C79005A31D1 /* SQLite watchOS */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 03A65E581C6BB0F50062603F /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03A65E611C6BB0F60062603F /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 19A17F3E1F7ACA33BD43E138 /* fixtures in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - A121AC431CA35C79005A31D1 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EE247AD11C3F04ED00AE3E12 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EE247ADB1C3F04ED00AE3E12 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 19A17FDA323BAFDEC627E76F /* fixtures in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EE247B3A1C3F3ED000AE3E12 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EE247B431C3F3ED000AE3E12 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 19A175DFF47B84757E547C62 /* fixtures in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 03A65E551C6BB0F50062603F /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 03A65E801C6BB2FB0062603F /* CoreFunctions.swift in Sources */, - 49EB68C61F7B3CB400D89D40 /* Coding.swift in Sources */, - 03A65E761C6BB2E60062603F /* Blob.swift in Sources */, - 03A65E7D1C6BB2F70062603F /* RTree.swift in Sources */, - 03A65E791C6BB2EF0062603F /* SQLite-Bridging.m in Sources */, - 03A65E7B1C6BB2F70062603F /* Value.swift in Sources */, - 03A65E821C6BB2FB0062603F /* Expression.swift in Sources */, - 03A65E731C6BB2D80062603F /* Foundation.swift in Sources */, - 03A65E7F1C6BB2FB0062603F /* Collation.swift in Sources */, - 03A65E861C6BB2FB0062603F /* Setter.swift in Sources */, - 03A65E811C6BB2FB0062603F /* CustomFunctions.swift in Sources */, - 03A65E7A1C6BB2F70062603F /* Statement.swift in Sources */, - 03A65E741C6BB2DA0062603F /* Helpers.swift in Sources */, - 03A65E831C6BB2FB0062603F /* Operators.swift in Sources */, - 03A65E851C6BB2FB0062603F /* Schema.swift in Sources */, - 03A65E841C6BB2FB0062603F /* Query.swift in Sources */, - 03A65E7C1C6BB2F70062603F /* FTS4.swift in Sources */, - 03A65E771C6BB2E60062603F /* Connection.swift in Sources */, - 03A65E7E1C6BB2FB0062603F /* AggregateFunctions.swift in Sources */, - 19A17EC0D68BA8C03288ADF7 /* FTS5.swift in Sources */, - 19A179E76EA6207669B60C1B /* Cipher.swift in Sources */, - 19A17FF4A10B44D3937C8CAC /* Errors.swift in Sources */, - 19A1737286A74F3CF7412906 /* DateAndTimeFunctions.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03A65E5F1C6BB0F60062603F /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 03A65E881C6BB3030062603F /* BlobTests.swift in Sources */, - 03A65E901C6BB3030062603F /* RTreeTests.swift in Sources */, - 03A65E941C6BB3030062603F /* ValueTests.swift in Sources */, - 03A65E8F1C6BB3030062603F /* QueryTests.swift in Sources */, - 03A65E8B1C6BB3030062603F /* CustomFunctionsTests.swift in Sources */, - 03A65E871C6BB3030062603F /* AggregateFunctionsTests.swift in Sources */, - 03A65E921C6BB3030062603F /* SetterTests.swift in Sources */, - 03A65E891C6BB3030062603F /* ConnectionTests.swift in Sources */, - 03A65E8A1C6BB3030062603F /* CoreFunctionsTests.swift in Sources */, - 03A65E931C6BB3030062603F /* StatementTests.swift in Sources */, - 03A65E911C6BB3030062603F /* SchemaTests.swift in Sources */, - 03A65E8D1C6BB3030062603F /* FTS4Tests.swift in Sources */, - 03A65E8C1C6BB3030062603F /* ExpressionTests.swift in Sources */, - 03A65E8E1C6BB3030062603F /* OperatorsTests.swift in Sources */, - 03A65E951C6BB3030062603F /* TestHelpers.swift in Sources */, - 19A17254FBA7894891F7297B /* FTS5Tests.swift in Sources */, - 19A17E04C4C0956715C5676A /* FoundationTests.swift in Sources */, - 19A179A0C45377CB09BB358C /* CipherTests.swift in Sources */, - 19A17F60B685636D1F83C2DD /* Fixtures.swift in Sources */, - 19A1785195182AF8731A8BDA /* RowTests.swift in Sources */, - 19A1769C1F3A7542BECF50FF /* DateAndTimeFunctionTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - A121AC401CA35C79005A31D1 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3D67B3F91DB246E700A4F4C6 /* SQLite-Bridging.m in Sources */, - 49EB68C71F7B3CB400D89D40 /* Coding.swift in Sources */, - 3D67B3F71DB246D700A4F4C6 /* Foundation.swift in Sources */, - 3D67B3F81DB246D700A4F4C6 /* Helpers.swift in Sources */, - 3D67B3E91DB246D100A4F4C6 /* Statement.swift in Sources */, - 3D67B3EA1DB246D100A4F4C6 /* Value.swift in Sources */, - 3D67B3EB1DB246D100A4F4C6 /* FTS4.swift in Sources */, - 3D67B3EC1DB246D100A4F4C6 /* RTree.swift in Sources */, - 3D67B3ED1DB246D100A4F4C6 /* FTS5.swift in Sources */, - 3D67B3EE1DB246D100A4F4C6 /* AggregateFunctions.swift in Sources */, - 3D67B3EF1DB246D100A4F4C6 /* Collation.swift in Sources */, - 3D67B3F01DB246D100A4F4C6 /* CoreFunctions.swift in Sources */, - 3D67B3F11DB246D100A4F4C6 /* CustomFunctions.swift in Sources */, - 3D67B3F21DB246D100A4F4C6 /* Expression.swift in Sources */, - 3D67B3F31DB246D100A4F4C6 /* Operators.swift in Sources */, - 3D67B3F41DB246D100A4F4C6 /* Query.swift in Sources */, - 3D67B3F51DB246D100A4F4C6 /* Schema.swift in Sources */, - 3D67B3F61DB246D100A4F4C6 /* Setter.swift in Sources */, - 3D67B3E71DB246BA00A4F4C6 /* Blob.swift in Sources */, - 3D67B3E81DB246BA00A4F4C6 /* Connection.swift in Sources */, - 19A179CCF9671E345E5A9811 /* Cipher.swift in Sources */, - 19A17DC282E36C4F41AA440B /* Errors.swift in Sources */, - 19A173668D948AD4DF1F5352 /* DateAndTimeFunctions.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EE247ACE1C3F04ED00AE3E12 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - EE247B0F1C3F06E900AE3E12 /* CoreFunctions.swift in Sources */, - 49EB68C41F7B3CB400D89D40 /* Coding.swift in Sources */, - EE247B0A1C3F06E900AE3E12 /* RTree.swift in Sources */, - EE247B031C3F06E900AE3E12 /* Blob.swift in Sources */, - EE247B0B1C3F06E900AE3E12 /* Foundation.swift in Sources */, - EE247B041C3F06E900AE3E12 /* Connection.swift in Sources */, - EE247B111C3F06E900AE3E12 /* Expression.swift in Sources */, - EE247B0C1C3F06E900AE3E12 /* Helpers.swift in Sources */, - EE247B0E1C3F06E900AE3E12 /* Collation.swift in Sources */, - EE247B151C3F06E900AE3E12 /* Setter.swift in Sources */, - EE247B101C3F06E900AE3E12 /* CustomFunctions.swift in Sources */, - EE247B091C3F06E900AE3E12 /* FTS4.swift in Sources */, - EE247B081C3F06E900AE3E12 /* Value.swift in Sources */, - EE247B121C3F06E900AE3E12 /* Operators.swift in Sources */, - EE247B141C3F06E900AE3E12 /* Schema.swift in Sources */, - EE247B131C3F06E900AE3E12 /* Query.swift in Sources */, - EE247B061C3F06E900AE3E12 /* SQLite-Bridging.m in Sources */, - EE247B071C3F06E900AE3E12 /* Statement.swift in Sources */, - EE247B0D1C3F06E900AE3E12 /* AggregateFunctions.swift in Sources */, - 19A1717B10CC941ACB5533D6 /* FTS5.swift in Sources */, - 19A171F12AB8B07F2FD7201A /* Cipher.swift in Sources */, - 19A1792C0520D4E83C2EB075 /* Errors.swift in Sources */, - 19A17E29278A12BC4F542506 /* DateAndTimeFunctions.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EE247AD91C3F04ED00AE3E12 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - EE247B261C3F137700AE3E12 /* CoreFunctionsTests.swift in Sources */, - EE247B291C3F137700AE3E12 /* FTS4Tests.swift in Sources */, - EE247B191C3F134A00AE3E12 /* SetterTests.swift in Sources */, - EE247B311C3F141E00AE3E12 /* SchemaTests.swift in Sources */, - EE247B171C3F127200AE3E12 /* TestHelpers.swift in Sources */, - EE247B281C3F137700AE3E12 /* ExpressionTests.swift in Sources */, - EE247B271C3F137700AE3E12 /* CustomFunctionsTests.swift in Sources */, - EE247B341C3F142E00AE3E12 /* StatementTests.swift in Sources */, - EE247B301C3F141E00AE3E12 /* RTreeTests.swift in Sources */, - EE247B231C3F137700AE3E12 /* BlobTests.swift in Sources */, - EE247B351C3F142E00AE3E12 /* ValueTests.swift in Sources */, - EE247B2F1C3F141E00AE3E12 /* QueryTests.swift in Sources */, - EE247B221C3F137700AE3E12 /* AggregateFunctionsTests.swift in Sources */, - EE247B2E1C3F141E00AE3E12 /* OperatorsTests.swift in Sources */, - EE247B251C3F137700AE3E12 /* ConnectionTests.swift in Sources */, - 19A171E6FA242F72A308C594 /* FTS5Tests.swift in Sources */, - 19A17FB80B94E882050AA908 /* FoundationTests.swift in Sources */, - 19A177CC33F2E6A24AF90B02 /* CipherTests.swift in Sources */, - 19A17408007B182F884E3A53 /* Fixtures.swift in Sources */, - 19A1720B67ED13E6150C6A3D /* RowTests.swift in Sources */, - 19A17C80076860CF7751A056 /* DateAndTimeFunctionTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EE247B371C3F3ED000AE3E12 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - EE247B6F1C3F3FEC00AE3E12 /* CoreFunctions.swift in Sources */, - 49EB68C51F7B3CB400D89D40 /* Coding.swift in Sources */, - EE247B651C3F3FEC00AE3E12 /* Blob.swift in Sources */, - EE247B6C1C3F3FEC00AE3E12 /* RTree.swift in Sources */, - EE247B681C3F3FEC00AE3E12 /* SQLite-Bridging.m in Sources */, - EE247B6A1C3F3FEC00AE3E12 /* Value.swift in Sources */, - EE247B711C3F3FEC00AE3E12 /* Expression.swift in Sources */, - EE247B631C3F3FDB00AE3E12 /* Foundation.swift in Sources */, - EE247B6E1C3F3FEC00AE3E12 /* Collation.swift in Sources */, - EE247B751C3F3FEC00AE3E12 /* Setter.swift in Sources */, - EE247B701C3F3FEC00AE3E12 /* CustomFunctions.swift in Sources */, - EE247B691C3F3FEC00AE3E12 /* Statement.swift in Sources */, - EE247B641C3F3FDB00AE3E12 /* Helpers.swift in Sources */, - EE247B721C3F3FEC00AE3E12 /* Operators.swift in Sources */, - EE247B741C3F3FEC00AE3E12 /* Schema.swift in Sources */, - EE247B731C3F3FEC00AE3E12 /* Query.swift in Sources */, - EE247B6B1C3F3FEC00AE3E12 /* FTS4.swift in Sources */, - EE247B661C3F3FEC00AE3E12 /* Connection.swift in Sources */, - EE247B6D1C3F3FEC00AE3E12 /* AggregateFunctions.swift in Sources */, - 19A1750CEE9B05267995CF3D /* FTS5.swift in Sources */, - 19A17835FD5886FDC5A3228F /* Cipher.swift in Sources */, - 19A17490543609FCED53CACC /* Errors.swift in Sources */, - 19A17152E32A9585831E3FE0 /* DateAndTimeFunctions.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EE247B411C3F3ED000AE3E12 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - EE247B561C3F3FC700AE3E12 /* CoreFunctionsTests.swift in Sources */, - EE247B5A1C3F3FC700AE3E12 /* OperatorsTests.swift in Sources */, - EE247B541C3F3FC700AE3E12 /* BlobTests.swift in Sources */, - EE247B5D1C3F3FC700AE3E12 /* SchemaTests.swift in Sources */, - EE247B591C3F3FC700AE3E12 /* FTS4Tests.swift in Sources */, - EE247B531C3F3FC700AE3E12 /* AggregateFunctionsTests.swift in Sources */, - EE247B5F1C3F3FC700AE3E12 /* StatementTests.swift in Sources */, - EE247B5C1C3F3FC700AE3E12 /* RTreeTests.swift in Sources */, - EE247B571C3F3FC700AE3E12 /* CustomFunctionsTests.swift in Sources */, - EE247B601C3F3FC700AE3E12 /* ValueTests.swift in Sources */, - EE247B551C3F3FC700AE3E12 /* ConnectionTests.swift in Sources */, - EE247B611C3F3FC700AE3E12 /* TestHelpers.swift in Sources */, - EE247B581C3F3FC700AE3E12 /* ExpressionTests.swift in Sources */, - EE247B5E1C3F3FC700AE3E12 /* SetterTests.swift in Sources */, - EE247B5B1C3F3FC700AE3E12 /* QueryTests.swift in Sources */, - 19A174D78559CD30679BCCCB /* FTS5Tests.swift in Sources */, - 19A178072B371489E6A1E839 /* FoundationTests.swift in Sources */, - 19A17C4B951CB054EE48AB1C /* CipherTests.swift in Sources */, - 19A1709C3E7A406E62293B2A /* Fixtures.swift in Sources */, - 19A171967CC511C4F6F773C9 /* RowTests.swift in Sources */, - 19A172EB202970561E5C4245 /* DateAndTimeFunctionTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 03A65E661C6BB0F60062603F /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 03A65E591C6BB0F50062603F /* SQLite tvOS */; - targetProxy = 03A65E651C6BB0F60062603F /* PBXContainerItemProxy */; - }; - EE247AE01C3F04ED00AE3E12 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = EE247AD21C3F04ED00AE3E12 /* SQLite iOS */; - targetProxy = EE247ADF1C3F04ED00AE3E12 /* PBXContainerItemProxy */; - }; - EE247B481C3F3ED000AE3E12 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = EE247B3B1C3F3ED000AE3E12 /* SQLite Mac */; - targetProxy = EE247B471C3F3ED000AE3E12 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 03A65E6B1C6BB0F60062603F /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite; - PRODUCT_NAME = SQLite; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - TVOS_DEPLOYMENT_TARGET = 9.1; - }; - name = Debug; - }; - 03A65E6C1C6BB0F60062603F /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite; - PRODUCT_NAME = SQLite; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - TVOS_DEPLOYMENT_TARGET = 9.1; - }; - name = Release; - }; - 03A65E6D1C6BB0F60062603F /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - INFOPLIST_FILE = Tests/SQLiteTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 9.1; - }; - name = Debug; - }; - 03A65E6E1C6BB0F60062603F /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - INFOPLIST_FILE = Tests/SQLiteTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 9.1; - }; - name = Release; - }; - A121AC4A1CA35C79005A31D1 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ANALYZER_NONNULL = YES; - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite; - PRODUCT_NAME = SQLite; - SDKROOT = watchos; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 2.2; - }; - name = Debug; - }; - A121AC4B1CA35C79005A31D1 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ANALYZER_NONNULL = YES; - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite; - PRODUCT_NAME = SQLite; - SDKROOT = watchos; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 2.2; - }; - name = Release; - }; - EE247AE51C3F04ED00AE3E12 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MACOSX_DEPLOYMENT_TARGET = 10.9; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - PRODUCT_NAME = ""; - SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2,3"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - EE247AE61C3F04ED00AE3E12 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MACOSX_DEPLOYMENT_TARGET = 10.9; - MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_NAME = ""; - SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2,3"; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - EE247AE81C3F04ED00AE3E12 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ENABLE_MODULES = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite; - PRODUCT_NAME = SQLite; - SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - EE247AE91C3F04ED00AE3E12 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ENABLE_MODULES = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite; - PRODUCT_NAME = SQLite; - SKIP_INSTALL = YES; - }; - name = Release; - }; - EE247AEB1C3F04ED00AE3E12 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - INFOPLIST_FILE = Tests/SQLiteTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - EE247AEC1C3F04ED00AE3E12 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - INFOPLIST_FILE = Tests/SQLiteTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - EE247B4D1C3F3ED000AE3E12 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CODE_SIGN_IDENTITY = ""; - COMBINE_HIDPI_IMAGES = YES; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_VERSION = A; - INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.10; - PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite; - PRODUCT_NAME = SQLite; - SDKROOT = macosx; - SKIP_INSTALL = YES; - SWIFT_INCLUDE_PATHS = ""; - }; - name = Debug; - }; - EE247B4E1C3F3ED000AE3E12 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CODE_SIGN_IDENTITY = ""; - COMBINE_HIDPI_IMAGES = YES; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_VERSION = A; - INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.10; - PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite; - PRODUCT_NAME = SQLite; - SDKROOT = macosx; - SKIP_INSTALL = YES; - SWIFT_INCLUDE_PATHS = ""; - }; - name = Release; - }; - EE247B4F1C3F3ED000AE3E12 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_IDENTITY = "-"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Tests/SQLiteTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.10; - PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx; - }; - name = Debug; - }; - EE247B501C3F3ED000AE3E12 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_IDENTITY = "-"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Tests/SQLiteTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.10; - PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 03A65E6F1C6BB0F60062603F /* Build configuration list for PBXNativeTarget "SQLite tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 03A65E6B1C6BB0F60062603F /* Debug */, - 03A65E6C1C6BB0F60062603F /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 03A65E701C6BB0F60062603F /* Build configuration list for PBXNativeTarget "SQLiteTests tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 03A65E6D1C6BB0F60062603F /* Debug */, - 03A65E6E1C6BB0F60062603F /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - A121AC4C1CA35C79005A31D1 /* Build configuration list for PBXNativeTarget "SQLite watchOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - A121AC4A1CA35C79005A31D1 /* Debug */, - A121AC4B1CA35C79005A31D1 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - EE247ACD1C3F04ED00AE3E12 /* Build configuration list for PBXProject "SQLite" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - EE247AE51C3F04ED00AE3E12 /* Debug */, - EE247AE61C3F04ED00AE3E12 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - EE247AE71C3F04ED00AE3E12 /* Build configuration list for PBXNativeTarget "SQLite iOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - EE247AE81C3F04ED00AE3E12 /* Debug */, - EE247AE91C3F04ED00AE3E12 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - EE247AEA1C3F04ED00AE3E12 /* Build configuration list for PBXNativeTarget "SQLiteTests iOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - EE247AEB1C3F04ED00AE3E12 /* Debug */, - EE247AEC1C3F04ED00AE3E12 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - EE247B511C3F3ED000AE3E12 /* Build configuration list for PBXNativeTarget "SQLite Mac" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - EE247B4D1C3F3ED000AE3E12 /* Debug */, - EE247B4E1C3F3ED000AE3E12 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - EE247B521C3F3ED000AE3E12 /* Build configuration list for PBXNativeTarget "SQLiteTests Mac" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - EE247B4F1C3F3ED000AE3E12 /* Debug */, - EE247B501C3F3ED000AE3E12 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = EE247ACA1C3F04ED00AE3E12 /* Project object */; -} diff --git a/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite Mac.xcscheme b/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite Mac.xcscheme deleted file mode 100644 index 4e94e80..0000000 --- a/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite Mac.xcscheme +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite iOS.xcscheme b/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite iOS.xcscheme deleted file mode 100644 index f4ba423..0000000 --- a/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite iOS.xcscheme +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite tvOS.xcscheme b/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite tvOS.xcscheme deleted file mode 100644 index 7a3ddbf..0000000 --- a/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite tvOS.xcscheme +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite watchOS.xcscheme b/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite watchOS.xcscheme deleted file mode 100644 index ace0271..0000000 --- a/ios/libs/Sqlite/SQLite.xcodeproj/xcshareddata/xcschemes/SQLite watchOS.xcscheme +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ios/libs/Sqlite/SQLite.xcodeproj/xcuserdata/nikitasirotkin.xcuserdatad/xcschemes/xcschememanagement.plist b/ios/libs/Sqlite/SQLite.xcodeproj/xcuserdata/nikitasirotkin.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index eb2f43a..0000000 --- a/ios/libs/Sqlite/SQLite.xcodeproj/xcuserdata/nikitasirotkin.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,29 +0,0 @@ - - - - - SchemeUserState - - SQLite Mac.xcscheme_^#shared#^_ - - orderHint - 4 - - SQLite iOS.xcscheme_^#shared#^_ - - orderHint - 3 - - SQLite tvOS.xcscheme_^#shared#^_ - - orderHint - 5 - - SQLite watchOS.xcscheme_^#shared#^_ - - orderHint - 6 - - - - diff --git a/ios/libs/Sqlite/Sources/SQLite/Core/Blob.swift b/ios/libs/Sqlite/Sources/SQLite/Core/Blob.swift deleted file mode 100644 index 2f5d2a1..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Core/Blob.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -public struct Blob { - - public let bytes: [UInt8] - - public init(bytes: [UInt8]) { - self.bytes = bytes - } - - public init(bytes: UnsafeRawPointer, length: Int) { - let i8bufptr = UnsafeBufferPointer(start: bytes.assumingMemoryBound(to: UInt8.self), count: length) - self.init(bytes: [UInt8](i8bufptr)) - } - - public func toHex() -> String { - return bytes.map { - ($0 < 16 ? "0" : "") + String($0, radix: 16, uppercase: false) - }.joined(separator: "") - } - -} - -extension Blob : CustomStringConvertible { - - public var description: String { - return "x'\(toHex())'" - } - -} - -extension Blob : Equatable { - -} - -public func ==(lhs: Blob, rhs: Blob) -> Bool { - return lhs.bytes == rhs.bytes -} diff --git a/ios/libs/Sqlite/Sources/SQLite/Core/Connection.swift b/ios/libs/Sqlite/Sources/SQLite/Core/Connection.swift deleted file mode 100644 index 1bbf7f7..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Core/Connection.swift +++ /dev/null @@ -1,750 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -import Foundation -import Dispatch -#if SQLITE_SWIFT_STANDALONE -import sqlite3 -#elseif SQLITE_SWIFT_SQLCIPHER -import SQLCipher -#elseif os(Linux) -import CSQLite -#else -import SQLite3 -#endif - -/// A connection to SQLite. -public final class Connection { - - /// The location of a SQLite database. - public enum Location { - - /// An in-memory database (equivalent to `.uri(":memory:")`). - /// - /// See: - case inMemory - - /// A temporary, file-backed database (equivalent to `.uri("")`). - /// - /// See: - case temporary - - /// A database located at the given URI filename (or path). - /// - /// See: - /// - /// - Parameter filename: A URI filename - case uri(String) - } - - /// An SQL operation passed to update callbacks. - public enum Operation { - - /// An INSERT operation. - case insert - - /// An UPDATE operation. - case update - - /// A DELETE operation. - case delete - - fileprivate init(rawValue:Int32) { - switch rawValue { - case SQLITE_INSERT: - self = .insert - case SQLITE_UPDATE: - self = .update - case SQLITE_DELETE: - self = .delete - default: - fatalError("unhandled operation code: \(rawValue)") - } - } - } - - public var handle: OpaquePointer { return _handle! } - - fileprivate var _handle: OpaquePointer? = nil - - /// Initializes a new SQLite connection. - /// - /// - Parameters: - /// - /// - location: The location of the database. Creates a new database if it - /// doesn’t already exist (unless in read-only mode). - /// - /// Default: `.inMemory`. - /// - /// - readonly: Whether or not to open the database in a read-only state. - /// - /// Default: `false`. - /// - /// - Returns: A new database connection. - public init(_ location: Location = .inMemory, readonly: Bool = false) throws { - let flags = readonly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE - try check(sqlite3_open_v2(location.description, &_handle, flags | SQLITE_OPEN_FULLMUTEX, nil)) - queue.setSpecific(key: Connection.queueKey, value: queueContext) - } - - /// Initializes a new connection to a database. - /// - /// - Parameters: - /// - /// - filename: The location of the database. Creates a new database if - /// it doesn’t already exist (unless in read-only mode). - /// - /// - readonly: Whether or not to open the database in a read-only state. - /// - /// Default: `false`. - /// - /// - Throws: `Result.Error` iff a connection cannot be established. - /// - /// - Returns: A new database connection. - public convenience init(_ filename: String, readonly: Bool = false) throws { - try self.init(.uri(filename), readonly: readonly) - } - - deinit { - sqlite3_close(handle) - } - - // MARK: - - - /// Whether or not the database was opened in a read-only state. - public var readonly: Bool { return sqlite3_db_readonly(handle, nil) == 1 } - - /// The last rowid inserted into the database via this connection. - public var lastInsertRowid: Int64 { - return sqlite3_last_insert_rowid(handle) - } - - /// The last number of changes (inserts, updates, or deletes) made to the - /// database via this connection. - public var changes: Int { - return Int(sqlite3_changes(handle)) - } - - /// The total number of changes (inserts, updates, or deletes) made to the - /// database via this connection. - public var totalChanges: Int { - return Int(sqlite3_total_changes(handle)) - } - - // MARK: - Execute - - /// Executes a batch of SQL statements. - /// - /// - Parameter SQL: A batch of zero or more semicolon-separated SQL - /// statements. - /// - /// - Throws: `Result.Error` if query execution fails. - public func execute(_ SQL: String) throws { - _ = try sync { try self.check(sqlite3_exec(self.handle, SQL, nil, nil, nil)) } - } - - // MARK: - Prepare - - /// Prepares a single SQL statement (with optional parameter bindings). - /// - /// - Parameters: - /// - /// - statement: A single SQL statement. - /// - /// - bindings: A list of parameters to bind to the statement. - /// - /// - Returns: A prepared statement. - public func prepare(_ statement: String, _ bindings: Binding?...) throws -> Statement { - if !bindings.isEmpty { return try prepare(statement, bindings) } - return try Statement(self, statement) - } - - /// Prepares a single SQL statement and binds parameters to it. - /// - /// - Parameters: - /// - /// - statement: A single SQL statement. - /// - /// - bindings: A list of parameters to bind to the statement. - /// - /// - Returns: A prepared statement. - public func prepare(_ statement: String, _ bindings: [Binding?]) throws -> Statement { - return try prepare(statement).bind(bindings) - } - - /// Prepares a single SQL statement and binds parameters to it. - /// - /// - Parameters: - /// - /// - statement: A single SQL statement. - /// - /// - bindings: A dictionary of named parameters to bind to the statement. - /// - /// - Returns: A prepared statement. - public func prepare(_ statement: String, _ bindings: [String: Binding?]) throws -> Statement { - return try prepare(statement).bind(bindings) - } - - // MARK: - Run - - /// Runs a single SQL statement (with optional parameter bindings). - /// - /// - Parameters: - /// - /// - statement: A single SQL statement. - /// - /// - bindings: A list of parameters to bind to the statement. - /// - /// - Throws: `Result.Error` if query execution fails. - /// - /// - Returns: The statement. - @discardableResult public func run(_ statement: String, _ bindings: Binding?...) throws -> Statement { - return try run(statement, bindings) - } - - /// Prepares, binds, and runs a single SQL statement. - /// - /// - Parameters: - /// - /// - statement: A single SQL statement. - /// - /// - bindings: A list of parameters to bind to the statement. - /// - /// - Throws: `Result.Error` if query execution fails. - /// - /// - Returns: The statement. - @discardableResult public func run(_ statement: String, _ bindings: [Binding?]) throws -> Statement { - return try prepare(statement).run(bindings) - } - - /// Prepares, binds, and runs a single SQL statement. - /// - /// - Parameters: - /// - /// - statement: A single SQL statement. - /// - /// - bindings: A dictionary of named parameters to bind to the statement. - /// - /// - Throws: `Result.Error` if query execution fails. - /// - /// - Returns: The statement. - @discardableResult public func run(_ statement: String, _ bindings: [String: Binding?]) throws -> Statement { - return try prepare(statement).run(bindings) - } - - // MARK: - Scalar - - /// Runs a single SQL statement (with optional parameter bindings), - /// returning the first value of the first row. - /// - /// - Parameters: - /// - /// - statement: A single SQL statement. - /// - /// - bindings: A list of parameters to bind to the statement. - /// - /// - Returns: The first value of the first row returned. - public func scalar(_ statement: String, _ bindings: Binding?...) throws -> Binding? { - return try scalar(statement, bindings) - } - - /// Runs a single SQL statement (with optional parameter bindings), - /// returning the first value of the first row. - /// - /// - Parameters: - /// - /// - statement: A single SQL statement. - /// - /// - bindings: A list of parameters to bind to the statement. - /// - /// - Returns: The first value of the first row returned. - public func scalar(_ statement: String, _ bindings: [Binding?]) throws -> Binding? { - return try prepare(statement).scalar(bindings) - } - - /// Runs a single SQL statement (with optional parameter bindings), - /// returning the first value of the first row. - /// - /// - Parameters: - /// - /// - statement: A single SQL statement. - /// - /// - bindings: A dictionary of named parameters to bind to the statement. - /// - /// - Returns: The first value of the first row returned. - public func scalar(_ statement: String, _ bindings: [String: Binding?]) throws -> Binding? { - return try prepare(statement).scalar(bindings) - } - - // MARK: - Transactions - - /// The mode in which a transaction acquires a lock. - public enum TransactionMode : String { - - /// Defers locking the database till the first read/write executes. - case deferred = "DEFERRED" - - /// Immediately acquires a reserved lock on the database. - case immediate = "IMMEDIATE" - - /// Immediately acquires an exclusive lock on all databases. - case exclusive = "EXCLUSIVE" - - } - - // TODO: Consider not requiring a throw to roll back? - /// Runs a transaction with the given mode. - /// - /// - Note: Transactions cannot be nested. To nest transactions, see - /// `savepoint()`, instead. - /// - /// - Parameters: - /// - /// - mode: The mode in which a transaction acquires a lock. - /// - /// Default: `.deferred` - /// - /// - block: A closure to run SQL statements within the transaction. - /// The transaction will be committed when the block returns. The block - /// must throw to roll the transaction back. - /// - /// - Throws: `Result.Error`, and rethrows. - public func transaction(_ mode: TransactionMode = .deferred, block: () throws -> Void) throws { - try transaction("BEGIN \(mode.rawValue) TRANSACTION", block, "COMMIT TRANSACTION", or: "ROLLBACK TRANSACTION") - } - - // TODO: Consider not requiring a throw to roll back? - // TODO: Consider removing ability to set a name? - /// Runs a transaction with the given savepoint name (if omitted, it will - /// generate a UUID). - /// - /// - SeeAlso: `transaction()`. - /// - /// - Parameters: - /// - /// - savepointName: A unique identifier for the savepoint (optional). - /// - /// - block: A closure to run SQL statements within the transaction. - /// The savepoint will be released (committed) when the block returns. - /// The block must throw to roll the savepoint back. - /// - /// - Throws: `SQLite.Result.Error`, and rethrows. - public func savepoint(_ name: String = UUID().uuidString, block: () throws -> Void) throws { - let name = name.quote("'") - let savepoint = "SAVEPOINT \(name)" - - try transaction(savepoint, block, "RELEASE \(savepoint)", or: "ROLLBACK TO \(savepoint)") - } - - fileprivate func transaction(_ begin: String, _ block: () throws -> Void, _ commit: String, or rollback: String) throws { - return try sync { - try self.run(begin) - do { - try block() - try self.run(commit) - } catch { - try self.run(rollback) - throw error - } - } - } - - /// Interrupts any long-running queries. - public func interrupt() { - sqlite3_interrupt(handle) - } - - // MARK: - Handlers - - /// The number of seconds a connection will attempt to retry a statement - /// after encountering a busy signal (lock). - public var busyTimeout: Double = 0 { - didSet { - sqlite3_busy_timeout(handle, Int32(busyTimeout * 1_000)) - } - } - - /// Sets a handler to call after encountering a busy signal (lock). - /// - /// - Parameter callback: This block is executed during a lock in which a - /// busy error would otherwise be returned. It’s passed the number of - /// times it’s been called for this lock. If it returns `true`, it will - /// try again. If it returns `false`, no further attempts will be made. - public func busyHandler(_ callback: ((_ tries: Int) -> Bool)?) { - guard let callback = callback else { - sqlite3_busy_handler(handle, nil, nil) - busyHandler = nil - return - } - - let box: BusyHandler = { callback(Int($0)) ? 1 : 0 } - sqlite3_busy_handler(handle, { callback, tries in - unsafeBitCast(callback, to: BusyHandler.self)(tries) - }, unsafeBitCast(box, to: UnsafeMutableRawPointer.self)) - busyHandler = box - } - fileprivate typealias BusyHandler = @convention(block) (Int32) -> Int32 - fileprivate var busyHandler: BusyHandler? - - /// Sets a handler to call when a statement is executed with the compiled - /// SQL. - /// - /// - Parameter callback: This block is invoked when a statement is executed - /// with the compiled SQL as its argument. - /// - /// db.trace { SQL in print(SQL) } - public func trace(_ callback: ((String) -> Void)?) { - #if SQLITE_SWIFT_SQLCIPHER || os(Linux) - trace_v1(callback) - #else - if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) { - trace_v2(callback) - } else { - trace_v1(callback) - } - #endif - } - - fileprivate func trace_v1(_ callback: ((String) -> Void)?) { - guard let callback = callback else { - sqlite3_trace(handle, nil /* xCallback */, nil /* pCtx */) - trace = nil - return - } - let box: Trace = { (pointer: UnsafeRawPointer) in - callback(String(cString: pointer.assumingMemoryBound(to: UInt8.self))) - } - sqlite3_trace(handle, - { - (C: UnsafeMutableRawPointer?, SQL: UnsafePointer?) in - if let C = C, let SQL = SQL { - unsafeBitCast(C, to: Trace.self)(SQL) - } - }, - unsafeBitCast(box, to: UnsafeMutableRawPointer.self) - ) - trace = box - } - - - - - fileprivate typealias Trace = @convention(block) (UnsafeRawPointer) -> Void - fileprivate var trace: Trace? - - /// Registers a callback to be invoked whenever a row is inserted, updated, - /// or deleted in a rowid table. - /// - /// - Parameter callback: A callback invoked with the `Operation` (one of - /// `.Insert`, `.Update`, or `.Delete`), database name, table name, and - /// rowid. - public func updateHook(_ callback: ((_ operation: Operation, _ db: String, _ table: String, _ rowid: Int64) -> Void)?) { - guard let callback = callback else { - sqlite3_update_hook(handle, nil, nil) - updateHook = nil - return - } - - let box: UpdateHook = { - callback( - Operation(rawValue: $0), - String(cString: $1), - String(cString: $2), - $3 - ) - } - sqlite3_update_hook(handle, { callback, operation, db, table, rowid in - unsafeBitCast(callback, to: UpdateHook.self)(operation, db!, table!, rowid) - }, unsafeBitCast(box, to: UnsafeMutableRawPointer.self)) - updateHook = box - } - fileprivate typealias UpdateHook = @convention(block) (Int32, UnsafePointer, UnsafePointer, Int64) -> Void - fileprivate var updateHook: UpdateHook? - - /// Registers a callback to be invoked whenever a transaction is committed. - /// - /// - Parameter callback: A callback invoked whenever a transaction is - /// committed. If this callback throws, the transaction will be rolled - /// back. - public func commitHook(_ callback: (() throws -> Void)?) { - guard let callback = callback else { - sqlite3_commit_hook(handle, nil, nil) - commitHook = nil - return - } - - let box: CommitHook = { - do { - try callback() - } catch { - return 1 - } - return 0 - } - sqlite3_commit_hook(handle, { callback in - unsafeBitCast(callback, to: CommitHook.self)() - }, unsafeBitCast(box, to: UnsafeMutableRawPointer.self)) - commitHook = box - } - fileprivate typealias CommitHook = @convention(block) () -> Int32 - fileprivate var commitHook: CommitHook? - - /// Registers a callback to be invoked whenever a transaction rolls back. - /// - /// - Parameter callback: A callback invoked when a transaction is rolled - /// back. - public func rollbackHook(_ callback: (() -> Void)?) { - guard let callback = callback else { - sqlite3_rollback_hook(handle, nil, nil) - rollbackHook = nil - return - } - - let box: RollbackHook = { callback() } - sqlite3_rollback_hook(handle, { callback in - unsafeBitCast(callback, to: RollbackHook.self)() - }, unsafeBitCast(box, to: UnsafeMutableRawPointer.self)) - rollbackHook = box - } - fileprivate typealias RollbackHook = @convention(block) () -> Void - fileprivate var rollbackHook: RollbackHook? - - /// Creates or redefines a custom SQL function. - /// - /// - Parameters: - /// - /// - function: The name of the function to create or redefine. - /// - /// - argumentCount: The number of arguments that the function takes. If - /// `nil`, the function may take any number of arguments. - /// - /// Default: `nil` - /// - /// - deterministic: Whether or not the function is deterministic (_i.e._ - /// the function always returns the same result for a given input). - /// - /// Default: `false` - /// - /// - block: A block of code to run when the function is called. The block - /// is called with an array of raw SQL values mapped to the function’s - /// parameters and should return a raw SQL value (or nil). - public func createFunction(_ function: String, argumentCount: UInt? = nil, deterministic: Bool = false, _ block: @escaping (_ args: [Binding?]) -> Binding?) { - let argc = argumentCount.map { Int($0) } ?? -1 - let box: Function = { context, argc, argv in - let arguments: [Binding?] = (0..?) -> Void - fileprivate var functions = [String: [Int: Function]]() - - /// Defines a new collating sequence. - /// - /// - Parameters: - /// - /// - collation: The name of the collation added. - /// - /// - block: A collation function that takes two strings and returns the - /// comparison result. - public func createCollation(_ collation: String, _ block: @escaping (_ lhs: String, _ rhs: String) -> ComparisonResult) throws { - let box: Collation = { (lhs: UnsafeRawPointer, rhs: UnsafeRawPointer) in - let lstr = String(cString: lhs.assumingMemoryBound(to: UInt8.self)) - let rstr = String(cString: rhs.assumingMemoryBound(to: UInt8.self)) - return Int32(block(lstr, rstr).rawValue) - } - try check(sqlite3_create_collation_v2(handle, collation, SQLITE_UTF8, - unsafeBitCast(box, to: UnsafeMutableRawPointer.self), - { (callback: UnsafeMutableRawPointer?, _, lhs: UnsafeRawPointer?, _, rhs: UnsafeRawPointer?) in /* xCompare */ - if let lhs = lhs, let rhs = rhs { - return unsafeBitCast(callback, to: Collation.self)(lhs, rhs) - } else { - fatalError("sqlite3_create_collation_v2 callback called with NULL pointer") - } - }, nil /* xDestroy */)) - collations[collation] = box - } - fileprivate typealias Collation = @convention(block) (UnsafeRawPointer, UnsafeRawPointer) -> Int32 - fileprivate var collations = [String: Collation]() - - // MARK: - Error Handling - - func sync(_ block: () throws -> T) rethrows -> T { - if DispatchQueue.getSpecific(key: Connection.queueKey) == queueContext { - return try block() - } else { - return try queue.sync(execute: block) - } - } - - @discardableResult func check(_ resultCode: Int32, statement: Statement? = nil) throws -> Int32 { - guard let error = Result(errorCode: resultCode, connection: self, statement: statement) else { - return resultCode - } - - throw error - } - - fileprivate var queue = DispatchQueue(label: "SQLite.Database", attributes: []) - - fileprivate static let queueKey = DispatchSpecificKey() - - fileprivate lazy var queueContext: Int = unsafeBitCast(self, to: Int.self) - -} - -extension Connection : CustomStringConvertible { - - public var description: String { - return String(cString: sqlite3_db_filename(handle, nil)) - } - -} - -extension Connection.Location : CustomStringConvertible { - - public var description: String { - switch self { - case .inMemory: - return ":memory:" - case .temporary: - return "" - case .uri(let URI): - return URI - } - } - -} - -public enum Result : Error { - - fileprivate static let successCodes: Set = [SQLITE_OK, SQLITE_ROW, SQLITE_DONE] - - /// Represents a SQLite specific [error code](https://sqlite.org/rescode.html) - /// - /// - message: English-language text that describes the error - /// - /// - code: SQLite [error code](https://sqlite.org/rescode.html#primary_result_code_list) - /// - /// - statement: the statement which produced the error - case error(message: String, code: Int32, statement: Statement?) - - init?(errorCode: Int32, connection: Connection, statement: Statement? = nil) { - guard !Result.successCodes.contains(errorCode) else { return nil } - - let message = String(cString: sqlite3_errmsg(connection.handle)) - self = .error(message: message, code: errorCode, statement: statement) - } - -} - -extension Result : CustomStringConvertible { - - public var description: String { - switch self { - case let .error(message, errorCode, statement): - if let statement = statement { - return "\(message) (\(statement)) (code: \(errorCode))" - } else { - return "\(message) (code: \(errorCode))" - } - } - } -} - -#if !SQLITE_SWIFT_SQLCIPHER && !os(Linux) -@available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) -extension Connection { - fileprivate func trace_v2(_ callback: ((String) -> Void)?) { - guard let callback = callback else { - // If the X callback is NULL or if the M mask is zero, then tracing is disabled. - sqlite3_trace_v2(handle, 0 /* mask */, nil /* xCallback */, nil /* pCtx */) - trace = nil - return - } - - let box: Trace = { (pointer: UnsafeRawPointer) in - callback(String(cString: pointer.assumingMemoryBound(to: UInt8.self))) - } - sqlite3_trace_v2(handle, - UInt32(SQLITE_TRACE_STMT) /* mask */, - { - // A trace callback is invoked with four arguments: callback(T,C,P,X). - // The T argument is one of the SQLITE_TRACE constants to indicate why the - // callback was invoked. The C argument is a copy of the context pointer. - // The P and X arguments are pointers whose meanings depend on T. - (T: UInt32, C: UnsafeMutableRawPointer?, P: UnsafeMutableRawPointer?, X: UnsafeMutableRawPointer?) in - if let P = P, - let expandedSQL = sqlite3_expanded_sql(OpaquePointer(P)) { - unsafeBitCast(C, to: Trace.self)(expandedSQL) - sqlite3_free(expandedSQL) - } - return Int32(0) // currently ignored - }, - unsafeBitCast(box, to: UnsafeMutableRawPointer.self) /* pCtx */ - ) - trace = box - } -} -#endif diff --git a/ios/libs/Sqlite/Sources/SQLite/Core/Errors.swift b/ios/libs/Sqlite/Sources/SQLite/Core/Errors.swift deleted file mode 100644 index 3cd7ae9..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Core/Errors.swift +++ /dev/null @@ -1,21 +0,0 @@ -import Foundation - -public enum QueryError: Error, CustomStringConvertible { - case noSuchTable(name: String) - case noSuchColumn(name: String, columns: [String]) - case ambiguousColumn(name: String, similar: [String]) - case unexpectedNullValue(name: String) - - public var description: String { - switch self { - case .noSuchTable(let name): - return "No such table: \(name)" - case .noSuchColumn(let name, let columns): - return "No such column `\(name)` in columns \(columns)" - case .ambiguousColumn(let name, let similar): - return "Ambiguous column `\(name)` (please disambiguate: \(similar))" - case .unexpectedNullValue(let name): - return "Unexpected null value for column `\(name)`" - } - } -} diff --git a/ios/libs/Sqlite/Sources/SQLite/Core/Statement.swift b/ios/libs/Sqlite/Sources/SQLite/Core/Statement.swift deleted file mode 100644 index dc91d3d..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Core/Statement.swift +++ /dev/null @@ -1,317 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -#if SQLITE_SWIFT_STANDALONE -import sqlite3 -#elseif SQLITE_SWIFT_SQLCIPHER -import SQLCipher -#elseif os(Linux) -import CSQLite -#else -import SQLite3 -#endif - -/// A single SQL statement. -public final class Statement { - - fileprivate var handle: OpaquePointer? = nil - - fileprivate let connection: Connection - - init(_ connection: Connection, _ SQL: String) throws { - self.connection = connection - try connection.check(sqlite3_prepare_v2(connection.handle, SQL, -1, &handle, nil)) - } - - deinit { - sqlite3_finalize(handle) - } - - public lazy var columnCount: Int = Int(sqlite3_column_count(self.handle)) - - public lazy var columnNames: [String] = (0.. Statement { - return bind(values) - } - - /// Binds a list of parameters to a statement. - /// - /// - Parameter values: A list of parameters to bind to the statement. - /// - /// - Returns: The statement object (useful for chaining). - public func bind(_ values: [Binding?]) -> Statement { - if values.isEmpty { return self } - reset() - guard values.count == Int(sqlite3_bind_parameter_count(handle)) else { - fatalError("\(sqlite3_bind_parameter_count(handle)) values expected, \(values.count) passed") - } - for idx in 1...values.count { bind(values[idx - 1], atIndex: idx) } - return self - } - - /// Binds a dictionary of named parameters to a statement. - /// - /// - Parameter values: A dictionary of named parameters to bind to the - /// statement. - /// - /// - Returns: The statement object (useful for chaining). - public func bind(_ values: [String: Binding?]) -> Statement { - reset() - for (name, value) in values { - let idx = sqlite3_bind_parameter_index(handle, name) - guard idx > 0 else { - fatalError("parameter not found: \(name)") - } - bind(value, atIndex: Int(idx)) - } - return self - } - - fileprivate func bind(_ value: Binding?, atIndex idx: Int) { - if value == nil { - sqlite3_bind_null(handle, Int32(idx)) - } else if let value = value as? Blob { - sqlite3_bind_blob(handle, Int32(idx), value.bytes, Int32(value.bytes.count), SQLITE_TRANSIENT) - } else if let value = value as? Double { - sqlite3_bind_double(handle, Int32(idx), value) - } else if let value = value as? Int64 { - sqlite3_bind_int64(handle, Int32(idx), value) - } else if let value = value as? String { - sqlite3_bind_text(handle, Int32(idx), value, -1, SQLITE_TRANSIENT) - } else if let value = value as? Int { - self.bind(value.datatypeValue, atIndex: idx) - } else if let value = value as? Bool { - self.bind(value.datatypeValue, atIndex: idx) - } else if let value = value { - fatalError("tried to bind unexpected value \(value)") - } - } - - /// - Parameter bindings: A list of parameters to bind to the statement. - /// - /// - Throws: `Result.Error` if query execution fails. - /// - /// - Returns: The statement object (useful for chaining). - @discardableResult public func run(_ bindings: Binding?...) throws -> Statement { - guard bindings.isEmpty else { - return try run(bindings) - } - - reset(clearBindings: false) - repeat {} while try step() - return self - } - - /// - Parameter bindings: A list of parameters to bind to the statement. - /// - /// - Throws: `Result.Error` if query execution fails. - /// - /// - Returns: The statement object (useful for chaining). - @discardableResult public func run(_ bindings: [Binding?]) throws -> Statement { - return try bind(bindings).run() - } - - /// - Parameter bindings: A dictionary of named parameters to bind to the - /// statement. - /// - /// - Throws: `Result.Error` if query execution fails. - /// - /// - Returns: The statement object (useful for chaining). - @discardableResult public func run(_ bindings: [String: Binding?]) throws -> Statement { - return try bind(bindings).run() - } - - /// - Parameter bindings: A list of parameters to bind to the statement. - /// - /// - Returns: The first value of the first row returned. - public func scalar(_ bindings: Binding?...) throws -> Binding? { - guard bindings.isEmpty else { - return try scalar(bindings) - } - - reset(clearBindings: false) - _ = try step() - return row[0] - } - - /// - Parameter bindings: A list of parameters to bind to the statement. - /// - /// - Returns: The first value of the first row returned. - public func scalar(_ bindings: [Binding?]) throws -> Binding? { - return try bind(bindings).scalar() - } - - - /// - Parameter bindings: A dictionary of named parameters to bind to the - /// statement. - /// - /// - Returns: The first value of the first row returned. - public func scalar(_ bindings: [String: Binding?]) throws -> Binding? { - return try bind(bindings).scalar() - } - - public func step() throws -> Bool { - return try connection.sync { try self.connection.check(sqlite3_step(self.handle)) == SQLITE_ROW } - } - - fileprivate func reset(clearBindings shouldClear: Bool = true) { - sqlite3_reset(handle) - if (shouldClear) { sqlite3_clear_bindings(handle) } - } - -} - -extension Statement : Sequence { - - public func makeIterator() -> Statement { - reset(clearBindings: false) - return self - } - -} - -public protocol FailableIterator : IteratorProtocol { - func failableNext() throws -> Self.Element? -} - -extension FailableIterator { - public func next() -> Element? { - return try! failableNext() - } -} - -extension Array { - public init(_ failableIterator: I) throws where I.Element == Element { - self.init() - while let row = try failableIterator.failableNext() { - append(row) - } - } -} - -extension Statement : FailableIterator { - public typealias Element = [Binding?] - public func failableNext() throws -> [Binding?]? { - return try step() ? Array(row) : nil - } -} - -extension Statement : CustomStringConvertible { - - public var description: String { - return String(cString: sqlite3_sql(handle)) - } - -} - -public struct Cursor { - - fileprivate let handle: OpaquePointer - - fileprivate let columnCount: Int - - fileprivate init(_ statement: Statement) { - handle = statement.handle! - columnCount = statement.columnCount - } - - public subscript(idx: Int) -> Double { - return sqlite3_column_double(handle, Int32(idx)) - } - - public subscript(idx: Int) -> Int64 { - return sqlite3_column_int64(handle, Int32(idx)) - } - - public subscript(idx: Int) -> String { - return String(cString: UnsafePointer(sqlite3_column_text(handle, Int32(idx)))) - } - - public subscript(idx: Int) -> Blob { - if let pointer = sqlite3_column_blob(handle, Int32(idx)) { - let length = Int(sqlite3_column_bytes(handle, Int32(idx))) - return Blob(bytes: pointer, length: length) - } else { - // The return value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer. - // https://www.sqlite.org/c3ref/column_blob.html - return Blob(bytes: []) - } - } - - // MARK: - - - public subscript(idx: Int) -> Bool { - return Bool.fromDatatypeValue(self[idx]) - } - - public subscript(idx: Int) -> Int { - return Int.fromDatatypeValue(self[idx]) - } - -} - -/// Cursors provide direct access to a statement’s current row. -extension Cursor : Sequence { - - public subscript(idx: Int) -> Binding? { - switch sqlite3_column_type(handle, Int32(idx)) { - case SQLITE_BLOB: - return self[idx] as Blob - case SQLITE_FLOAT: - return self[idx] as Double - case SQLITE_INTEGER: - return self[idx] as Int64 - case SQLITE_NULL: - return nil - case SQLITE_TEXT: - return self[idx] as String - case let type: - fatalError("unsupported column type: \(type)") - } - } - - public func makeIterator() -> AnyIterator { - var idx = 0 - return AnyIterator { - if idx >= self.columnCount { - return Optional.none - } else { - idx += 1 - return self[idx - 1] - } - } - } - -} diff --git a/ios/libs/Sqlite/Sources/SQLite/Core/Value.swift b/ios/libs/Sqlite/Sources/SQLite/Core/Value.swift deleted file mode 100644 index 608f0ce..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Core/Value.swift +++ /dev/null @@ -1,132 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -/// - Warning: `Binding` is a protocol that SQLite.swift uses internally to -/// directly map SQLite types to Swift types. -/// -/// Do not conform custom types to the Binding protocol. See the `Value` -/// protocol, instead. -public protocol Binding {} - -public protocol Number : Binding {} - -public protocol Value : Expressible { // extensions cannot have inheritance clauses - - associatedtype ValueType = Self - - associatedtype Datatype : Binding - - static var declaredDatatype: String { get } - - static func fromDatatypeValue(_ datatypeValue: Datatype) -> ValueType - - var datatypeValue: Datatype { get } - -} - -extension Double : Number, Value { - - public static let declaredDatatype = "REAL" - - public static func fromDatatypeValue(_ datatypeValue: Double) -> Double { - return datatypeValue - } - - public var datatypeValue: Double { - return self - } - -} - -extension Int64 : Number, Value { - - public static let declaredDatatype = "INTEGER" - - public static func fromDatatypeValue(_ datatypeValue: Int64) -> Int64 { - return datatypeValue - } - - public var datatypeValue: Int64 { - return self - } - -} - -extension String : Binding, Value { - - public static let declaredDatatype = "TEXT" - - public static func fromDatatypeValue(_ datatypeValue: String) -> String { - return datatypeValue - } - - public var datatypeValue: String { - return self - } - -} - -extension Blob : Binding, Value { - - public static let declaredDatatype = "BLOB" - - public static func fromDatatypeValue(_ datatypeValue: Blob) -> Blob { - return datatypeValue - } - - public var datatypeValue: Blob { - return self - } - -} - -// MARK: - - -extension Bool : Binding, Value { - - public static var declaredDatatype = Int64.declaredDatatype - - public static func fromDatatypeValue(_ datatypeValue: Int64) -> Bool { - return datatypeValue != 0 - } - - public var datatypeValue: Int64 { - return self ? 1 : 0 - } - -} - -extension Int : Number, Value { - - public static var declaredDatatype = Int64.declaredDatatype - - public static func fromDatatypeValue(_ datatypeValue: Int64) -> Int { - return Int(datatypeValue) - } - - public var datatypeValue: Int64 { - return Int64(self) - } - -} diff --git a/ios/libs/Sqlite/Sources/SQLite/Extensions/Cipher.swift b/ios/libs/Sqlite/Sources/SQLite/Extensions/Cipher.swift deleted file mode 100644 index 44919aa..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Extensions/Cipher.swift +++ /dev/null @@ -1,66 +0,0 @@ -#if SQLITE_SWIFT_SQLCIPHER -import SQLCipher - - -/// Extension methods for [SQLCipher](https://www.zetetic.net/sqlcipher/). -/// @see [sqlcipher api](https://www.zetetic.net/sqlcipher/sqlcipher-api/) -extension Connection { - - /// - Returns: the SQLCipher version - public var cipherVersion: String? { - return (try? scalar("PRAGMA cipher_version")) as? String - } - - /// Specify the key for an encrypted database. This routine should be - /// called right after sqlite3_open(). - /// - /// @param key The key to use.The key itself can be a passphrase, which is converted to a key - /// using [PBKDF2](https://en.wikipedia.org/wiki/PBKDF2) key derivation. The result - /// is used as the encryption key for the database. - /// - /// Alternatively, it is possible to specify an exact byte sequence using a blob literal. - /// With this method, it is the calling application's responsibility to ensure that the data - /// provided is a 64 character hex string, which will be converted directly to 32 bytes (256 bits) - /// of key data. - /// e.g. x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99' - /// @param db name of the database, defaults to 'main' - public func key(_ key: String, db: String = "main") throws { - try _key_v2(db: db, keyPointer: key, keySize: key.utf8.count) - } - - public func key(_ key: Blob, db: String = "main") throws { - try _key_v2(db: db, keyPointer: key.bytes, keySize: key.bytes.count) - } - - - /// Change the key on an open database. If the current database is not encrypted, this routine - /// will encrypt it. - /// To change the key on an existing encrypted database, it must first be unlocked with the - /// current encryption key. Once the database is readable and writeable, rekey can be used - /// to re-encrypt every page in the database with a new key. - public func rekey(_ key: String, db: String = "main") throws { - try _rekey_v2(db: db, keyPointer: key, keySize: key.utf8.count) - } - - public func rekey(_ key: Blob, db: String = "main") throws { - try _rekey_v2(db: db, keyPointer: key.bytes, keySize: key.bytes.count) - } - - // MARK: - private - private func _key_v2(db: String, keyPointer: UnsafePointer, keySize: Int) throws { - try check(sqlite3_key_v2(handle, db, keyPointer, Int32(keySize))) - try cipher_key_check() - } - - private func _rekey_v2(db: String, keyPointer: UnsafePointer, keySize: Int) throws { - try check(sqlite3_rekey_v2(handle, db, keyPointer, Int32(keySize))) - } - - // When opening an existing database, sqlite3_key_v2 will not immediately throw an error if - // the key provided is incorrect. To test that the database can be successfully opened with the - // provided key, it is necessary to perform some operation on the database (i.e. read from it). - private func cipher_key_check() throws { - let _ = try scalar("SELECT count(*) FROM sqlite_master;") - } -} -#endif diff --git a/ios/libs/Sqlite/Sources/SQLite/Extensions/FTS4.swift b/ios/libs/Sqlite/Sources/SQLite/Extensions/FTS4.swift deleted file mode 100644 index 5ef84dd..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Extensions/FTS4.swift +++ /dev/null @@ -1,352 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -#if SWIFT_PACKAGE -import SQLiteObjc -#endif - -extension Module { - - public static func FTS4(_ column: Expressible, _ more: Expressible...) -> Module { - return FTS4([column] + more) - } - - public static func FTS4(_ columns: [Expressible] = [], tokenize tokenizer: Tokenizer? = nil) -> Module { - return FTS4(FTS4Config().columns(columns).tokenizer(tokenizer)) - } - - public static func FTS4(_ config: FTS4Config) -> Module { - return Module(name: "fts4", arguments: config.arguments()) - } -} - -extension VirtualTable { - - /// Builds an expression appended with a `MATCH` query against the given - /// pattern. - /// - /// let emails = VirtualTable("emails") - /// - /// emails.filter(emails.match("Hello")) - /// // SELECT * FROM "emails" WHERE "emails" MATCH 'Hello' - /// - /// - Parameter pattern: A pattern to match. - /// - /// - Returns: An expression appended with a `MATCH` query against the given - /// pattern. - public func match(_ pattern: String) -> Expression { - return "MATCH".infix(tableName(), pattern) - } - - public func match(_ pattern: Expression) -> Expression { - return "MATCH".infix(tableName(), pattern) - } - - public func match(_ pattern: Expression) -> Expression { - return "MATCH".infix(tableName(), pattern) - } - - /// Builds a copy of the query with a `WHERE … MATCH` clause. - /// - /// let emails = VirtualTable("emails") - /// - /// emails.match("Hello") - /// // SELECT * FROM "emails" WHERE "emails" MATCH 'Hello' - /// - /// - Parameter pattern: A pattern to match. - /// - /// - Returns: A query with the given `WHERE … MATCH` clause applied. - public func match(_ pattern: String) -> QueryType { - return filter(match(pattern)) - } - - public func match(_ pattern: Expression) -> QueryType { - return filter(match(pattern)) - } - - public func match(_ pattern: Expression) -> QueryType { - return filter(match(pattern)) - } - -} - -public struct Tokenizer { - - public static let Simple = Tokenizer("simple") - - public static let Porter = Tokenizer("porter") - - public static func Unicode61(removeDiacritics: Bool? = nil, tokenchars: Set = [], separators: Set = []) -> Tokenizer { - var arguments = [String]() - - if let removeDiacritics = removeDiacritics { - arguments.append("removeDiacritics=\(removeDiacritics ? 1 : 0)".quote()) - } - - if !tokenchars.isEmpty { - let joined = tokenchars.map { String($0) }.joined(separator: "") - arguments.append("tokenchars=\(joined)".quote()) - } - - if !separators.isEmpty { - let joined = separators.map { String($0) }.joined(separator: "") - arguments.append("separators=\(joined)".quote()) - } - - return Tokenizer("unicode61", arguments) - } - - public static func Custom(_ name: String) -> Tokenizer { - return Tokenizer(Tokenizer.moduleName.quote(), [name.quote()]) - } - - public let name: String - - public let arguments: [String] - - fileprivate init(_ name: String, _ arguments: [String] = []) { - self.name = name - self.arguments = arguments - } - - fileprivate static let moduleName = "SQLite.swift" - -} - -extension Tokenizer : CustomStringConvertible { - - public var description: String { - return ([name] + arguments).joined(separator: " ") - } - -} - -extension Connection { - - public func registerTokenizer(_ submoduleName: String, next: @escaping (String) -> (String, Range)?) throws { - try check(_SQLiteRegisterTokenizer(handle, Tokenizer.moduleName, submoduleName) { ( - input: UnsafePointer, offset: UnsafeMutablePointer, length: UnsafeMutablePointer) in - let string = String(cString: input) - - guard let (token, range) = next(string) else { return nil } - - let view:String.UTF8View = string.utf8 - - if let from = range.lowerBound.samePosition(in: view), - let to = range.upperBound.samePosition(in: view) { - offset.pointee += Int32(string[string.startIndex.. Self { - self.columnDefinitions.append((column, options)) - return self - } - - @discardableResult open func columns(_ columns: [Expressible]) -> Self { - for column in columns { - self.column(column) - } - return self - } - - /// [Tokenizers](https://www.sqlite.org/fts3.html#tokenizer) - open func tokenizer(_ tokenizer: Tokenizer?) -> Self { - self.tokenizer = tokenizer - return self - } - - /// [The prefix= option](https://www.sqlite.org/fts3.html#section_6_6) - open func prefix(_ prefix: [Int]) -> Self { - self.prefixes += prefix - return self - } - - /// [The content= option](https://www.sqlite.org/fts3.html#section_6_2) - open func externalContent(_ schema: SchemaType) -> Self { - self.externalContentSchema = schema - return self - } - - /// [Contentless FTS4 Tables](https://www.sqlite.org/fts3.html#section_6_2_1) - open func contentless() -> Self { - self.isContentless = true - return self - } - - func formatColumnDefinitions() -> [Expressible] { - return columnDefinitions.map { $0.0 } - } - - func arguments() -> [Expressible] { - return options().arguments - } - - func options() -> Options { - var options = Options() - options.append(formatColumnDefinitions()) - if let tokenizer = tokenizer { - options.append("tokenize", value: Expression(literal: tokenizer.description)) - } - options.appendCommaSeparated("prefix", values:prefixes.sorted().map { String($0) }) - if isContentless { - options.append("content", value: "") - } else if let externalContentSchema = externalContentSchema { - options.append("content", value: externalContentSchema.tableName()) - } - return options - } - - struct Options { - var arguments = [Expressible]() - - @discardableResult mutating func append(_ columns: [Expressible]) -> Options { - arguments.append(contentsOf: columns) - return self - } - - @discardableResult mutating func appendCommaSeparated(_ key: String, values: [String]) -> Options { - if values.isEmpty { - return self - } else { - return append(key, value: values.joined(separator: ",")) - } - } - - @discardableResult mutating func append(_ key: String, value: CustomStringConvertible?) -> Options { - return append(key, value: value?.description) - } - - @discardableResult mutating func append(_ key: String, value: String?) -> Options { - return append(key, value: value.map { Expression($0) }) - } - - @discardableResult mutating func append(_ key: String, value: Expressible?) -> Options { - if let value = value { - arguments.append("=".join([Expression(literal: key), value])) - } - return self - } - } -} - -/// Configuration for the [FTS4](https://www.sqlite.org/fts3.html) extension. -open class FTS4Config : FTSConfig { - /// [The matchinfo= option](https://www.sqlite.org/fts3.html#section_6_4) - public enum MatchInfo : CustomStringConvertible { - case fts3 - public var description: String { - return "fts3" - } - } - - /// [FTS4 options](https://www.sqlite.org/fts3.html#fts4_options) - public enum Order : CustomStringConvertible { - /// Data structures are optimized for returning results in ascending order by docid (default) - case asc - /// FTS4 stores its data in such a way as to optimize returning results in descending order by docid. - case desc - - public var description: String { - switch self { - case .asc: return "asc" - case .desc: return "desc" - } - } - } - - var compressFunction: String? - var uncompressFunction: String? - var languageId: String? - var matchInfo: MatchInfo? - var order: Order? - - override public init() { - } - - /// [The compress= and uncompress= options](https://www.sqlite.org/fts3.html#section_6_1) - open func compress(_ functionName: String) -> Self { - self.compressFunction = functionName - return self - } - - /// [The compress= and uncompress= options](https://www.sqlite.org/fts3.html#section_6_1) - open func uncompress(_ functionName: String) -> Self { - self.uncompressFunction = functionName - return self - } - - /// [The languageid= option](https://www.sqlite.org/fts3.html#section_6_3) - open func languageId(_ columnName: String) -> Self { - self.languageId = columnName - return self - } - - /// [The matchinfo= option](https://www.sqlite.org/fts3.html#section_6_4) - open func matchInfo(_ matchInfo: MatchInfo) -> Self { - self.matchInfo = matchInfo - return self - } - - /// [FTS4 options](https://www.sqlite.org/fts3.html#fts4_options) - open func order(_ order: Order) -> Self { - self.order = order - return self - } - - override func options() -> Options { - var options = super.options() - for (column, _) in (columnDefinitions.filter { $0.options.contains(.unindexed) }) { - options.append("notindexed", value: column) - } - options.append("languageid", value: languageId) - options.append("compress", value: compressFunction) - options.append("uncompress", value: uncompressFunction) - options.append("matchinfo", value: matchInfo) - options.append("order", value: order) - return options - } -} diff --git a/ios/libs/Sqlite/Sources/SQLite/Extensions/FTS5.swift b/ios/libs/Sqlite/Sources/SQLite/Extensions/FTS5.swift deleted file mode 100644 index 763927f..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Extensions/FTS5.swift +++ /dev/null @@ -1,97 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -extension Module { - public static func FTS5(_ config: FTS5Config) -> Module { - return Module(name: "fts5", arguments: config.arguments()) - } -} - -/// Configuration for the [FTS5](https://www.sqlite.org/fts5.html) extension. -/// -/// **Note:** this is currently only applicable when using SQLite.swift together with a FTS5-enabled version -/// of SQLite. -open class FTS5Config : FTSConfig { - public enum Detail : CustomStringConvertible { - /// store rowid, column number, term offset - case full - /// store rowid, column number - case column - /// store rowid - case none - - public var description: String { - switch self { - case .full: return "full" - case .column: return "column" - case .none: return "none" - } - } - } - - var detail: Detail? - var contentRowId: Expressible? - var columnSize: Int? - - override public init() { - } - - /// [External Content Tables](https://www.sqlite.org/fts5.html#section_4_4_2) - open func contentRowId(_ column: Expressible) -> Self { - self.contentRowId = column - return self - } - - /// [The Columnsize Option](https://www.sqlite.org/fts5.html#section_4_5) - open func columnSize(_ size: Int) -> Self { - self.columnSize = size - return self - } - - /// [The Detail Option](https://www.sqlite.org/fts5.html#section_4_6) - open func detail(_ detail: Detail) -> Self { - self.detail = detail - return self - } - - override func options() -> Options { - var options = super.options() - options.append("content_rowid", value: contentRowId) - if let columnSize = columnSize { - options.append("columnsize", value: Expression(value: columnSize)) - } - options.append("detail", value: detail) - return options - } - - override func formatColumnDefinitions() -> [Expressible] { - return columnDefinitions.map { definition in - if definition.options.contains(.unindexed) { - return " ".join([definition.0, Expression(literal: "UNINDEXED")]) - } else { - return definition.0 - } - } - } -} diff --git a/ios/libs/Sqlite/Sources/SQLite/Extensions/RTree.swift b/ios/libs/Sqlite/Sources/SQLite/Extensions/RTree.swift deleted file mode 100644 index 4fc1a23..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Extensions/RTree.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -extension Module { - - public static func RTree(_ primaryKey: Expression, _ pairs: (Expression, Expression)...) -> Module where T.Datatype == Int64, U.Datatype == Double { - var arguments: [Expressible] = [primaryKey] - - for pair in pairs { - arguments.append(contentsOf: [pair.0, pair.1] as [Expressible]) - } - - return Module(name: "rtree", arguments: arguments) - } - -} diff --git a/ios/libs/Sqlite/Sources/SQLite/Foundation.swift b/ios/libs/Sqlite/Sources/SQLite/Foundation.swift deleted file mode 100644 index cfb79be..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Foundation.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -import Foundation - -extension Data : Value { - - public static var declaredDatatype: String { - return Blob.declaredDatatype - } - - public static func fromDatatypeValue(_ dataValue: Blob) -> Data { - return Data(dataValue.bytes) - } - - public var datatypeValue: Blob { - return withUnsafeBytes { (pointer: UnsafeRawBufferPointer) -> Blob in - return Blob(bytes: pointer.baseAddress!, length: count) - } - } - -} - -extension Date : Value { - - public static var declaredDatatype: String { - return String.declaredDatatype - } - - public static func fromDatatypeValue(_ stringValue: String) -> Date { - return dateFormatter.date(from: stringValue)! - } - - public var datatypeValue: String { - return dateFormatter.string(from: self) - } - -} - -/// A global date formatter used to serialize and deserialize `NSDate` objects. -/// If multiple date formats are used in an application’s database(s), use a -/// custom `Value` type per additional format. -public var dateFormatter: DateFormatter = { - let formatter = DateFormatter() - formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS" - formatter.locale = Locale(identifier: "en_US_POSIX") - formatter.timeZone = TimeZone(secondsFromGMT: 0) - return formatter -}() diff --git a/ios/libs/Sqlite/Sources/SQLite/Helpers.swift b/ios/libs/Sqlite/Sources/SQLite/Helpers.swift deleted file mode 100644 index 115ea5c..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Helpers.swift +++ /dev/null @@ -1,120 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -#if SQLITE_SWIFT_STANDALONE -import sqlite3 -#elseif SQLITE_SWIFT_SQLCIPHER -import SQLCipher -#elseif os(Linux) -import CSQLite -#else -import SQLite3 -#endif - -public typealias Star = (Expression?, Expression?) -> Expression - -public func *(_: Expression?, _: Expression?) -> Expression { - return Expression(literal: "*") -} - -public protocol _OptionalType { - - associatedtype WrappedType - -} - -extension Optional : _OptionalType { - - public typealias WrappedType = Wrapped - -} - -// let SQLITE_STATIC = unsafeBitCast(0, sqlite3_destructor_type.self) -let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self) - -extension String { - - func quote(_ mark: Character = "\"") -> String { - let escaped = reduce("") { string, character in - string + (character == mark ? "\(mark)\(mark)" : "\(character)") - } - return "\(mark)\(escaped)\(mark)" - } - - func join(_ expressions: [Expressible]) -> Expressible { - var (template, bindings) = ([String](), [Binding?]()) - for expressible in expressions { - let expression = expressible.expression - template.append(expression.template) - bindings.append(contentsOf: expression.bindings) - } - return Expression(template.joined(separator: self), bindings) - } - - func infix(_ lhs: Expressible, _ rhs: Expressible, wrap: Bool = true) -> Expression { - let expression = Expression(" \(self) ".join([lhs, rhs]).expression) - guard wrap else { - return expression - } - return "".wrap(expression) - } - - func prefix(_ expressions: Expressible) -> Expressible { - return "\(self) ".wrap(expressions) as Expression - } - - func prefix(_ expressions: [Expressible]) -> Expressible { - return "\(self) ".wrap(expressions) as Expression - } - - func wrap(_ expression: Expressible) -> Expression { - return Expression("\(self)(\(expression.expression.template))", expression.expression.bindings) - } - - func wrap(_ expressions: [Expressible]) -> Expression { - return wrap(", ".join(expressions)) - } - -} - -func transcode(_ literal: Binding?) -> String { - guard let literal = literal else { return "NULL" } - - switch literal { - case let blob as Blob: - return blob.description - case let string as String: - return string.quote("'") - case let binding: - return "\(binding)" - } -} - -func value(_ v: Binding) -> A { - return A.fromDatatypeValue(v as! A.Datatype) as! A -} - -func value(_ v: Binding?) -> A { - return value(v!) -} diff --git a/ios/libs/Sqlite/Sources/SQLite/Info.plist b/ios/libs/Sqlite/Sources/SQLite/Info.plist deleted file mode 100644 index db84c71..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 0.12.0 - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/ios/libs/Sqlite/Sources/SQLite/SQLite.h b/ios/libs/Sqlite/Sources/SQLite/SQLite.h deleted file mode 100644 index 693ce32..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/SQLite.h +++ /dev/null @@ -1,6 +0,0 @@ -@import Foundation; - -FOUNDATION_EXPORT double SQLiteVersionNumber; -FOUNDATION_EXPORT const unsigned char SQLiteVersionString[]; - -#import diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/AggregateFunctions.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/AggregateFunctions.swift deleted file mode 100644 index 2ec2828..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Typed/AggregateFunctions.swift +++ /dev/null @@ -1,264 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -private enum Function: String { - case count - case max - case min - case avg - case sum - case total - - func wrap(_ expression: Expressible) -> Expression { - return self.rawValue.wrap(expression) - } -} - -extension ExpressionType where UnderlyingType : Value { - - /// Builds a copy of the expression prefixed with the `DISTINCT` keyword. - /// - /// let name = Expression("name") - /// name.distinct - /// // DISTINCT "name" - /// - /// - Returns: A copy of the expression prefixed with the `DISTINCT` - /// keyword. - public var distinct: Expression { - return Expression("DISTINCT \(template)", bindings) - } - - /// Builds a copy of the expression wrapped with the `count` aggregate - /// function. - /// - /// let name = Expression("name") - /// name.count - /// // count("name") - /// name.distinct.count - /// // count(DISTINCT "name") - /// - /// - Returns: A copy of the expression wrapped with the `count` aggregate - /// function. - public var count: Expression { - return Function.count.wrap(self) - } - -} - -extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value { - - /// Builds a copy of the expression prefixed with the `DISTINCT` keyword. - /// - /// let name = Expression("name") - /// name.distinct - /// // DISTINCT "name" - /// - /// - Returns: A copy of the expression prefixed with the `DISTINCT` - /// keyword. - public var distinct: Expression { - return Expression("DISTINCT \(template)", bindings) - } - - /// Builds a copy of the expression wrapped with the `count` aggregate - /// function. - /// - /// let name = Expression("name") - /// name.count - /// // count("name") - /// name.distinct.count - /// // count(DISTINCT "name") - /// - /// - Returns: A copy of the expression wrapped with the `count` aggregate - /// function. - public var count: Expression { - return Function.count.wrap(self) - } - -} - -extension ExpressionType where UnderlyingType : Value, UnderlyingType.Datatype : Comparable { - - /// Builds a copy of the expression wrapped with the `max` aggregate - /// function. - /// - /// let age = Expression("age") - /// age.max - /// // max("age") - /// - /// - Returns: A copy of the expression wrapped with the `max` aggregate - /// function. - public var max: Expression { - return Function.max.wrap(self) - } - - /// Builds a copy of the expression wrapped with the `min` aggregate - /// function. - /// - /// let age = Expression("age") - /// age.min - /// // min("age") - /// - /// - Returns: A copy of the expression wrapped with the `min` aggregate - /// function. - public var min: Expression { - return Function.min.wrap(self) - } - -} - -extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value, UnderlyingType.WrappedType.Datatype : Comparable { - - /// Builds a copy of the expression wrapped with the `max` aggregate - /// function. - /// - /// let age = Expression("age") - /// age.max - /// // max("age") - /// - /// - Returns: A copy of the expression wrapped with the `max` aggregate - /// function. - public var max: Expression { - return Function.max.wrap(self) - } - - /// Builds a copy of the expression wrapped with the `min` aggregate - /// function. - /// - /// let age = Expression("age") - /// age.min - /// // min("age") - /// - /// - Returns: A copy of the expression wrapped with the `min` aggregate - /// function. - public var min: Expression { - return Function.min.wrap(self) - } - -} - -extension ExpressionType where UnderlyingType : Value, UnderlyingType.Datatype : Number { - - /// Builds a copy of the expression wrapped with the `avg` aggregate - /// function. - /// - /// let salary = Expression("salary") - /// salary.average - /// // avg("salary") - /// - /// - Returns: A copy of the expression wrapped with the `min` aggregate - /// function. - public var average: Expression { - return Function.avg.wrap(self) - } - - /// Builds a copy of the expression wrapped with the `sum` aggregate - /// function. - /// - /// let salary = Expression("salary") - /// salary.sum - /// // sum("salary") - /// - /// - Returns: A copy of the expression wrapped with the `min` aggregate - /// function. - public var sum: Expression { - return Function.sum.wrap(self) - } - - /// Builds a copy of the expression wrapped with the `total` aggregate - /// function. - /// - /// let salary = Expression("salary") - /// salary.total - /// // total("salary") - /// - /// - Returns: A copy of the expression wrapped with the `min` aggregate - /// function. - public var total: Expression { - return Function.total.wrap(self) - } - -} - -extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value, UnderlyingType.WrappedType.Datatype : Number { - - /// Builds a copy of the expression wrapped with the `avg` aggregate - /// function. - /// - /// let salary = Expression("salary") - /// salary.average - /// // avg("salary") - /// - /// - Returns: A copy of the expression wrapped with the `min` aggregate - /// function. - public var average: Expression { - return Function.avg.wrap(self) - } - - /// Builds a copy of the expression wrapped with the `sum` aggregate - /// function. - /// - /// let salary = Expression("salary") - /// salary.sum - /// // sum("salary") - /// - /// - Returns: A copy of the expression wrapped with the `min` aggregate - /// function. - public var sum: Expression { - return Function.sum.wrap(self) - } - - /// Builds a copy of the expression wrapped with the `total` aggregate - /// function. - /// - /// let salary = Expression("salary") - /// salary.total - /// // total("salary") - /// - /// - Returns: A copy of the expression wrapped with the `min` aggregate - /// function. - public var total: Expression { - return Function.total.wrap(self) - } - -} - -extension ExpressionType where UnderlyingType == Int { - - static func count(_ star: Star) -> Expression { - return Function.count.wrap(star(nil, nil)) - } - -} - -/// Builds an expression representing `count(*)` (when called with the `*` -/// function literal). -/// -/// count(*) -/// // count(*) -/// -/// - Returns: An expression returning `count(*)` (when called with the `*` -/// function literal). -public func count(_ star: Star) -> Expression { - return Expression.count(star) -} diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/Coding.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/Coding.swift deleted file mode 100644 index c3fb931..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Typed/Coding.swift +++ /dev/null @@ -1,340 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -import Foundation - -extension QueryType { - /// Creates an `INSERT` statement by encoding the given object - /// This method converts any custom nested types to JSON data and does not handle any sort - /// of object relationships. If you want to support relationships between objects you will - /// have to provide your own Encodable implementations that encode the correct ids. - /// - /// - Parameters: - /// - /// - encodable: An encodable object to insert - /// - /// - userInfo: User info to be passed to encoder - /// - /// - otherSetters: Any other setters to include in the insert - /// - /// - Returns: An `INSERT` statement fort the encodable object - public func insert(_ encodable: Encodable, userInfo: [CodingUserInfoKey:Any] = [:], otherSetters: [Setter] = []) throws -> Insert { - let encoder = SQLiteEncoder(userInfo: userInfo) - try encodable.encode(to: encoder) - return self.insert(encoder.setters + otherSetters) - } - - /// Creates an `UPDATE` statement by encoding the given object - /// This method converts any custom nested types to JSON data and does not handle any sort - /// of object relationships. If you want to support relationships between objects you will - /// have to provide your own Encodable implementations that encode the correct ids. - /// - /// - Parameters: - /// - /// - encodable: An encodable object to insert - /// - /// - userInfo: User info to be passed to encoder - /// - /// - otherSetters: Any other setters to include in the insert - /// - /// - Returns: An `UPDATE` statement fort the encodable object - public func update(_ encodable: Encodable, userInfo: [CodingUserInfoKey:Any] = [:], otherSetters: [Setter] = []) throws -> Update { - let encoder = SQLiteEncoder(userInfo: userInfo) - try encodable.encode(to: encoder) - return self.update(encoder.setters + otherSetters) - } -} - -extension Row { - /// Decode an object from this row - /// This method expects any custom nested types to be in the form of JSON data and does not handle - /// any sort of object relationships. If you want to support relationships between objects you will - /// have to provide your own Decodable implementations that decodes the correct columns. - /// - /// - Parameter: userInfo - /// - /// - Returns: a decoded object from this row - public func decode(userInfo: [CodingUserInfoKey: Any] = [:]) throws -> V { - return try V(from: self.decoder(userInfo: userInfo)) - } - - public func decoder(userInfo: [CodingUserInfoKey: Any] = [:]) -> Decoder { - return SQLiteDecoder(row: self, userInfo: userInfo) - } -} - -/// Generates a list of settings for an Encodable object -fileprivate class SQLiteEncoder: Encoder { - class SQLiteKeyedEncodingContainer: KeyedEncodingContainerProtocol { - typealias Key = MyKey - - let encoder: SQLiteEncoder - let codingPath: [CodingKey] = [] - - init(encoder: SQLiteEncoder) { - self.encoder = encoder - } - - func superEncoder() -> Swift.Encoder { - fatalError("SQLiteEncoding does not support super encoders") - } - - func superEncoder(forKey key: Key) -> Swift.Encoder { - fatalError("SQLiteEncoding does not support super encoders") - } - - func encodeNil(forKey key: SQLiteEncoder.SQLiteKeyedEncodingContainer.Key) throws { - self.encoder.setters.append(Expression(key.stringValue) <- nil) - } - - func encode(_ value: Int, forKey key: SQLiteEncoder.SQLiteKeyedEncodingContainer.Key) throws { - self.encoder.setters.append(Expression(key.stringValue) <- value) - } - - func encode(_ value: Bool, forKey key: Key) throws { - self.encoder.setters.append(Expression(key.stringValue) <- value) - } - - func encode(_ value: Float, forKey key: Key) throws { - self.encoder.setters.append(Expression(key.stringValue) <- Double(value)) - } - - func encode(_ value: Double, forKey key: Key) throws { - self.encoder.setters.append(Expression(key.stringValue) <- value) - } - - func encode(_ value: String, forKey key: Key) throws { - self.encoder.setters.append(Expression(key.stringValue) <- value) - } - - func encode(_ value: T, forKey key: Key) throws where T : Swift.Encodable { - if let data = value as? Data { - self.encoder.setters.append(Expression(key.stringValue) <- data) - } - else { - let encoded = try JSONEncoder().encode(value) - let string = String(data: encoded, encoding: .utf8) - self.encoder.setters.append(Expression(key.stringValue) <- string) - } - } - - func encode(_ value: Int8, forKey key: Key) throws { - throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: "encoding an Int8 is not supported")) - } - - func encode(_ value: Int16, forKey key: Key) throws { - throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: "encoding an Int16 is not supported")) - } - - func encode(_ value: Int32, forKey key: Key) throws { - throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: "encoding an Int32 is not supported")) - } - - func encode(_ value: Int64, forKey key: Key) throws { - throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: "encoding an Int64 is not supported")) - } - - func encode(_ value: UInt, forKey key: Key) throws { - throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: "encoding an UInt is not supported")) - } - - func encode(_ value: UInt8, forKey key: Key) throws { - throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: "encoding an UInt8 is not supported")) - } - - func encode(_ value: UInt16, forKey key: Key) throws { - throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: "encoding an UInt16 is not supported")) - } - - func encode(_ value: UInt32, forKey key: Key) throws { - throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: "encoding an UInt32 is not supported")) - } - - func encode(_ value: UInt64, forKey key: Key) throws { - throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: self.codingPath, debugDescription: "encoding an UInt64 is not supported")) - } - - func nestedContainer(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer where NestedKey : CodingKey { - fatalError("encoding a nested container is not supported") - } - - func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { - fatalError("encoding nested values is not supported") - } - } - - fileprivate var setters: [Setter] = [] - let codingPath: [CodingKey] = [] - let userInfo: [CodingUserInfoKey: Any] - - init(userInfo: [CodingUserInfoKey: Any]) { - self.userInfo = userInfo - } - - func singleValueContainer() -> SingleValueEncodingContainer { - fatalError("not supported") - } - - func unkeyedContainer() -> UnkeyedEncodingContainer { - fatalError("not supported") - } - - func container(keyedBy type: Key.Type) -> KeyedEncodingContainer where Key : CodingKey { - return KeyedEncodingContainer(SQLiteKeyedEncodingContainer(encoder: self)) - } -} - -fileprivate class SQLiteDecoder : Decoder { - class SQLiteKeyedDecodingContainer : KeyedDecodingContainerProtocol { - typealias Key = MyKey - - let codingPath: [CodingKey] = [] - let row: Row - - init(row: Row) { - self.row = row - } - - var allKeys: [Key] { - return self.row.columnNames.keys.compactMap({Key(stringValue: $0)}) - } - - func contains(_ key: Key) -> Bool { - return self.row.hasValue(for: key.stringValue) - } - - func decodeNil(forKey key: Key) throws -> Bool { - return !self.contains(key) - } - - func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool { - return try self.row.get(Expression(key.stringValue)) - } - - func decode(_ type: Int.Type, forKey key: Key) throws -> Int { - return try self.row.get(Expression(key.stringValue)) - } - - func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 { - throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an Int8 is not supported")) - } - - func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 { - throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an Int16 is not supported")) - } - - func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 { - throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an Int32 is not supported")) - } - - func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 { - throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an UInt64 is not supported")) - } - - func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt { - throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an UInt is not supported")) - - } - - func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 { - throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an UInt8 is not supported")) - } - - func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 { - throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an UInt16 is not supported")) - } - - func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 { - throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an UInt32 is not supported")) - } - - func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 { - throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an UInt64 is not supported")) - } - - func decode(_ type: Float.Type, forKey key: Key) throws -> Float { - return Float(try self.row.get(Expression(key.stringValue))) - } - - func decode(_ type: Double.Type, forKey key: Key) throws -> Double { - return try self.row.get(Expression(key.stringValue)) - } - - func decode(_ type: String.Type, forKey key: Key) throws -> String { - return try self.row.get(Expression(key.stringValue)) - } - - func decode(_ type: T.Type, forKey key: Key) throws -> T where T: Swift.Decodable { - if type == Data.self { - let data = try self.row.get(Expression(key.stringValue)) - return data as! T - } - guard let JSONString = try self.row.get(Expression(key.stringValue)) else { - throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "an unsupported type was found")) - } - guard let data = JSONString.data(using: .utf8) else { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "invalid utf8 data found")) - } - return try JSONDecoder().decode(type, from: data) - } - - func nestedContainer(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer where NestedKey : CodingKey { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding nested containers is not supported")) - } - - func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding unkeyed containers is not supported")) - } - - func superDecoder() throws -> Swift.Decoder { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding super encoders containers is not supported")) - } - - func superDecoder(forKey key: Key) throws -> Swift.Decoder { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding super decoders is not supported")) - } - } - - let row: Row - let codingPath: [CodingKey] = [] - let userInfo: [CodingUserInfoKey: Any] - - init(row: Row, userInfo: [CodingUserInfoKey: Any]) { - self.row = row - self.userInfo = userInfo - } - - func container(keyedBy type: Key.Type) throws -> KeyedDecodingContainer where Key : CodingKey { - return KeyedDecodingContainer(SQLiteKeyedDecodingContainer(row: self.row)) - } - - func unkeyedContainer() throws -> UnkeyedDecodingContainer { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding an unkeyed container is not supported")) - } - - func singleValueContainer() throws -> SingleValueDecodingContainer { - throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "decoding a single value container is not supported")) - } -} - diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/Collation.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/Collation.swift deleted file mode 100644 index e2ff9d1..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Typed/Collation.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -/// A collating function used to compare to strings. -/// -/// - SeeAlso: -public enum Collation { - - /// Compares string by raw data. - case binary - - /// Like binary, but folds uppercase ASCII letters into their lowercase - /// equivalents. - case nocase - - /// Like binary, but strips trailing space. - case rtrim - - /// A custom collating sequence identified by the given string, registered - /// using `Database.create(collation:…)` - case custom(String) - -} - -extension Collation : Expressible { - - public var expression: Expression { - return Expression(literal: description) - } - -} - -extension Collation : CustomStringConvertible { - - public var description : String { - switch self { - case .binary: - return "BINARY" - case .nocase: - return "NOCASE" - case .rtrim: - return "RTRIM" - case .custom(let collation): - return collation.quote() - } - } - -} diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/CoreFunctions.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/CoreFunctions.swift deleted file mode 100644 index 068dcf0..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Typed/CoreFunctions.swift +++ /dev/null @@ -1,796 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -import Foundation - -private enum Function: String { - case abs - case round - case random - case randomblob - case zeroblob - case length - case lower - case upper - case ltrim - case rtrim - case trim - case replace - case substr - case like = "LIKE" - case `in` = "IN" - case glob = "GLOB" - case match = "MATCH" - case regexp = "REGEXP" - case collate = "COLLATE" - case ifnull - - func infix(_ lhs: Expressible, _ rhs: Expressible, wrap: Bool = true) -> Expression { - return self.rawValue.infix(lhs, rhs, wrap: wrap) - } - - func wrap(_ expression: Expressible) -> Expression { - return self.rawValue.wrap(expression) - } - - func wrap(_ expressions: [Expressible]) -> Expression { - return self.rawValue.wrap(", ".join(expressions)) - } -} - -extension ExpressionType where UnderlyingType : Number { - - /// Builds a copy of the expression wrapped with the `abs` function. - /// - /// let x = Expression("x") - /// x.absoluteValue - /// // abs("x") - /// - /// - Returns: A copy of the expression wrapped with the `abs` function. - public var absoluteValue : Expression { - return Function.abs.wrap(self) - } - -} - -extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Number { - - /// Builds a copy of the expression wrapped with the `abs` function. - /// - /// let x = Expression("x") - /// x.absoluteValue - /// // abs("x") - /// - /// - Returns: A copy of the expression wrapped with the `abs` function. - public var absoluteValue : Expression { - return Function.abs.wrap(self) - } - -} - -extension ExpressionType where UnderlyingType == Double { - - /// Builds a copy of the expression wrapped with the `round` function. - /// - /// let salary = Expression("salary") - /// salary.round() - /// // round("salary") - /// salary.round(2) - /// // round("salary", 2) - /// - /// - Returns: A copy of the expression wrapped with the `round` function. - public func round(_ precision: Int? = nil) -> Expression { - guard let precision = precision else { - return Function.round.wrap([self]) - } - return Function.round.wrap([self, Int(precision)]) - } - -} - -extension ExpressionType where UnderlyingType == Double? { - - /// Builds a copy of the expression wrapped with the `round` function. - /// - /// let salary = Expression("salary") - /// salary.round() - /// // round("salary") - /// salary.round(2) - /// // round("salary", 2) - /// - /// - Returns: A copy of the expression wrapped with the `round` function. - public func round(_ precision: Int? = nil) -> Expression { - guard let precision = precision else { - return Function.round.wrap(self) - } - return Function.round.wrap([self, Int(precision)]) - } - -} - -extension ExpressionType where UnderlyingType : Value, UnderlyingType.Datatype == Int64 { - - /// Builds an expression representing the `random` function. - /// - /// Expression.random() - /// // random() - /// - /// - Returns: An expression calling the `random` function. - public static func random() -> Expression { - return Function.random.wrap([]) - } - -} - -extension ExpressionType where UnderlyingType == Data { - - /// Builds an expression representing the `randomblob` function. - /// - /// Expression.random(16) - /// // randomblob(16) - /// - /// - Parameter length: Length in bytes. - /// - /// - Returns: An expression calling the `randomblob` function. - public static func random(_ length: Int) -> Expression { - return Function.randomblob.wrap([]) - } - - /// Builds an expression representing the `zeroblob` function. - /// - /// Expression.allZeros(16) - /// // zeroblob(16) - /// - /// - Parameter length: Length in bytes. - /// - /// - Returns: An expression calling the `zeroblob` function. - public static func allZeros(_ length: Int) -> Expression { - return Function.zeroblob.wrap([]) - } - - /// Builds a copy of the expression wrapped with the `length` function. - /// - /// let data = Expression("data") - /// data.length - /// // length("data") - /// - /// - Returns: A copy of the expression wrapped with the `length` function. - public var length: Expression { - return Function.length.wrap(self) - } - -} - -extension ExpressionType where UnderlyingType == Data? { - - /// Builds a copy of the expression wrapped with the `length` function. - /// - /// let data = Expression("data") - /// data.length - /// // length("data") - /// - /// - Returns: A copy of the expression wrapped with the `length` function. - public var length: Expression { - return Function.length.wrap(self) - } - -} - -extension ExpressionType where UnderlyingType == String { - - /// Builds a copy of the expression wrapped with the `length` function. - /// - /// let name = Expression("name") - /// name.length - /// // length("name") - /// - /// - Returns: A copy of the expression wrapped with the `length` function. - public var length: Expression { - return Function.length.wrap(self) - } - - /// Builds a copy of the expression wrapped with the `lower` function. - /// - /// let name = Expression("name") - /// name.lowercaseString - /// // lower("name") - /// - /// - Returns: A copy of the expression wrapped with the `lower` function. - public var lowercaseString: Expression { - return Function.lower.wrap(self) - } - - /// Builds a copy of the expression wrapped with the `upper` function. - /// - /// let name = Expression("name") - /// name.uppercaseString - /// // lower("name") - /// - /// - Returns: A copy of the expression wrapped with the `upper` function. - public var uppercaseString: Expression { - return Function.upper.wrap(self) - } - - /// Builds a copy of the expression appended with a `LIKE` query against the - /// given pattern. - /// - /// let email = Expression("email") - /// email.like("%@example.com") - /// // "email" LIKE '%@example.com' - /// email.like("99\\%@%", escape: "\\") - /// // "email" LIKE '99\%@%' ESCAPE '\' - /// - /// - Parameters: - /// - /// - pattern: A pattern to match. - /// - /// - escape: An (optional) character designated for escaping - /// pattern-matching characters (*i.e.*, the `%` and `_` characters). - /// - /// - Returns: A copy of the expression appended with a `LIKE` query against - /// the given pattern. - public func like(_ pattern: String, escape character: Character? = nil) -> Expression { - guard let character = character else { - return "LIKE".infix(self, pattern) - } - return Expression("(\(template) LIKE ? ESCAPE ?)", bindings + [pattern, String(character)]) - } - - /// Builds a copy of the expression appended with a `LIKE` query against the - /// given pattern. - /// - /// let email = Expression("email") - /// let pattern = Expression("pattern") - /// email.like(pattern) - /// // "email" LIKE "pattern" - /// - /// - Parameters: - /// - /// - pattern: A pattern to match. - /// - /// - escape: An (optional) character designated for escaping - /// pattern-matching characters (*i.e.*, the `%` and `_` characters). - /// - /// - Returns: A copy of the expression appended with a `LIKE` query against - /// the given pattern. - public func like(_ pattern: Expression, escape character: Character? = nil) -> Expression { - guard let character = character else { - return Function.like.infix(self, pattern) - } - let like: Expression = Function.like.infix(self, pattern, wrap: false) - return Expression("(\(like.template) ESCAPE ?)", like.bindings + [String(character)]) - } - - /// Builds a copy of the expression appended with a `GLOB` query against the - /// given pattern. - /// - /// let path = Expression("path") - /// path.glob("*.png") - /// // "path" GLOB '*.png' - /// - /// - Parameter pattern: A pattern to match. - /// - /// - Returns: A copy of the expression appended with a `GLOB` query against - /// the given pattern. - public func glob(_ pattern: String) -> Expression { - return Function.glob.infix(self, pattern) - } - - /// Builds a copy of the expression appended with a `MATCH` query against - /// the given pattern. - /// - /// let title = Expression("title") - /// title.match("swift AND programming") - /// // "title" MATCH 'swift AND programming' - /// - /// - Parameter pattern: A pattern to match. - /// - /// - Returns: A copy of the expression appended with a `MATCH` query - /// against the given pattern. - public func match(_ pattern: String) -> Expression { - return Function.match.infix(self, pattern) - } - - /// Builds a copy of the expression appended with a `REGEXP` query against - /// the given pattern. - /// - /// - Parameter pattern: A pattern to match. - /// - /// - Returns: A copy of the expression appended with a `REGEXP` query - /// against the given pattern. - public func regexp(_ pattern: String) -> Expression { - return Function.regexp.infix(self, pattern) - } - - /// Builds a copy of the expression appended with a `COLLATE` clause with - /// the given sequence. - /// - /// let name = Expression("name") - /// name.collate(.Nocase) - /// // "name" COLLATE NOCASE - /// - /// - Parameter collation: A collating sequence. - /// - /// - Returns: A copy of the expression appended with a `COLLATE` clause - /// with the given sequence. - public func collate(_ collation: Collation) -> Expression { - return Function.collate.infix(self, collation) - } - - /// Builds a copy of the expression wrapped with the `ltrim` function. - /// - /// let name = Expression("name") - /// name.ltrim() - /// // ltrim("name") - /// name.ltrim([" ", "\t"]) - /// // ltrim("name", ' \t') - /// - /// - Parameter characters: A set of characters to trim. - /// - /// - Returns: A copy of the expression wrapped with the `ltrim` function. - public func ltrim(_ characters: Set? = nil) -> Expression { - guard let characters = characters else { - return Function.ltrim.wrap(self) - } - return Function.ltrim.wrap([self, String(characters)]) - } - - /// Builds a copy of the expression wrapped with the `rtrim` function. - /// - /// let name = Expression("name") - /// name.rtrim() - /// // rtrim("name") - /// name.rtrim([" ", "\t"]) - /// // rtrim("name", ' \t') - /// - /// - Parameter characters: A set of characters to trim. - /// - /// - Returns: A copy of the expression wrapped with the `rtrim` function. - public func rtrim(_ characters: Set? = nil) -> Expression { - guard let characters = characters else { - return Function.rtrim.wrap(self) - } - return Function.rtrim.wrap([self, String(characters)]) - } - - /// Builds a copy of the expression wrapped with the `trim` function. - /// - /// let name = Expression("name") - /// name.trim() - /// // trim("name") - /// name.trim([" ", "\t"]) - /// // trim("name", ' \t') - /// - /// - Parameter characters: A set of characters to trim. - /// - /// - Returns: A copy of the expression wrapped with the `trim` function. - public func trim(_ characters: Set? = nil) -> Expression { - guard let characters = characters else { - return Function.trim.wrap([self]) - } - return Function.trim.wrap([self, String(characters)]) - } - - /// Builds a copy of the expression wrapped with the `replace` function. - /// - /// let email = Expression("email") - /// email.replace("@mac.com", with: "@icloud.com") - /// // replace("email", '@mac.com', '@icloud.com') - /// - /// - Parameters: - /// - /// - pattern: A pattern to match. - /// - /// - replacement: The replacement string. - /// - /// - Returns: A copy of the expression wrapped with the `replace` function. - public func replace(_ pattern: String, with replacement: String) -> Expression { - return Function.replace.wrap([self, pattern, replacement]) - } - - public func substring(_ location: Int, length: Int? = nil) -> Expression { - guard let length = length else { - return Function.substr.wrap([self, location]) - } - return Function.substr.wrap([self, location, length]) - } - - public subscript(range: Range) -> Expression { - return substring(range.lowerBound, length: range.upperBound - range.lowerBound) - } - -} - -extension ExpressionType where UnderlyingType == String? { - - /// Builds a copy of the expression wrapped with the `length` function. - /// - /// let name = Expression("name") - /// name.length - /// // length("name") - /// - /// - Returns: A copy of the expression wrapped with the `length` function. - public var length: Expression { - return Function.length.wrap(self) - } - - /// Builds a copy of the expression wrapped with the `lower` function. - /// - /// let name = Expression("name") - /// name.lowercaseString - /// // lower("name") - /// - /// - Returns: A copy of the expression wrapped with the `lower` function. - public var lowercaseString: Expression { - return Function.lower.wrap(self) - } - - /// Builds a copy of the expression wrapped with the `upper` function. - /// - /// let name = Expression("name") - /// name.uppercaseString - /// // lower("name") - /// - /// - Returns: A copy of the expression wrapped with the `upper` function. - public var uppercaseString: Expression { - return Function.upper.wrap(self) - } - - /// Builds a copy of the expression appended with a `LIKE` query against the - /// given pattern. - /// - /// let email = Expression("email") - /// email.like("%@example.com") - /// // "email" LIKE '%@example.com' - /// email.like("99\\%@%", escape: "\\") - /// // "email" LIKE '99\%@%' ESCAPE '\' - /// - /// - Parameters: - /// - /// - pattern: A pattern to match. - /// - /// - escape: An (optional) character designated for escaping - /// pattern-matching characters (*i.e.*, the `%` and `_` characters). - /// - /// - Returns: A copy of the expression appended with a `LIKE` query against - /// the given pattern. - public func like(_ pattern: String, escape character: Character? = nil) -> Expression { - guard let character = character else { - return Function.like.infix(self, pattern) - } - return Expression("(\(template) LIKE ? ESCAPE ?)", bindings + [pattern, String(character)]) - } - - /// Builds a copy of the expression appended with a `LIKE` query against the - /// given pattern. - /// - /// let email = Expression("email") - /// let pattern = Expression("pattern") - /// email.like(pattern) - /// // "email" LIKE "pattern" - /// - /// - Parameters: - /// - /// - pattern: A pattern to match. - /// - /// - escape: An (optional) character designated for escaping - /// pattern-matching characters (*i.e.*, the `%` and `_` characters). - /// - /// - Returns: A copy of the expression appended with a `LIKE` query against - /// the given pattern. - public func like(_ pattern: Expression, escape character: Character? = nil) -> Expression { - guard let character = character else { - return Function.like.infix(self, pattern) - } - let like: Expression = Function.like.infix(self, pattern, wrap: false) - return Expression("(\(like.template) ESCAPE ?)", like.bindings + [String(character)]) - } - - /// Builds a copy of the expression appended with a `GLOB` query against the - /// given pattern. - /// - /// let path = Expression("path") - /// path.glob("*.png") - /// // "path" GLOB '*.png' - /// - /// - Parameter pattern: A pattern to match. - /// - /// - Returns: A copy of the expression appended with a `GLOB` query against - /// the given pattern. - public func glob(_ pattern: String) -> Expression { - return Function.glob.infix(self, pattern) - } - - /// Builds a copy of the expression appended with a `MATCH` query against - /// the given pattern. - /// - /// let title = Expression("title") - /// title.match("swift AND programming") - /// // "title" MATCH 'swift AND programming' - /// - /// - Parameter pattern: A pattern to match. - /// - /// - Returns: A copy of the expression appended with a `MATCH` query - /// against the given pattern. - public func match(_ pattern: String) -> Expression { - return Function.match.infix(self, pattern) - } - - /// Builds a copy of the expression appended with a `REGEXP` query against - /// the given pattern. - /// - /// - Parameter pattern: A pattern to match. - /// - /// - Returns: A copy of the expression appended with a `REGEXP` query - /// against the given pattern. - public func regexp(_ pattern: String) -> Expression { - return Function.regexp.infix(self, pattern) - } - - /// Builds a copy of the expression appended with a `COLLATE` clause with - /// the given sequence. - /// - /// let name = Expression("name") - /// name.collate(.Nocase) - /// // "name" COLLATE NOCASE - /// - /// - Parameter collation: A collating sequence. - /// - /// - Returns: A copy of the expression appended with a `COLLATE` clause - /// with the given sequence. - public func collate(_ collation: Collation) -> Expression { - return Function.collate.infix(self, collation) - } - - /// Builds a copy of the expression wrapped with the `ltrim` function. - /// - /// let name = Expression("name") - /// name.ltrim() - /// // ltrim("name") - /// name.ltrim([" ", "\t"]) - /// // ltrim("name", ' \t') - /// - /// - Parameter characters: A set of characters to trim. - /// - /// - Returns: A copy of the expression wrapped with the `ltrim` function. - public func ltrim(_ characters: Set? = nil) -> Expression { - guard let characters = characters else { - return Function.ltrim.wrap(self) - } - return Function.ltrim.wrap([self, String(characters)]) - } - - /// Builds a copy of the expression wrapped with the `rtrim` function. - /// - /// let name = Expression("name") - /// name.rtrim() - /// // rtrim("name") - /// name.rtrim([" ", "\t"]) - /// // rtrim("name", ' \t') - /// - /// - Parameter characters: A set of characters to trim. - /// - /// - Returns: A copy of the expression wrapped with the `rtrim` function. - public func rtrim(_ characters: Set? = nil) -> Expression { - guard let characters = characters else { - return Function.rtrim.wrap(self) - } - return Function.rtrim.wrap([self, String(characters)]) - } - - /// Builds a copy of the expression wrapped with the `trim` function. - /// - /// let name = Expression("name") - /// name.trim() - /// // trim("name") - /// name.trim([" ", "\t"]) - /// // trim("name", ' \t') - /// - /// - Parameter characters: A set of characters to trim. - /// - /// - Returns: A copy of the expression wrapped with the `trim` function. - public func trim(_ characters: Set? = nil) -> Expression { - guard let characters = characters else { - return Function.trim.wrap(self) - } - return Function.trim.wrap([self, String(characters)]) - } - - /// Builds a copy of the expression wrapped with the `replace` function. - /// - /// let email = Expression("email") - /// email.replace("@mac.com", with: "@icloud.com") - /// // replace("email", '@mac.com', '@icloud.com') - /// - /// - Parameters: - /// - /// - pattern: A pattern to match. - /// - /// - replacement: The replacement string. - /// - /// - Returns: A copy of the expression wrapped with the `replace` function. - public func replace(_ pattern: String, with replacement: String) -> Expression { - return Function.replace.wrap([self, pattern, replacement]) - } - - /// Builds a copy of the expression wrapped with the `substr` function. - /// - /// let title = Expression("title") - /// title.substr(-100) - /// // substr("title", -100) - /// title.substr(0, length: 100) - /// // substr("title", 0, 100) - /// - /// - Parameters: - /// - /// - location: The substring’s start index. - /// - /// - length: An optional substring length. - /// - /// - Returns: A copy of the expression wrapped with the `substr` function. - public func substring(_ location: Int, length: Int? = nil) -> Expression { - guard let length = length else { - return Function.substr.wrap([self, location]) - } - return Function.substr.wrap([self, location, length]) - } - - /// Builds a copy of the expression wrapped with the `substr` function. - /// - /// let title = Expression("title") - /// title[0..<100] - /// // substr("title", 0, 100) - /// - /// - Parameter range: The character index range of the substring. - /// - /// - Returns: A copy of the expression wrapped with the `substr` function. - public subscript(range: Range) -> Expression { - return substring(range.lowerBound, length: range.upperBound - range.lowerBound) - } - -} - -extension Collection where Iterator.Element : Value { - - /// Builds a copy of the expression prepended with an `IN` check against the - /// collection. - /// - /// let name = Expression("name") - /// ["alice", "betty"].contains(name) - /// // "name" IN ('alice', 'betty') - /// - /// - Parameter pattern: A pattern to match. - /// - /// - Returns: A copy of the expression prepended with an `IN` check against - /// the collection. - public func contains(_ expression: Expression) -> Expression { - let templates = [String](repeating: "?", count: count).joined(separator: ", ") - return Function.in.infix(expression, Expression("(\(templates))", map { $0.datatypeValue })) - } - - /// Builds a copy of the expression prepended with an `IN` check against the - /// collection. - /// - /// let name = Expression("name") - /// ["alice", "betty"].contains(name) - /// // "name" IN ('alice', 'betty') - /// - /// - Parameter pattern: A pattern to match. - /// - /// - Returns: A copy of the expression prepended with an `IN` check against - /// the collection. - public func contains(_ expression: Expression) -> Expression { - let templates = [String](repeating: "?", count: count).joined(separator: ", ") - return Function.in.infix(expression, Expression("(\(templates))", map { $0.datatypeValue })) - } - -} - -extension String { - - /// Builds a copy of the expression appended with a `LIKE` query against the - /// given pattern. - /// - /// let email = "some@thing.com" - /// let pattern = Expression("pattern") - /// email.like(pattern) - /// // 'some@thing.com' LIKE "pattern" - /// - /// - Parameters: - /// - /// - pattern: A pattern to match. - /// - /// - escape: An (optional) character designated for escaping - /// pattern-matching characters (*i.e.*, the `%` and `_` characters). - /// - /// - Returns: A copy of the expression appended with a `LIKE` query against - /// the given pattern. - public func like(_ pattern: Expression, escape character: Character? = nil) -> Expression { - guard let character = character else { - return Function.like.infix(self, pattern) - } - let like: Expression = Function.like.infix(self, pattern, wrap: false) - return Expression("(\(like.template) ESCAPE ?)", like.bindings + [String(character)]) - } - -} - -/// Builds a copy of the given expressions wrapped with the `ifnull` function. -/// -/// let name = Expression("name") -/// name ?? "An Anonymous Coward" -/// // ifnull("name", 'An Anonymous Coward') -/// -/// - Parameters: -/// -/// - optional: An optional expression. -/// -/// - defaultValue: A fallback value for when the optional expression is -/// `nil`. -/// -/// - Returns: A copy of the given expressions wrapped with the `ifnull` -/// function. -public func ??(optional: Expression, defaultValue: V) -> Expression { - return Function.ifnull.wrap([optional, defaultValue]) -} - -/// Builds a copy of the given expressions wrapped with the `ifnull` function. -/// -/// let nick = Expression("nick") -/// let name = Expression("name") -/// nick ?? name -/// // ifnull("nick", "name") -/// -/// - Parameters: -/// -/// - optional: An optional expression. -/// -/// - defaultValue: A fallback expression for when the optional expression is -/// `nil`. -/// -/// - Returns: A copy of the given expressions wrapped with the `ifnull` -/// function. -public func ??(optional: Expression, defaultValue: Expression) -> Expression { - return Function.ifnull.wrap([optional, defaultValue]) -} - -/// Builds a copy of the given expressions wrapped with the `ifnull` function. -/// -/// let nick = Expression("nick") -/// let name = Expression("name") -/// nick ?? name -/// // ifnull("nick", "name") -/// -/// - Parameters: -/// -/// - optional: An optional expression. -/// -/// - defaultValue: A fallback expression for when the optional expression is -/// `nil`. -/// -/// - Returns: A copy of the given expressions wrapped with the `ifnull` -/// function. -public func ??(optional: Expression, defaultValue: Expression) -> Expression { - return Function.ifnull.wrap([optional, defaultValue]) -} diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/CustomFunctions.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/CustomFunctions.swift deleted file mode 100644 index 8910a24..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Typed/CustomFunctions.swift +++ /dev/null @@ -1,136 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -public extension Connection { - - /// Creates or redefines a custom SQL function. - /// - /// - Parameters: - /// - /// - function: The name of the function to create or redefine. - /// - /// - deterministic: Whether or not the function is deterministic (_i.e._ - /// the function always returns the same result for a given input). - /// - /// Default: `false` - /// - /// - block: A block of code to run when the function is called. - /// The assigned types must be explicit. - /// - /// - Returns: A closure returning an SQL expression to call the function. - func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping () -> Z) throws -> (() -> Expression) { - let fn = try createFunction(function, 0, deterministic) { _ in block() } - return { fn([]) } - } - - func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping () -> Z?) throws -> (() -> Expression) { - let fn = try createFunction(function, 0, deterministic) { _ in block() } - return { fn([]) } - } - - // MARK: - - - func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A) -> Z) throws -> ((Expression) -> Expression) { - let fn = try createFunction(function, 1, deterministic) { args in block(value(args[0])) } - return { arg in fn([arg]) } - } - - func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A?) -> Z) throws -> ((Expression) -> Expression) { - let fn = try createFunction(function, 1, deterministic) { args in block(args[0].map(value)) } - return { arg in fn([arg]) } - } - - func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A) -> Z?) throws -> ((Expression) -> Expression) { - let fn = try createFunction(function, 1, deterministic) { args in block(value(args[0])) } - return { arg in fn([arg]) } - } - - func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A?) -> Z?) throws -> ((Expression) -> Expression) { - let fn = try createFunction(function, 1, deterministic) { args in block(args[0].map(value)) } - return { arg in fn([arg]) } - } - - // MARK: - - - func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B) -> Z) throws -> (Expression, Expression) -> Expression { - let fn = try createFunction(function, 2, deterministic) { args in block(value(args[0]), value(args[1])) } - return { a, b in fn([a, b]) } - } - - func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B) -> Z) throws -> (Expression, Expression) -> Expression { - let fn = try createFunction(function, 2, deterministic) { args in block(args[0].map(value), value(args[1])) } - return { a, b in fn([a, b]) } - } - - func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B?) -> Z) throws -> (Expression, Expression) -> Expression { - let fn = try createFunction(function, 2, deterministic) { args in block(value(args[0]), args[1].map(value)) } - return { a, b in fn([a, b]) } - } - - func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B) -> Z?) throws -> (Expression, Expression) -> Expression { - let fn = try createFunction(function, 2, deterministic) { args in block(value(args[0]), value(args[1])) } - return { a, b in fn([a, b]) } - } - - func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B?) -> Z) throws -> (Expression, Expression) -> Expression { - let fn = try createFunction(function, 2, deterministic) { args in block(args[0].map(value), args[1].map(value)) } - return { a, b in fn([a, b]) } - } - - func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B) -> Z?) throws -> (Expression, Expression) -> Expression { - let fn = try createFunction(function, 2, deterministic) { args in block(args[0].map(value), value(args[1])) } - return { a, b in fn([a, b]) } - } - - func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B?) -> Z?) throws -> (Expression, Expression) -> Expression { - let fn = try createFunction(function, 2, deterministic) { args in block(value(args[0]), args[1].map(value)) } - return { a, b in fn([a, b]) } - } - - func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B?) -> Z?) throws -> (Expression, Expression) -> Expression { - let fn = try createFunction(function, 2, deterministic) { args in block(args[0].map(value), args[1].map(value)) } - return { a, b in fn([a, b]) } - } - - // MARK: - - - fileprivate func createFunction(_ function: String, _ argumentCount: UInt, _ deterministic: Bool, _ block: @escaping ([Binding?]) -> Z) throws -> (([Expressible]) -> Expression) { - createFunction(function, argumentCount: argumentCount, deterministic: deterministic) { arguments in - block(arguments).datatypeValue - } - return { arguments in - function.quote().wrap(", ".join(arguments)) - } - } - - fileprivate func createFunction(_ function: String, _ argumentCount: UInt, _ deterministic: Bool, _ block: @escaping ([Binding?]) -> Z?) throws -> (([Expressible]) -> Expression) { - createFunction(function, argumentCount: argumentCount, deterministic: deterministic) { arguments in - block(arguments)?.datatypeValue - } - return { arguments in - function.quote().wrap(", ".join(arguments)) - } - } - -} diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/DateAndTimeFunctions.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/DateAndTimeFunctions.swift deleted file mode 100644 index 0b9a497..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Typed/DateAndTimeFunctions.swift +++ /dev/null @@ -1,106 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -import Foundation - -/// All five date and time functions take a time string as an argument. -/// The time string is followed by zero or more modifiers. -/// The strftime() function also takes a format string as its first argument. -/// -/// https://www.sqlite.org/lang_datefunc.html -public class DateFunctions { - /// The date() function returns the date in this format: YYYY-MM-DD. - public static func date(_ timestring: String, _ modifiers: String...) -> Expression { - return timefunction("date", timestring: timestring, modifiers: modifiers) - } - - /// The time() function returns the time as HH:MM:SS. - public static func time(_ timestring: String, _ modifiers: String...) -> Expression { - return timefunction("time", timestring: timestring, modifiers: modifiers) - } - - /// The datetime() function returns "YYYY-MM-DD HH:MM:SS". - public static func datetime(_ timestring: String, _ modifiers: String...) -> Expression { - return timefunction("datetime", timestring: timestring, modifiers: modifiers) - } - - /// The julianday() function returns the Julian day - - /// the number of days since noon in Greenwich on November 24, 4714 B.C. - public static func julianday(_ timestring: String, _ modifiers: String...) -> Expression { - return timefunction("julianday", timestring: timestring, modifiers: modifiers) - } - - /// The strftime() routine returns the date formatted according to the format string specified as the first argument. - public static func strftime(_ format: String, _ timestring: String, _ modifiers: String...) -> Expression { - if !modifiers.isEmpty { - let templates = [String](repeating: "?", count: modifiers.count).joined(separator: ", ") - return Expression("strftime(?, ?, \(templates))", [format, timestring] + modifiers) - } - return Expression("strftime(?, ?)", [format, timestring]) - } - - private static func timefunction(_ name: String, timestring: String, modifiers: [String]) -> Expression { - if !modifiers.isEmpty { - let templates = [String](repeating: "?", count: modifiers.count).joined(separator: ", ") - return Expression("\(name)(?, \(templates))", [timestring] + modifiers) - } - return Expression("\(name)(?)", [timestring]) - } -} - -extension Date { - public var date: Expression { - return DateFunctions.date(dateFormatter.string(from: self)) - } - - public var time: Expression { - return DateFunctions.time(dateFormatter.string(from: self)) - } - - public var datetime: Expression { - return DateFunctions.datetime(dateFormatter.string(from: self)) - } - - public var julianday: Expression { - return DateFunctions.julianday(dateFormatter.string(from: self)) - } -} - -extension Expression where UnderlyingType == Date { - public var date: Expression { - return Expression("date(\(template))", bindings) - } - - public var time: Expression { - return Expression("time(\(template))", bindings) - } - - public var datetime: Expression { - return Expression("datetime(\(template))", bindings) - } - - public var julianday: Expression { - return Expression("julianday(\(template))", bindings) - } -} diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/Expression.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/Expression.swift deleted file mode 100644 index 76ba04c..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Typed/Expression.swift +++ /dev/null @@ -1,147 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -public protocol ExpressionType : Expressible { // extensions cannot have inheritance clauses - - associatedtype UnderlyingType = Void - - var template: String { get } - var bindings: [Binding?] { get } - - init(_ template: String, _ bindings: [Binding?]) - -} - -extension ExpressionType { - - public init(literal: String) { - self.init(literal, []) - } - - public init(_ identifier: String) { - self.init(literal: identifier.quote()) - } - - public init(_ expression: U) { - self.init(expression.template, expression.bindings) - } - -} - -/// An `Expression` represents a raw SQL fragment and any associated bindings. -public struct Expression : ExpressionType { - - public typealias UnderlyingType = Datatype - - public var template: String - public var bindings: [Binding?] - - public init(_ template: String, _ bindings: [Binding?]) { - self.template = template - self.bindings = bindings - } - -} - -public protocol Expressible { - - var expression: Expression { get } - -} - -extension Expressible { - - // naïve compiler for statements that can’t be bound, e.g., CREATE TABLE - // FIXME: make internal (0.13.0) - public func asSQL() -> String { - let expressed = expression - var idx = 0 - return expressed.template.reduce("") { template, character in - let transcoded: String - - if character == "?" { - transcoded = transcode(expressed.bindings[idx]) - idx += 1 - } else { - transcoded = String(character) - } - return template + transcoded - } - } - -} - -extension ExpressionType { - - public var expression: Expression { - return Expression(template, bindings) - } - - public var asc: Expressible { - return " ".join([self, Expression(literal: "ASC")]) - } - - public var desc: Expressible { - return " ".join([self, Expression(literal: "DESC")]) - } - -} - -extension ExpressionType where UnderlyingType : Value { - - public init(value: UnderlyingType) { - self.init("?", [value.datatypeValue]) - } - -} - -extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value { - - public static var null: Self { - return self.init(value: nil) - } - - public init(value: UnderlyingType.WrappedType?) { - self.init("?", [value?.datatypeValue]) - } - -} - -extension Value { - - public var expression: Expression { - return Expression(value: self).expression - } - -} - -public let rowid = Expression("ROWID") - -public func cast(_ expression: Expression) -> Expression { - return Expression("CAST (\(expression.template) AS \(U.declaredDatatype))", expression.bindings) -} - -public func cast(_ expression: Expression) -> Expression { - return Expression("CAST (\(expression.template) AS \(U.declaredDatatype))", expression.bindings) -} diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/Operators.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/Operators.swift deleted file mode 100644 index b5637ea..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Typed/Operators.swift +++ /dev/null @@ -1,605 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -// TODO: use `@warn_unused_result` by the time operator functions support it - -private enum Operator: String { - case plus = "+" - case minus = "-" - case or = "OR" - case and = "AND" - case not = "NOT " - case mul = "*" - case div = "/" - case mod = "%" - case bitwiseLeft = "<<" - case bitwiseRight = ">>" - case bitwiseAnd = "&" - case bitwiseOr = "|" - case bitwiseXor = "~" - case eq = "=" - case neq = "!=" - case gt = ">" - case lt = "<" - case gte = ">=" - case lte = "<=" - case concatenate = "||" - - func infix(_ lhs: Expressible, _ rhs: Expressible, wrap: Bool = true) -> Expression { - return self.rawValue.infix(lhs, rhs, wrap: wrap) - } - - func wrap(_ expression: Expressible) -> Expression { - return self.rawValue.wrap(expression) - } -} - -public func +(lhs: Expression, rhs: Expression) -> Expression { - return Operator.concatenate.infix(lhs, rhs) -} - -public func +(lhs: Expression, rhs: Expression) -> Expression { - return Operator.concatenate.infix(lhs, rhs) -} -public func +(lhs: Expression, rhs: Expression) -> Expression { - return Operator.concatenate.infix(lhs, rhs) -} -public func +(lhs: Expression, rhs: Expression) -> Expression { - return Operator.concatenate.infix(lhs, rhs) -} -public func +(lhs: Expression, rhs: String) -> Expression { - return Operator.concatenate.infix(lhs, rhs) -} -public func +(lhs: Expression, rhs: String) -> Expression { - return Operator.concatenate.infix(lhs, rhs) -} -public func +(lhs: String, rhs: Expression) -> Expression { - return Operator.concatenate.infix(lhs, rhs) -} -public func +(lhs: String, rhs: Expression) -> Expression { - return Operator.concatenate.infix(lhs, rhs) -} - -// MARK: - - -public func +(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.plus.infix(lhs, rhs) -} -public func +(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.plus.infix(lhs, rhs) -} -public func +(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.plus.infix(lhs, rhs) -} -public func +(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.plus.infix(lhs, rhs) -} -public func +(lhs: Expression, rhs: V) -> Expression where V.Datatype : Number { - return Operator.plus.infix(lhs, rhs) -} -public func +(lhs: Expression, rhs: V) -> Expression where V.Datatype : Number { - return Operator.plus.infix(lhs, rhs) -} -public func +(lhs: V, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.plus.infix(lhs, rhs) -} -public func +(lhs: V, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.plus.infix(lhs, rhs) -} - -public func -(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.minus.infix(lhs, rhs) -} -public func -(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.minus.infix(lhs, rhs) -} -public func -(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.minus.infix(lhs, rhs) -} -public func -(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.minus.infix(lhs, rhs) -} -public func -(lhs: Expression, rhs: V) -> Expression where V.Datatype : Number { - return Operator.minus.infix(lhs, rhs) -} -public func -(lhs: Expression, rhs: V) -> Expression where V.Datatype : Number { - return Operator.minus.infix(lhs, rhs) -} -public func -(lhs: V, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.minus.infix(lhs, rhs) -} -public func -(lhs: V, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.minus.infix(lhs, rhs) -} - -public func *(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.mul.infix(lhs, rhs) -} -public func *(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.mul.infix(lhs, rhs) -} -public func *(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.mul.infix(lhs, rhs) -} -public func *(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.mul.infix(lhs, rhs) -} -public func *(lhs: Expression, rhs: V) -> Expression where V.Datatype : Number { - return Operator.mul.infix(lhs, rhs) -} -public func *(lhs: Expression, rhs: V) -> Expression where V.Datatype : Number { - return Operator.mul.infix(lhs, rhs) -} -public func *(lhs: V, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.mul.infix(lhs, rhs) -} -public func *(lhs: V, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.mul.infix(lhs, rhs) -} - -public func /(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.div.infix(lhs, rhs) -} -public func /(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.div.infix(lhs, rhs) -} -public func /(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.div.infix(lhs, rhs) -} -public func /(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.div.infix(lhs, rhs) -} -public func /(lhs: Expression, rhs: V) -> Expression where V.Datatype : Number { - return Operator.div.infix(lhs, rhs) -} -public func /(lhs: Expression, rhs: V) -> Expression where V.Datatype : Number { - return Operator.div.infix(lhs, rhs) -} -public func /(lhs: V, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.div.infix(lhs, rhs) -} -public func /(lhs: V, rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.div.infix(lhs, rhs) -} - -public prefix func -(rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.minus.wrap(rhs) -} -public prefix func -(rhs: Expression) -> Expression where V.Datatype : Number { - return Operator.minus.wrap(rhs) -} - -// MARK: - - -public func %(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.mod.infix(lhs, rhs) -} -public func %(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.mod.infix(lhs, rhs) -} -public func %(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.mod.infix(lhs, rhs) -} -public func %(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.mod.infix(lhs, rhs) -} -public func %(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { - return Operator.mod.infix(lhs, rhs) -} -public func %(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { - return Operator.mod.infix(lhs, rhs) -} -public func %(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.mod.infix(lhs, rhs) -} -public func %(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.mod.infix(lhs, rhs) -} - -public func <<(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseLeft.infix(lhs, rhs) -} -public func <<(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseLeft.infix(lhs, rhs) -} -public func <<(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseLeft.infix(lhs, rhs) -} -public func <<(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseLeft.infix(lhs, rhs) -} -public func <<(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseLeft.infix(lhs, rhs) -} -public func <<(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseLeft.infix(lhs, rhs) -} -public func <<(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseLeft.infix(lhs, rhs) -} -public func <<(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseLeft.infix(lhs, rhs) -} - -public func >>(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseRight.infix(lhs, rhs) -} -public func >>(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseRight.infix(lhs, rhs) -} -public func >>(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseRight.infix(lhs, rhs) -} -public func >>(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseRight.infix(lhs, rhs) -} -public func >>(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseRight.infix(lhs, rhs) -} -public func >>(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseRight.infix(lhs, rhs) -} -public func >>(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseRight.infix(lhs, rhs) -} -public func >>(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseRight.infix(lhs, rhs) -} - -public func &(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseAnd.infix(lhs, rhs) -} -public func &(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseAnd.infix(lhs, rhs) -} -public func &(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseAnd.infix(lhs, rhs) -} -public func &(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseAnd.infix(lhs, rhs) -} -public func &(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseAnd.infix(lhs, rhs) -} -public func &(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseAnd.infix(lhs, rhs) -} -public func &(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseAnd.infix(lhs, rhs) -} -public func &(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseAnd.infix(lhs, rhs) -} - -public func |(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseOr.infix(lhs, rhs) -} -public func |(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseOr.infix(lhs, rhs) -} -public func |(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseOr.infix(lhs, rhs) -} -public func |(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseOr.infix(lhs, rhs) -} -public func |(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseOr.infix(lhs, rhs) -} -public func |(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseOr.infix(lhs, rhs) -} -public func |(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseOr.infix(lhs, rhs) -} -public func |(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseOr.infix(lhs, rhs) -} - -public func ^(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return (~(lhs & rhs)) & (lhs | rhs) -} -public func ^(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return (~(lhs & rhs)) & (lhs | rhs) -} -public func ^(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return (~(lhs & rhs)) & (lhs | rhs) -} -public func ^(lhs: Expression, rhs: Expression) -> Expression where V.Datatype == Int64 { - return (~(lhs & rhs)) & (lhs | rhs) -} -public func ^(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { - return (~(lhs & rhs)) & (lhs | rhs) -} -public func ^(lhs: Expression, rhs: V) -> Expression where V.Datatype == Int64 { - return (~(lhs & rhs)) & (lhs | rhs) -} -public func ^(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { - return (~(lhs & rhs)) & (lhs | rhs) -} -public func ^(lhs: V, rhs: Expression) -> Expression where V.Datatype == Int64 { - return (~(lhs & rhs)) & (lhs | rhs) -} - -public prefix func ~(rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseXor.wrap(rhs) -} -public prefix func ~(rhs: Expression) -> Expression where V.Datatype == Int64 { - return Operator.bitwiseXor.wrap(rhs) -} - -// MARK: - - -public func ==(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Equatable { - return Operator.eq.infix(lhs, rhs) -} -public func ==(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Equatable { - return Operator.eq.infix(lhs, rhs) -} -public func ==(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Equatable { - return Operator.eq.infix(lhs, rhs) -} -public func ==(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Equatable { - return Operator.eq.infix(lhs, rhs) -} -public func ==(lhs: Expression, rhs: V) -> Expression where V.Datatype : Equatable { - return Operator.eq.infix(lhs, rhs) -} -public func ==(lhs: Expression, rhs: V?) -> Expression where V.Datatype : Equatable { - guard let rhs = rhs else { return "IS".infix(lhs, Expression(value: nil)) } - return Operator.eq.infix(lhs, rhs) -} -public func ==(lhs: V, rhs: Expression) -> Expression where V.Datatype : Equatable { - return Operator.eq.infix(lhs, rhs) -} -public func ==(lhs: V?, rhs: Expression) -> Expression where V.Datatype : Equatable { - guard let lhs = lhs else { return "IS".infix(Expression(value: nil), rhs) } - return Operator.eq.infix(lhs, rhs) -} - -public func !=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Equatable { - return Operator.neq.infix(lhs, rhs) -} -public func !=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Equatable { - return Operator.neq.infix(lhs, rhs) -} -public func !=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Equatable { - return Operator.neq.infix(lhs, rhs) -} -public func !=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Equatable { - return Operator.neq.infix(lhs, rhs) -} -public func !=(lhs: Expression, rhs: V) -> Expression where V.Datatype : Equatable { - return Operator.neq.infix(lhs, rhs) -} -public func !=(lhs: Expression, rhs: V?) -> Expression where V.Datatype : Equatable { - guard let rhs = rhs else { return "IS NOT".infix(lhs, Expression(value: nil)) } - return Operator.neq.infix(lhs, rhs) -} -public func !=(lhs: V, rhs: Expression) -> Expression where V.Datatype : Equatable { - return Operator.neq.infix(lhs, rhs) -} -public func !=(lhs: V?, rhs: Expression) -> Expression where V.Datatype : Equatable { - guard let lhs = lhs else { return "IS NOT".infix(Expression(value: nil), rhs) } - return Operator.neq.infix(lhs, rhs) -} - -public func >(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.gt.infix(lhs, rhs) -} -public func >(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.gt.infix(lhs, rhs) -} -public func >(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.gt.infix(lhs, rhs) -} -public func >(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.gt.infix(lhs, rhs) -} -public func >(lhs: Expression, rhs: V) -> Expression where V.Datatype : Comparable { - return Operator.gt.infix(lhs, rhs) -} -public func >(lhs: Expression, rhs: V) -> Expression where V.Datatype : Comparable { - return Operator.gt.infix(lhs, rhs) -} -public func >(lhs: V, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.gt.infix(lhs, rhs) -} -public func >(lhs: V, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.gt.infix(lhs, rhs) -} - -public func >=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.gte.infix(lhs, rhs) -} -public func >=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.gte.infix(lhs, rhs) -} -public func >=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.gte.infix(lhs, rhs) -} -public func >=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.gte.infix(lhs, rhs) -} -public func >=(lhs: Expression, rhs: V) -> Expression where V.Datatype : Comparable { - return Operator.gte.infix(lhs, rhs) -} -public func >=(lhs: Expression, rhs: V) -> Expression where V.Datatype : Comparable { - return Operator.gte.infix(lhs, rhs) -} -public func >=(lhs: V, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.gte.infix(lhs, rhs) -} -public func >=(lhs: V, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.gte.infix(lhs, rhs) -} - -public func <(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.lt.infix(lhs, rhs) -} -public func <(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.lt.infix(lhs, rhs) -} -public func <(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.lt.infix(lhs, rhs) -} -public func <(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.lt.infix(lhs, rhs) -} -public func <(lhs: Expression, rhs: V) -> Expression where V.Datatype : Comparable { - return Operator.lt.infix(lhs, rhs) -} -public func <(lhs: Expression, rhs: V) -> Expression where V.Datatype : Comparable { - return Operator.lt.infix(lhs, rhs) -} -public func <(lhs: V, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.lt.infix(lhs, rhs) -} -public func <(lhs: V, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.lt.infix(lhs, rhs) -} - -public func <=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.lte.infix(lhs, rhs) -} -public func <=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.lte.infix(lhs, rhs) -} -public func <=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.lte.infix(lhs, rhs) -} -public func <=(lhs: Expression, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.lte.infix(lhs, rhs) -} -public func <=(lhs: Expression, rhs: V) -> Expression where V.Datatype : Comparable { - return Operator.lte.infix(lhs, rhs) -} -public func <=(lhs: Expression, rhs: V) -> Expression where V.Datatype : Comparable { - return Operator.lte.infix(lhs, rhs) -} -public func <=(lhs: V, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.lte.infix(lhs, rhs) -} -public func <=(lhs: V, rhs: Expression) -> Expression where V.Datatype : Comparable { - return Operator.lte.infix(lhs, rhs) -} - -public func ~=(lhs: ClosedRange, rhs: Expression) -> Expression where V.Datatype : Comparable & Value { - return Expression("\(rhs.template) BETWEEN ? AND ?", rhs.bindings + [lhs.lowerBound.datatypeValue, lhs.upperBound.datatypeValue]) -} - -public func ~=(lhs: ClosedRange, rhs: Expression) -> Expression where V.Datatype : Comparable & Value { - return Expression("\(rhs.template) BETWEEN ? AND ?", rhs.bindings + [lhs.lowerBound.datatypeValue, lhs.upperBound.datatypeValue]) -} - -public func ~=(lhs: Range, rhs: Expression) -> Expression where V.Datatype : Comparable & Value { - return Expression("\(rhs.template) >= ? AND \(rhs.template) < ?", rhs.bindings + [lhs.lowerBound.datatypeValue] + rhs.bindings + [lhs.upperBound.datatypeValue]) -} - -public func ~=(lhs: Range, rhs: Expression) -> Expression where V.Datatype : Comparable & Value { - return Expression("\(rhs.template) >= ? AND \(rhs.template) < ?", rhs.bindings + [lhs.lowerBound.datatypeValue] + rhs.bindings + [lhs.upperBound.datatypeValue]) -} - -public func ~=(lhs: PartialRangeThrough, rhs: Expression) -> Expression where V.Datatype : Comparable & Value { - return Expression("\(rhs.template) <= ?", rhs.bindings + [lhs.upperBound.datatypeValue]) -} - -public func ~=(lhs: PartialRangeThrough, rhs: Expression) -> Expression where V.Datatype : Comparable & Value { - return Expression("\(rhs.template) <= ?", rhs.bindings + [lhs.upperBound.datatypeValue]) -} - -public func ~=(lhs: PartialRangeUpTo, rhs: Expression) -> Expression where V.Datatype : Comparable & Value { - return Expression("\(rhs.template) < ?", rhs.bindings + [lhs.upperBound.datatypeValue]) -} - -public func ~=(lhs: PartialRangeUpTo, rhs: Expression) -> Expression where V.Datatype : Comparable & Value { - return Expression("\(rhs.template) < ?", rhs.bindings + [lhs.upperBound.datatypeValue]) -} - -public func ~=(lhs: PartialRangeFrom, rhs: Expression) -> Expression where V.Datatype : Comparable & Value { - return Expression("\(rhs.template) >= ?", rhs.bindings + [lhs.lowerBound.datatypeValue]) -} - -public func ~=(lhs: PartialRangeFrom, rhs: Expression) -> Expression where V.Datatype : Comparable & Value { - return Expression("\(rhs.template) >= ?", rhs.bindings + [lhs.lowerBound.datatypeValue]) -} - -// MARK: - - -public func &&(lhs: Expression, rhs: Expression) -> Expression { - return Operator.and.infix(lhs, rhs) -} -public func &&(lhs: Expression, rhs: Expression) -> Expression { - return Operator.and.infix(lhs, rhs) -} -public func &&(lhs: Expression, rhs: Expression) -> Expression { - return Operator.and.infix(lhs, rhs) -} -public func &&(lhs: Expression, rhs: Expression) -> Expression { - return Operator.and.infix(lhs, rhs) -} -public func &&(lhs: Expression, rhs: Bool) -> Expression { - return Operator.and.infix(lhs, rhs) -} -public func &&(lhs: Expression, rhs: Bool) -> Expression { - return Operator.and.infix(lhs, rhs) -} -public func &&(lhs: Bool, rhs: Expression) -> Expression { - return Operator.and.infix(lhs, rhs) -} -public func &&(lhs: Bool, rhs: Expression) -> Expression { - return Operator.and.infix(lhs, rhs) -} - -public func ||(lhs: Expression, rhs: Expression) -> Expression { - return Operator.or.infix(lhs, rhs) -} -public func ||(lhs: Expression, rhs: Expression) -> Expression { - return Operator.or.infix(lhs, rhs) -} -public func ||(lhs: Expression, rhs: Expression) -> Expression { - return Operator.or.infix(lhs, rhs) -} -public func ||(lhs: Expression, rhs: Expression) -> Expression { - return Operator.or.infix(lhs, rhs) -} -public func ||(lhs: Expression, rhs: Bool) -> Expression { - return Operator.or.infix(lhs, rhs) -} -public func ||(lhs: Expression, rhs: Bool) -> Expression { - return Operator.or.infix(lhs, rhs) -} -public func ||(lhs: Bool, rhs: Expression) -> Expression { - return Operator.or.infix(lhs, rhs) -} -public func ||(lhs: Bool, rhs: Expression) -> Expression { - return Operator.or.infix(lhs, rhs) -} - -public prefix func !(rhs: Expression) -> Expression { - return Operator.not.wrap(rhs) -} -public prefix func !(rhs: Expression) -> Expression { - return Operator.not.wrap(rhs) -} diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/Query.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/Query.swift deleted file mode 100644 index f6ef6df..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Typed/Query.swift +++ /dev/null @@ -1,1175 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -import Foundation - -public protocol QueryType : Expressible { - - var clauses: QueryClauses { get set } - - init(_ name: String, database: String?) - -} - -public protocol SchemaType : QueryType { - - static var identifier: String { get } - -} - -extension SchemaType { - - /// Builds a copy of the query with the `SELECT` clause applied. - /// - /// let users = Table("users") - /// let id = Expression("id") - /// let email = Expression("email") - /// - /// users.select(id, email) - /// // SELECT "id", "email" FROM "users" - /// - /// - Parameter all: A list of expressions to select. - /// - /// - Returns: A query with the given `SELECT` clause applied. - public func select(_ column1: Expressible, _ more: Expressible...) -> Self { - return select(false, [column1] + more) - } - - /// Builds a copy of the query with the `SELECT DISTINCT` clause applied. - /// - /// let users = Table("users") - /// let email = Expression("email") - /// - /// users.select(distinct: email) - /// // SELECT DISTINCT "email" FROM "users" - /// - /// - Parameter columns: A list of expressions to select. - /// - /// - Returns: A query with the given `SELECT DISTINCT` clause applied. - public func select(distinct column1: Expressible, _ more: Expressible...) -> Self { - return select(true, [column1] + more) - } - - /// Builds a copy of the query with the `SELECT` clause applied. - /// - /// let users = Table("users") - /// let id = Expression("id") - /// let email = Expression("email") - /// - /// users.select([id, email]) - /// // SELECT "id", "email" FROM "users" - /// - /// - Parameter all: A list of expressions to select. - /// - /// - Returns: A query with the given `SELECT` clause applied. - public func select(_ all: [Expressible]) -> Self { - return select(false, all) - } - - /// Builds a copy of the query with the `SELECT DISTINCT` clause applied. - /// - /// let users = Table("users") - /// let email = Expression("email") - /// - /// users.select(distinct: [email]) - /// // SELECT DISTINCT "email" FROM "users" - /// - /// - Parameter columns: A list of expressions to select. - /// - /// - Returns: A query with the given `SELECT DISTINCT` clause applied. - public func select(distinct columns: [Expressible]) -> Self { - return select(true, columns) - } - - /// Builds a copy of the query with the `SELECT *` clause applied. - /// - /// let users = Table("users") - /// - /// users.select(*) - /// // SELECT * FROM "users" - /// - /// - Parameter star: A star literal. - /// - /// - Returns: A query with the given `SELECT *` clause applied. - public func select(_ star: Star) -> Self { - return select([star(nil, nil)]) - } - - /// Builds a copy of the query with the `SELECT DISTINCT *` clause applied. - /// - /// let users = Table("users") - /// - /// users.select(distinct: *) - /// // SELECT DISTINCT * FROM "users" - /// - /// - Parameter star: A star literal. - /// - /// - Returns: A query with the given `SELECT DISTINCT *` clause applied. - public func select(distinct star: Star) -> Self { - return select(distinct: [star(nil, nil)]) - } - - /// Builds a scalar copy of the query with the `SELECT` clause applied. - /// - /// let users = Table("users") - /// let id = Expression("id") - /// - /// users.select(id) - /// // SELECT "id" FROM "users" - /// - /// - Parameter all: A list of expressions to select. - /// - /// - Returns: A query with the given `SELECT` clause applied. - public func select(_ column: Expression) -> ScalarQuery { - return select(false, [column]) - } - public func select(_ column: Expression) -> ScalarQuery { - return select(false, [column]) - } - - /// Builds a scalar copy of the query with the `SELECT DISTINCT` clause - /// applied. - /// - /// let users = Table("users") - /// let email = Expression("email") - /// - /// users.select(distinct: email) - /// // SELECT DISTINCT "email" FROM "users" - /// - /// - Parameter column: A list of expressions to select. - /// - /// - Returns: A query with the given `SELECT DISTINCT` clause applied. - public func select(distinct column: Expression) -> ScalarQuery { - return select(true, [column]) - } - public func select(distinct column: Expression) -> ScalarQuery { - return select(true, [column]) - } - - public var count: ScalarQuery { - return select(Expression.count(*)) - } - -} - -extension QueryType { - - fileprivate func select(_ distinct: Bool, _ columns: [Expressible]) -> Q { - var query = Q.init(clauses.from.name, database: clauses.from.database) - query.clauses = clauses - query.clauses.select = (distinct, columns) - return query - } - - // MARK: UNION - - /// Adds a `UNION` clause to the query. - /// - /// let users = Table("users") - /// let email = Expression("email") - /// - /// users.filter(email == "alice@example.com").union(users.filter(email == "sally@example.com")) - /// // SELECT * FROM "users" WHERE email = 'alice@example.com' UNION SELECT * FROM "users" WHERE email = 'sally@example.com' - /// - /// - Parameters: - /// - /// - table: A query representing the other table. - /// - /// - Returns: A query with the given `UNION` clause applied. - public func union(_ table: QueryType) -> Self { - var query = self - query.clauses.union.append(table) - return query - } - - // MARK: JOIN - - /// Adds a `JOIN` clause to the query. - /// - /// let users = Table("users") - /// let id = Expression("id") - /// let posts = Table("posts") - /// let userId = Expression("user_id") - /// - /// users.join(posts, on: posts[userId] == users[id]) - /// // SELECT * FROM "users" INNER JOIN "posts" ON ("posts"."user_id" = "users"."id") - /// - /// - Parameters: - /// - /// - table: A query representing the other table. - /// - /// - condition: A boolean expression describing the join condition. - /// - /// - Returns: A query with the given `JOIN` clause applied. - public func join(_ table: QueryType, on condition: Expression) -> Self { - return join(table, on: Expression(condition)) - } - - /// Adds a `JOIN` clause to the query. - /// - /// let users = Table("users") - /// let id = Expression("id") - /// let posts = Table("posts") - /// let userId = Expression("user_id") - /// - /// users.join(posts, on: posts[userId] == users[id]) - /// // SELECT * FROM "users" INNER JOIN "posts" ON ("posts"."user_id" = "users"."id") - /// - /// - Parameters: - /// - /// - table: A query representing the other table. - /// - /// - condition: A boolean expression describing the join condition. - /// - /// - Returns: A query with the given `JOIN` clause applied. - public func join(_ table: QueryType, on condition: Expression) -> Self { - return join(.inner, table, on: condition) - } - - /// Adds a `JOIN` clause to the query. - /// - /// let users = Table("users") - /// let id = Expression("id") - /// let posts = Table("posts") - /// let userId = Expression("user_id") - /// - /// users.join(.LeftOuter, posts, on: posts[userId] == users[id]) - /// // SELECT * FROM "users" LEFT OUTER JOIN "posts" ON ("posts"."user_id" = "users"."id") - /// - /// - Parameters: - /// - /// - type: The `JOIN` operator. - /// - /// - table: A query representing the other table. - /// - /// - condition: A boolean expression describing the join condition. - /// - /// - Returns: A query with the given `JOIN` clause applied. - public func join(_ type: JoinType, _ table: QueryType, on condition: Expression) -> Self { - return join(type, table, on: Expression(condition)) - } - - /// Adds a `JOIN` clause to the query. - /// - /// let users = Table("users") - /// let id = Expression("id") - /// let posts = Table("posts") - /// let userId = Expression("user_id") - /// - /// users.join(.LeftOuter, posts, on: posts[userId] == users[id]) - /// // SELECT * FROM "users" LEFT OUTER JOIN "posts" ON ("posts"."user_id" = "users"."id") - /// - /// - Parameters: - /// - /// - type: The `JOIN` operator. - /// - /// - table: A query representing the other table. - /// - /// - condition: A boolean expression describing the join condition. - /// - /// - Returns: A query with the given `JOIN` clause applied. - public func join(_ type: JoinType, _ table: QueryType, on condition: Expression) -> Self { - var query = self - query.clauses.join.append((type: type, query: table, condition: table.clauses.filters.map { condition && $0 } ?? condition as Expressible)) - return query - } - - // MARK: WHERE - - /// Adds a condition to the query’s `WHERE` clause. - /// - /// let users = Table("users") - /// let id = Expression("id") - /// - /// users.filter(id == 1) - /// // SELECT * FROM "users" WHERE ("id" = 1) - /// - /// - Parameter condition: A boolean expression to filter on. - /// - /// - Returns: A query with the given `WHERE` clause applied. - public func filter(_ predicate: Expression) -> Self { - return filter(Expression(predicate)) - } - - /// Adds a condition to the query’s `WHERE` clause. - /// - /// let users = Table("users") - /// let age = Expression("age") - /// - /// users.filter(age >= 35) - /// // SELECT * FROM "users" WHERE ("age" >= 35) - /// - /// - Parameter condition: A boolean expression to filter on. - /// - /// - Returns: A query with the given `WHERE` clause applied. - public func filter(_ predicate: Expression) -> Self { - var query = self - query.clauses.filters = query.clauses.filters.map { $0 && predicate } ?? predicate - return query - } - - /// Adds a condition to the query’s `WHERE` clause. - /// This is an alias for `filter(predicate)` - public func `where`(_ predicate: Expression) -> Self { - return `where`(Expression(predicate)) - } - - /// Adds a condition to the query’s `WHERE` clause. - /// This is an alias for `filter(predicate)` - public func `where`(_ predicate: Expression) -> Self { - return filter(predicate) - } - - // MARK: GROUP BY - - /// Sets a `GROUP BY` clause on the query. - /// - /// - Parameter by: A list of columns to group by. - /// - /// - Returns: A query with the given `GROUP BY` clause applied. - public func group(_ by: Expressible...) -> Self { - return group(by) - } - - /// Sets a `GROUP BY` clause on the query. - /// - /// - Parameter by: A list of columns to group by. - /// - /// - Returns: A query with the given `GROUP BY` clause applied. - public func group(_ by: [Expressible]) -> Self { - return group(by, nil) - } - - /// Sets a `GROUP BY`-`HAVING` clause on the query. - /// - /// - Parameters: - /// - /// - by: A column to group by. - /// - /// - having: A condition determining which groups are returned. - /// - /// - Returns: A query with the given `GROUP BY`–`HAVING` clause applied. - public func group(_ by: Expressible, having: Expression) -> Self { - return group([by], having: having) - } - - /// Sets a `GROUP BY`-`HAVING` clause on the query. - /// - /// - Parameters: - /// - /// - by: A column to group by. - /// - /// - having: A condition determining which groups are returned. - /// - /// - Returns: A query with the given `GROUP BY`–`HAVING` clause applied. - public func group(_ by: Expressible, having: Expression) -> Self { - return group([by], having: having) - } - - /// Sets a `GROUP BY`-`HAVING` clause on the query. - /// - /// - Parameters: - /// - /// - by: A list of columns to group by. - /// - /// - having: A condition determining which groups are returned. - /// - /// - Returns: A query with the given `GROUP BY`–`HAVING` clause applied. - public func group(_ by: [Expressible], having: Expression) -> Self { - return group(by, Expression(having)) - } - - /// Sets a `GROUP BY`-`HAVING` clause on the query. - /// - /// - Parameters: - /// - /// - by: A list of columns to group by. - /// - /// - having: A condition determining which groups are returned. - /// - /// - Returns: A query with the given `GROUP BY`–`HAVING` clause applied. - public func group(_ by: [Expressible], having: Expression) -> Self { - return group(by, having) - } - - fileprivate func group(_ by: [Expressible], _ having: Expression?) -> Self { - var query = self - query.clauses.group = (by, having) - return query - } - - // MARK: ORDER BY - - /// Sets an `ORDER BY` clause on the query. - /// - /// let users = Table("users") - /// let email = Expression("email") - /// let name = Expression("name") - /// - /// users.order(email.desc, name.asc) - /// // SELECT * FROM "users" ORDER BY "email" DESC, "name" ASC - /// - /// - Parameter by: An ordered list of columns and directions to sort by. - /// - /// - Returns: A query with the given `ORDER BY` clause applied. - public func order(_ by: Expressible...) -> Self { - return order(by) - } - - /// Sets an `ORDER BY` clause on the query. - /// - /// let users = Table("users") - /// let email = Expression("email") - /// let name = Expression("name") - /// - /// users.order([email.desc, name.asc]) - /// // SELECT * FROM "users" ORDER BY "email" DESC, "name" ASC - /// - /// - Parameter by: An ordered list of columns and directions to sort by. - /// - /// - Returns: A query with the given `ORDER BY` clause applied. - public func order(_ by: [Expressible]) -> Self { - var query = self - query.clauses.order = by - return query - } - - // MARK: LIMIT/OFFSET - - /// Sets the LIMIT clause (and resets any OFFSET clause) on the query. - /// - /// let users = Table("users") - /// - /// users.limit(20) - /// // SELECT * FROM "users" LIMIT 20 - /// - /// - Parameter length: The maximum number of rows to return (or `nil` to - /// return unlimited rows). - /// - /// - Returns: A query with the given LIMIT clause applied. - public func limit(_ length: Int?) -> Self { - return limit(length, nil) - } - - /// Sets LIMIT and OFFSET clauses on the query. - /// - /// let users = Table("users") - /// - /// users.limit(20, offset: 20) - /// // SELECT * FROM "users" LIMIT 20 OFFSET 20 - /// - /// - Parameters: - /// - /// - length: The maximum number of rows to return. - /// - /// - offset: The number of rows to skip. - /// - /// - Returns: A query with the given LIMIT and OFFSET clauses applied. - public func limit(_ length: Int, offset: Int) -> Self { - return limit(length, offset) - } - - // prevents limit(nil, offset: 5) - fileprivate func limit(_ length: Int?, _ offset: Int?) -> Self { - var query = self - query.clauses.limit = length.map { ($0, offset) } - return query - } - - // MARK: - Clauses - // - // MARK: SELECT - - // MARK: - - - fileprivate var selectClause: Expressible { - return " ".join([ - Expression(literal: clauses.select.distinct ? "SELECT DISTINCT" : "SELECT"), - ", ".join(clauses.select.columns), - Expression(literal: "FROM"), - tableName(alias: true) - ]) - } - - fileprivate var joinClause: Expressible? { - guard !clauses.join.isEmpty else { - return nil - } - - return " ".join(clauses.join.map { arg in - let (type, query, condition) = arg - return " ".join([ - Expression(literal: "\(type.rawValue) JOIN"), - query.tableName(alias: true), - Expression(literal: "ON"), - condition - ]) - }) - } - - fileprivate var whereClause: Expressible? { - guard let filters = clauses.filters else { - return nil - } - - return " ".join([ - Expression(literal: "WHERE"), - filters - ]) - } - - fileprivate var groupByClause: Expressible? { - guard let group = clauses.group else { - return nil - } - - let groupByClause = " ".join([ - Expression(literal: "GROUP BY"), - ", ".join(group.by) - ]) - - guard let having = group.having else { - return groupByClause - } - - return " ".join([ - groupByClause, - " ".join([ - Expression(literal: "HAVING"), - having - ]) - ]) - } - - fileprivate var orderClause: Expressible? { - guard !clauses.order.isEmpty else { - return nil - } - - return " ".join([ - Expression(literal: "ORDER BY"), - ", ".join(clauses.order) - ]) - } - - fileprivate var limitOffsetClause: Expressible? { - guard let limit = clauses.limit else { - return nil - } - - let limitClause = Expression(literal: "LIMIT \(limit.length)") - - guard let offset = limit.offset else { - return limitClause - } - - return " ".join([ - limitClause, - Expression(literal: "OFFSET \(offset)") - ]) - } - - fileprivate var unionClause: Expressible? { - guard !clauses.union.isEmpty else { - return nil - } - - return " ".join(clauses.union.map { query in - " ".join([ - Expression(literal: "UNION"), - query - ]) - }) - } - - // MARK: - - - public func alias(_ aliasName: String) -> Self { - var query = self - query.clauses.from = (clauses.from.name, aliasName, clauses.from.database) - return query - } - - // MARK: - Operations - // - // MARK: INSERT - - public func insert(_ value: Setter, _ more: Setter...) -> Insert { - return insert([value] + more) - } - - public func insert(_ values: [Setter]) -> Insert { - return insert(nil, values) - } - - public func insert(or onConflict: OnConflict, _ values: Setter...) -> Insert { - return insert(or: onConflict, values) - } - - public func insert(or onConflict: OnConflict, _ values: [Setter]) -> Insert { - return insert(onConflict, values) - } - - fileprivate func insert(_ or: OnConflict?, _ values: [Setter]) -> Insert { - let insert = values.reduce((columns: [Expressible](), values: [Expressible]())) { insert, setter in - (insert.columns + [setter.column], insert.values + [setter.value]) - } - - let clauses: [Expressible?] = [ - Expression(literal: "INSERT"), - or.map { Expression(literal: "OR \($0.rawValue)") }, - Expression(literal: "INTO"), - tableName(), - "".wrap(insert.columns) as Expression, - Expression(literal: "VALUES"), - "".wrap(insert.values) as Expression, - whereClause - ] - - return Insert(" ".join(clauses.compactMap { $0 }).expression) - } - - /// Runs an `INSERT` statement against the query with `DEFAULT VALUES`. - public func insert() -> Insert { - return Insert(" ".join([ - Expression(literal: "INSERT INTO"), - tableName(), - Expression(literal: "DEFAULT VALUES") - ]).expression) - } - - /// Runs an `INSERT` statement against the query with the results of another - /// query. - /// - /// - Parameter query: A query to `SELECT` results from. - /// - /// - Returns: The number of updated rows and statement. - public func insert(_ query: QueryType) -> Update { - return Update(" ".join([ - Expression(literal: "INSERT INTO"), - tableName(), - query.expression - ]).expression) - } - - // MARK: UPDATE - - public func update(_ values: Setter...) -> Update { - return update(values) - } - - public func update(_ values: [Setter]) -> Update { - let clauses: [Expressible?] = [ - Expression(literal: "UPDATE"), - tableName(), - Expression(literal: "SET"), - ", ".join(values.map { " = ".join([$0.column, $0.value]) }), - whereClause, - orderClause, - limitOffsetClause - ] - - return Update(" ".join(clauses.compactMap { $0 }).expression) - } - - // MARK: DELETE - - public func delete() -> Delete { - let clauses: [Expressible?] = [ - Expression(literal: "DELETE FROM"), - tableName(), - whereClause, - orderClause, - limitOffsetClause - ] - - return Delete(" ".join(clauses.compactMap { $0 }).expression) - } - - // MARK: EXISTS - - public var exists: Select { - return Select(" ".join([ - Expression(literal: "SELECT EXISTS"), - "".wrap(expression) as Expression - ]).expression) - } - - // MARK: - - - /// Prefixes a column expression with the query’s table name or alias. - /// - /// - Parameter column: A column expression. - /// - /// - Returns: A column expression namespaced with the query’s table name or - /// alias. - public func namespace(_ column: Expression) -> Expression { - return Expression(".".join([tableName(), column]).expression) - } - - public subscript(column: Expression) -> Expression { - return namespace(column) - } - - public subscript(column: Expression) -> Expression { - return namespace(column) - } - - /// Prefixes a star with the query’s table name or alias. - /// - /// - Parameter star: A literal `*`. - /// - /// - Returns: A `*` expression namespaced with the query’s table name or - /// alias. - public subscript(star: Star) -> Expression { - return namespace(star(nil, nil)) - } - - // MARK: - - - // TODO: alias support - func tableName(alias aliased: Bool = false) -> Expressible { - guard let alias = clauses.from.alias , aliased else { - return database(namespace: clauses.from.alias ?? clauses.from.name) - } - - return " ".join([ - database(namespace: clauses.from.name), - Expression(literal: "AS"), - Expression(alias) - ]) - } - - func tableName(qualified: Bool) -> Expressible { - if qualified { - return tableName() - } - return Expression(clauses.from.alias ?? clauses.from.name) - } - - func database(namespace name: String) -> Expressible { - let name = Expression(name) - - guard let database = clauses.from.database else { - return name - } - - return ".".join([Expression(database), name]) - } - - public var expression: Expression { - let clauses: [Expressible?] = [ - selectClause, - joinClause, - whereClause, - groupByClause, - unionClause, - orderClause, - limitOffsetClause - ] - - return " ".join(clauses.compactMap { $0 }).expression - } - -} - -// TODO: decide: simplify the below with a boxed type instead - -/// Queries a collection of chainable helper functions and expressions to build -/// executable SQL statements. -public struct Table : SchemaType { - - public static let identifier = "TABLE" - - public var clauses: QueryClauses - - public init(_ name: String, database: String? = nil) { - clauses = QueryClauses(name, alias: nil, database: database) - } - -} - -public struct View : SchemaType { - - public static let identifier = "VIEW" - - public var clauses: QueryClauses - - public init(_ name: String, database: String? = nil) { - clauses = QueryClauses(name, alias: nil, database: database) - } - -} - -public struct VirtualTable : SchemaType { - - public static let identifier = "VIRTUAL TABLE" - - public var clauses: QueryClauses - - public init(_ name: String, database: String? = nil) { - clauses = QueryClauses(name, alias: nil, database: database) - } - -} - -// TODO: make `ScalarQuery` work in `QueryType.select()`, `.filter()`, etc. - -public struct ScalarQuery : QueryType { - - public var clauses: QueryClauses - - public init(_ name: String, database: String? = nil) { - clauses = QueryClauses(name, alias: nil, database: database) - } - -} - -// TODO: decide: simplify the below with a boxed type instead - -public struct Select : ExpressionType { - - public var template: String - public var bindings: [Binding?] - - public init(_ template: String, _ bindings: [Binding?]) { - self.template = template - self.bindings = bindings - } - -} - -public struct Insert : ExpressionType { - - public var template: String - public var bindings: [Binding?] - - public init(_ template: String, _ bindings: [Binding?]) { - self.template = template - self.bindings = bindings - } - -} - -public struct Update : ExpressionType { - - public var template: String - public var bindings: [Binding?] - - public init(_ template: String, _ bindings: [Binding?]) { - self.template = template - self.bindings = bindings - } - -} - -public struct Delete : ExpressionType { - - public var template: String - public var bindings: [Binding?] - - public init(_ template: String, _ bindings: [Binding?]) { - self.template = template - self.bindings = bindings - } - -} - - -public struct RowIterator: FailableIterator { - public typealias Element = Row - let statement: Statement - let columnNames: [String: Int] - - public func failableNext() throws -> Row? { - return try statement.failableNext().flatMap { Row(columnNames, $0) } - } - - public func map(_ transform: (Element) throws -> T) throws -> [T] { - var elements = [T]() - while let row = try failableNext() { - elements.append(try transform(row)) - } - return elements - } -} - -extension Connection { - - public func prepare(_ query: QueryType) throws -> AnySequence { - let expression = query.expression - let statement = try prepare(expression.template, expression.bindings) - - let columnNames = try columnNamesForQuery(query) - - return AnySequence { - AnyIterator { statement.next().map { Row(columnNames, $0) } } - } - } - - - public func prepareRowIterator(_ query: QueryType) throws -> RowIterator { - let expression = query.expression - let statement = try prepare(expression.template, expression.bindings) - return RowIterator(statement: statement, columnNames: try columnNamesForQuery(query)) - } - - private func columnNamesForQuery(_ query: QueryType) throws -> [String: Int] { - var (columnNames, idx) = ([String: Int](), 0) - column: for each in query.clauses.select.columns { - var names = each.expression.template.split { $0 == "." }.map(String.init) - let column = names.removeLast() - let namespace = names.joined(separator: ".") - - func expandGlob(_ namespace: Bool) -> ((QueryType) throws -> Void) { - return { (query: QueryType) throws -> (Void) in - var q = type(of: query).init(query.clauses.from.name, database: query.clauses.from.database) - q.clauses.select = query.clauses.select - let e = q.expression - var names = try self.prepare(e.template, e.bindings).columnNames.map { $0.quote() } - if namespace { names = names.map { "\(query.tableName().expression.template).\($0)" } } - for name in names { columnNames[name] = idx; idx += 1 } - } - } - - if column == "*" { - var select = query - select.clauses.select = (false, [Expression(literal: "*") as Expressible]) - let queries = [select] + query.clauses.join.map { $0.query } - if !namespace.isEmpty { - for q in queries { - if q.tableName().expression.template == namespace { - try expandGlob(true)(q) - continue column - } - throw QueryError.noSuchTable(name: namespace) - } - throw QueryError.noSuchTable(name: namespace) - } - for q in queries { - try expandGlob(query.clauses.join.count > 0)(q) - } - continue - } - - columnNames[each.expression.template] = idx - idx += 1 - } - return columnNames - } - - public func scalar(_ query: ScalarQuery) throws -> V { - let expression = query.expression - return value(try scalar(expression.template, expression.bindings)) - } - - public func scalar(_ query: ScalarQuery) throws -> V.ValueType? { - let expression = query.expression - guard let value = try scalar(expression.template, expression.bindings) as? V.Datatype else { return nil } - return V.fromDatatypeValue(value) - } - - public func scalar(_ query: Select) throws -> V { - let expression = query.expression - return value(try scalar(expression.template, expression.bindings)) - } - - public func scalar(_ query: Select) throws -> V.ValueType? { - let expression = query.expression - guard let value = try scalar(expression.template, expression.bindings) as? V.Datatype else { return nil } - return V.fromDatatypeValue(value) - } - - public func pluck(_ query: QueryType) throws -> Row? { - return try prepareRowIterator(query.limit(1, query.clauses.limit?.offset)).failableNext() - } - - /// Runs an `Insert` query. - /// - /// - SeeAlso: `QueryType.insert(value:_:)` - /// - SeeAlso: `QueryType.insert(values:)` - /// - SeeAlso: `QueryType.insert(or:_:)` - /// - SeeAlso: `QueryType.insert()` - /// - /// - Parameter query: An insert query. - /// - /// - Returns: The insert’s rowid. - @discardableResult public func run(_ query: Insert) throws -> Int64 { - let expression = query.expression - return try sync { - try self.run(expression.template, expression.bindings) - return self.lastInsertRowid - } - } - - /// Runs an `Update` query. - /// - /// - SeeAlso: `QueryType.insert(query:)` - /// - SeeAlso: `QueryType.update(values:)` - /// - /// - Parameter query: An update query. - /// - /// - Returns: The number of updated rows. - @discardableResult public func run(_ query: Update) throws -> Int { - let expression = query.expression - return try sync { - try self.run(expression.template, expression.bindings) - return self.changes - } - } - - /// Runs a `Delete` query. - /// - /// - SeeAlso: `QueryType.delete()` - /// - /// - Parameter query: A delete query. - /// - /// - Returns: The number of deleted rows. - @discardableResult public func run(_ query: Delete) throws -> Int { - let expression = query.expression - return try sync { - try self.run(expression.template, expression.bindings) - return self.changes - } - } - -} - -public struct Row { - - let columnNames: [String: Int] - - fileprivate let values: [Binding?] - - internal init(_ columnNames: [String: Int], _ values: [Binding?]) { - self.columnNames = columnNames - self.values = values - } - - func hasValue(for column: String) -> Bool { - guard let idx = columnNames[column.quote()] else { - return false - } - return values[idx] != nil - } - - /// Returns a row’s value for the given column. - /// - /// - Parameter column: An expression representing a column selected in a Query. - /// - /// - Returns: The value for the given column. - public func get(_ column: Expression) throws -> V { - if let value = try get(Expression(column)) { - return value - } else { - throw QueryError.unexpectedNullValue(name: column.template) - } - } - - public func get(_ column: Expression) throws -> V? { - func valueAtIndex(_ idx: Int) -> V? { - guard let value = values[idx] as? V.Datatype else { return nil } - return V.fromDatatypeValue(value) as? V - } - - guard let idx = columnNames[column.template] else { - let similar = Array(columnNames.keys).filter { $0.hasSuffix(".\(column.template)") } - - switch similar.count { - case 0: - throw QueryError.noSuchColumn(name: column.template, columns: columnNames.keys.sorted()) - case 1: - return valueAtIndex(columnNames[similar[0]]!) - default: - throw QueryError.ambiguousColumn(name: column.template, similar: similar) - } - } - - return valueAtIndex(idx) - } - - public subscript(column: Expression) -> T { - return try! get(column) - } - - public subscript(column: Expression) -> T? { - return try! get(column) - } -} - -/// Determines the join operator for a query’s `JOIN` clause. -public enum JoinType : String { - - /// A `CROSS` join. - case cross = "CROSS" - - /// An `INNER` join. - case inner = "INNER" - - /// A `LEFT OUTER` join. - case leftOuter = "LEFT OUTER" - -} - -/// ON CONFLICT resolutions. -public enum OnConflict: String { - - case replace = "REPLACE" - - case rollback = "ROLLBACK" - - case abort = "ABORT" - - case fail = "FAIL" - - case ignore = "IGNORE" - -} - -// MARK: - Private - -public struct QueryClauses { - - var select = (distinct: false, columns: [Expression(literal: "*") as Expressible]) - - var from: (name: String, alias: String?, database: String?) - - var join = [(type: JoinType, query: QueryType, condition: Expressible)]() - - var filters: Expression? - - var group: (by: [Expressible], having: Expression?)? - - var order = [Expressible]() - - var limit: (length: Int, offset: Int?)? - - var union = [QueryType]() - - fileprivate init(_ name: String, alias: String?, database: String?) { - self.from = (name, alias, database) - } - -} - diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/Schema.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/Schema.swift deleted file mode 100644 index febfe68..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Typed/Schema.swift +++ /dev/null @@ -1,517 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -extension SchemaType { - - // MARK: - DROP TABLE / VIEW / VIRTUAL TABLE - - public func drop(ifExists: Bool = false) -> String { - return drop("TABLE", tableName(), ifExists) - } - -} - -extension Table { - - // MARK: - CREATE TABLE - - public func create(temporary: Bool = false, ifNotExists: Bool = false, withoutRowid: Bool = false, block: (TableBuilder) -> Void) -> String { - let builder = TableBuilder() - - block(builder) - - let clauses: [Expressible?] = [ - create(Table.identifier, tableName(), temporary ? .temporary : nil, ifNotExists), - "".wrap(builder.definitions) as Expression, - withoutRowid ? Expression(literal: "WITHOUT ROWID") : nil - ] - - return " ".join(clauses.compactMap { $0 }).asSQL() - } - - public func create(_ query: QueryType, temporary: Bool = false, ifNotExists: Bool = false) -> String { - let clauses: [Expressible?] = [ - create(Table.identifier, tableName(), temporary ? .temporary : nil, ifNotExists), - Expression(literal: "AS"), - query - ] - - return " ".join(clauses.compactMap { $0 }).asSQL() - } - - // MARK: - ALTER TABLE … ADD COLUMN - - public func addColumn(_ name: Expression, check: Expression? = nil, defaultValue: V) -> String { - return addColumn(definition(name, V.declaredDatatype, nil, false, false, check, defaultValue, nil, nil)) - } - - public func addColumn(_ name: Expression, check: Expression, defaultValue: V) -> String { - return addColumn(definition(name, V.declaredDatatype, nil, false, false, check, defaultValue, nil, nil)) - } - - public func addColumn(_ name: Expression, check: Expression? = nil, defaultValue: V? = nil) -> String { - return addColumn(definition(name, V.declaredDatatype, nil, true, false, check, defaultValue, nil, nil)) - } - - public func addColumn(_ name: Expression, check: Expression, defaultValue: V? = nil) -> String { - return addColumn(definition(name, V.declaredDatatype, nil, true, false, check, defaultValue, nil, nil)) - } - - public func addColumn(_ name: Expression, unique: Bool = false, check: Expression? = nil, references table: QueryType, _ other: Expression) -> String where V.Datatype == Int64 { - return addColumn(definition(name, V.declaredDatatype, nil, false, unique, check, nil, (table, other), nil)) - } - - public func addColumn(_ name: Expression, unique: Bool = false, check: Expression, references table: QueryType, _ other: Expression) -> String where V.Datatype == Int64 { - return addColumn(definition(name, V.declaredDatatype, nil, false, unique, check, nil, (table, other), nil)) - } - - public func addColumn(_ name: Expression, unique: Bool = false, check: Expression? = nil, references table: QueryType, _ other: Expression) -> String where V.Datatype == Int64 { - return addColumn(definition(name, V.declaredDatatype, nil, true, unique, check, nil, (table, other), nil)) - } - - public func addColumn(_ name: Expression, unique: Bool = false, check: Expression, references table: QueryType, _ other: Expression) -> String where V.Datatype == Int64 { - return addColumn(definition(name, V.declaredDatatype, nil, true, unique, check, nil, (table, other), nil)) - } - - public func addColumn(_ name: Expression, check: Expression? = nil, defaultValue: V, collate: Collation) -> String where V.Datatype == String { - return addColumn(definition(name, V.declaredDatatype, nil, false, false, check, defaultValue, nil, collate)) - } - - public func addColumn(_ name: Expression, check: Expression, defaultValue: V, collate: Collation) -> String where V.Datatype == String { - return addColumn(definition(name, V.declaredDatatype, nil, false, false, check, defaultValue, nil, collate)) - } - - public func addColumn(_ name: Expression, check: Expression? = nil, defaultValue: V? = nil, collate: Collation) -> String where V.Datatype == String { - return addColumn(definition(name, V.declaredDatatype, nil, true, false, check, defaultValue, nil, collate)) - } - - public func addColumn(_ name: Expression, check: Expression, defaultValue: V? = nil, collate: Collation) -> String where V.Datatype == String { - return addColumn(definition(name, V.declaredDatatype, nil, true, false, check, defaultValue, nil, collate)) - } - - fileprivate func addColumn(_ expression: Expressible) -> String { - return " ".join([ - Expression(literal: "ALTER TABLE"), - tableName(), - Expression(literal: "ADD COLUMN"), - expression - ]).asSQL() - } - - // MARK: - ALTER TABLE … RENAME TO - - public func rename(_ to: Table) -> String { - return rename(to: to) - } - - // MARK: - CREATE INDEX - - public func createIndex(_ columns: Expressible..., unique: Bool = false, ifNotExists: Bool = false) -> String { - let clauses: [Expressible?] = [ - create("INDEX", indexName(columns), unique ? .unique : nil, ifNotExists), - Expression(literal: "ON"), - tableName(qualified: false), - "".wrap(columns) as Expression - ] - - return " ".join(clauses.compactMap { $0 }).asSQL() - } - - // MARK: - DROP INDEX - - - public func dropIndex(_ columns: Expressible..., ifExists: Bool = false) -> String { - return drop("INDEX", indexName(columns), ifExists) - } - - fileprivate func indexName(_ columns: [Expressible]) -> Expressible { - let string = (["index", clauses.from.name, "on"] + columns.map { $0.expression.template }).joined(separator: " ").lowercased() - - let index = string.reduce("") { underscored, character in - guard character != "\"" else { - return underscored - } - guard "a"..."z" ~= character || "0"..."9" ~= character else { - return underscored + "_" - } - return underscored + String(character) - } - - return database(namespace: index) - } - -} - -extension View { - - // MARK: - CREATE VIEW - - public func create(_ query: QueryType, temporary: Bool = false, ifNotExists: Bool = false) -> String { - let clauses: [Expressible?] = [ - create(View.identifier, tableName(), temporary ? .temporary : nil, ifNotExists), - Expression(literal: "AS"), - query - ] - - return " ".join(clauses.compactMap { $0 }).asSQL() - } - - // MARK: - DROP VIEW - - public func drop(ifExists: Bool = false) -> String { - return drop("VIEW", tableName(), ifExists) - } - -} - -extension VirtualTable { - - // MARK: - CREATE VIRTUAL TABLE - - public func create(_ using: Module, ifNotExists: Bool = false) -> String { - let clauses: [Expressible?] = [ - create(VirtualTable.identifier, tableName(), nil, ifNotExists), - Expression(literal: "USING"), - using - ] - - return " ".join(clauses.compactMap { $0 }).asSQL() - } - - // MARK: - ALTER TABLE … RENAME TO - - public func rename(_ to: VirtualTable) -> String { - return rename(to: to) - } - -} - -public final class TableBuilder { - - fileprivate var definitions = [Expressible]() - - public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: Expression? = nil) { - column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, nil) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: V) { - column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, nil) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: Expression? = nil) { - column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, nil) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: V) { - column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, nil) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: Expression? = nil) { - column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: Expression) { - column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: V) { - column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: Expression? = nil) { - column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: Expression) { - column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: V) { - column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil) - } - - public func column(_ name: Expression, primaryKey: Bool, check: Expression? = nil, defaultValue: Expression? = nil) { - column(name, V.declaredDatatype, primaryKey ? .default : nil, false, false, check, defaultValue, nil, nil) - } - - public func column(_ name: Expression, primaryKey: Bool, check: Expression, defaultValue: Expression? = nil) { - column(name, V.declaredDatatype, primaryKey ? .default : nil, false, false, check, defaultValue, nil, nil) - } - - public func column(_ name: Expression, primaryKey: PrimaryKey, check: Expression? = nil) where V.Datatype == Int64 { - column(name, V.declaredDatatype, primaryKey, false, false, check, nil, nil, nil) - } - - public func column(_ name: Expression, primaryKey: PrimaryKey, check: Expression) where V.Datatype == Int64 { - column(name, V.declaredDatatype, primaryKey, false, false, check, nil, nil, nil) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, references table: QueryType, _ other: Expression) where V.Datatype == Int64 { - column(name, V.declaredDatatype, nil, false, unique, check, nil, (table, other), nil) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression, references table: QueryType, _ other: Expression) where V.Datatype == Int64 { - column(name, V.declaredDatatype, nil, false, unique, check, nil, (table, other), nil) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, references table: QueryType, _ other: Expression) where V.Datatype == Int64 { - column(name, V.declaredDatatype, nil, true, unique, check, nil, (table, other), nil) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression, references table: QueryType, _ other: Expression) where V.Datatype == Int64 { - column(name, V.declaredDatatype, nil, true, unique, check, nil, (table, other), nil) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: Expression? = nil, collate: Collation) where V.Datatype == String { - column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: V, collate: Collation) where V.Datatype == String { - column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: Expression? = nil, collate: Collation) where V.Datatype == String { - column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: V, collate: Collation) where V.Datatype == String { - column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: Expression? = nil, collate: Collation) where V.Datatype == String { - column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, collate) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: Expression, collate: Collation) where V.Datatype == String { - column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, collate) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression? = nil, defaultValue: V, collate: Collation) where V.Datatype == String { - column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, collate) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: Expression? = nil, collate: Collation) where V.Datatype == String { - column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, collate) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: Expression, collate: Collation) where V.Datatype == String { - column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, collate) - } - - public func column(_ name: Expression, unique: Bool = false, check: Expression, defaultValue: V, collate: Collation) where V.Datatype == String { - column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, collate) - } - - fileprivate func column(_ name: Expressible, _ datatype: String, _ primaryKey: PrimaryKey?, _ null: Bool, _ unique: Bool, _ check: Expressible?, _ defaultValue: Expressible?, _ references: (QueryType, Expressible)?, _ collate: Collation?) { - definitions.append(definition(name, datatype, primaryKey, null, unique, check, defaultValue, references, collate)) - } - - // MARK: - - - public func primaryKey(_ column: Expression) { - primaryKey([column]) - } - - public func primaryKey(_ compositeA: Expression, _ b: Expression) { - primaryKey([compositeA, b]) - } - - public func primaryKey(_ compositeA: Expression, _ b: Expression, _ c: Expression) { - primaryKey([compositeA, b, c]) - } - - public func primaryKey(_ compositeA: Expression, _ b: Expression, _ c: Expression, _ d: Expression) { - primaryKey([compositeA, b, c, d]) - } - - fileprivate func primaryKey(_ composite: [Expressible]) { - definitions.append("PRIMARY KEY".prefix(composite)) - } - - public func unique(_ columns: Expressible...) { - unique(columns) - } - - public func unique(_ columns: [Expressible]) { - definitions.append("UNIQUE".prefix(columns)) - } - - public func check(_ condition: Expression) { - check(Expression(condition)) - } - - public func check(_ condition: Expression) { - definitions.append("CHECK".prefix(condition)) - } - - public enum Dependency: String { - - case noAction = "NO ACTION" - - case restrict = "RESTRICT" - - case setNull = "SET NULL" - - case setDefault = "SET DEFAULT" - - case cascade = "CASCADE" - - } - - public func foreignKey(_ column: Expression, references table: QueryType, _ other: Expression, update: Dependency? = nil, delete: Dependency? = nil) { - foreignKey(column, (table, other), update, delete) - } - - public func foreignKey(_ column: Expression, references table: QueryType, _ other: Expression, update: Dependency? = nil, delete: Dependency? = nil) { - foreignKey(column, (table, other), update, delete) - } - - public func foreignKey(_ composite: (Expression, Expression), references table: QueryType, _ other: (Expression, Expression), update: Dependency? = nil, delete: Dependency? = nil) { - let composite = ", ".join([composite.0, composite.1]) - let references = (table, ", ".join([other.0, other.1])) - - foreignKey(composite, references, update, delete) - } - - public func foreignKey(_ composite: (Expression, Expression, Expression), references table: QueryType, _ other: (Expression, Expression, Expression), update: Dependency? = nil, delete: Dependency? = nil) { - let composite = ", ".join([composite.0, composite.1, composite.2]) - let references = (table, ", ".join([other.0, other.1, other.2])) - - foreignKey(composite, references, update, delete) - } - - fileprivate func foreignKey(_ column: Expressible, _ references: (QueryType, Expressible), _ update: Dependency?, _ delete: Dependency?) { - let clauses: [Expressible?] = [ - "FOREIGN KEY".prefix(column), - reference(references), - update.map { Expression(literal: "ON UPDATE \($0.rawValue)") }, - delete.map { Expression(literal: "ON DELETE \($0.rawValue)") } - ] - - definitions.append(" ".join(clauses.compactMap { $0 })) - } - -} - -public enum PrimaryKey { - - case `default` - - case autoincrement - -} - -public struct Module { - - fileprivate let name: String - - fileprivate let arguments: [Expressible] - - public init(_ name: String, _ arguments: [Expressible]) { - self.init(name: name.quote(), arguments: arguments) - } - - init(name: String, arguments: [Expressible]) { - self.name = name - self.arguments = arguments - } - -} - -extension Module : Expressible { - - public var expression: Expression { - return name.wrap(arguments) - } - -} - -// MARK: - Private - -private extension QueryType { - - func create(_ identifier: String, _ name: Expressible, _ modifier: Modifier?, _ ifNotExists: Bool) -> Expressible { - let clauses: [Expressible?] = [ - Expression(literal: "CREATE"), - modifier.map { Expression(literal: $0.rawValue) }, - Expression(literal: identifier), - ifNotExists ? Expression(literal: "IF NOT EXISTS") : nil, - name - ] - - return " ".join(clauses.compactMap { $0 }) - } - - func rename(to: Self) -> String { - return " ".join([ - Expression(literal: "ALTER TABLE"), - tableName(), - Expression(literal: "RENAME TO"), - Expression(to.clauses.from.name) - ]).asSQL() - } - - func drop(_ identifier: String, _ name: Expressible, _ ifExists: Bool) -> String { - let clauses: [Expressible?] = [ - Expression(literal: "DROP \(identifier)"), - ifExists ? Expression(literal: "IF EXISTS") : nil, - name - ] - - return " ".join(clauses.compactMap { $0 }).asSQL() - } - -} - -private func definition(_ column: Expressible, _ datatype: String, _ primaryKey: PrimaryKey?, _ null: Bool, _ unique: Bool, _ check: Expressible?, _ defaultValue: Expressible?, _ references: (QueryType, Expressible)?, _ collate: Collation?) -> Expressible { - let clauses: [Expressible?] = [ - column, - Expression(literal: datatype), - primaryKey.map { Expression(literal: $0 == .autoincrement ? "PRIMARY KEY AUTOINCREMENT" : "PRIMARY KEY") }, - null ? nil : Expression(literal: "NOT NULL"), - unique ? Expression(literal: "UNIQUE") : nil, - check.map { " ".join([Expression(literal: "CHECK"), $0]) }, - defaultValue.map { "DEFAULT".prefix($0) }, - references.map(reference), - collate.map { " ".join([Expression(literal: "COLLATE"), $0]) } - ] - - return " ".join(clauses.compactMap { $0 }) -} - -private func reference(_ primary: (QueryType, Expressible)) -> Expressible { - return " ".join([ - Expression(literal: "REFERENCES"), - primary.0.tableName(qualified: false), - "".wrap(primary.1) as Expression - ]) -} - -private enum Modifier : String { - - case unique = "UNIQUE" - - case temporary = "TEMPORARY" - -} diff --git a/ios/libs/Sqlite/Sources/SQLite/Typed/Setter.swift b/ios/libs/Sqlite/Sources/SQLite/Typed/Setter.swift deleted file mode 100644 index 86f16fc..0000000 --- a/ios/libs/Sqlite/Sources/SQLite/Typed/Setter.swift +++ /dev/null @@ -1,277 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -precedencegroup ColumnAssignment { - associativity: left - assignment: true - lowerThan: AssignmentPrecedence -} - -infix operator <- : ColumnAssignment - -public struct Setter { - - let column: Expressible - let value: Expressible - - fileprivate init(column: Expression, value: Expression) { - self.column = column - self.value = value - } - - fileprivate init(column: Expression, value: V) { - self.column = column - self.value = value - } - - fileprivate init(column: Expression, value: Expression) { - self.column = column - self.value = value - } - - fileprivate init(column: Expression, value: Expression) { - self.column = column - self.value = value - } - - fileprivate init(column: Expression, value: V?) { - self.column = column - self.value = Expression(value: value) - } - -} - -extension Setter : Expressible { - - public var expression: Expression { - return "=".infix(column, value, wrap: false) - } - -} - -public func <-(column: Expression, value: Expression) -> Setter { - return Setter(column: column, value: value) -} -public func <-(column: Expression, value: V) -> Setter { - return Setter(column: column, value: value) -} -public func <-(column: Expression, value: Expression) -> Setter { - return Setter(column: column, value: value) -} -public func <-(column: Expression, value: Expression) -> Setter { - return Setter(column: column, value: value) -} -public func <-(column: Expression, value: V?) -> Setter { - return Setter(column: column, value: value) -} - -public func +=(column: Expression, value: Expression) -> Setter { - return column <- column + value -} -public func +=(column: Expression, value: String) -> Setter { - return column <- column + value -} -public func +=(column: Expression, value: Expression) -> Setter { - return column <- column + value -} -public func +=(column: Expression, value: Expression) -> Setter { - return column <- column + value -} -public func +=(column: Expression, value: String) -> Setter { - return column <- column + value -} - -public func +=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { - return column <- column + value -} -public func +=(column: Expression, value: V) -> Setter where V.Datatype : Number { - return column <- column + value -} -public func +=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { - return column <- column + value -} -public func +=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { - return column <- column + value -} -public func +=(column: Expression, value: V) -> Setter where V.Datatype : Number { - return column <- column + value -} - -public func -=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { - return column <- column - value -} -public func -=(column: Expression, value: V) -> Setter where V.Datatype : Number { - return column <- column - value -} -public func -=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { - return column <- column - value -} -public func -=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { - return column <- column - value -} -public func -=(column: Expression, value: V) -> Setter where V.Datatype : Number { - return column <- column - value -} - -public func *=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { - return column <- column * value -} -public func *=(column: Expression, value: V) -> Setter where V.Datatype : Number { - return column <- column * value -} -public func *=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { - return column <- column * value -} -public func *=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { - return column <- column * value -} -public func *=(column: Expression, value: V) -> Setter where V.Datatype : Number { - return column <- column * value -} - -public func /=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { - return column <- column / value -} -public func /=(column: Expression, value: V) -> Setter where V.Datatype : Number { - return column <- column / value -} -public func /=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { - return column <- column / value -} -public func /=(column: Expression, value: Expression) -> Setter where V.Datatype : Number { - return column <- column / value -} -public func /=(column: Expression, value: V) -> Setter where V.Datatype : Number { - return column <- column / value -} - -public func %=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { - return column <- column % value -} -public func %=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { - return column <- column % value -} -public func %=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { - return column <- column % value -} -public func %=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { - return column <- column % value -} -public func %=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { - return column <- column % value -} - -public func <<=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { - return column <- column << value -} -public func <<=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { - return column <- column << value -} -public func <<=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { - return column <- column << value -} -public func <<=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { - return column <- column << value -} -public func <<=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { - return column <- column << value -} - -public func >>=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { - return column <- column >> value -} -public func >>=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { - return column <- column >> value -} -public func >>=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { - return column <- column >> value -} -public func >>=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { - return column <- column >> value -} -public func >>=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { - return column <- column >> value -} - -public func &=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { - return column <- column & value -} -public func &=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { - return column <- column & value -} -public func &=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { - return column <- column & value -} -public func &=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { - return column <- column & value -} -public func &=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { - return column <- column & value -} - -public func |=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { - return column <- column | value -} -public func |=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { - return column <- column | value -} -public func |=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { - return column <- column | value -} -public func |=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { - return column <- column | value -} -public func |=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { - return column <- column | value -} - -public func ^=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { - return column <- column ^ value -} -public func ^=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { - return column <- column ^ value -} -public func ^=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { - return column <- column ^ value -} -public func ^=(column: Expression, value: Expression) -> Setter where V.Datatype == Int64 { - return column <- column ^ value -} -public func ^=(column: Expression, value: V) -> Setter where V.Datatype == Int64 { - return column <- column ^ value -} - -public postfix func ++(column: Expression) -> Setter where V.Datatype == Int64 { - return Expression(column) += 1 -} -public postfix func ++(column: Expression) -> Setter where V.Datatype == Int64 { - return Expression(column) += 1 -} - -public postfix func --(column: Expression) -> Setter where V.Datatype == Int64 { - return Expression(column) -= 1 -} -public postfix func --(column: Expression) -> Setter where V.Datatype == Int64 { - return Expression(column) -= 1 -} diff --git a/ios/libs/Sqlite/Sources/SQLiteObjc/SQLite-Bridging.m b/ios/libs/Sqlite/Sources/SQLiteObjc/SQLite-Bridging.m deleted file mode 100644 index e00a731..0000000 --- a/ios/libs/Sqlite/Sources/SQLiteObjc/SQLite-Bridging.m +++ /dev/null @@ -1,138 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -#import "SQLite-Bridging.h" -#import "fts3_tokenizer.h" - -#pragma mark - FTS - -typedef struct __SQLiteTokenizer { - sqlite3_tokenizer base; - __unsafe_unretained _SQLiteTokenizerNextCallback callback; -} __SQLiteTokenizer; - -typedef struct __SQLiteTokenizerCursor { - void * base; - const char * input; - int inputOffset; - int inputLength; - int idx; -} __SQLiteTokenizerCursor; - -static NSMutableDictionary * __SQLiteTokenizerMap; - -static int __SQLiteTokenizerCreate(int argc, const char * const * argv, sqlite3_tokenizer ** ppTokenizer) { - __SQLiteTokenizer * tokenizer = (__SQLiteTokenizer *)sqlite3_malloc(sizeof(__SQLiteTokenizer)); - if (!tokenizer) { - return SQLITE_NOMEM; - } - memset(tokenizer, 0, sizeof(* tokenizer)); - - NSString * key = [NSString stringWithUTF8String:argv[0]]; - tokenizer->callback = [__SQLiteTokenizerMap objectForKey:key]; - if (!tokenizer->callback) { - return SQLITE_ERROR; - } - - *ppTokenizer = &tokenizer->base; - return SQLITE_OK; -} - -static int __SQLiteTokenizerDestroy(sqlite3_tokenizer * pTokenizer) { - sqlite3_free(pTokenizer); - return SQLITE_OK; -} - -static int __SQLiteTokenizerOpen(sqlite3_tokenizer * pTokenizer, const char * pInput, int nBytes, sqlite3_tokenizer_cursor ** ppCursor) { - __SQLiteTokenizerCursor * cursor = (__SQLiteTokenizerCursor *)sqlite3_malloc(sizeof(__SQLiteTokenizerCursor)); - if (!cursor) { - return SQLITE_NOMEM; - } - - cursor->input = pInput; - cursor->inputOffset = 0; - cursor->inputLength = 0; - cursor->idx = 0; - - *ppCursor = (sqlite3_tokenizer_cursor *)cursor; - return SQLITE_OK; -} - -static int __SQLiteTokenizerClose(sqlite3_tokenizer_cursor * pCursor) { - sqlite3_free(pCursor); - return SQLITE_OK; -} - -static int __SQLiteTokenizerNext(sqlite3_tokenizer_cursor * pCursor, const char ** ppToken, int * pnBytes, int * piStartOffset, int * piEndOffset, int * piPosition) { - __SQLiteTokenizerCursor * cursor = (__SQLiteTokenizerCursor *)pCursor; - __SQLiteTokenizer * tokenizer = (__SQLiteTokenizer *)cursor->base; - - cursor->inputOffset += cursor->inputLength; - const char * input = cursor->input + cursor->inputOffset; - const char * token = [tokenizer->callback(input, &cursor->inputOffset, &cursor->inputLength) cStringUsingEncoding:NSUTF8StringEncoding]; - if (!token) { - return SQLITE_DONE; - } - - *ppToken = token; - *pnBytes = (int)strlen(token); - *piStartOffset = cursor->inputOffset; - *piEndOffset = cursor->inputOffset + cursor->inputLength; - *piPosition = cursor->idx++; - return SQLITE_OK; -} - -static const sqlite3_tokenizer_module __SQLiteTokenizerModule = { - 0, - __SQLiteTokenizerCreate, - __SQLiteTokenizerDestroy, - __SQLiteTokenizerOpen, - __SQLiteTokenizerClose, - __SQLiteTokenizerNext -}; - -int _SQLiteRegisterTokenizer(sqlite3 *db, const char * moduleName, const char * submoduleName, _SQLiteTokenizerNextCallback callback) { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - __SQLiteTokenizerMap = [NSMutableDictionary new]; - }); - - sqlite3_stmt * stmt; - int status = sqlite3_prepare_v2(db, "SELECT fts3_tokenizer(?, ?)", -1, &stmt, 0); - if (status != SQLITE_OK ){ - return status; - } - const sqlite3_tokenizer_module * pModule = &__SQLiteTokenizerModule; - sqlite3_bind_text(stmt, 1, moduleName, -1, SQLITE_STATIC); - sqlite3_bind_blob(stmt, 2, &pModule, sizeof(pModule), SQLITE_STATIC); - sqlite3_step(stmt); - status = sqlite3_finalize(stmt); - if (status != SQLITE_OK ){ - return status; - } - - [__SQLiteTokenizerMap setObject:[callback copy] forKey:[NSString stringWithUTF8String:submoduleName]]; - - return SQLITE_OK; -} diff --git a/ios/libs/Sqlite/Sources/SQLiteObjc/fts3_tokenizer.h b/ios/libs/Sqlite/Sources/SQLiteObjc/fts3_tokenizer.h deleted file mode 100644 index d8a1e44..0000000 --- a/ios/libs/Sqlite/Sources/SQLiteObjc/fts3_tokenizer.h +++ /dev/null @@ -1,161 +0,0 @@ -/* -** 2006 July 10 -** -** The author disclaims copyright to this source code. -** -************************************************************************* -** Defines the interface to tokenizers used by fulltext-search. There -** are three basic components: -** -** sqlite3_tokenizer_module is a singleton defining the tokenizer -** interface functions. This is essentially the class structure for -** tokenizers. -** -** sqlite3_tokenizer is used to define a particular tokenizer, perhaps -** including customization information defined at creation time. -** -** sqlite3_tokenizer_cursor is generated by a tokenizer to generate -** tokens from a particular input. -*/ -#ifndef _FTS3_TOKENIZER_H_ -#define _FTS3_TOKENIZER_H_ - -/* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time. -** If tokenizers are to be allowed to call sqlite3_*() functions, then -** we will need a way to register the API consistently. -*/ -#import "sqlite3.h" - -/* -** Structures used by the tokenizer interface. When a new tokenizer -** implementation is registered, the caller provides a pointer to -** an sqlite3_tokenizer_module containing pointers to the callback -** functions that make up an implementation. -** -** When an fts3 table is created, it passes any arguments passed to -** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the -** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer -** implementation. The xCreate() function in turn returns an -** sqlite3_tokenizer structure representing the specific tokenizer to -** be used for the fts3 table (customized by the tokenizer clause arguments). -** -** To tokenize an input buffer, the sqlite3_tokenizer_module.xOpen() -** method is called. It returns an sqlite3_tokenizer_cursor object -** that may be used to tokenize a specific input buffer based on -** the tokenization rules supplied by a specific sqlite3_tokenizer -** object. -*/ -typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module; -typedef struct sqlite3_tokenizer sqlite3_tokenizer; -typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor; - -struct sqlite3_tokenizer_module { - - /* - ** Structure version. Should always be set to 0 or 1. - */ - int iVersion; - - /* - ** Create a new tokenizer. The values in the argv[] array are the - ** arguments passed to the "tokenizer" clause of the CREATE VIRTUAL - ** TABLE statement that created the fts3 table. For example, if - ** the following SQL is executed: - ** - ** CREATE .. USING fts3( ... , tokenizer arg1 arg2) - ** - ** then argc is set to 2, and the argv[] array contains pointers - ** to the strings "arg1" and "arg2". - ** - ** This method should return either SQLITE_OK (0), or an SQLite error - ** code. If SQLITE_OK is returned, then *ppTokenizer should be set - ** to point at the newly created tokenizer structure. The generic - ** sqlite3_tokenizer.pModule variable should not be initialized by - ** this callback. The caller will do so. - */ - int (*xCreate)( - int argc, /* Size of argv array */ - const char *const*argv, /* Tokenizer argument strings */ - sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ - ); - - /* - ** Destroy an existing tokenizer. The fts3 module calls this method - ** exactly once for each successful call to xCreate(). - */ - int (*xDestroy)(sqlite3_tokenizer *pTokenizer); - - /* - ** Create a tokenizer cursor to tokenize an input buffer. The caller - ** is responsible for ensuring that the input buffer remains valid - ** until the cursor is closed (using the xClose() method). - */ - int (*xOpen)( - sqlite3_tokenizer *pTokenizer, /* Tokenizer object */ - const char *pInput, int nBytes, /* Input buffer */ - sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */ - ); - - /* - ** Destroy an existing tokenizer cursor. The fts3 module calls this - ** method exactly once for each successful call to xOpen(). - */ - int (*xClose)(sqlite3_tokenizer_cursor *pCursor); - - /* - ** Retrieve the next token from the tokenizer cursor pCursor. This - ** method should either return SQLITE_OK and set the values of the - ** "OUT" variables identified below, or SQLITE_DONE to indicate that - ** the end of the buffer has been reached, or an SQLite error code. - ** - ** *ppToken should be set to point at a buffer containing the - ** normalized version of the token (i.e. after any case-folding and/or - ** stemming has been performed). *pnBytes should be set to the length - ** of this buffer in bytes. The input text that generated the token is - ** identified by the byte offsets returned in *piStartOffset and - ** *piEndOffset. *piStartOffset should be set to the index of the first - ** byte of the token in the input buffer. *piEndOffset should be set - ** to the index of the first byte just past the end of the token in - ** the input buffer. - ** - ** The buffer *ppToken is set to point at is managed by the tokenizer - ** implementation. It is only required to be valid until the next call - ** to xNext() or xClose(). - */ - /* TODO(shess) current implementation requires pInput to be - ** nul-terminated. This should either be fixed, or pInput/nBytes - ** should be converted to zInput. - */ - int (*xNext)( - sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */ - const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */ - int *piStartOffset, /* OUT: Byte offset of token in input buffer */ - int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */ - int *piPosition /* OUT: Number of tokens returned before this one */ - ); - - /*********************************************************************** - ** Methods below this point are only available if iVersion>=1. - */ - - /* - ** Configure the language id of a tokenizer cursor. - */ - int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid); -}; - -struct sqlite3_tokenizer { - const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */ - /* Tokenizer implementations will typically add additional fields */ -}; - -struct sqlite3_tokenizer_cursor { - sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */ - /* Tokenizer implementations will typically add additional fields */ -}; - -int fts3_global_term_cnt(int iTerm, int iCol); -int fts3_term_cnt(int iTerm, int iCol); - - -#endif /* _FTS3_TOKENIZER_H_ */ diff --git a/ios/libs/Sqlite/Sources/SQLiteObjc/include/SQLite-Bridging.h b/ios/libs/Sqlite/Sources/SQLiteObjc/include/SQLite-Bridging.h deleted file mode 100644 index f8c2a3b..0000000 --- a/ios/libs/Sqlite/Sources/SQLiteObjc/include/SQLite-Bridging.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// SQLite.swift -// https://github.com/stephencelis/SQLite.swift -// Copyright © 2014-2015 Stephen Celis. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -@import Foundation; -@import SQLite3; - -NS_ASSUME_NONNULL_BEGIN -typedef NSString * _Nullable (^_SQLiteTokenizerNextCallback)(const char *input, int *inputOffset, int *inputLength); -int _SQLiteRegisterTokenizer(sqlite3 *db, const char *module, const char *tokenizer, _Nullable _SQLiteTokenizerNextCallback callback); -NS_ASSUME_NONNULL_END - diff --git a/ios/libs/Sqlite/Tests/Carthage/.gitignore b/ios/libs/Sqlite/Tests/Carthage/.gitignore deleted file mode 100644 index 2d43454..0000000 --- a/ios/libs/Sqlite/Tests/Carthage/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -Carthage/ -Cartfile -Cartfile.resolved diff --git a/ios/libs/Sqlite/Tests/Carthage/Makefile b/ios/libs/Sqlite/Tests/Carthage/Makefile deleted file mode 100644 index f28eb25..0000000 --- a/ios/libs/Sqlite/Tests/Carthage/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -CARTHAGE := /usr/local/bin/carthage -CARTHAGE_PLATFORM := iOS -CARTHAGE_CONFIGURATION := Release -CARTHAGE_DIR := Carthage -CARTHAGE_ARGS := --no-use-binaries -CARTHAGE_TOOLCHAIN := com.apple.dt.toolchain.Swift_3_0 -CARTHAGE_CMDLINE := --configuration $(CARTHAGE_CONFIGURATION) --platform $(CARTHAGE_PLATFORM) --toolchain $(CARTHAGE_TOOLCHAIN) $(CARTHAGE_ARGS) - -test: $(CARTHAGE) Cartfile - $< bootstrap $(CARTHAGE_CMDLINE) - -Cartfile: - echo 'git "$(TRAVIS_BUILD_DIR)" "HEAD"' > $@ - -clean: - @rm -f Cartfile Cartfile.resolved diff --git a/ios/libs/Sqlite/Tests/CocoaPods/.gitignore b/ios/libs/Sqlite/Tests/CocoaPods/.gitignore deleted file mode 100644 index 4cf24de..0000000 --- a/ios/libs/Sqlite/Tests/CocoaPods/.gitignore +++ /dev/null @@ -1 +0,0 @@ -gems/ diff --git a/ios/libs/Sqlite/Tests/CocoaPods/Gemfile b/ios/libs/Sqlite/Tests/CocoaPods/Gemfile deleted file mode 100644 index 77d90ee..0000000 --- a/ios/libs/Sqlite/Tests/CocoaPods/Gemfile +++ /dev/null @@ -1,4 +0,0 @@ -source 'https://rubygems.org' - -gem 'cocoapods', '~> 1.6.1' -gem 'minitest' diff --git a/ios/libs/Sqlite/Tests/CocoaPods/Gemfile.lock b/ios/libs/Sqlite/Tests/CocoaPods/Gemfile.lock deleted file mode 100644 index b517214..0000000 --- a/ios/libs/Sqlite/Tests/CocoaPods/Gemfile.lock +++ /dev/null @@ -1,77 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - CFPropertyList (3.0.0) - activesupport (4.2.11) - i18n (~> 0.7) - minitest (~> 5.1) - thread_safe (~> 0.3, >= 0.3.4) - tzinfo (~> 1.1) - atomos (0.1.3) - claide (1.0.2) - cocoapods (1.6.0.beta.2) - activesupport (>= 4.0.2, < 5) - claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.6.0.beta.2) - cocoapods-deintegrate (>= 1.0.2, < 2.0) - cocoapods-downloader (>= 1.2.2, < 2.0) - cocoapods-plugins (>= 1.0.0, < 2.0) - cocoapods-search (>= 1.0.0, < 2.0) - cocoapods-stats (>= 1.0.0, < 2.0) - cocoapods-trunk (>= 1.3.1, < 2.0) - cocoapods-try (>= 1.1.0, < 2.0) - colored2 (~> 3.1) - escape (~> 0.0.4) - fourflusher (~> 2.0.1) - gh_inspector (~> 1.0) - molinillo (~> 0.6.6) - nap (~> 1.0) - ruby-macho (~> 1.3, >= 1.3.1) - xcodeproj (>= 1.7.0, < 2.0) - cocoapods-core (1.6.0.beta.2) - activesupport (>= 4.0.2, < 6) - fuzzy_match (~> 2.0.4) - nap (~> 1.0) - cocoapods-deintegrate (1.0.2) - cocoapods-downloader (1.2.2) - cocoapods-plugins (1.0.0) - nap - cocoapods-search (1.0.0) - cocoapods-stats (1.0.0) - cocoapods-trunk (1.3.1) - nap (>= 0.8, < 2.0) - netrc (~> 0.11) - cocoapods-try (1.1.0) - colored2 (3.1.2) - concurrent-ruby (1.1.4) - escape (0.0.4) - fourflusher (2.0.1) - fuzzy_match (2.0.4) - gh_inspector (1.1.3) - i18n (0.9.5) - concurrent-ruby (~> 1.0) - minitest (5.11.3) - molinillo (0.6.6) - nanaimo (0.2.6) - nap (1.1.0) - netrc (0.11.0) - ruby-macho (1.3.1) - thread_safe (0.3.6) - tzinfo (1.2.5) - thread_safe (~> 0.1) - xcodeproj (1.7.0) - CFPropertyList (>= 2.3.3, < 4.0) - atomos (~> 0.1.3) - claide (>= 1.0.2, < 2.0) - colored2 (~> 3.1) - nanaimo (~> 0.2.6) - -PLATFORMS - ruby - -DEPENDENCIES - cocoapods (~> 1.6.0beta2) - minitest - -BUNDLED WITH - 1.17.1 diff --git a/ios/libs/Sqlite/Tests/CocoaPods/Makefile b/ios/libs/Sqlite/Tests/CocoaPods/Makefile deleted file mode 100644 index 532dcbf..0000000 --- a/ios/libs/Sqlite/Tests/CocoaPods/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -XCPRETTY := $(shell command -v xcpretty) - -test: install repo_update - @set -e; \ - for test in *_test.rb; do \ - bundle exec ./$$test | $(XCPRETTY) -c; \ - done - -repo_update: - @bundle exec pod repo update --silent - -install: - @bundle install --path gems - -.PHONY: test install diff --git a/ios/libs/Sqlite/Tests/CocoaPods/integration_test.rb b/ios/libs/Sqlite/Tests/CocoaPods/integration_test.rb deleted file mode 100644 index 98a539b..0000000 --- a/ios/libs/Sqlite/Tests/CocoaPods/integration_test.rb +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env ruby - -require 'cocoapods' -require 'cocoapods/validator' -require 'minitest/autorun' - -class IntegrationTest < Minitest::Test - - def test_validate_project - assert validator.validate, "validation failed: #{validator.failure_reason}" - end - - private - - def validator - @validator ||= CustomValidator.new(podspec, ['https://github.com/CocoaPods/Specs.git']).tap do |validator| - validator.config.verbose = true - validator.no_clean = true - validator.use_frameworks = true - validator.fail_fast = true - validator.local = true - validator.allow_warnings = true - subspec = ENV['VALIDATOR_SUBSPEC'] - if subspec == 'none' - validator.no_subspecs = true - else - validator.only_subspec = subspec - end - end - end - - def podspec - File.expand_path(File.dirname(__FILE__) + '/../../SQLite.swift.podspec') - end - - - class CustomValidator < Pod::Validator - def test_pod - # https://github.com/CocoaPods/CocoaPods/issues/7009 - super unless consumer.platform_name == :watchos - end - - def xcodebuild(action, scheme, configuration) - require 'fourflusher' - command = %W(#{action} -workspace #{File.join(validation_dir, 'App.xcworkspace')} -scheme #{scheme} -configuration #{configuration}) - case consumer.platform_name - when :osx, :macos - command += %w(CODE_SIGN_IDENTITY=) - when :ios - command += %w(CODE_SIGN_IDENTITY=- -sdk iphonesimulator) - command += Fourflusher::SimControl.new.destination(nil, 'iOS', deployment_target) - when :watchos - command += %w(CODE_SIGN_IDENTITY=- -sdk watchsimulator) - command += Fourflusher::SimControl.new.destination(:oldest, 'watchOS', deployment_target) - when :tvos - command += %w(CODE_SIGN_IDENTITY=- -sdk appletvsimulator) - command += Fourflusher::SimControl.new.destination(:oldest, 'tvOS', deployment_target) - end - - begin - _xcodebuild(command, true) - rescue => e - message = 'Returned an unsuccessful exit code.' - message += ' You can use `--verbose` for more information.' unless config.verbose? - error('xcodebuild', message) - e.message - end - end - end -end diff --git a/ios/libs/Sqlite/Tests/LinuxMain.swift b/ios/libs/Sqlite/Tests/LinuxMain.swift deleted file mode 100644 index 59796fd..0000000 --- a/ios/libs/Sqlite/Tests/LinuxMain.swift +++ /dev/null @@ -1,6 +0,0 @@ -import XCTest -@testable import SQLiteTests - -XCTMain([ -testCase([ -])]) diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/AggregateFunctionsTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/AggregateFunctionsTests.swift deleted file mode 100644 index 6b583cc..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/AggregateFunctionsTests.swift +++ /dev/null @@ -1,68 +0,0 @@ -import XCTest -import SQLite - -class AggregateFunctionsTests : XCTestCase { - - func test_distinct_prependsExpressionsWithDistinctKeyword() { - AssertSQL("DISTINCT \"int\"", int.distinct) - AssertSQL("DISTINCT \"intOptional\"", intOptional.distinct) - AssertSQL("DISTINCT \"double\"", double.distinct) - AssertSQL("DISTINCT \"doubleOptional\"", doubleOptional.distinct) - AssertSQL("DISTINCT \"string\"", string.distinct) - AssertSQL("DISTINCT \"stringOptional\"", stringOptional.distinct) - } - - func test_count_wrapsOptionalExpressionsWithCountFunction() { - AssertSQL("count(\"intOptional\")", intOptional.count) - AssertSQL("count(\"doubleOptional\")", doubleOptional.count) - AssertSQL("count(\"stringOptional\")", stringOptional.count) - } - - func test_max_wrapsComparableExpressionsWithMaxFunction() { - AssertSQL("max(\"int\")", int.max) - AssertSQL("max(\"intOptional\")", intOptional.max) - AssertSQL("max(\"double\")", double.max) - AssertSQL("max(\"doubleOptional\")", doubleOptional.max) - AssertSQL("max(\"string\")", string.max) - AssertSQL("max(\"stringOptional\")", stringOptional.max) - AssertSQL("max(\"date\")", date.max) - AssertSQL("max(\"dateOptional\")", dateOptional.max) - } - - func test_min_wrapsComparableExpressionsWithMinFunction() { - AssertSQL("min(\"int\")", int.min) - AssertSQL("min(\"intOptional\")", intOptional.min) - AssertSQL("min(\"double\")", double.min) - AssertSQL("min(\"doubleOptional\")", doubleOptional.min) - AssertSQL("min(\"string\")", string.min) - AssertSQL("min(\"stringOptional\")", stringOptional.min) - AssertSQL("min(\"date\")", date.min) - AssertSQL("min(\"dateOptional\")", dateOptional.min) - } - - func test_average_wrapsNumericExpressionsWithAvgFunction() { - AssertSQL("avg(\"int\")", int.average) - AssertSQL("avg(\"intOptional\")", intOptional.average) - AssertSQL("avg(\"double\")", double.average) - AssertSQL("avg(\"doubleOptional\")", doubleOptional.average) - } - - func test_sum_wrapsNumericExpressionsWithSumFunction() { - AssertSQL("sum(\"int\")", int.sum) - AssertSQL("sum(\"intOptional\")", intOptional.sum) - AssertSQL("sum(\"double\")", double.sum) - AssertSQL("sum(\"doubleOptional\")", doubleOptional.sum) - } - - func test_total_wrapsNumericExpressionsWithTotalFunction() { - AssertSQL("total(\"int\")", int.total) - AssertSQL("total(\"intOptional\")", intOptional.total) - AssertSQL("total(\"double\")", double.total) - AssertSQL("total(\"doubleOptional\")", doubleOptional.total) - } - - func test_count_withStar_wrapsStarWithCountFunction() { - AssertSQL("count(*)", count(*)) - } - -} diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/BlobTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/BlobTests.swift deleted file mode 100644 index 817205d..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/BlobTests.swift +++ /dev/null @@ -1,23 +0,0 @@ -import XCTest -import SQLite - -class BlobTests : XCTestCase { - - func test_toHex() { - let blob = Blob(bytes: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 150, 250, 255]) - - XCTAssertEqual(blob.toHex(), "000a141e28323c46505a6496faff") - } - - func test_init_array() { - let blob = Blob(bytes: [42, 42, 42]) - XCTAssertEqual(blob.bytes, [42, 42, 42]) - } - - func test_init_unsafeRawPointer() { - let pointer = UnsafeMutablePointer.allocate(capacity: 3) - pointer.initialize(repeating: 42, count: 3) - let blob = Blob(bytes: pointer, length: 3) - XCTAssertEqual(blob.bytes, [42, 42, 42]) - } -} diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/CipherTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/CipherTests.swift deleted file mode 100644 index abecffb..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/CipherTests.swift +++ /dev/null @@ -1,104 +0,0 @@ -#if SQLITE_SWIFT_SQLCIPHER -import XCTest -import SQLite -import SQLCipher - -class CipherTests: XCTestCase { - - let db1 = try! Connection() - let db2 = try! Connection() - - override func setUp() { - // db - - try! db1.key("hello") - - try! db1.run("CREATE TABLE foo (bar TEXT)") - try! db1.run("INSERT INTO foo (bar) VALUES ('world')") - - // db2 - let key2 = keyData() - try! db2.key(Blob(bytes: key2.bytes, length: key2.length)) - - try! db2.run("CREATE TABLE foo (bar TEXT)") - try! db2.run("INSERT INTO foo (bar) VALUES ('world')") - - super.setUp() - } - - func test_key() { - XCTAssertEqual(1, try! db1.scalar("SELECT count(*) FROM foo") as? Int64) - } - - func test_key_blob_literal() { - let db = try! Connection() - try! db.key("x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'") - } - - func test_rekey() { - try! db1.rekey("goodbye") - XCTAssertEqual(1, try! db1.scalar("SELECT count(*) FROM foo") as? Int64) - } - - func test_data_key() { - XCTAssertEqual(1, try! db2.scalar("SELECT count(*) FROM foo") as? Int64) - } - - func test_data_rekey() { - let newKey = keyData() - try! db2.rekey(Blob(bytes: newKey.bytes, length: newKey.length)) - XCTAssertEqual(1, try! db2.scalar("SELECT count(*) FROM foo") as? Int64) - } - - func test_keyFailure() { - let path = "\(NSTemporaryDirectory())/db.sqlite3" - _ = try? FileManager.default.removeItem(atPath: path) - - let connA = try! Connection(path) - defer { try! FileManager.default.removeItem(atPath: path) } - - try! connA.key("hello") - try! connA.run("CREATE TABLE foo (bar TEXT)") - - let connB = try! Connection(path, readonly: true) - - do { - try connB.key("world") - XCTFail("expected exception") - } catch Result.error(_, let code, _) { - XCTAssertEqual(SQLITE_NOTADB, code) - } catch { - XCTFail("unexpected error: \(error)") - } - } - - func test_open_db_encrypted_with_sqlcipher() { - // $ sqlcipher Tests/SQLiteTests/fixtures/encrypted-[version].x.sqlite - // sqlite> pragma key = 'sqlcipher-test'; - // sqlite> CREATE TABLE foo (bar TEXT); - // sqlite> INSERT INTO foo (bar) VALUES ('world'); - guard let cipherVersion:String = db1.cipherVersion, - cipherVersion.starts(with: "3.") || cipherVersion.starts(with: "4.") - else { return } - - let encryptedFile = cipherVersion.starts(with: "3.") ? - fixture("encrypted-3.x", withExtension: "sqlite") : - fixture("encrypted-4.x", withExtension: "sqlite") - - try! FileManager.default.setAttributes([FileAttributeKey.immutable : 1], ofItemAtPath: encryptedFile) - XCTAssertFalse(FileManager.default.isWritableFile(atPath: encryptedFile)) - - let conn = try! Connection(encryptedFile) - try! conn.key("sqlcipher-test") - XCTAssertEqual(1, try! conn.scalar("SELECT count(*) FROM foo") as? Int64) - } - - private func keyData(length: Int = 64) -> NSMutableData { - let keyData = NSMutableData(length: length)! - let result = SecRandomCopyBytes(kSecRandomDefault, length, - keyData.mutableBytes.assumingMemoryBound(to: UInt8.self)) - XCTAssertEqual(0, result) - return keyData - } -} -#endif diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/ConnectionTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/ConnectionTests.swift deleted file mode 100644 index eab3cf0..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/ConnectionTests.swift +++ /dev/null @@ -1,451 +0,0 @@ -import XCTest -import Foundation -import Dispatch -@testable import SQLite - -#if SQLITE_SWIFT_STANDALONE -import sqlite3 -#elseif SQLITE_SWIFT_SQLCIPHER -import SQLCipher -#elseif os(Linux) -import CSQLite -#else -import SQLite3 -#endif - -class ConnectionTests : SQLiteTestCase { - - override func setUp() { - super.setUp() - - CreateUsersTable() - } - - func test_init_withInMemory_returnsInMemoryConnection() { - let db = try! Connection(.inMemory) - XCTAssertEqual("", db.description) - } - - func test_init_returnsInMemoryByDefault() { - let db = try! Connection() - XCTAssertEqual("", db.description) - } - - func test_init_withTemporary_returnsTemporaryConnection() { - let db = try! Connection(.temporary) - XCTAssertEqual("", db.description) - } - - func test_init_withURI_returnsURIConnection() { - let db = try! Connection(.uri("\(NSTemporaryDirectory())/SQLite.swift Tests.sqlite3")) - XCTAssertEqual("\(NSTemporaryDirectory())/SQLite.swift Tests.sqlite3", db.description) - } - - func test_init_withString_returnsURIConnection() { - let db = try! Connection("\(NSTemporaryDirectory())/SQLite.swift Tests.sqlite3") - XCTAssertEqual("\(NSTemporaryDirectory())/SQLite.swift Tests.sqlite3", db.description) - } - - func test_readonly_returnsFalseOnReadWriteConnections() { - XCTAssertFalse(db.readonly) - } - - func test_readonly_returnsTrueOnReadOnlyConnections() { - let db = try! Connection(readonly: true) - XCTAssertTrue(db.readonly) - } - - func test_changes_returnsZeroOnNewConnections() { - XCTAssertEqual(0, db.changes) - } - - func test_lastInsertRowid_returnsLastIdAfterInserts() { - try! InsertUser("alice") - XCTAssertEqual(1, db.lastInsertRowid) - } - - func test_lastInsertRowid_doesNotResetAfterError() { - XCTAssert(db.lastInsertRowid == 0) - try! InsertUser("alice") - XCTAssertEqual(1, db.lastInsertRowid) - XCTAssertThrowsError( - try db.run("INSERT INTO \"users\" (email, age, admin) values ('invalid@example.com', 12, 'invalid')") - ) { error in - if case SQLite.Result.error(_, let code, _) = error { - XCTAssertEqual(SQLITE_CONSTRAINT, code) - } else { - XCTFail("expected error") - } - } - XCTAssertEqual(1, db.lastInsertRowid) - } - - func test_changes_returnsNumberOfChanges() { - try! InsertUser("alice") - XCTAssertEqual(1, db.changes) - try! InsertUser("betsy") - XCTAssertEqual(1, db.changes) - } - - func test_totalChanges_returnsTotalNumberOfChanges() { - XCTAssertEqual(0, db.totalChanges) - try! InsertUser("alice") - XCTAssertEqual(1, db.totalChanges) - try! InsertUser("betsy") - XCTAssertEqual(2, db.totalChanges) - } - - func test_prepare_preparesAndReturnsStatements() { - _ = try! db.prepare("SELECT * FROM users WHERE admin = 0") - _ = try! db.prepare("SELECT * FROM users WHERE admin = ?", 0) - _ = try! db.prepare("SELECT * FROM users WHERE admin = ?", [0]) - _ = try! db.prepare("SELECT * FROM users WHERE admin = $admin", ["$admin": 0]) - } - - func test_run_preparesRunsAndReturnsStatements() { - try! db.run("SELECT * FROM users WHERE admin = 0") - try! db.run("SELECT * FROM users WHERE admin = ?", 0) - try! db.run("SELECT * FROM users WHERE admin = ?", [0]) - try! db.run("SELECT * FROM users WHERE admin = $admin", ["$admin": 0]) - AssertSQL("SELECT * FROM users WHERE admin = 0", 4) - } - - func test_scalar_preparesRunsAndReturnsScalarValues() { - XCTAssertEqual(0, try! db.scalar("SELECT count(*) FROM users WHERE admin = 0") as? Int64) - XCTAssertEqual(0, try! db.scalar("SELECT count(*) FROM users WHERE admin = ?", 0) as? Int64) - XCTAssertEqual(0, try! db.scalar("SELECT count(*) FROM users WHERE admin = ?", [0]) as? Int64) - XCTAssertEqual(0, try! db.scalar("SELECT count(*) FROM users WHERE admin = $admin", ["$admin": 0]) as? Int64) - AssertSQL("SELECT count(*) FROM users WHERE admin = 0", 4) - } - - func test_execute_comment() { - try! db.run("-- this is a comment\nSELECT 1") - AssertSQL("-- this is a comment", 0) - AssertSQL("SELECT 1", 0) - } - - func test_transaction_executesBeginDeferred() { - try! db.transaction(.deferred) {} - - AssertSQL("BEGIN DEFERRED TRANSACTION") - } - - func test_transaction_executesBeginImmediate() { - try! db.transaction(.immediate) {} - - AssertSQL("BEGIN IMMEDIATE TRANSACTION") - } - - func test_transaction_executesBeginExclusive() { - try! db.transaction(.exclusive) {} - - AssertSQL("BEGIN EXCLUSIVE TRANSACTION") - } - - func test_transaction_beginsAndCommitsTransactions() { - let stmt = try! db.prepare("INSERT INTO users (email) VALUES (?)", "alice@example.com") - - try! db.transaction { - try stmt.run() - } - - AssertSQL("BEGIN DEFERRED TRANSACTION") - AssertSQL("INSERT INTO users (email) VALUES ('alice@example.com')") - AssertSQL("COMMIT TRANSACTION") - AssertSQL("ROLLBACK TRANSACTION", 0) - } - - func test_transaction_rollsBackTransactionsIfCommitsFail() { - let sqliteVersion = String(describing: try! db.scalar("SELECT sqlite_version()")!) - .split(separator: ".").compactMap { Int($0) } - // PRAGMA defer_foreign_keys only supported in SQLite >= 3.8.0 - guard sqliteVersion[0] == 3 && sqliteVersion[1] >= 8 else { - NSLog("skipping test for SQLite version \(sqliteVersion)") - return - } - // This test case needs to emulate an environment where the individual statements succeed, but committing the - // transaction fails. Using deferred foreign keys is one option to achieve this. - try! db.execute("PRAGMA foreign_keys = ON;") - try! db.execute("PRAGMA defer_foreign_keys = ON;") - let stmt = try! db.prepare("INSERT INTO users (email, manager_id) VALUES (?, ?)", "alice@example.com", 100) - - do { - try db.transaction { - try stmt.run() - } - XCTFail("expected error") - } catch let Result.error(_, code, _) { - XCTAssertEqual(SQLITE_CONSTRAINT, code) - } catch let error { - XCTFail("unexpected error: \(error)") - } - - AssertSQL("BEGIN DEFERRED TRANSACTION") - AssertSQL("INSERT INTO users (email, manager_id) VALUES ('alice@example.com', 100)") - AssertSQL("COMMIT TRANSACTION") - AssertSQL("ROLLBACK TRANSACTION") - - // Run another transaction to ensure that a subsequent transaction does not fail with an "cannot start a - // transaction within a transaction" error. - let stmt2 = try! db.prepare("INSERT INTO users (email) VALUES (?)", "alice@example.com") - try! db.transaction { - try stmt2.run() - } - } - - func test_transaction_beginsAndRollsTransactionsBack() { - let stmt = try! db.prepare("INSERT INTO users (email) VALUES (?)", "alice@example.com") - - do { - try db.transaction { - try stmt.run() - try stmt.run() - } - } catch { - } - - AssertSQL("BEGIN DEFERRED TRANSACTION") - AssertSQL("INSERT INTO users (email) VALUES ('alice@example.com')", 2) - AssertSQL("ROLLBACK TRANSACTION") - AssertSQL("COMMIT TRANSACTION", 0) - } - - func test_savepoint_beginsAndCommitsSavepoints() { - let db:Connection = self.db - - try! db.savepoint("1") { - try db.savepoint("2") { - try db.run("INSERT INTO users (email) VALUES (?)", "alice@example.com") - } - } - - AssertSQL("SAVEPOINT '1'") - AssertSQL("SAVEPOINT '2'") - AssertSQL("INSERT INTO users (email) VALUES ('alice@example.com')") - AssertSQL("RELEASE SAVEPOINT '2'") - AssertSQL("RELEASE SAVEPOINT '1'") - AssertSQL("ROLLBACK TO SAVEPOINT '2'", 0) - AssertSQL("ROLLBACK TO SAVEPOINT '1'", 0) - } - - func test_savepoint_beginsAndRollsSavepointsBack() { - let db:Connection = self.db - let stmt = try! db.prepare("INSERT INTO users (email) VALUES (?)", "alice@example.com") - - do { - try db.savepoint("1") { - try db.savepoint("2") { - try stmt.run() - try stmt.run() - try stmt.run() - } - try db.savepoint("2") { - try stmt.run() - try stmt.run() - try stmt.run() - } - } - } catch { - } - - AssertSQL("SAVEPOINT '1'") - AssertSQL("SAVEPOINT '2'") - AssertSQL("INSERT INTO users (email) VALUES ('alice@example.com')", 2) - AssertSQL("ROLLBACK TO SAVEPOINT '2'") - AssertSQL("ROLLBACK TO SAVEPOINT '1'") - AssertSQL("RELEASE SAVEPOINT '2'", 0) - AssertSQL("RELEASE SAVEPOINT '1'", 0) - } - - func test_updateHook_setsUpdateHook_withInsert() { - async { done in - db.updateHook { operation, db, table, rowid in - XCTAssertEqual(Connection.Operation.insert, operation) - XCTAssertEqual("main", db) - XCTAssertEqual("users", table) - XCTAssertEqual(1, rowid) - done() - } - try! InsertUser("alice") - } - } - - func test_updateHook_setsUpdateHook_withUpdate() { - try! InsertUser("alice") - async { done in - db.updateHook { operation, db, table, rowid in - XCTAssertEqual(Connection.Operation.update, operation) - XCTAssertEqual("main", db) - XCTAssertEqual("users", table) - XCTAssertEqual(1, rowid) - done() - } - try! db.run("UPDATE users SET email = 'alice@example.com'") - } - } - - func test_updateHook_setsUpdateHook_withDelete() { - try! InsertUser("alice") - async { done in - db.updateHook { operation, db, table, rowid in - XCTAssertEqual(Connection.Operation.delete, operation) - XCTAssertEqual("main", db) - XCTAssertEqual("users", table) - XCTAssertEqual(1, rowid) - done() - } - try! db.run("DELETE FROM users WHERE id = 1") - } - } - - func test_commitHook_setsCommitHook() { - async { done in - db.commitHook { - done() - } - try! db.transaction { - try self.InsertUser("alice") - } - XCTAssertEqual(1, try! db.scalar("SELECT count(*) FROM users") as? Int64) - } - } - - func test_rollbackHook_setsRollbackHook() { - async { done in - db.rollbackHook(done) - do { - try db.transaction { - try self.InsertUser("alice") - try self.InsertUser("alice") // throw - } - } catch { - } - XCTAssertEqual(0, try! db.scalar("SELECT count(*) FROM users") as? Int64) - } - } - - func test_commitHook_withRollback_rollsBack() { - async { done in - db.commitHook { - throw NSError(domain: "com.stephencelis.SQLiteTests", code: 1, userInfo: nil) - } - db.rollbackHook(done) - do { - try db.transaction { - try self.InsertUser("alice") - } - } catch { - } - XCTAssertEqual(0, try! db.scalar("SELECT count(*) FROM users") as? Int64) - } - } - - func test_createFunction_withArrayArguments() { - db.createFunction("hello") { $0[0].map { "Hello, \($0)!" } } - - XCTAssertEqual("Hello, world!", try! db.scalar("SELECT hello('world')") as? String) - XCTAssert(try! db.scalar("SELECT hello(NULL)") == nil) - } - - func test_createFunction_createsQuotableFunction() { - db.createFunction("hello world") { $0[0].map { "Hello, \($0)!" } } - - XCTAssertEqual("Hello, world!", try! db.scalar("SELECT \"hello world\"('world')") as? String) - XCTAssert(try! db.scalar("SELECT \"hello world\"(NULL)") == nil) - } - - func test_createCollation_createsCollation() { - try! db.createCollation("NODIACRITIC") { lhs, rhs in - return lhs.compare(rhs, options: .diacriticInsensitive) - } - XCTAssertEqual(1, try! db.scalar("SELECT ? = ? COLLATE NODIACRITIC", "cafe", "café") as? Int64) - } - - func test_createCollation_createsQuotableCollation() { - try! db.createCollation("NO DIACRITIC") { lhs, rhs in - return lhs.compare(rhs, options: .diacriticInsensitive) - } - XCTAssertEqual(1, try! db.scalar("SELECT ? = ? COLLATE \"NO DIACRITIC\"", "cafe", "café") as? Int64) - } - - func test_interrupt_interruptsLongRunningQuery() { - let semaphore = DispatchSemaphore(value: 0) - db.createFunction("sleep") { args in - DispatchQueue.global(qos: .background).async { - self.db.interrupt() - semaphore.signal() - } - semaphore.wait() - return nil - } - let stmt = try! db.prepare("SELECT sleep()") - XCTAssertThrowsError(try stmt.run()) { error in - if case Result.error(_, let code, _) = error { - XCTAssertEqual(code, SQLITE_INTERRUPT) - } else { - XCTFail("unexpected error: \(error)") - } - } - } - - func test_concurrent_access_single_connection() { - // test can fail on iOS/tvOS 9.x: SQLite compile-time differences? - guard #available(iOS 10.0, OSX 10.10, tvOS 10.0, watchOS 2.2, *) else { return } - - let conn = try! Connection("\(NSTemporaryDirectory())/\(UUID().uuidString)") - try! conn.execute("DROP TABLE IF EXISTS test; CREATE TABLE test(value);") - try! conn.run("INSERT INTO test(value) VALUES(?)", 0) - let queue = DispatchQueue(label: "Readers", attributes: [.concurrent]) - - let nReaders = 5 - let semaphores = Array(repeating: DispatchSemaphore(value: 100), count: nReaders) - for index in 0...random()) - AssertSQL("random()", Expression.random()) - } - - func test_length_wrapsStringExpressionWithLengthFunction() { - AssertSQL("length(\"string\")", string.length) - AssertSQL("length(\"stringOptional\")", stringOptional.length) - } - - func test_lowercaseString_wrapsStringExpressionWithLowerFunction() { - AssertSQL("lower(\"string\")", string.lowercaseString) - AssertSQL("lower(\"stringOptional\")", stringOptional.lowercaseString) - } - - func test_uppercaseString_wrapsStringExpressionWithUpperFunction() { - AssertSQL("upper(\"string\")", string.uppercaseString) - AssertSQL("upper(\"stringOptional\")", stringOptional.uppercaseString) - } - - func test_like_buildsExpressionWithLikeOperator() { - AssertSQL("(\"string\" LIKE 'a%')", string.like("a%")) - AssertSQL("(\"stringOptional\" LIKE 'b%')", stringOptional.like("b%")) - - AssertSQL("(\"string\" LIKE '%\\%' ESCAPE '\\')", string.like("%\\%", escape: "\\")) - AssertSQL("(\"stringOptional\" LIKE '_\\_' ESCAPE '\\')", stringOptional.like("_\\_", escape: "\\")) - - AssertSQL("(\"string\" LIKE \"a\")", string.like(Expression("a"))) - AssertSQL("(\"stringOptional\" LIKE \"a\")", stringOptional.like(Expression("a"))) - - AssertSQL("(\"string\" LIKE \"a\" ESCAPE '\\')", string.like(Expression("a"), escape: "\\")) - AssertSQL("(\"stringOptional\" LIKE \"a\" ESCAPE '\\')", stringOptional.like(Expression("a"), escape: "\\")) - - AssertSQL("('string' LIKE \"a\")", "string".like(Expression("a"))) - AssertSQL("('string' LIKE \"a\" ESCAPE '\\')", "string".like(Expression("a"), escape: "\\")) - } - - func test_glob_buildsExpressionWithGlobOperator() { - AssertSQL("(\"string\" GLOB 'a*')", string.glob("a*")) - AssertSQL("(\"stringOptional\" GLOB 'b*')", stringOptional.glob("b*")) - } - - func test_match_buildsExpressionWithMatchOperator() { - AssertSQL("(\"string\" MATCH 'a*')", string.match("a*")) - AssertSQL("(\"stringOptional\" MATCH 'b*')", stringOptional.match("b*")) - } - - func test_regexp_buildsExpressionWithRegexpOperator() { - AssertSQL("(\"string\" REGEXP '^.+@.+\\.com$')", string.regexp("^.+@.+\\.com$")) - AssertSQL("(\"stringOptional\" REGEXP '^.+@.+\\.net$')", stringOptional.regexp("^.+@.+\\.net$")) - } - - func test_collate_buildsExpressionWithCollateOperator() { - AssertSQL("(\"string\" COLLATE BINARY)", string.collate(.binary)) - AssertSQL("(\"string\" COLLATE NOCASE)", string.collate(.nocase)) - AssertSQL("(\"string\" COLLATE RTRIM)", string.collate(.rtrim)) - AssertSQL("(\"string\" COLLATE \"CUSTOM\")", string.collate(.custom("CUSTOM"))) - - AssertSQL("(\"stringOptional\" COLLATE BINARY)", stringOptional.collate(.binary)) - AssertSQL("(\"stringOptional\" COLLATE NOCASE)", stringOptional.collate(.nocase)) - AssertSQL("(\"stringOptional\" COLLATE RTRIM)", stringOptional.collate(.rtrim)) - AssertSQL("(\"stringOptional\" COLLATE \"CUSTOM\")", stringOptional.collate(.custom("CUSTOM"))) - } - - func test_ltrim_wrapsStringWithLtrimFunction() { - AssertSQL("ltrim(\"string\")", string.ltrim()) - AssertSQL("ltrim(\"stringOptional\")", stringOptional.ltrim()) - - AssertSQL("ltrim(\"string\", ' ')", string.ltrim([" "])) - AssertSQL("ltrim(\"stringOptional\", ' ')", stringOptional.ltrim([" "])) - } - - func test_ltrim_wrapsStringWithRtrimFunction() { - AssertSQL("rtrim(\"string\")", string.rtrim()) - AssertSQL("rtrim(\"stringOptional\")", stringOptional.rtrim()) - - AssertSQL("rtrim(\"string\", ' ')", string.rtrim([" "])) - AssertSQL("rtrim(\"stringOptional\", ' ')", stringOptional.rtrim([" "])) - } - - func test_ltrim_wrapsStringWithTrimFunction() { - AssertSQL("trim(\"string\")", string.trim()) - AssertSQL("trim(\"stringOptional\")", stringOptional.trim()) - - AssertSQL("trim(\"string\", ' ')", string.trim([" "])) - AssertSQL("trim(\"stringOptional\", ' ')", stringOptional.trim([" "])) - } - - func test_replace_wrapsStringWithReplaceFunction() { - AssertSQL("replace(\"string\", '@example.com', '@example.net')", string.replace("@example.com", with: "@example.net")) - AssertSQL("replace(\"stringOptional\", '@example.net', '@example.com')", stringOptional.replace("@example.net", with: "@example.com")) - } - - func test_substring_wrapsStringWithSubstrFunction() { - AssertSQL("substr(\"string\", 1, 2)", string.substring(1, length: 2)) - AssertSQL("substr(\"stringOptional\", 2, 1)", stringOptional.substring(2, length: 1)) - } - - func test_subscriptWithRange_wrapsStringWithSubstrFunction() { - AssertSQL("substr(\"string\", 1, 2)", string[1..<3]) - AssertSQL("substr(\"stringOptional\", 2, 1)", stringOptional[2..<3]) - } - - func test_nilCoalescingOperator_wrapsOptionalsWithIfnullFunction() { - AssertSQL("ifnull(\"intOptional\", 1)", intOptional ?? 1) - // AssertSQL("ifnull(\"doubleOptional\", 1.0)", doubleOptional ?? 1) // rdar://problem/21677256 - XCTAssertEqual("ifnull(\"doubleOptional\", 1.0)", (doubleOptional ?? 1).asSQL()) - AssertSQL("ifnull(\"stringOptional\", 'literal')", stringOptional ?? "literal") - - AssertSQL("ifnull(\"intOptional\", \"int\")", intOptional ?? int) - AssertSQL("ifnull(\"doubleOptional\", \"double\")", doubleOptional ?? double) - AssertSQL("ifnull(\"stringOptional\", \"string\")", stringOptional ?? string) - - AssertSQL("ifnull(\"intOptional\", \"intOptional\")", intOptional ?? intOptional) - AssertSQL("ifnull(\"doubleOptional\", \"doubleOptional\")", doubleOptional ?? doubleOptional) - AssertSQL("ifnull(\"stringOptional\", \"stringOptional\")", stringOptional ?? stringOptional) - } - - func test_absoluteValue_wrapsNumberWithAbsFucntion() { - AssertSQL("abs(\"int\")", int.absoluteValue) - AssertSQL("abs(\"intOptional\")", intOptional.absoluteValue) - - AssertSQL("abs(\"double\")", double.absoluteValue) - AssertSQL("abs(\"doubleOptional\")", doubleOptional.absoluteValue) - } - - func test_contains_buildsExpressionWithInOperator() { - AssertSQL("(\"string\" IN ('hello', 'world'))", ["hello", "world"].contains(string)) - AssertSQL("(\"stringOptional\" IN ('hello', 'world'))", ["hello", "world"].contains(stringOptional)) - } - -} diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/CustomFunctionsTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/CustomFunctionsTests.swift deleted file mode 100644 index 919986b..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/CustomFunctionsTests.swift +++ /dev/null @@ -1,137 +0,0 @@ -import XCTest -import SQLite - -class CustomFunctionNoArgsTests : SQLiteTestCase { - typealias FunctionNoOptional = () -> Expression - typealias FunctionResultOptional = () -> Expression - - func testFunctionNoOptional() { - let _: FunctionNoOptional = try! db.createFunction("test", deterministic: true) { - return "a" - } - let result = try! db.prepare("SELECT test()").scalar() as! String - XCTAssertEqual("a", result) - } - - func testFunctionResultOptional() { - let _: FunctionResultOptional = try! db.createFunction("test", deterministic: true) { - return "a" - } - let result = try! db.prepare("SELECT test()").scalar() as! String? - XCTAssertEqual("a", result) - } -} - -class CustomFunctionWithOneArgTests : SQLiteTestCase { - typealias FunctionNoOptional = (Expression) -> Expression - typealias FunctionLeftOptional = (Expression) -> Expression - typealias FunctionResultOptional = (Expression) -> Expression - typealias FunctionLeftResultOptional = (Expression) -> Expression - - func testFunctionNoOptional() { - let _: FunctionNoOptional = try! db.createFunction("test", deterministic: true) { a in - return "b"+a - } - let result = try! db.prepare("SELECT test(?)").scalar("a") as! String - XCTAssertEqual("ba", result) - } - - func testFunctionLeftOptional() { - let _: FunctionLeftOptional = try! db.createFunction("test", deterministic: true) { a in - return "b"+a! - } - let result = try! db.prepare("SELECT test(?)").scalar("a") as! String - XCTAssertEqual("ba", result) - } - - func testFunctionResultOptional() { - let _: FunctionResultOptional = try! db.createFunction("test", deterministic: true) { a in - return "b"+a - } - let result = try! db.prepare("SELECT test(?)").scalar("a") as! String - XCTAssertEqual("ba", result) - } - - func testFunctionLeftResultOptional() { - let _: FunctionLeftResultOptional = try! db.createFunction("test", deterministic: true) { (a:String?) -> String? in - return "b"+a! - } - let result = try! db.prepare("SELECT test(?)").scalar("a") as! String - XCTAssertEqual("ba", result) - } -} - -class CustomFunctionWithTwoArgsTests : SQLiteTestCase { - typealias FunctionNoOptional = (Expression, Expression) -> Expression - typealias FunctionLeftOptional = (Expression, Expression) -> Expression - typealias FunctionRightOptional = (Expression, Expression) -> Expression - typealias FunctionResultOptional = (Expression, Expression) -> Expression - typealias FunctionLeftRightOptional = (Expression, Expression) -> Expression - typealias FunctionLeftResultOptional = (Expression, Expression) -> Expression - typealias FunctionRightResultOptional = (Expression, Expression) -> Expression - typealias FunctionLeftRightResultOptional = (Expression, Expression) -> Expression - - func testNoOptional() { - let _: FunctionNoOptional = try! db.createFunction("test", deterministic: true) { a, b in - return a+b - } - let result = try! db.prepare("SELECT test(?, ?)").scalar("a", "b") as! String - XCTAssertEqual("ab", result) - } - - func testLeftOptional() { - let _: FunctionLeftOptional = try! db.createFunction("test", deterministic: true) { a, b in - return a!+b - } - let result = try! db.prepare("SELECT test(?, ?)").scalar("a", "b") as! String - XCTAssertEqual("ab", result) - } - - func testRightOptional() { - let _: FunctionRightOptional = try! db.createFunction("test", deterministic: true) { a, b in - return a+b! - } - let result = try! db.prepare("SELECT test(?, ?)").scalar("a", "b") as! String - XCTAssertEqual("ab", result) - } - - func testResultOptional() { - let _: FunctionResultOptional = try! db.createFunction("test", deterministic: true) { a, b in - return a+b - } - let result = try! db.prepare("SELECT test(?, ?)").scalar("a", "b") as! String? - XCTAssertEqual("ab", result) - } - - func testFunctionLeftRightOptional() { - let _: FunctionLeftRightOptional = try! db.createFunction("test", deterministic: true) { a, b in - return a!+b! - } - let result = try! db.prepare("SELECT test(?, ?)").scalar("a", "b") as! String - XCTAssertEqual("ab", result) - } - - func testFunctionLeftResultOptional() { - let _: FunctionLeftResultOptional = try! db.createFunction("test", deterministic: true) { a, b in - return a!+b - } - let result = try! db.prepare("SELECT test(?, ?)").scalar("a", "b") as! String? - XCTAssertEqual("ab", result) - } - - func testFunctionRightResultOptional() { - let _: FunctionRightResultOptional = try! db.createFunction("test", deterministic: true) { a, b in - return a+b! - } - let result = try! db.prepare("SELECT test(?, ?)").scalar("a", "b") as! String? - XCTAssertEqual("ab", result) - } - - func testFunctionLeftRightResultOptional() { - let _: FunctionLeftRightResultOptional = try! db.createFunction("test", deterministic: true) { a, b in - return a!+b! - } - let result = try! db.prepare("SELECT test(?, ?)").scalar("a", "b") as! String? - XCTAssertEqual("ab", result) - } -} diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/DateAndTimeFunctionTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/DateAndTimeFunctionTests.swift deleted file mode 100644 index 628b591..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/DateAndTimeFunctionTests.swift +++ /dev/null @@ -1,66 +0,0 @@ -import XCTest -@testable import SQLite - -class DateAndTimeFunctionsTests : XCTestCase { - - func test_date() { - AssertSQL("date('now')", DateFunctions.date("now")) - AssertSQL("date('now', 'localtime')", DateFunctions.date("now", "localtime")) - } - - func test_time() { - AssertSQL("time('now')", DateFunctions.time("now")) - AssertSQL("time('now', 'localtime')", DateFunctions.time("now", "localtime")) - } - - func test_datetime() { - AssertSQL("datetime('now')", DateFunctions.datetime("now")) - AssertSQL("datetime('now', 'localtime')", DateFunctions.datetime("now", "localtime")) - } - - func test_julianday() { - AssertSQL("julianday('now')", DateFunctions.julianday("now")) - AssertSQL("julianday('now', 'localtime')", DateFunctions.julianday("now", "localtime")) - } - - func test_strftime() { - AssertSQL("strftime('%Y-%m-%d', 'now')", DateFunctions.strftime("%Y-%m-%d", "now")) - AssertSQL("strftime('%Y-%m-%d', 'now', 'localtime')", DateFunctions.strftime("%Y-%m-%d", "now", "localtime")) - } -} - -class DateExtensionTests : XCTestCase { - func test_time() { - AssertSQL("time('1970-01-01T00:00:00.000')", Date(timeIntervalSince1970: 0).time) - } - - func test_date() { - AssertSQL("date('1970-01-01T00:00:00.000')", Date(timeIntervalSince1970: 0).date) - } - - func test_datetime() { - AssertSQL("datetime('1970-01-01T00:00:00.000')", Date(timeIntervalSince1970: 0).datetime) - } - - func test_julianday() { - AssertSQL("julianday('1970-01-01T00:00:00.000')", Date(timeIntervalSince1970: 0).julianday) - } -} - -class DateExpressionTests : XCTestCase { - func test_date() { - AssertSQL("date(\"date\")", date.date) - } - - func test_time() { - AssertSQL("time(\"date\")", date.time) - } - - func test_datetime() { - AssertSQL("datetime(\"date\")", date.datetime) - } - - func test_julianday() { - AssertSQL("julianday(\"date\")", date.julianday) - } -} diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/ExpressionTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/ExpressionTests.swift deleted file mode 100644 index 036e10c..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/ExpressionTests.swift +++ /dev/null @@ -1,6 +0,0 @@ -import XCTest -import SQLite - -class ExpressionTests : XCTestCase { - -} diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/FTS4Tests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/FTS4Tests.swift deleted file mode 100644 index 79f0a8e..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/FTS4Tests.swift +++ /dev/null @@ -1,208 +0,0 @@ -import XCTest -import SQLite - -class FTS4Tests : XCTestCase { - - func test_create_onVirtualTable_withFTS4_compilesCreateVirtualTableExpression() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4()", - virtualTable.create(.FTS4()) - ) - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(\"string\")", - virtualTable.create(.FTS4(string)) - ) - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=simple)", - virtualTable.create(.FTS4(tokenize: .Simple)) - ) - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(\"string\", tokenize=porter)", - virtualTable.create(.FTS4([string], tokenize: .Porter)) - ) - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=unicode61 \"removeDiacritics=0\")", - virtualTable.create(.FTS4(tokenize: .Unicode61(removeDiacritics: false))) - ) - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=unicode61 \"removeDiacritics=1\" \"tokenchars=.\" \"separators=X\")", - virtualTable.create(.FTS4(tokenize: .Unicode61(removeDiacritics: true, tokenchars: ["."], separators: ["X"]))) - ) - } - - func test_match_onVirtualTableAsExpression_compilesMatchExpression() { - AssertSQL("(\"virtual_table\" MATCH 'string')", virtualTable.match("string") as Expression) - AssertSQL("(\"virtual_table\" MATCH \"string\")", virtualTable.match(string) as Expression) - AssertSQL("(\"virtual_table\" MATCH \"stringOptional\")", virtualTable.match(stringOptional) as Expression) - } - - func test_match_onVirtualTableAsQueryType_compilesMatchExpression() { - AssertSQL("SELECT * FROM \"virtual_table\" WHERE (\"virtual_table\" MATCH 'string')", virtualTable.match("string") as QueryType) - AssertSQL("SELECT * FROM \"virtual_table\" WHERE (\"virtual_table\" MATCH \"string\")", virtualTable.match(string) as QueryType) - AssertSQL("SELECT * FROM \"virtual_table\" WHERE (\"virtual_table\" MATCH \"stringOptional\")", virtualTable.match(stringOptional) as QueryType) - } - -} - -class FTS4ConfigTests : XCTestCase { - var config: FTS4Config! - - override func setUp() { - super.setUp() - config = FTS4Config() - } - - func test_empty_config() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4()", - sql(config)) - } - - func test_config_column() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(\"string\")", - sql(config.column(string))) - } - - func test_config_columns() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(\"string\", \"int\")", - sql(config.columns([string, int]))) - } - - func test_config_unindexed_column() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(\"string\", notindexed=\"string\")", - sql(config.column(string, [.unindexed]))) - } - - func test_external_content_view() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(content=\"view\")", - sql(config.externalContent(_view ))) - } - - func test_external_content_virtual_table() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(content=\"virtual_table\")", - sql(config.externalContent(virtualTable))) - } - - func test_tokenizer_simple() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=simple)", - sql(config.tokenizer(.Simple))) - } - - func test_tokenizer_porter() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=porter)", - sql(config.tokenizer(.Porter))) - } - - func test_tokenizer_unicode61() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=unicode61)", - sql(config.tokenizer(.Unicode61()))) - } - - func test_tokenizer_unicode61_with_options() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=unicode61 \"removeDiacritics=1\" \"tokenchars=.\" \"separators=X\")", - sql(config.tokenizer(.Unicode61(removeDiacritics: true, tokenchars: ["."], separators: ["X"])))) - } - - func test_content_less() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(content=\"\")", - sql(config.contentless())) - } - - func test_config_matchinfo() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(matchinfo=\"fts3\")", - sql(config.matchInfo(.fts3))) - } - - func test_config_order_asc() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(order=\"asc\")", - sql(config.order(.asc))) - } - - func test_config_order_desc() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(order=\"desc\")", - sql(config.order(.desc))) - } - - func test_config_compress() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(compress=\"compress_foo\")", - sql(config.compress("compress_foo"))) - } - - func test_config_uncompress() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(uncompress=\"uncompress_foo\")", - sql(config.uncompress("uncompress_foo"))) - } - - func test_config_languageId() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(languageid=\"lid\")", - sql(config.languageId("lid"))) - } - - func test_config_all() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(\"int\", \"string\", \"date\", tokenize=porter, prefix=\"2,4\", content=\"table\", notindexed=\"string\", notindexed=\"date\", languageid=\"lid\", matchinfo=\"fts3\", order=\"desc\")", - sql(config - .tokenizer(.Porter) - .column(int) - .column(string, [.unindexed]) - .column(date, [.unindexed]) - .externalContent(table) - .matchInfo(.fts3) - .languageId("lid") - .order(.desc) - .prefix([2, 4])) - ) - } - - func sql(_ config: FTS4Config) -> String { - return virtualTable.create(.FTS4(config)) - } -} - -class FTS4IntegrationTests : SQLiteTestCase { -#if !SQLITE_SWIFT_STANDALONE && !SQLITE_SWIFT_SQLCIPHER - func test_registerTokenizer_registersTokenizer() { - let emails = VirtualTable("emails") - let subject = Expression("subject") - let body = Expression("body") - - let locale = CFLocaleCopyCurrent() - let tokenizerName = "tokenizer" - let tokenizer = CFStringTokenizerCreate(nil, "" as CFString, CFRangeMake(0, 0), UInt(kCFStringTokenizerUnitWord), locale) - try! db.registerTokenizer(tokenizerName) { string in - CFStringTokenizerSetString(tokenizer, string as CFString, CFRangeMake(0, CFStringGetLength(string as CFString))) - if CFStringTokenizerAdvanceToNextToken(tokenizer).isEmpty { - return nil - } - let range = CFStringTokenizerGetCurrentTokenRange(tokenizer) - let input = CFStringCreateWithSubstring(kCFAllocatorDefault, string as CFString, range)! - let token = CFStringCreateMutableCopy(nil, range.length, input)! - CFStringLowercase(token, locale) - CFStringTransform(token, nil, kCFStringTransformStripDiacritics, false) - return (token as String, string.range(of: input as String)!) - } - - try! db.run(emails.create(.FTS4([subject, body], tokenize: .Custom(tokenizerName)))) - AssertSQL("CREATE VIRTUAL TABLE \"emails\" USING fts4(\"subject\", \"body\", tokenize=\"SQLite.swift\" \"tokenizer\")") - - try! _ = db.run(emails.insert(subject <- "Aún más cáfe!")) - XCTAssertEqual(1, try! db.scalar(emails.filter(emails.match("aun")).count)) - } -#endif -} diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/FTS5Tests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/FTS5Tests.swift deleted file mode 100644 index 63d8dc4..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/FTS5Tests.swift +++ /dev/null @@ -1,124 +0,0 @@ -import XCTest -import SQLite - -class FTS5Tests: XCTestCase { - var config: FTS5Config! - - override func setUp() { - super.setUp() - config = FTS5Config() - } - - func test_empty_config() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5()", - sql(config)) - } - - func test_config_column() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(\"string\")", - sql(config.column(string))) - } - - func test_config_columns() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(\"string\", \"int\")", - sql(config.columns([string, int]))) - } - - func test_config_unindexed_column() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(\"string\" UNINDEXED)", - sql(config.column(string, [.unindexed]))) - } - - func test_external_content_table() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(content=\"table\")", - sql(config.externalContent(table))) - } - - func test_external_content_view() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(content=\"view\")", - sql(config.externalContent(_view))) - } - - func test_external_content_virtual_table() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(content=\"virtual_table\")", - sql(config.externalContent(virtualTable))) - } - - func test_content_less() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(content=\"\")", - sql(config.contentless())) - } - - func test_content_rowid() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(content_rowid=\"string\")", - sql(config.contentRowId(string))) - } - - func test_tokenizer_porter() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(tokenize=porter)", - sql(config.tokenizer(.Porter))) - } - - func test_tokenizer_unicode61() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(tokenize=unicode61)", - sql(config.tokenizer(.Unicode61()))) - } - - func test_tokenizer_unicode61_with_options() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(tokenize=unicode61 \"removeDiacritics=1\" \"tokenchars=.\" \"separators=X\")", - sql(config.tokenizer(.Unicode61(removeDiacritics: true, tokenchars: ["."], separators: ["X"])))) - } - - func test_column_size() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(columnsize=1)", - sql(config.columnSize(1))) - } - - func test_detail_full() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(detail=\"full\")", - sql(config.detail(.full))) - } - - func test_detail_column() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(detail=\"column\")", - sql(config.detail(.column))) - } - - func test_detail_none() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(detail=\"none\")", - sql(config.detail(.none))) - } - - func test_fts5_config_all() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(\"int\", \"string\" UNINDEXED, \"date\" UNINDEXED, tokenize=porter, prefix=\"2,4\", content=\"table\")", - sql(config - .tokenizer(.Porter) - .column(int) - .column(string, [.unindexed]) - .column(date, [.unindexed]) - .externalContent(table) - .prefix([2, 4])) - ) - } - - func sql(_ config: FTS5Config) -> String { - return virtualTable.create(.FTS5(config)) - } -} diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/Fixtures.swift b/ios/libs/Sqlite/Tests/SQLiteTests/Fixtures.swift deleted file mode 100644 index d068313..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/Fixtures.swift +++ /dev/null @@ -1,8 +0,0 @@ -import Foundation - -func fixture(_ name: String, withExtension: String?) -> String { - let testBundle = Bundle(for: SQLiteTestCase.self) - return testBundle.url( - forResource: name, - withExtension: withExtension)!.path -} diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/FoundationTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/FoundationTests.swift deleted file mode 100644 index dd80afc..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/FoundationTests.swift +++ /dev/null @@ -1,16 +0,0 @@ -import XCTest -import SQLite - -class FoundationTests : XCTestCase { - func testDataFromBlob() { - let data = Data([1, 2, 3]) - let blob = data.datatypeValue - XCTAssertEqual([1, 2, 3], blob.bytes) - } - - func testBlobToData() { - let blob = Blob(bytes: [1, 2, 3]) - let data = Data.fromDatatypeValue(blob) - XCTAssertEqual(Data([1, 2, 3]), data) - } -} diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/Info.plist b/ios/libs/Sqlite/Tests/SQLiteTests/Info.plist deleted file mode 100644 index ba72822..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - - diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/OperatorsTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/OperatorsTests.swift deleted file mode 100644 index 948eb0a..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/OperatorsTests.swift +++ /dev/null @@ -1,342 +0,0 @@ -import XCTest -import SQLite - -class OperatorsTests : XCTestCase { - - func test_stringExpressionPlusStringExpression_buildsConcatenatingStringExpression() { - AssertSQL("(\"string\" || \"string\")", string + string) - AssertSQL("(\"string\" || \"stringOptional\")", string + stringOptional) - AssertSQL("(\"stringOptional\" || \"string\")", stringOptional + string) - AssertSQL("(\"stringOptional\" || \"stringOptional\")", stringOptional + stringOptional) - AssertSQL("(\"string\" || 'literal')", string + "literal") - AssertSQL("(\"stringOptional\" || 'literal')", stringOptional + "literal") - AssertSQL("('literal' || \"string\")", "literal" + string) - AssertSQL("('literal' || \"stringOptional\")", "literal" + stringOptional) - } - - func test_numberExpression_plusNumberExpression_buildsAdditiveNumberExpression() { - AssertSQL("(\"int\" + \"int\")", int + int) - AssertSQL("(\"int\" + \"intOptional\")", int + intOptional) - AssertSQL("(\"intOptional\" + \"int\")", intOptional + int) - AssertSQL("(\"intOptional\" + \"intOptional\")", intOptional + intOptional) - AssertSQL("(\"int\" + 1)", int + 1) - AssertSQL("(\"intOptional\" + 1)", intOptional + 1) - AssertSQL("(1 + \"int\")", 1 + int) - AssertSQL("(1 + \"intOptional\")", 1 + intOptional) - - AssertSQL("(\"double\" + \"double\")", double + double) - AssertSQL("(\"double\" + \"doubleOptional\")", double + doubleOptional) - AssertSQL("(\"doubleOptional\" + \"double\")", doubleOptional + double) - AssertSQL("(\"doubleOptional\" + \"doubleOptional\")", doubleOptional + doubleOptional) - AssertSQL("(\"double\" + 1.0)", double + 1) - AssertSQL("(\"doubleOptional\" + 1.0)", doubleOptional + 1) - AssertSQL("(1.0 + \"double\")", 1 + double) - AssertSQL("(1.0 + \"doubleOptional\")", 1 + doubleOptional) - } - - func test_numberExpression_minusNumberExpression_buildsSubtractiveNumberExpression() { - AssertSQL("(\"int\" - \"int\")", int - int) - AssertSQL("(\"int\" - \"intOptional\")", int - intOptional) - AssertSQL("(\"intOptional\" - \"int\")", intOptional - int) - AssertSQL("(\"intOptional\" - \"intOptional\")", intOptional - intOptional) - AssertSQL("(\"int\" - 1)", int - 1) - AssertSQL("(\"intOptional\" - 1)", intOptional - 1) - AssertSQL("(1 - \"int\")", 1 - int) - AssertSQL("(1 - \"intOptional\")", 1 - intOptional) - - AssertSQL("(\"double\" - \"double\")", double - double) - AssertSQL("(\"double\" - \"doubleOptional\")", double - doubleOptional) - AssertSQL("(\"doubleOptional\" - \"double\")", doubleOptional - double) - AssertSQL("(\"doubleOptional\" - \"doubleOptional\")", doubleOptional - doubleOptional) - AssertSQL("(\"double\" - 1.0)", double - 1) - AssertSQL("(\"doubleOptional\" - 1.0)", doubleOptional - 1) - AssertSQL("(1.0 - \"double\")", 1 - double) - AssertSQL("(1.0 - \"doubleOptional\")", 1 - doubleOptional) - } - - func test_numberExpression_timesNumberExpression_buildsMultiplicativeNumberExpression() { - AssertSQL("(\"int\" * \"int\")", int * int) - AssertSQL("(\"int\" * \"intOptional\")", int * intOptional) - AssertSQL("(\"intOptional\" * \"int\")", intOptional * int) - AssertSQL("(\"intOptional\" * \"intOptional\")", intOptional * intOptional) - AssertSQL("(\"int\" * 1)", int * 1) - AssertSQL("(\"intOptional\" * 1)", intOptional * 1) - AssertSQL("(1 * \"int\")", 1 * int) - AssertSQL("(1 * \"intOptional\")", 1 * intOptional) - - AssertSQL("(\"double\" * \"double\")", double * double) - AssertSQL("(\"double\" * \"doubleOptional\")", double * doubleOptional) - AssertSQL("(\"doubleOptional\" * \"double\")", doubleOptional * double) - AssertSQL("(\"doubleOptional\" * \"doubleOptional\")", doubleOptional * doubleOptional) - AssertSQL("(\"double\" * 1.0)", double * 1) - AssertSQL("(\"doubleOptional\" * 1.0)", doubleOptional * 1) - AssertSQL("(1.0 * \"double\")", 1 * double) - AssertSQL("(1.0 * \"doubleOptional\")", 1 * doubleOptional) - } - - func test_numberExpression_dividedByNumberExpression_buildsDivisiveNumberExpression() { - AssertSQL("(\"int\" / \"int\")", int / int) - AssertSQL("(\"int\" / \"intOptional\")", int / intOptional) - AssertSQL("(\"intOptional\" / \"int\")", intOptional / int) - AssertSQL("(\"intOptional\" / \"intOptional\")", intOptional / intOptional) - AssertSQL("(\"int\" / 1)", int / 1) - AssertSQL("(\"intOptional\" / 1)", intOptional / 1) - AssertSQL("(1 / \"int\")", 1 / int) - AssertSQL("(1 / \"intOptional\")", 1 / intOptional) - - AssertSQL("(\"double\" / \"double\")", double / double) - AssertSQL("(\"double\" / \"doubleOptional\")", double / doubleOptional) - AssertSQL("(\"doubleOptional\" / \"double\")", doubleOptional / double) - AssertSQL("(\"doubleOptional\" / \"doubleOptional\")", doubleOptional / doubleOptional) - AssertSQL("(\"double\" / 1.0)", double / 1) - AssertSQL("(\"doubleOptional\" / 1.0)", doubleOptional / 1) - AssertSQL("(1.0 / \"double\")", 1 / double) - AssertSQL("(1.0 / \"doubleOptional\")", 1 / doubleOptional) - } - - func test_numberExpression_prefixedWithMinus_buildsInvertedNumberExpression() { - AssertSQL("-(\"int\")", -int) - AssertSQL("-(\"intOptional\")", -intOptional) - - AssertSQL("-(\"double\")", -double) - AssertSQL("-(\"doubleOptional\")", -doubleOptional) - } - - func test_integerExpression_moduloIntegerExpression_buildsModuloIntegerExpression() { - AssertSQL("(\"int\" % \"int\")", int % int) - AssertSQL("(\"int\" % \"intOptional\")", int % intOptional) - AssertSQL("(\"intOptional\" % \"int\")", intOptional % int) - AssertSQL("(\"intOptional\" % \"intOptional\")", intOptional % intOptional) - AssertSQL("(\"int\" % 1)", int % 1) - AssertSQL("(\"intOptional\" % 1)", intOptional % 1) - AssertSQL("(1 % \"int\")", 1 % int) - AssertSQL("(1 % \"intOptional\")", 1 % intOptional) - } - - func test_integerExpression_bitShiftLeftIntegerExpression_buildsLeftShiftedIntegerExpression() { - AssertSQL("(\"int\" << \"int\")", int << int) - AssertSQL("(\"int\" << \"intOptional\")", int << intOptional) - AssertSQL("(\"intOptional\" << \"int\")", intOptional << int) - AssertSQL("(\"intOptional\" << \"intOptional\")", intOptional << intOptional) - AssertSQL("(\"int\" << 1)", int << 1) - AssertSQL("(\"intOptional\" << 1)", intOptional << 1) - AssertSQL("(1 << \"int\")", 1 << int) - AssertSQL("(1 << \"intOptional\")", 1 << intOptional) - } - - func test_integerExpression_bitShiftRightIntegerExpression_buildsRightShiftedIntegerExpression() { - AssertSQL("(\"int\" >> \"int\")", int >> int) - AssertSQL("(\"int\" >> \"intOptional\")", int >> intOptional) - AssertSQL("(\"intOptional\" >> \"int\")", intOptional >> int) - AssertSQL("(\"intOptional\" >> \"intOptional\")", intOptional >> intOptional) - AssertSQL("(\"int\" >> 1)", int >> 1) - AssertSQL("(\"intOptional\" >> 1)", intOptional >> 1) - AssertSQL("(1 >> \"int\")", 1 >> int) - AssertSQL("(1 >> \"intOptional\")", 1 >> intOptional) - } - - func test_integerExpression_bitwiseAndIntegerExpression_buildsAndedIntegerExpression() { - AssertSQL("(\"int\" & \"int\")", int & int) - AssertSQL("(\"int\" & \"intOptional\")", int & intOptional) - AssertSQL("(\"intOptional\" & \"int\")", intOptional & int) - AssertSQL("(\"intOptional\" & \"intOptional\")", intOptional & intOptional) - AssertSQL("(\"int\" & 1)", int & 1) - AssertSQL("(\"intOptional\" & 1)", intOptional & 1) - AssertSQL("(1 & \"int\")", 1 & int) - AssertSQL("(1 & \"intOptional\")", 1 & intOptional) - } - - func test_integerExpression_bitwiseOrIntegerExpression_buildsOredIntegerExpression() { - AssertSQL("(\"int\" | \"int\")", int | int) - AssertSQL("(\"int\" | \"intOptional\")", int | intOptional) - AssertSQL("(\"intOptional\" | \"int\")", intOptional | int) - AssertSQL("(\"intOptional\" | \"intOptional\")", intOptional | intOptional) - AssertSQL("(\"int\" | 1)", int | 1) - AssertSQL("(\"intOptional\" | 1)", intOptional | 1) - AssertSQL("(1 | \"int\")", 1 | int) - AssertSQL("(1 | \"intOptional\")", 1 | intOptional) - } - - func test_integerExpression_bitwiseExclusiveOrIntegerExpression_buildsOredIntegerExpression() { - AssertSQL("(~((\"int\" & \"int\")) & (\"int\" | \"int\"))", int ^ int) - AssertSQL("(~((\"int\" & \"intOptional\")) & (\"int\" | \"intOptional\"))", int ^ intOptional) - AssertSQL("(~((\"intOptional\" & \"int\")) & (\"intOptional\" | \"int\"))", intOptional ^ int) - AssertSQL("(~((\"intOptional\" & \"intOptional\")) & (\"intOptional\" | \"intOptional\"))", intOptional ^ intOptional) - AssertSQL("(~((\"int\" & 1)) & (\"int\" | 1))", int ^ 1) - AssertSQL("(~((\"intOptional\" & 1)) & (\"intOptional\" | 1))", intOptional ^ 1) - AssertSQL("(~((1 & \"int\")) & (1 | \"int\"))", 1 ^ int) - AssertSQL("(~((1 & \"intOptional\")) & (1 | \"intOptional\"))", 1 ^ intOptional) - } - - func test_bitwiseNot_integerExpression_buildsComplementIntegerExpression() { - AssertSQL("~(\"int\")", ~int) - AssertSQL("~(\"intOptional\")", ~intOptional) - } - - func test_equalityOperator_withEquatableExpressions_buildsBooleanExpression() { - AssertSQL("(\"bool\" = \"bool\")", bool == bool) - AssertSQL("(\"bool\" = \"boolOptional\")", bool == boolOptional) - AssertSQL("(\"boolOptional\" = \"bool\")", boolOptional == bool) - AssertSQL("(\"boolOptional\" = \"boolOptional\")", boolOptional == boolOptional) - AssertSQL("(\"bool\" = 1)", bool == true) - AssertSQL("(\"boolOptional\" = 1)", boolOptional == true) - AssertSQL("(1 = \"bool\")", true == bool) - AssertSQL("(1 = \"boolOptional\")", true == boolOptional) - - AssertSQL("(\"boolOptional\" IS NULL)", boolOptional == nil) - AssertSQL("(NULL IS \"boolOptional\")", nil == boolOptional) - } - - func test_inequalityOperator_withEquatableExpressions_buildsBooleanExpression() { - AssertSQL("(\"bool\" != \"bool\")", bool != bool) - AssertSQL("(\"bool\" != \"boolOptional\")", bool != boolOptional) - AssertSQL("(\"boolOptional\" != \"bool\")", boolOptional != bool) - AssertSQL("(\"boolOptional\" != \"boolOptional\")", boolOptional != boolOptional) - AssertSQL("(\"bool\" != 1)", bool != true) - AssertSQL("(\"boolOptional\" != 1)", boolOptional != true) - AssertSQL("(1 != \"bool\")", true != bool) - AssertSQL("(1 != \"boolOptional\")", true != boolOptional) - - AssertSQL("(\"boolOptional\" IS NOT NULL)", boolOptional != nil) - AssertSQL("(NULL IS NOT \"boolOptional\")", nil != boolOptional) - } - - func test_greaterThanOperator_withComparableExpressions_buildsBooleanExpression() { - AssertSQL("(\"bool\" > \"bool\")", bool > bool) - AssertSQL("(\"bool\" > \"boolOptional\")", bool > boolOptional) - AssertSQL("(\"boolOptional\" > \"bool\")", boolOptional > bool) - AssertSQL("(\"boolOptional\" > \"boolOptional\")", boolOptional > boolOptional) - AssertSQL("(\"bool\" > 1)", bool > true) - AssertSQL("(\"boolOptional\" > 1)", boolOptional > true) - AssertSQL("(1 > \"bool\")", true > bool) - AssertSQL("(1 > \"boolOptional\")", true > boolOptional) - } - - func test_greaterThanOrEqualToOperator_withComparableExpressions_buildsBooleanExpression() { - AssertSQL("(\"bool\" >= \"bool\")", bool >= bool) - AssertSQL("(\"bool\" >= \"boolOptional\")", bool >= boolOptional) - AssertSQL("(\"boolOptional\" >= \"bool\")", boolOptional >= bool) - AssertSQL("(\"boolOptional\" >= \"boolOptional\")", boolOptional >= boolOptional) - AssertSQL("(\"bool\" >= 1)", bool >= true) - AssertSQL("(\"boolOptional\" >= 1)", boolOptional >= true) - AssertSQL("(1 >= \"bool\")", true >= bool) - AssertSQL("(1 >= \"boolOptional\")", true >= boolOptional) - } - - func test_lessThanOperator_withComparableExpressions_buildsBooleanExpression() { - AssertSQL("(\"bool\" < \"bool\")", bool < bool) - AssertSQL("(\"bool\" < \"boolOptional\")", bool < boolOptional) - AssertSQL("(\"boolOptional\" < \"bool\")", boolOptional < bool) - AssertSQL("(\"boolOptional\" < \"boolOptional\")", boolOptional < boolOptional) - AssertSQL("(\"bool\" < 1)", bool < true) - AssertSQL("(\"boolOptional\" < 1)", boolOptional < true) - AssertSQL("(1 < \"bool\")", true < bool) - AssertSQL("(1 < \"boolOptional\")", true < boolOptional) - } - - func test_lessThanOrEqualToOperator_withComparableExpressions_buildsBooleanExpression() { - AssertSQL("(\"bool\" <= \"bool\")", bool <= bool) - AssertSQL("(\"bool\" <= \"boolOptional\")", bool <= boolOptional) - AssertSQL("(\"boolOptional\" <= \"bool\")", boolOptional <= bool) - AssertSQL("(\"boolOptional\" <= \"boolOptional\")", boolOptional <= boolOptional) - AssertSQL("(\"bool\" <= 1)", bool <= true) - AssertSQL("(\"boolOptional\" <= 1)", boolOptional <= true) - AssertSQL("(1 <= \"bool\")", true <= bool) - AssertSQL("(1 <= \"boolOptional\")", true <= boolOptional) - } - - func test_patternMatchingOperator_withComparableCountableClosedRange_buildsBetweenBooleanExpression() { - AssertSQL("\"int\" BETWEEN 0 AND 5", 0...5 ~= int) - AssertSQL("\"intOptional\" BETWEEN 0 AND 5", 0...5 ~= intOptional) - } - - func test_patternMatchingOperator_withComparableClosedRange_buildsBetweenBooleanExpression() { - AssertSQL("\"double\" BETWEEN 1.2 AND 4.5", 1.2...4.5 ~= double) - AssertSQL("\"doubleOptional\" BETWEEN 1.2 AND 4.5", 1.2...4.5 ~= doubleOptional) - } - - func test_patternMatchingOperator_withComparableRange_buildsBooleanExpression() { - AssertSQL("\"double\" >= 1.2 AND \"double\" < 4.5", 1.2..<4.5 ~= double) - AssertSQL("\"doubleOptional\" >= 1.2 AND \"doubleOptional\" < 4.5", 1.2..<4.5 ~= doubleOptional) - } - - func test_patternMatchingOperator_withComparablePartialRangeThrough_buildsBooleanExpression() { - AssertSQL("\"double\" <= 4.5", ...4.5 ~= double) - AssertSQL("\"doubleOptional\" <= 4.5", ...4.5 ~= doubleOptional) - } - - func test_patternMatchingOperator_withComparablePartialRangeUpTo_buildsBooleanExpression() { - AssertSQL("\"double\" < 4.5", ..<4.5 ~= double) - AssertSQL("\"doubleOptional\" < 4.5", ..<4.5 ~= doubleOptional) - } - - func test_patternMatchingOperator_withComparablePartialRangeFrom_buildsBooleanExpression() { - AssertSQL("\"double\" >= 4.5", 4.5... ~= double) - AssertSQL("\"doubleOptional\" >= 4.5", 4.5... ~= doubleOptional) - } - - func test_patternMatchingOperator_withComparableClosedRangeString_buildsBetweenBooleanExpression() { - AssertSQL("\"string\" BETWEEN 'a' AND 'b'", "a"..."b" ~= string) - AssertSQL("\"stringOptional\" BETWEEN 'a' AND 'b'", "a"..."b" ~= stringOptional) - } - - func test_doubleAndOperator_withBooleanExpressions_buildsCompoundExpression() { - AssertSQL("(\"bool\" AND \"bool\")", bool && bool) - AssertSQL("(\"bool\" AND \"boolOptional\")", bool && boolOptional) - AssertSQL("(\"boolOptional\" AND \"bool\")", boolOptional && bool) - AssertSQL("(\"boolOptional\" AND \"boolOptional\")", boolOptional && boolOptional) - AssertSQL("(\"bool\" AND 1)", bool && true) - AssertSQL("(\"boolOptional\" AND 1)", boolOptional && true) - AssertSQL("(1 AND \"bool\")", true && bool) - AssertSQL("(1 AND \"boolOptional\")", true && boolOptional) - } - - func test_doubleOrOperator_withBooleanExpressions_buildsCompoundExpression() { - AssertSQL("(\"bool\" OR \"bool\")", bool || bool) - AssertSQL("(\"bool\" OR \"boolOptional\")", bool || boolOptional) - AssertSQL("(\"boolOptional\" OR \"bool\")", boolOptional || bool) - AssertSQL("(\"boolOptional\" OR \"boolOptional\")", boolOptional || boolOptional) - AssertSQL("(\"bool\" OR 1)", bool || true) - AssertSQL("(\"boolOptional\" OR 1)", boolOptional || true) - AssertSQL("(1 OR \"bool\")", true || bool) - AssertSQL("(1 OR \"boolOptional\")", true || boolOptional) - } - - func test_unaryNotOperator_withBooleanExpressions_buildsNotExpression() { - AssertSQL("NOT (\"bool\")", !bool) - AssertSQL("NOT (\"boolOptional\")", !boolOptional) - } - - func test_precedencePreserved() { - let n = Expression(value: 1) - AssertSQL("(((1 = 1) AND (1 = 1)) OR (1 = 1))", (n == n && n == n) || n == n) - AssertSQL("((1 = 1) AND ((1 = 1) OR (1 = 1)))", n == n && (n == n || n == n)) - } - - func test_dateExpressionLessGreater() { - let begin = Date(timeIntervalSince1970: 0) - AssertSQL("(\"date\" < '1970-01-01T00:00:00.000')", date < begin) - AssertSQL("(\"date\" > '1970-01-01T00:00:00.000')", date > begin) - AssertSQL("(\"date\" >= '1970-01-01T00:00:00.000')", date >= begin) - AssertSQL("(\"date\" <= '1970-01-01T00:00:00.000')", date <= begin) - } - - func test_dateExpressionRange() { - let begin = Date(timeIntervalSince1970: 0) - let end = Date(timeIntervalSince1970: 5000) - AssertSQL( - "\"date\" >= '1970-01-01T00:00:00.000' AND \"date\" < '1970-01-01T01:23:20.000'", - (begin..("id") - let email = Expression("email") - let age = Expression("age") - let admin = Expression("admin") - let optionalAdmin = Expression("admin") - - let posts = Table("posts") - let userId = Expression("user_id") - let categoryId = Expression("category_id") - let published = Expression("published") - - let categories = Table("categories") - let tag = Expression("tag") - - func test_select_withExpression_compilesSelectClause() { - AssertSQL("SELECT \"email\" FROM \"users\"", users.select(email)) - } - - func test_select_withStarExpression_compilesSelectClause() { - AssertSQL("SELECT * FROM \"users\"", users.select(*)) - } - - func test_select_withNamespacedStarExpression_compilesSelectClause() { - AssertSQL("SELECT \"users\".* FROM \"users\"", users.select(users[*])) - } - - func test_select_withVariadicExpressions_compilesSelectClause() { - AssertSQL("SELECT \"email\", count(*) FROM \"users\"", users.select(email, count(*))) - } - - func test_select_withExpressions_compilesSelectClause() { - AssertSQL("SELECT \"email\", count(*) FROM \"users\"", users.select([email, count(*)])) - } - - func test_selectDistinct_withExpression_compilesSelectClause() { - AssertSQL("SELECT DISTINCT \"age\" FROM \"users\"", users.select(distinct: age)) - } - - func test_selectDistinct_withExpressions_compilesSelectClause() { - AssertSQL("SELECT DISTINCT \"age\", \"admin\" FROM \"users\"", users.select(distinct: [age, admin])) - } - - func test_selectDistinct_withStar_compilesSelectClause() { - AssertSQL("SELECT DISTINCT * FROM \"users\"", users.select(distinct: *)) - } - - func test_join_compilesJoinClause() { - AssertSQL( - "SELECT * FROM \"users\" INNER JOIN \"posts\" ON (\"posts\".\"user_id\" = \"users\".\"id\")", - users.join(posts, on: posts[userId] == users[id]) - ) - } - - func test_join_withExplicitType_compilesJoinClauseWithType() { - AssertSQL( - "SELECT * FROM \"users\" LEFT OUTER JOIN \"posts\" ON (\"posts\".\"user_id\" = \"users\".\"id\")", - users.join(.leftOuter, posts, on: posts[userId] == users[id]) - ) - - AssertSQL( - "SELECT * FROM \"users\" CROSS JOIN \"posts\" ON (\"posts\".\"user_id\" = \"users\".\"id\")", - users.join(.cross, posts, on: posts[userId] == users[id]) - ) - } - - func test_join_withTableCondition_compilesJoinClauseWithTableCondition() { - AssertSQL( - "SELECT * FROM \"users\" INNER JOIN \"posts\" ON ((\"posts\".\"user_id\" = \"users\".\"id\") AND \"published\")", - users.join(posts.filter(published), on: posts[userId] == users[id]) - ) - } - - func test_join_whenChained_compilesAggregateJoinClause() { - AssertSQL( - "SELECT * FROM \"users\" " + - "INNER JOIN \"posts\" ON (\"posts\".\"user_id\" = \"users\".\"id\") " + - "INNER JOIN \"categories\" ON (\"categories\".\"id\" = \"posts\".\"category_id\")", - users.join(posts, on: posts[userId] == users[id]).join(categories, on: categories[id] == posts[categoryId]) - ) - } - - func test_filter_compilesWhereClause() { - AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 1)", users.filter(admin == true)) - } - - func test_filter_compilesWhereClause_false() { - AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 0)", users.filter(admin == false)) - } - - func test_filter_compilesWhereClause_optional() { - AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 1)", users.filter(optionalAdmin == true)) - } - - func test_filter_compilesWhereClause_optional_false() { - AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 0)", users.filter(optionalAdmin == false)) - } - - func test_where_compilesWhereClause() { - AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 1)", users.where(admin == true)) - } - - func test_where_compilesWhereClause_false() { - AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 0)", users.where(admin == false)) - } - - func test_where_compilesWhereClause_optional() { - AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 1)", users.where(optionalAdmin == true)) - } - - func test_where_compilesWhereClause_optional_false() { - AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 0)", users.where(optionalAdmin == false)) - } - - func test_filter_whenChained_compilesAggregateWhereClause() { - AssertSQL( - "SELECT * FROM \"users\" WHERE ((\"age\" >= 35) AND \"admin\")", - users.filter(age >= 35).filter(admin) - ) - } - - func test_group_withSingleExpressionName_compilesGroupClause() { - AssertSQL("SELECT * FROM \"users\" GROUP BY \"age\"", - users.group(age)) - } - - func test_group_withVariadicExpressionNames_compilesGroupClause() { - AssertSQL("SELECT * FROM \"users\" GROUP BY \"age\", \"admin\"", users.group(age, admin)) - } - - func test_group_withExpressionNameAndHavingBindings_compilesGroupClause() { - AssertSQL("SELECT * FROM \"users\" GROUP BY \"age\" HAVING \"admin\"", users.group(age, having: admin)) - AssertSQL("SELECT * FROM \"users\" GROUP BY \"age\" HAVING (\"age\" >= 30)", users.group(age, having: age >= 30)) - } - - func test_group_withExpressionNamesAndHavingBindings_compilesGroupClause() { - AssertSQL( - "SELECT * FROM \"users\" GROUP BY \"age\", \"admin\" HAVING \"admin\"", - users.group([age, admin], having: admin) - ) - AssertSQL( - "SELECT * FROM \"users\" GROUP BY \"age\", \"admin\" HAVING (\"age\" >= 30)", - users.group([age, admin], having: age >= 30) - ) - } - - func test_order_withSingleExpressionName_compilesOrderClause() { - AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\"", users.order(age)) - } - - func test_order_withVariadicExpressionNames_compilesOrderClause() { - AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\", \"email\"", users.order(age, email)) - } - - func test_order_withArrayExpressionNames_compilesOrderClause() { - AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\", \"email\"", users.order([age, email])) - } - - func test_order_withExpressionAndSortDirection_compilesOrderClause() { -// AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\" DESC, \"email\" ASC", users.order(age.desc, email.asc)) - } - - func test_order_whenChained_resetsOrderClause() { - AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\"", users.order(email).order(age)) - } - - func test_reverse_withoutOrder_ordersByRowIdDescending() { -// AssertSQL("SELECT * FROM \"users\" ORDER BY \"ROWID\" DESC", users.reverse()) - } - - func test_reverse_withOrder_reversesOrder() { -// AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\" DESC, \"email\" ASC", users.order(age, email.desc).reverse()) - } - - func test_limit_compilesLimitClause() { - AssertSQL("SELECT * FROM \"users\" LIMIT 5", users.limit(5)) - } - - func test_limit_withOffset_compilesOffsetClause() { - AssertSQL("SELECT * FROM \"users\" LIMIT 5 OFFSET 5", users.limit(5, offset: 5)) - } - - func test_limit_whenChained_overridesLimit() { - let query = users.limit(5) - - AssertSQL("SELECT * FROM \"users\" LIMIT 10", query.limit(10)) - AssertSQL("SELECT * FROM \"users\"", query.limit(nil)) - } - - func test_limit_whenChained_withOffset_overridesOffset() { - let query = users.limit(5, offset: 5) - - AssertSQL("SELECT * FROM \"users\" LIMIT 10 OFFSET 20", query.limit(10, offset: 20)) - AssertSQL("SELECT * FROM \"users\"", query.limit(nil)) - } - - func test_alias_aliasesTable() { - let managerId = Expression("manager_id") - - let managers = users.alias("managers") - - AssertSQL( - "SELECT * FROM \"users\" " + - "INNER JOIN \"users\" AS \"managers\" ON (\"managers\".\"id\" = \"users\".\"manager_id\")", - users.join(managers, on: managers[id] == users[managerId]) - ) - } - - func test_insert_compilesInsertExpression() { - AssertSQL( - "INSERT INTO \"users\" (\"email\", \"age\") VALUES ('alice@example.com', 30)", - users.insert(email <- "alice@example.com", age <- 30) - ) - } - - func test_insert_withOnConflict_compilesInsertOrOnConflictExpression() { - AssertSQL( - "INSERT OR REPLACE INTO \"users\" (\"email\", \"age\") VALUES ('alice@example.com', 30)", - users.insert(or: .replace, email <- "alice@example.com", age <- 30) - ) - } - - func test_insert_compilesInsertExpressionWithDefaultValues() { - AssertSQL("INSERT INTO \"users\" DEFAULT VALUES", users.insert()) - } - - func test_insert_withQuery_compilesInsertExpressionWithSelectStatement() { - let emails = Table("emails") - - AssertSQL( - "INSERT INTO \"emails\" SELECT \"email\" FROM \"users\" WHERE \"admin\"", - emails.insert(users.select(email).filter(admin)) - ) - } - - func test_insert_encodable() throws { - let emails = Table("emails") - let value = TestCodable(int: 1, string: "2", bool: true, float: 3, double: 4, optional: nil, sub: nil) - let insert = try emails.insert(value) - AssertSQL( - "INSERT INTO \"emails\" (\"int\", \"string\", \"bool\", \"float\", \"double\") VALUES (1, '2', 1, 3.0, 4.0)", - insert - ) - } - - func test_insert_encodable_with_nested_encodable() throws { - let emails = Table("emails") - let value1 = TestCodable(int: 1, string: "2", bool: true, float: 3, double: 4, optional: nil, sub: nil) - let value = TestCodable(int: 1, string: "2", bool: true, float: 3, double: 4, optional: "optional", sub: value1) - let insert = try emails.insert(value) - let encodedJSON = try JSONEncoder().encode(value1) - let encodedJSONString = String(data: encodedJSON, encoding: .utf8)! - AssertSQL( - "INSERT INTO \"emails\" (\"int\", \"string\", \"bool\", \"float\", \"double\", \"optional\", \"sub\") VALUES (1, '2', 1, 3.0, 4.0, 'optional', '\(encodedJSONString)')", - insert - ) - } - - func test_update_compilesUpdateExpression() { - AssertSQL( - "UPDATE \"users\" SET \"age\" = 30, \"admin\" = 1 WHERE (\"id\" = 1)", - users.filter(id == 1).update(age <- 30, admin <- true) - ) - } - - func test_update_compilesUpdateLimitOrderExpression() { - AssertSQL( - "UPDATE \"users\" SET \"age\" = 30 ORDER BY \"id\" LIMIT 1", - users.order(id).limit(1).update(age <- 30) - ) - } - - func test_update_encodable() throws { - let emails = Table("emails") - let value = TestCodable(int: 1, string: "2", bool: true, float: 3, double: 4, optional: nil, sub: nil) - let update = try emails.update(value) - AssertSQL( - "UPDATE \"emails\" SET \"int\" = 1, \"string\" = '2', \"bool\" = 1, \"float\" = 3.0, \"double\" = 4.0", - update - ) - } - - func test_update_encodable_with_nested_encodable() throws { - let emails = Table("emails") - let value1 = TestCodable(int: 1, string: "2", bool: true, float: 3, double: 4, optional: nil, sub: nil) - let value = TestCodable(int: 1, string: "2", bool: true, float: 3, double: 4, optional: nil, sub: value1) - let update = try emails.update(value) - let encodedJSON = try JSONEncoder().encode(value1) - let encodedJSONString = String(data: encodedJSON, encoding: .utf8)! - AssertSQL( - "UPDATE \"emails\" SET \"int\" = 1, \"string\" = '2', \"bool\" = 1, \"float\" = 3.0, \"double\" = 4.0, \"sub\" = '\(encodedJSONString)'", - update - ) - } - - func test_delete_compilesDeleteExpression() { - AssertSQL( - "DELETE FROM \"users\" WHERE (\"id\" = 1)", - users.filter(id == 1).delete() - ) - } - - func test_delete_compilesDeleteLimitOrderExpression() { - AssertSQL( - "DELETE FROM \"users\" ORDER BY \"id\" LIMIT 1", - users.order(id).limit(1).delete() - ) - } - - func test_delete_compilesExistsExpression() { - AssertSQL( - "SELECT EXISTS (SELECT * FROM \"users\")", - users.exists - ) - } - - func test_count_returnsCountExpression() { - AssertSQL("SELECT count(*) FROM \"users\"", users.count) - } - - func test_scalar_returnsScalarExpression() { - AssertSQL("SELECT \"int\" FROM \"table\"", table.select(int) as ScalarQuery) - AssertSQL("SELECT \"intOptional\" FROM \"table\"", table.select(intOptional) as ScalarQuery) - AssertSQL("SELECT DISTINCT \"int\" FROM \"table\"", table.select(distinct: int) as ScalarQuery) - AssertSQL("SELECT DISTINCT \"intOptional\" FROM \"table\"", table.select(distinct: intOptional) as ScalarQuery) - } - - func test_subscript_withExpression_returnsNamespacedExpression() { - let query = Table("query") - - AssertSQL("\"query\".\"blob\"", query[data]) - AssertSQL("\"query\".\"blobOptional\"", query[dataOptional]) - - AssertSQL("\"query\".\"bool\"", query[bool]) - AssertSQL("\"query\".\"boolOptional\"", query[boolOptional]) - - AssertSQL("\"query\".\"date\"", query[date]) - AssertSQL("\"query\".\"dateOptional\"", query[dateOptional]) - - AssertSQL("\"query\".\"double\"", query[double]) - AssertSQL("\"query\".\"doubleOptional\"", query[doubleOptional]) - - AssertSQL("\"query\".\"int\"", query[int]) - AssertSQL("\"query\".\"intOptional\"", query[intOptional]) - - AssertSQL("\"query\".\"int64\"", query[int64]) - AssertSQL("\"query\".\"int64Optional\"", query[int64Optional]) - - AssertSQL("\"query\".\"string\"", query[string]) - AssertSQL("\"query\".\"stringOptional\"", query[stringOptional]) - - AssertSQL("\"query\".*", query[*]) - } - - func test_tableNamespacedByDatabase() { - let table = Table("table", database: "attached") - - AssertSQL("SELECT * FROM \"attached\".\"table\"", table) - } - -} - -class QueryIntegrationTests : SQLiteTestCase { - - let id = Expression("id") - let email = Expression("email") - - override func setUp() { - super.setUp() - - CreateUsersTable() - } - - // MARK: - - - func test_select() { - let managerId = Expression("manager_id") - let managers = users.alias("managers") - - let alice = try! db.run(users.insert(email <- "alice@example.com")) - _ = try! db.run(users.insert(email <- "betsy@example.com", managerId <- alice)) - - for user in try! db.prepare(users.join(managers, on: managers[id] == users[managerId])) { - _ = user[users[managerId]] - } - } - - func test_prepareRowIterator() { - let names = ["a", "b", "c"] - try! InsertUsers(names) - - let emailColumn = Expression("email") - let emails = try! db.prepareRowIterator(users).map { $0[emailColumn] } - - XCTAssertEqual(names.map({ "\($0)@example.com" }), emails.sorted()) - } - - func test_ambiguousMap() { - let names = ["a", "b", "c"] - try! InsertUsers(names) - - let emails = try! db.prepare("select email from users", []).map { $0[0] as! String } - - XCTAssertEqual(names.map({ "\($0)@example.com" }), emails.sorted()) - } - - func test_select_optional() { - let managerId = Expression("manager_id") - let managers = users.alias("managers") - - let alice = try! db.run(users.insert(email <- "alice@example.com")) - _ = try! db.run(users.insert(email <- "betsy@example.com", managerId <- alice)) - - for user in try! db.prepare(users.join(managers, on: managers[id] == users[managerId])) { - _ = user[users[managerId]] - } - } - - func test_select_codable() throws { - let table = Table("codable") - try db.run(table.create { builder in - builder.column(Expression("int")) - builder.column(Expression("string")) - builder.column(Expression("bool")) - builder.column(Expression("float")) - builder.column(Expression("double")) - builder.column(Expression("optional")) - builder.column(Expression("sub")) - }) - - let value1 = TestCodable(int: 1, string: "2", bool: true, float: 3, double: 4, optional: nil, sub: nil) - let value = TestCodable(int: 5, string: "6", bool: true, float: 7, double: 8, optional: "optional", sub: value1) - - try db.run(table.insert(value)) - - let rows = try db.prepare(table) - let values: [TestCodable] = try rows.map({ try $0.decode() }) - XCTAssertEqual(values.count, 1) - XCTAssertEqual(values[0].int, 5) - XCTAssertEqual(values[0].string, "6") - XCTAssertEqual(values[0].bool, true) - XCTAssertEqual(values[0].float, 7) - XCTAssertEqual(values[0].double, 8) - XCTAssertEqual(values[0].optional, "optional") - XCTAssertEqual(values[0].sub?.int, 1) - XCTAssertEqual(values[0].sub?.string, "2") - XCTAssertEqual(values[0].sub?.bool, true) - XCTAssertEqual(values[0].sub?.float, 3) - XCTAssertEqual(values[0].sub?.double, 4) - XCTAssertNil(values[0].sub?.optional) - XCTAssertNil(values[0].sub?.sub) - } - - func test_scalar() { - XCTAssertEqual(0, try! db.scalar(users.count)) - XCTAssertEqual(false, try! db.scalar(users.exists)) - - try! InsertUsers("alice") - XCTAssertEqual(1, try! db.scalar(users.select(id.average))) - } - - func test_pluck() { - let rowid = try! db.run(users.insert(email <- "alice@example.com")) - XCTAssertEqual(rowid, try! db.pluck(users)![id]) - } - - func test_insert() { - let id = try! db.run(users.insert(email <- "alice@example.com")) - XCTAssertEqual(1, id) - } - - func test_update() { - let changes = try! db.run(users.update(email <- "alice@example.com")) - XCTAssertEqual(0, changes) - } - - func test_delete() { - let changes = try! db.run(users.delete()) - XCTAssertEqual(0, changes) - } - - func test_union() throws { - let expectedIDs = [ - try db.run(users.insert(email <- "alice@example.com")), - try db.run(users.insert(email <- "sally@example.com")) - ] - - let query1 = users.filter(email == "alice@example.com") - let query2 = users.filter(email == "sally@example.com") - - let actualIDs = try db.prepare(query1.union(query2)).map { $0[id] } - XCTAssertEqual(expectedIDs, actualIDs) - - let query3 = users.select(users[*], Expression(literal: "1 AS weight")).filter(email == "sally@example.com") - let query4 = users.select(users[*], Expression(literal: "2 AS weight")).filter(email == "alice@example.com") - - print(query3.union(query4).order(Expression(literal: "weight")).asSQL()) - - let orderedIDs = try db.prepare(query3.union(query4).order(Expression(literal: "weight"), email)).map { $0[id] } - XCTAssertEqual(Array(expectedIDs.reversed()), orderedIDs) - } - - func test_no_such_column() throws { - let doesNotExist = Expression("doesNotExist") - try! InsertUser("alice") - let row = try! db.pluck(users.filter(email == "alice@example.com"))! - - XCTAssertThrowsError(try row.get(doesNotExist)) { error in - if case QueryError.noSuchColumn(let name, _) = error { - XCTAssertEqual("\"doesNotExist\"", name) - } else { - XCTFail("unexpected error: \(error)") - } - } - } - - func test_catchConstraintError() { - try! db.run(users.insert(email <- "alice@example.com")) - do { - try db.run(users.insert(email <- "alice@example.com")) - XCTFail("expected error") - } catch let Result.error(_, code, _) where code == SQLITE_CONSTRAINT { - // expected - } catch let error { - XCTFail("unexpected error: \(error)") - } - } -} diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/RTreeTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/RTreeTests.swift deleted file mode 100644 index 7147533..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/RTreeTests.swift +++ /dev/null @@ -1,17 +0,0 @@ -import XCTest -import SQLite - -class RTreeTests : XCTestCase { - - func test_create_onVirtualTable_withRTree_createVirtualTableExpression() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING rtree(\"int64\", \"double\", \"double\")", - virtualTable.create(.RTree(int64, (double, double))) - ) - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING rtree(\"int64\", \"double\", \"double\", \"double\", \"double\")", - virtualTable.create(.RTree(int64, (double, double), (double, double))) - ) - } - -} \ No newline at end of file diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/RowTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/RowTests.swift deleted file mode 100644 index 17873e7..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/RowTests.swift +++ /dev/null @@ -1,88 +0,0 @@ -import XCTest -@testable import SQLite - -class RowTests : XCTestCase { - - public func test_get_value() { - let row = Row(["\"foo\"": 0], ["value"]) - let result = try! row.get(Expression("foo")) - - XCTAssertEqual("value", result) - } - - public func test_get_value_subscript() { - let row = Row(["\"foo\"": 0], ["value"]) - let result = row[Expression("foo")] - - XCTAssertEqual("value", result) - } - - public func test_get_value_optional() { - let row = Row(["\"foo\"": 0], ["value"]) - let result = try! row.get(Expression("foo")) - - XCTAssertEqual("value", result) - } - - public func test_get_value_optional_subscript() { - let row = Row(["\"foo\"": 0], ["value"]) - let result = row[Expression("foo")] - - XCTAssertEqual("value", result) - } - - public func test_get_value_optional_nil() { - let row = Row(["\"foo\"": 0], [nil]) - let result = try! row.get(Expression("foo")) - - XCTAssertNil(result) - } - - public func test_get_value_optional_nil_subscript() { - let row = Row(["\"foo\"": 0], [nil]) - let result = row[Expression("foo")] - - XCTAssertNil(result) - } - - public func test_get_type_mismatch_throws_unexpected_null_value() { - let row = Row(["\"foo\"": 0], ["value"]) - XCTAssertThrowsError(try row.get(Expression("foo"))) { error in - if case QueryError.unexpectedNullValue(let name) = error { - XCTAssertEqual("\"foo\"", name) - } else { - XCTFail("unexpected error: \(error)") - } - } - } - - public func test_get_type_mismatch_optional_returns_nil() { - let row = Row(["\"foo\"": 0], ["value"]) - let result = try! row.get(Expression("foo")) - XCTAssertNil(result) - } - - public func test_get_non_existent_column_throws_no_such_column() { - let row = Row(["\"foo\"": 0], ["value"]) - XCTAssertThrowsError(try row.get(Expression("bar"))) { error in - if case QueryError.noSuchColumn(let name, let columns) = error { - XCTAssertEqual("\"bar\"", name) - XCTAssertEqual(["\"foo\""], columns) - } else { - XCTFail("unexpected error: \(error)") - } - } - } - - public func test_get_ambiguous_column_throws() { - let row = Row(["table1.\"foo\"": 0, "table2.\"foo\"": 1], ["value"]) - XCTAssertThrowsError(try row.get(Expression("foo"))) { error in - if case QueryError.ambiguousColumn(let name, let columns) = error { - XCTAssertEqual("\"foo\"", name) - XCTAssertEqual(["table1.\"foo\"", "table2.\"foo\""], columns.sorted()) - } else { - XCTFail("unexpected error: \(error)") - } - } - } -} diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/SchemaTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/SchemaTests.swift deleted file mode 100644 index 30646b9..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/SchemaTests.swift +++ /dev/null @@ -1,788 +0,0 @@ -import XCTest -import SQLite - -class SchemaTests : XCTestCase { - - func test_drop_compilesDropTableExpression() { - XCTAssertEqual("DROP TABLE \"table\"", table.drop()) - XCTAssertEqual("DROP TABLE IF EXISTS \"table\"", table.drop(ifExists: true)) - } - - func test_drop_compilesDropVirtualTableExpression() { - XCTAssertEqual("DROP TABLE \"virtual_table\"", virtualTable.drop()) - XCTAssertEqual("DROP TABLE IF EXISTS \"virtual_table\"", virtualTable.drop(ifExists: true)) - } - - func test_drop_compilesDropViewExpression() { - XCTAssertEqual("DROP VIEW \"view\"", _view.drop()) - XCTAssertEqual("DROP VIEW IF EXISTS \"view\"", _view.drop(ifExists: true)) - } - - func test_create_withBuilder_compilesCreateTableExpression() { - XCTAssertEqual( - "CREATE TABLE \"table\" (" + - "\"blob\" BLOB NOT NULL, " + - "\"blobOptional\" BLOB, " + - "\"double\" REAL NOT NULL, " + - "\"doubleOptional\" REAL, " + - "\"int64\" INTEGER NOT NULL, " + - "\"int64Optional\" INTEGER, " + - "\"string\" TEXT NOT NULL, " + - "\"stringOptional\" TEXT" + - ")", - table.create { t in - t.column(data) - t.column(dataOptional) - t.column(double) - t.column(doubleOptional) - t.column(int64) - t.column(int64Optional) - t.column(string) - t.column(stringOptional) - } - ) - XCTAssertEqual( - "CREATE TEMPORARY TABLE \"table\" (\"int64\" INTEGER NOT NULL)", - table.create(temporary: true) { $0.column(int64) } - ) - XCTAssertEqual( - "CREATE TABLE IF NOT EXISTS \"table\" (\"int64\" INTEGER NOT NULL)", - table.create(ifNotExists: true) { $0.column(int64) } - ) - XCTAssertEqual( - "CREATE TEMPORARY TABLE IF NOT EXISTS \"table\" (\"int64\" INTEGER NOT NULL)", - table.create(temporary: true, ifNotExists: true) { $0.column(int64) } - ) - - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL) WITHOUT ROWID", - table.create(withoutRowid: true) { $0.column(int64) } - ) - XCTAssertEqual( - "CREATE TEMPORARY TABLE IF NOT EXISTS \"table\" (\"int64\" INTEGER NOT NULL) WITHOUT ROWID", - table.create(temporary: true, ifNotExists: true, withoutRowid: true) { $0.column(int64) } - ) - } - - func test_create_withQuery_compilesCreateTableExpression() { - XCTAssertEqual( - "CREATE TABLE \"table\" AS SELECT \"int64\" FROM \"view\"", - table.create(_view.select(int64)) - ) - } - - // thoroughness test for ambiguity - func test_column_compilesColumnDefinitionExpression() { - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL)", - table.create { t in t.column(int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE)", - table.create { t in t.column(int64, unique: true) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64\" > 0))", - table.create { t in t.column(int64, check: int64 > 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64Optional\" > 0))", - table.create { t in t.column(int64, check: int64Optional > 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL DEFAULT (\"int64\"))", - table.create { t in t.column(int64, defaultValue: int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL DEFAULT (0))", - table.create { t in t.column(int64, defaultValue: 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64\" > 0))", - table.create { t in t.column(int64, unique: true, check: int64 > 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64Optional\" > 0))", - table.create { t in t.column(int64, unique: true, check: int64Optional > 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE DEFAULT (\"int64\"))", - table.create { t in t.column(int64, unique: true, defaultValue: int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE DEFAULT (0))", - table.create { t in t.column(int64, unique: true, defaultValue: 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64\" > 0))", - table.create { t in t.column(int64, unique: true, check: int64 > 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64Optional\" > 0))", - table.create { t in t.column(int64, unique: true, check: int64Optional > 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64\" > 0) DEFAULT (\"int64\"))", - table.create { t in t.column(int64, unique: true, check: int64 > 0, defaultValue: int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64Optional\" > 0) DEFAULT (\"int64\"))", - table.create { t in t.column(int64, unique: true, check: int64Optional > 0, defaultValue: int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64\" > 0) DEFAULT (0))", - table.create { t in t.column(int64, unique: true, check: int64 > 0, defaultValue: 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64Optional\" > 0) DEFAULT (0))", - table.create { t in t.column(int64, unique: true, check: int64Optional > 0, defaultValue: 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64\" > 0) DEFAULT (\"int64\"))", - table.create { t in t.column(int64, check: int64 > 0, defaultValue: int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64Optional\" > 0) DEFAULT (\"int64\"))", - table.create { t in t.column(int64, check: int64Optional > 0, defaultValue: int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64\" > 0) DEFAULT (0))", - table.create { t in t.column(int64, check: int64 > 0, defaultValue: 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64Optional\" > 0) DEFAULT (0))", - table.create { t in t.column(int64, check: int64Optional > 0, defaultValue: 0) } - ) - - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL CHECK (\"int64\" > 0))", - table.create { t in t.column(int64, primaryKey: true, check: int64 > 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL CHECK (\"int64Optional\" > 0))", - table.create { t in t.column(int64, primaryKey: true, check: int64Optional > 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL DEFAULT (\"int64\"))", - table.create { t in t.column(int64, primaryKey: true, defaultValue: int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL CHECK (\"int64\" > 0))", - table.create { t in t.column(int64, primaryKey: true, check: int64 > 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL CHECK (\"int64Optional\" > 0))", - table.create { t in t.column(int64, primaryKey: true, check: int64Optional > 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL CHECK (\"int64\" > 0) DEFAULT (\"int64\"))", - table.create { t in t.column(int64, primaryKey: true, check: int64 > 0, defaultValue: int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL CHECK (\"int64Optional\" > 0) DEFAULT (\"int64\"))", - table.create { t in t.column(int64, primaryKey: true, check: int64Optional > 0, defaultValue: int64) } - ) - - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER)", - table.create { t in t.column(int64Optional) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE)", - table.create { t in t.column(int64Optional, unique: true) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64\" > 0))", - table.create { t in t.column(int64Optional, check: int64 > 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0))", - table.create { t in t.column(int64Optional, check: int64Optional > 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER DEFAULT (\"int64\"))", - table.create { t in t.column(int64Optional, defaultValue: int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER DEFAULT (\"int64Optional\"))", - table.create { t in t.column(int64Optional, defaultValue: int64Optional) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER DEFAULT (0))", - table.create { t in t.column(int64Optional, defaultValue: 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0))", - table.create { t in t.column(int64Optional, unique: true, check: int64 > 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0))", - table.create { t in t.column(int64Optional, unique: true, check: int64Optional > 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE DEFAULT (\"int64\"))", - table.create { t in t.column(int64Optional, unique: true, defaultValue: int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE DEFAULT (\"int64Optional\"))", - table.create { t in t.column(int64Optional, unique: true, defaultValue: int64Optional) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE DEFAULT (0))", - table.create { t in t.column(int64Optional, unique: true, defaultValue: 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0))", - table.create { t in t.column(int64Optional, unique: true, check: int64 > 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0))", - table.create { t in t.column(int64Optional, unique: true, check: int64Optional > 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0) DEFAULT (\"int64\"))", - table.create { t in t.column(int64Optional, unique: true, check: int64 > 0, defaultValue: int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0) DEFAULT (\"int64Optional\"))", - table.create { t in t.column(int64Optional, unique: true, check: int64 > 0, defaultValue: int64Optional) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0) DEFAULT (\"int64\"))", - table.create { t in t.column(int64Optional, unique: true, check: int64Optional > 0, defaultValue: int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0) DEFAULT (\"int64Optional\"))", - table.create { t in t.column(int64Optional, unique: true, check: int64Optional > 0, defaultValue: int64Optional) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0) DEFAULT (0))", - table.create { t in t.column(int64Optional, unique: true, check: int64 > 0, defaultValue: 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0) DEFAULT (0))", - table.create { t in t.column(int64Optional, unique: true, check: int64Optional > 0, defaultValue: 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64\" > 0) DEFAULT (\"int64\"))", - table.create { t in t.column(int64Optional, check: int64 > 0, defaultValue: int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0) DEFAULT (\"int64\"))", - table.create { t in t.column(int64Optional, check: int64Optional > 0, defaultValue: int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64\" > 0) DEFAULT (\"int64Optional\"))", - table.create { t in t.column(int64Optional, check: int64 > 0, defaultValue: int64Optional) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0) DEFAULT (\"int64Optional\"))", - table.create { t in t.column(int64Optional, check: int64Optional > 0, defaultValue: int64Optional) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64\" > 0) DEFAULT (0))", - table.create { t in t.column(int64Optional, check: int64 > 0, defaultValue: 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0) DEFAULT (0))", - table.create { t in t.column(int64Optional, check: int64Optional > 0, defaultValue: 0) } - ) - } - - func test_column_withIntegerExpression_compilesPrimaryKeyAutoincrementColumnDefinitionExpression() { - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", - table.create { t in t.column(int64, primaryKey: .autoincrement) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK (\"int64\" > 0))", - table.create { t in t.column(int64, primaryKey: .autoincrement, check: int64 > 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK (\"int64Optional\" > 0))", - table.create { t in t.column(int64, primaryKey: .autoincrement, check: int64Optional > 0) } - ) - } - - func test_column_withIntegerExpression_compilesReferentialColumnDefinitionExpression() { - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL REFERENCES \"table\" (\"int64\"))", - table.create { t in t.column(int64, references: table, int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL REFERENCES \"table\" (\"int64\"))", - table.create { t in t.column(int64, references: qualifiedTable, int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE REFERENCES \"table\" (\"int64\"))", - table.create { t in t.column(int64, unique: true, references: table, int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\"))", - table.create { t in t.column(int64, check: int64 > 0, references: table, int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\"))", - table.create { t in t.column(int64, check: int64Optional > 0, references: table, int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\"))", - table.create { t in t.column(int64, unique: true, check: int64 > 0, references: table, int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\"))", - table.create { t in t.column(int64, unique: true, check: int64Optional > 0, references: table, int64) } - ) - - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER REFERENCES \"table\" (\"int64\"))", - table.create { t in t.column(int64Optional, references: table, int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE REFERENCES \"table\" (\"int64\"))", - table.create { t in t.column(int64Optional, unique: true, references: table, int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\"))", - table.create { t in t.column(int64Optional, check: int64 > 0, references: table, int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\"))", - table.create { t in t.column(int64Optional, check: int64Optional > 0, references: table, int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\"))", - table.create { t in t.column(int64Optional, unique: true, check: int64 > 0, references: table, int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\"))", - table.create { t in t.column(int64Optional, unique: true, check: int64Optional > 0, references: table, int64) } - ) - } - - func test_column_withStringExpression_compilesCollatedColumnDefinitionExpression() { - XCTAssertEqual( - "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL COLLATE RTRIM)", - table.create { t in t.column(string, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE COLLATE RTRIM)", - table.create { t in t.column(string, unique: true, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL CHECK (\"string\" != '') COLLATE RTRIM)", - table.create { t in t.column(string, check: string != "", collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL CHECK (\"stringOptional\" != '') COLLATE RTRIM)", - table.create { t in t.column(string, check: stringOptional != "", collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL DEFAULT (\"string\") COLLATE RTRIM)", - table.create { t in t.column(string, defaultValue: string, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL DEFAULT ('string') COLLATE RTRIM)", - table.create { t in t.column(string, defaultValue: "string", collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE CHECK (\"string\" != '') COLLATE RTRIM)", - table.create { t in t.column(string, unique: true, check: string != "", collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE CHECK (\"stringOptional\" != '') COLLATE RTRIM)", - table.create { t in t.column(string, unique: true, check: stringOptional != "", collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE DEFAULT (\"string\") COLLATE RTRIM)", - table.create { t in t.column(string, unique: true, defaultValue: string, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE DEFAULT ('string') COLLATE RTRIM)", - table.create { t in t.column(string, unique: true, defaultValue: "string", collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE CHECK (\"string\" != '') DEFAULT (\"string\") COLLATE RTRIM)", - table.create { t in t.column(string, unique: true, check: string != "", defaultValue: string, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE CHECK (\"stringOptional\" != '') DEFAULT (\"string\") COLLATE RTRIM)", - table.create { t in t.column(string, unique: true, check: stringOptional != "", defaultValue: string, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE CHECK (\"string\" != '') DEFAULT ('string') COLLATE RTRIM)", - table.create { t in t.column(string, unique: true, check: string != "", defaultValue: "string", collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE CHECK (\"stringOptional\" != '') DEFAULT ('string') COLLATE RTRIM)", - table.create { t in t.column(string, unique: true, check: stringOptional != "", defaultValue: "string", collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL CHECK (\"string\" != '') DEFAULT (\"string\") COLLATE RTRIM)", - table.create { t in t.column(string, check: string != "", defaultValue: string, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL CHECK (\"stringOptional\" != '') DEFAULT (\"string\") COLLATE RTRIM)", - table.create { t in t.column(string, check: stringOptional != "", defaultValue: string, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL CHECK (\"string\" != '') DEFAULT ('string') COLLATE RTRIM)", - table.create { t in t.column(string, check: string != "", defaultValue: "string", collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"string\" TEXT NOT NULL CHECK (\"stringOptional\" != '') DEFAULT ('string') COLLATE RTRIM)", - table.create { t in t.column(string, check: stringOptional != "", defaultValue: "string", collate: .rtrim) } - ) - - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT COLLATE RTRIM)", - table.create { t in t.column(stringOptional, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT UNIQUE COLLATE RTRIM)", - table.create { t in t.column(stringOptional, unique: true, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT CHECK (\"string\" != '') COLLATE RTRIM)", - table.create { t in t.column(stringOptional, check: string != "", collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT CHECK (\"stringOptional\" != '') COLLATE RTRIM)", - table.create { t in t.column(stringOptional, check: stringOptional != "", collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT DEFAULT (\"string\") COLLATE RTRIM)", - table.create { t in t.column(stringOptional, defaultValue: string, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT DEFAULT (\"stringOptional\") COLLATE RTRIM)", - table.create { t in t.column(stringOptional, defaultValue: stringOptional, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT DEFAULT ('string') COLLATE RTRIM)", - table.create { t in t.column(stringOptional, defaultValue: "string", collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT UNIQUE CHECK (\"string\" != '') COLLATE RTRIM)", - table.create { t in t.column(stringOptional, unique: true, check: string != "", collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT UNIQUE CHECK (\"stringOptional\" != '') COLLATE RTRIM)", - table.create { t in t.column(stringOptional, unique: true, check: stringOptional != "", collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT UNIQUE DEFAULT (\"string\") COLLATE RTRIM)", - table.create { t in t.column(stringOptional, unique: true, defaultValue: string, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT UNIQUE DEFAULT (\"stringOptional\") COLLATE RTRIM)", - table.create { t in t.column(stringOptional, unique: true, defaultValue: stringOptional, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT UNIQUE DEFAULT ('string') COLLATE RTRIM)", - table.create { t in t.column(stringOptional, unique: true, defaultValue: "string", collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT UNIQUE CHECK (\"string\" != '') DEFAULT (\"string\") COLLATE RTRIM)", - table.create { t in t.column(stringOptional, unique: true, check: string != "", defaultValue: string, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT UNIQUE CHECK (\"string\" != '') DEFAULT (\"stringOptional\") COLLATE RTRIM)", - table.create { t in t.column(stringOptional, unique: true, check: string != "", defaultValue: stringOptional, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT UNIQUE CHECK (\"stringOptional\" != '') DEFAULT (\"string\") COLLATE RTRIM)", - table.create { t in t.column(stringOptional, unique: true, check: stringOptional != "", defaultValue: string, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT UNIQUE CHECK (\"stringOptional\" != '') DEFAULT (\"stringOptional\") COLLATE RTRIM)", - table.create { t in t.column(stringOptional, unique: true, check: stringOptional != "", defaultValue: stringOptional, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT UNIQUE CHECK (\"string\" != '') DEFAULT ('string') COLLATE RTRIM)", - table.create { t in t.column(stringOptional, unique: true, check: string != "", defaultValue: "string", collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT UNIQUE CHECK (\"stringOptional\" != '') DEFAULT ('string') COLLATE RTRIM)", - table.create { t in t.column(stringOptional, unique: true, check: stringOptional != "", defaultValue: "string", collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT CHECK (\"string\" != '') DEFAULT (\"string\") COLLATE RTRIM)", - table.create { t in t.column(stringOptional, check: string != "", defaultValue: string, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT CHECK (\"stringOptional\" != '') DEFAULT (\"string\") COLLATE RTRIM)", - table.create { t in t.column(stringOptional, check: stringOptional != "", defaultValue: string, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT CHECK (\"string\" != '') DEFAULT (\"stringOptional\") COLLATE RTRIM)", - table.create { t in t.column(stringOptional, check: string != "", defaultValue: stringOptional, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT CHECK (\"stringOptional\" != '') DEFAULT (\"stringOptional\") COLLATE RTRIM)", - table.create { t in t.column(stringOptional, check: stringOptional != "", defaultValue: stringOptional, collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT CHECK (\"string\" != '') DEFAULT ('string') COLLATE RTRIM)", - table.create { t in t.column(stringOptional, check: string != "", defaultValue: "string", collate: .rtrim) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (\"stringOptional\" TEXT CHECK (\"stringOptional\" != '') DEFAULT ('string') COLLATE RTRIM)", - table.create { t in t.column(stringOptional, check: stringOptional != "", defaultValue: "string", collate: .rtrim) } - ) - } - - func test_primaryKey_compilesPrimaryKeyExpression() { - XCTAssertEqual( - "CREATE TABLE \"table\" (PRIMARY KEY (\"int64\"))", - table.create { t in t.primaryKey(int64) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (PRIMARY KEY (\"int64\", \"string\"))", - table.create { t in t.primaryKey(int64, string) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (PRIMARY KEY (\"int64\", \"string\", \"double\"))", - table.create { t in t.primaryKey(int64, string, double) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (PRIMARY KEY (\"int64\", \"string\", \"double\", \"date\"))", - table.create { t in t.primaryKey(int64, string, double, date) } - ) - } - - func test_unique_compilesUniqueExpression() { - XCTAssertEqual( - "CREATE TABLE \"table\" (UNIQUE (\"int64\"))", - table.create { t in t.unique(int64) } - ) - } - - func test_check_compilesCheckExpression() { - XCTAssertEqual( - "CREATE TABLE \"table\" (CHECK ((\"int64\" > 0)))", - table.create { t in t.check(int64 > 0) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (CHECK ((\"int64Optional\" > 0)))", - table.create { t in t.check(int64Optional > 0) } - ) - } - - func test_foreignKey_compilesForeignKeyExpression() { - XCTAssertEqual( - "CREATE TABLE \"table\" (FOREIGN KEY (\"string\") REFERENCES \"table\" (\"string\"))", - table.create { t in t.foreignKey(string, references: table, string) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (FOREIGN KEY (\"stringOptional\") REFERENCES \"table\" (\"string\"))", - table.create { t in t.foreignKey(stringOptional, references: table, string) } - ) - - XCTAssertEqual( - "CREATE TABLE \"table\" (FOREIGN KEY (\"string\") REFERENCES \"table\" (\"string\") ON UPDATE CASCADE ON DELETE SET NULL)", - table.create { t in t.foreignKey(string, references: table, string, update: .cascade, delete: .setNull) } - ) - - XCTAssertEqual( - "CREATE TABLE \"table\" (FOREIGN KEY (\"string\", \"string\") REFERENCES \"table\" (\"string\", \"string\"))", - table.create { t in t.foreignKey((string, string), references: table, (string, string)) } - ) - XCTAssertEqual( - "CREATE TABLE \"table\" (FOREIGN KEY (\"string\", \"string\", \"string\") REFERENCES \"table\" (\"string\", \"string\", \"string\"))", - table.create { t in t.foreignKey((string, string, string), references: table, (string, string, string)) } - ) - } - - func test_addColumn_compilesAlterTableExpression() { - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL DEFAULT (1)", - table.addColumn(int64, defaultValue: 1) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL CHECK (\"int64\" > 0) DEFAULT (1)", - table.addColumn(int64, check: int64 > 0, defaultValue: 1) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL CHECK (\"int64Optional\" > 0) DEFAULT (1)", - table.addColumn(int64, check: int64Optional > 0, defaultValue: 1) - ) - - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER", - table.addColumn(int64Optional) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER CHECK (\"int64\" > 0)", - table.addColumn(int64Optional, check: int64 > 0) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0)", - table.addColumn(int64Optional, check: int64Optional > 0) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER DEFAULT (1)", - table.addColumn(int64Optional, defaultValue: 1) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER CHECK (\"int64\" > 0) DEFAULT (1)", - table.addColumn(int64Optional, check: int64 > 0, defaultValue: 1) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0) DEFAULT (1)", - table.addColumn(int64Optional, check: int64Optional > 0, defaultValue: 1) - ) - } - - func test_addColumn_withIntegerExpression_compilesReferentialAlterTableExpression() { - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL REFERENCES \"table\" (\"int64\")", - table.addColumn(int64, references: table, int64) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL UNIQUE REFERENCES \"table\" (\"int64\")", - table.addColumn(int64, unique: true, references: table, int64) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\")", - table.addColumn(int64, check: int64 > 0, references: table, int64) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\")", - table.addColumn(int64, check: int64Optional > 0, references: table, int64) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\")", - table.addColumn(int64, unique: true, check: int64 > 0, references: table, int64) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\")", - table.addColumn(int64, unique: true, check: int64Optional > 0, references: table, int64) - ) - - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER REFERENCES \"table\" (\"int64\")", - table.addColumn(int64Optional, references: table, int64) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER UNIQUE REFERENCES \"table\" (\"int64\")", - table.addColumn(int64Optional, unique: true, references: table, int64) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\")", - table.addColumn(int64Optional, check: int64 > 0, references: table, int64) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\")", - table.addColumn(int64Optional, check: int64Optional > 0, references: table, int64) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\")", - table.addColumn(int64Optional, unique: true, check: int64 > 0, references: table, int64) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\")", - table.addColumn(int64Optional, unique: true, check: int64Optional > 0, references: table, int64) - ) - } - - func test_addColumn_withStringExpression_compilesCollatedAlterTableExpression() { - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"string\" TEXT NOT NULL DEFAULT ('string') COLLATE RTRIM", - table.addColumn(string, defaultValue: "string", collate: .rtrim) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"string\" TEXT NOT NULL CHECK (\"string\" != '') DEFAULT ('string') COLLATE RTRIM", - table.addColumn(string, check: string != "", defaultValue: "string", collate: .rtrim) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"string\" TEXT NOT NULL CHECK (\"stringOptional\" != '') DEFAULT ('string') COLLATE RTRIM", - table.addColumn(string, check: stringOptional != "", defaultValue: "string", collate: .rtrim) - ) - - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"stringOptional\" TEXT COLLATE RTRIM", - table.addColumn(stringOptional, collate: .rtrim) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"stringOptional\" TEXT CHECK (\"string\" != '') COLLATE RTRIM", - table.addColumn(stringOptional, check: string != "", collate: .rtrim) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"stringOptional\" TEXT CHECK (\"stringOptional\" != '') COLLATE RTRIM", - table.addColumn(stringOptional, check: stringOptional != "", collate: .rtrim) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"stringOptional\" TEXT CHECK (\"string\" != '') DEFAULT ('string') COLLATE RTRIM", - table.addColumn(stringOptional, check: string != "", defaultValue: "string", collate: .rtrim) - ) - XCTAssertEqual( - "ALTER TABLE \"table\" ADD COLUMN \"stringOptional\" TEXT CHECK (\"stringOptional\" != '') DEFAULT ('string') COLLATE RTRIM", - table.addColumn(stringOptional, check: stringOptional != "", defaultValue: "string", collate: .rtrim) - ) - } - - func test_rename_compilesAlterTableRenameToExpression() { - XCTAssertEqual("ALTER TABLE \"old\" RENAME TO \"table\"", Table("old").rename(table)) - } - - func test_createIndex_compilesCreateIndexExpression() { - XCTAssertEqual("CREATE INDEX \"index_table_on_int64\" ON \"table\" (\"int64\")", table.createIndex(int64)) - - XCTAssertEqual( - "CREATE UNIQUE INDEX \"index_table_on_int64\" ON \"table\" (\"int64\")", - table.createIndex(int64, unique: true) - ) - XCTAssertEqual( - "CREATE INDEX IF NOT EXISTS \"index_table_on_int64\" ON \"table\" (\"int64\")", - table.createIndex(int64, ifNotExists: true) - ) - XCTAssertEqual( - "CREATE UNIQUE INDEX IF NOT EXISTS \"index_table_on_int64\" ON \"table\" (\"int64\")", - table.createIndex(int64, unique: true, ifNotExists: true) - ) - XCTAssertEqual( - "CREATE UNIQUE INDEX IF NOT EXISTS \"main\".\"index_table_on_int64\" ON \"table\" (\"int64\")", - qualifiedTable.createIndex(int64, unique: true, ifNotExists: true) - ) - } - - func test_dropIndex_compilesCreateIndexExpression() { - XCTAssertEqual("DROP INDEX \"index_table_on_int64\"", table.dropIndex(int64)) - XCTAssertEqual("DROP INDEX IF EXISTS \"index_table_on_int64\"", table.dropIndex(int64, ifExists: true)) - } - - func test_create_onView_compilesCreateViewExpression() { - XCTAssertEqual( - "CREATE VIEW \"view\" AS SELECT \"int64\" FROM \"table\"", - _view.create(table.select(int64)) - ) - XCTAssertEqual( - "CREATE TEMPORARY VIEW \"view\" AS SELECT \"int64\" FROM \"table\"", - _view.create(table.select(int64), temporary: true) - ) - XCTAssertEqual( - "CREATE VIEW IF NOT EXISTS \"view\" AS SELECT \"int64\" FROM \"table\"", - _view.create(table.select(int64), ifNotExists: true) - ) - XCTAssertEqual( - "CREATE TEMPORARY VIEW IF NOT EXISTS \"view\" AS SELECT \"int64\" FROM \"table\"", - _view.create(table.select(int64), temporary: true, ifNotExists: true) - ) - } - - func test_create_onVirtualTable_compilesCreateVirtualTableExpression() { - XCTAssertEqual( - "CREATE VIRTUAL TABLE \"virtual_table\" USING \"custom\"('foo', 'bar')", - virtualTable.create(Module("custom", ["foo", "bar"])) - ) - } - - func test_rename_onVirtualTable_compilesAlterTableRenameToExpression() { - XCTAssertEqual( - "ALTER TABLE \"old\" RENAME TO \"virtual_table\"", - VirtualTable("old").rename(virtualTable) - ) - } - -} diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/SetterTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/SetterTests.swift deleted file mode 100644 index d4f189d..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/SetterTests.swift +++ /dev/null @@ -1,137 +0,0 @@ -import XCTest -import SQLite - -class SetterTests : XCTestCase { - - func test_setterAssignmentOperator_buildsSetter() { - AssertSQL("\"int\" = \"int\"", int <- int) - AssertSQL("\"int\" = 1", int <- 1) - AssertSQL("\"intOptional\" = \"int\"", intOptional <- int) - AssertSQL("\"intOptional\" = \"intOptional\"", intOptional <- intOptional) - AssertSQL("\"intOptional\" = 1", intOptional <- 1) - AssertSQL("\"intOptional\" = NULL", intOptional <- nil) - } - - func test_plusEquals_withStringExpression_buildsSetter() { - AssertSQL("\"string\" = (\"string\" || \"string\")", string += string) - AssertSQL("\"string\" = (\"string\" || 'literal')", string += "literal") - AssertSQL("\"stringOptional\" = (\"stringOptional\" || \"string\")", stringOptional += string) - AssertSQL("\"stringOptional\" = (\"stringOptional\" || \"stringOptional\")", stringOptional += stringOptional) - AssertSQL("\"stringOptional\" = (\"stringOptional\" || 'literal')", stringOptional += "literal") - } - - func test_plusEquals_withNumberExpression_buildsSetter() { - AssertSQL("\"int\" = (\"int\" + \"int\")", int += int) - AssertSQL("\"int\" = (\"int\" + 1)", int += 1) - AssertSQL("\"intOptional\" = (\"intOptional\" + \"int\")", intOptional += int) - AssertSQL("\"intOptional\" = (\"intOptional\" + \"intOptional\")", intOptional += intOptional) - AssertSQL("\"intOptional\" = (\"intOptional\" + 1)", intOptional += 1) - - AssertSQL("\"double\" = (\"double\" + \"double\")", double += double) - AssertSQL("\"double\" = (\"double\" + 1.0)", double += 1) - AssertSQL("\"doubleOptional\" = (\"doubleOptional\" + \"double\")", doubleOptional += double) - AssertSQL("\"doubleOptional\" = (\"doubleOptional\" + \"doubleOptional\")", doubleOptional += doubleOptional) - AssertSQL("\"doubleOptional\" = (\"doubleOptional\" + 1.0)", doubleOptional += 1) - } - - func test_minusEquals_withNumberExpression_buildsSetter() { - AssertSQL("\"int\" = (\"int\" - \"int\")", int -= int) - AssertSQL("\"int\" = (\"int\" - 1)", int -= 1) - AssertSQL("\"intOptional\" = (\"intOptional\" - \"int\")", intOptional -= int) - AssertSQL("\"intOptional\" = (\"intOptional\" - \"intOptional\")", intOptional -= intOptional) - AssertSQL("\"intOptional\" = (\"intOptional\" - 1)", intOptional -= 1) - - AssertSQL("\"double\" = (\"double\" - \"double\")", double -= double) - AssertSQL("\"double\" = (\"double\" - 1.0)", double -= 1) - AssertSQL("\"doubleOptional\" = (\"doubleOptional\" - \"double\")", doubleOptional -= double) - AssertSQL("\"doubleOptional\" = (\"doubleOptional\" - \"doubleOptional\")", doubleOptional -= doubleOptional) - AssertSQL("\"doubleOptional\" = (\"doubleOptional\" - 1.0)", doubleOptional -= 1) - } - - func test_timesEquals_withNumberExpression_buildsSetter() { - AssertSQL("\"int\" = (\"int\" * \"int\")", int *= int) - AssertSQL("\"int\" = (\"int\" * 1)", int *= 1) - AssertSQL("\"intOptional\" = (\"intOptional\" * \"int\")", intOptional *= int) - AssertSQL("\"intOptional\" = (\"intOptional\" * \"intOptional\")", intOptional *= intOptional) - AssertSQL("\"intOptional\" = (\"intOptional\" * 1)", intOptional *= 1) - - AssertSQL("\"double\" = (\"double\" * \"double\")", double *= double) - AssertSQL("\"double\" = (\"double\" * 1.0)", double *= 1) - AssertSQL("\"doubleOptional\" = (\"doubleOptional\" * \"double\")", doubleOptional *= double) - AssertSQL("\"doubleOptional\" = (\"doubleOptional\" * \"doubleOptional\")", doubleOptional *= doubleOptional) - AssertSQL("\"doubleOptional\" = (\"doubleOptional\" * 1.0)", doubleOptional *= 1) - } - - func test_dividedByEquals_withNumberExpression_buildsSetter() { - AssertSQL("\"int\" = (\"int\" / \"int\")", int /= int) - AssertSQL("\"int\" = (\"int\" / 1)", int /= 1) - AssertSQL("\"intOptional\" = (\"intOptional\" / \"int\")", intOptional /= int) - AssertSQL("\"intOptional\" = (\"intOptional\" / \"intOptional\")", intOptional /= intOptional) - AssertSQL("\"intOptional\" = (\"intOptional\" / 1)", intOptional /= 1) - - AssertSQL("\"double\" = (\"double\" / \"double\")", double /= double) - AssertSQL("\"double\" = (\"double\" / 1.0)", double /= 1) - AssertSQL("\"doubleOptional\" = (\"doubleOptional\" / \"double\")", doubleOptional /= double) - AssertSQL("\"doubleOptional\" = (\"doubleOptional\" / \"doubleOptional\")", doubleOptional /= doubleOptional) - AssertSQL("\"doubleOptional\" = (\"doubleOptional\" / 1.0)", doubleOptional /= 1) - } - - func test_moduloEquals_withIntegerExpression_buildsSetter() { - AssertSQL("\"int\" = (\"int\" % \"int\")", int %= int) - AssertSQL("\"int\" = (\"int\" % 1)", int %= 1) - AssertSQL("\"intOptional\" = (\"intOptional\" % \"int\")", intOptional %= int) - AssertSQL("\"intOptional\" = (\"intOptional\" % \"intOptional\")", intOptional %= intOptional) - AssertSQL("\"intOptional\" = (\"intOptional\" % 1)", intOptional %= 1) - } - - func test_leftShiftEquals_withIntegerExpression_buildsSetter() { - AssertSQL("\"int\" = (\"int\" << \"int\")", int <<= int) - AssertSQL("\"int\" = (\"int\" << 1)", int <<= 1) - AssertSQL("\"intOptional\" = (\"intOptional\" << \"int\")", intOptional <<= int) - AssertSQL("\"intOptional\" = (\"intOptional\" << \"intOptional\")", intOptional <<= intOptional) - AssertSQL("\"intOptional\" = (\"intOptional\" << 1)", intOptional <<= 1) - } - - func test_rightShiftEquals_withIntegerExpression_buildsSetter() { - AssertSQL("\"int\" = (\"int\" >> \"int\")", int >>= int) - AssertSQL("\"int\" = (\"int\" >> 1)", int >>= 1) - AssertSQL("\"intOptional\" = (\"intOptional\" >> \"int\")", intOptional >>= int) - AssertSQL("\"intOptional\" = (\"intOptional\" >> \"intOptional\")", intOptional >>= intOptional) - AssertSQL("\"intOptional\" = (\"intOptional\" >> 1)", intOptional >>= 1) - } - - func test_bitwiseAndEquals_withIntegerExpression_buildsSetter() { - AssertSQL("\"int\" = (\"int\" & \"int\")", int &= int) - AssertSQL("\"int\" = (\"int\" & 1)", int &= 1) - AssertSQL("\"intOptional\" = (\"intOptional\" & \"int\")", intOptional &= int) - AssertSQL("\"intOptional\" = (\"intOptional\" & \"intOptional\")", intOptional &= intOptional) - AssertSQL("\"intOptional\" = (\"intOptional\" & 1)", intOptional &= 1) - } - - func test_bitwiseOrEquals_withIntegerExpression_buildsSetter() { - AssertSQL("\"int\" = (\"int\" | \"int\")", int |= int) - AssertSQL("\"int\" = (\"int\" | 1)", int |= 1) - AssertSQL("\"intOptional\" = (\"intOptional\" | \"int\")", intOptional |= int) - AssertSQL("\"intOptional\" = (\"intOptional\" | \"intOptional\")", intOptional |= intOptional) - AssertSQL("\"intOptional\" = (\"intOptional\" | 1)", intOptional |= 1) - } - - func test_bitwiseExclusiveOrEquals_withIntegerExpression_buildsSetter() { - AssertSQL("\"int\" = (~((\"int\" & \"int\")) & (\"int\" | \"int\"))", int ^= int) - AssertSQL("\"int\" = (~((\"int\" & 1)) & (\"int\" | 1))", int ^= 1) - AssertSQL("\"intOptional\" = (~((\"intOptional\" & \"int\")) & (\"intOptional\" | \"int\"))", intOptional ^= int) - AssertSQL("\"intOptional\" = (~((\"intOptional\" & \"intOptional\")) & (\"intOptional\" | \"intOptional\"))", intOptional ^= intOptional) - AssertSQL("\"intOptional\" = (~((\"intOptional\" & 1)) & (\"intOptional\" | 1))", intOptional ^= 1) - } - - func test_postfixPlus_withIntegerValue_buildsSetter() { - AssertSQL("\"int\" = (\"int\" + 1)", int++) - AssertSQL("\"intOptional\" = (\"intOptional\" + 1)", intOptional++) - } - - func test_postfixMinus_withIntegerValue_buildsSetter() { - AssertSQL("\"int\" = (\"int\" - 1)", int--) - AssertSQL("\"intOptional\" = (\"intOptional\" - 1)", intOptional--) - } - -} diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/StatementTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/StatementTests.swift deleted file mode 100644 index 326259b..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/StatementTests.swift +++ /dev/null @@ -1,26 +0,0 @@ -import XCTest -import SQLite - -class StatementTests : SQLiteTestCase { - override func setUp() { - super.setUp() - CreateUsersTable() - } - - func test_cursor_to_blob() { - try! InsertUsers("alice") - let statement = try! db.prepare("SELECT email FROM users") - XCTAssert(try! statement.step()) - let blob = statement.row[0] as Blob - XCTAssertEqual("alice@example.com", String(bytes: blob.bytes, encoding: .utf8)!) - } - - func test_zero_sized_blob_returns_null() { - let blobs = Table("blobs") - let blobColumn = Expression("blob_column") - try! db.run(blobs.create { $0.column(blobColumn) }) - try! db.run(blobs.insert(blobColumn <- Blob(bytes: []))) - let blobValue = try! db.scalar(blobs.select(blobColumn).limit(1, offset: 0)) - XCTAssertEqual([], blobValue.bytes) - } -} diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/TestHelpers.swift b/ios/libs/Sqlite/Tests/SQLiteTests/TestHelpers.swift deleted file mode 100644 index 2e491b0..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/TestHelpers.swift +++ /dev/null @@ -1,126 +0,0 @@ -import XCTest -@testable import SQLite - -class SQLiteTestCase : XCTestCase { - private var trace:[String: Int]! - var db:Connection! - let users = Table("users") - - override func setUp() { - super.setUp() - db = try! Connection() - trace = [String:Int]() - - db.trace { SQL in - print(SQL) - self.trace[SQL, default: 0] += 1 - } - } - - func CreateUsersTable() { - try! db.execute(""" - CREATE TABLE users ( - id INTEGER PRIMARY KEY, - email TEXT NOT NULL UNIQUE, - age INTEGER, - salary REAL, - admin BOOLEAN NOT NULL DEFAULT 0 CHECK (admin IN (0, 1)), - manager_id INTEGER, - FOREIGN KEY(manager_id) REFERENCES users(id) - ) - """ - ) - } - - func InsertUsers(_ names: String...) throws { - try InsertUsers(names) - } - - func InsertUsers(_ names: [String]) throws { - for name in names { try InsertUser(name) } - } - - @discardableResult func InsertUser(_ name: String, age: Int? = nil, admin: Bool = false) throws -> Statement { - return try db.run( - "INSERT INTO \"users\" (email, age, admin) values (?, ?, ?)", - "\(name)@example.com", age?.datatypeValue, admin.datatypeValue - ) - } - - func AssertSQL(_ SQL: String, _ executions: Int = 1, _ message: String? = nil, file: StaticString = #file, line: UInt = #line) { - XCTAssertEqual( - executions, trace[SQL] ?? 0, - message ?? SQL, - file: file, line: line - ) - } - - func AssertSQL(_ SQL: String, _ statement: Statement, _ message: String? = nil, file: StaticString = #file, line: UInt = #line) { - try! statement.run() - AssertSQL(SQL, 1, message, file: file, line: line) - if let count = trace[SQL] { trace[SQL] = count - 1 } - } - -// func AssertSQL(SQL: String, _ query: Query, _ message: String? = nil, file: String = __FILE__, line: UInt = __LINE__) { -// for _ in query {} -// AssertSQL(SQL, 1, message, file: file, line: line) -// if let count = trace[SQL] { trace[SQL] = count - 1 } -// } - - func async(expect description: String = "async", timeout: Double = 5, block: (@escaping () -> Void) -> Void) { - let expectation = self.expectation(description: description) - block({ expectation.fulfill() }) - waitForExpectations(timeout: timeout, handler: nil) - } - -} - -let bool = Expression("bool") -let boolOptional = Expression("boolOptional") - -let data = Expression("blob") -let dataOptional = Expression("blobOptional") - -let date = Expression("date") -let dateOptional = Expression("dateOptional") - -let double = Expression("double") -let doubleOptional = Expression("doubleOptional") - -let int = Expression("int") -let intOptional = Expression("intOptional") - -let int64 = Expression("int64") -let int64Optional = Expression("int64Optional") - -let string = Expression("string") -let stringOptional = Expression("stringOptional") - -func AssertSQL(_ expression1: @autoclosure () -> String, _ expression2: @autoclosure () -> Expressible, file: StaticString = #file, line: UInt = #line) { - XCTAssertEqual(expression1(), expression2().asSQL(), file: file, line: line) -} - -let table = Table("table") -let qualifiedTable = Table("table", database: "main") -let virtualTable = VirtualTable("virtual_table") -let _view = View("view") // avoid Mac XCTestCase collision - -class TestCodable: Codable { - let int: Int - let string: String - let bool: Bool - let float: Float - let double: Double - let optional: String? - let sub: TestCodable? - - init(int: Int, string: String, bool: Bool, float: Float, double: Double, optional: String?, sub: TestCodable?) { - self.int = int - self.string = string - self.bool = bool - self.float = float - self.double = double - self.optional = optional - self.sub = sub - } -} diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/ValueTests.swift b/ios/libs/Sqlite/Tests/SQLiteTests/ValueTests.swift deleted file mode 100644 index bda2b4b..0000000 --- a/ios/libs/Sqlite/Tests/SQLiteTests/ValueTests.swift +++ /dev/null @@ -1,6 +0,0 @@ -import XCTest -import SQLite - -class ValueTests : XCTestCase { - -} diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/fixtures/encrypted-3.x.sqlite b/ios/libs/Sqlite/Tests/SQLiteTests/fixtures/encrypted-3.x.sqlite deleted file mode 100644 index e69de29..0000000 diff --git a/ios/libs/Sqlite/Tests/SQLiteTests/fixtures/encrypted-4.x.sqlite b/ios/libs/Sqlite/Tests/SQLiteTests/fixtures/encrypted-4.x.sqlite deleted file mode 100644 index e69de29..0000000 diff --git a/ios/libs/Sqlite/run-tests.sh b/ios/libs/Sqlite/run-tests.sh deleted file mode 100644 index 0a105c4..0000000 --- a/ios/libs/Sqlite/run-tests.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -set -ev -if [ -n "$BUILD_SCHEME" ]; then - if [ -n "$IOS_SIMULATOR" ]; then - make test BUILD_SCHEME="$BUILD_SCHEME" IOS_SIMULATOR="$IOS_SIMULATOR" IOS_VERSION="$IOS_VERSION" - else - make test BUILD_SCHEME="$BUILD_SCHEME" - fi -elif [ -n "$VALIDATOR_SUBSPEC" ]; then - cd Tests/CocoaPods && make test -elif [ -n "$CARTHAGE_PLATFORM" ]; then - cd Tests/Carthage && make test CARTHAGE_PLATFORM="$CARTHAGE_PLATFORM" -elif [ -n "${PACKAGE_MANAGER_COMMAND}" ]; then - swift ${PACKAGE_MANAGER_COMMAND} -fi diff --git a/ios/libs/Webim/Cartfile b/ios/libs/Webim/Cartfile deleted file mode 100644 index 9f85bbe..0000000 --- a/ios/libs/Webim/Cartfile +++ /dev/null @@ -1 +0,0 @@ -github "stephencelis/SQLite.swift" == 0.11.5 diff --git a/ios/libs/Webim/Cartfile.resolved b/ios/libs/Webim/Cartfile.resolved deleted file mode 100644 index 438fb56..0000000 --- a/ios/libs/Webim/Cartfile.resolved +++ /dev/null @@ -1 +0,0 @@ -github "stephencelis/SQLite.swift" "0.11.4" diff --git a/ios/libs/Webim/Documentation/Images/Logo.png b/ios/libs/Webim/Documentation/Images/Logo.png deleted file mode 100644 index feb4675aef36902bfe030aac38cacb2290d21971..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7933 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 Z02NKNbT6>z3Qr9as48kHRLi~n_+Q|Ac7*@{ diff --git a/ios/libs/Webim/Documentation/Images/Screenshots/ChatScreenClassic.png b/ios/libs/Webim/Documentation/Images/Screenshots/ChatScreenClassic.png deleted file mode 100644 index f11a5d23be642d92afdee63e40bdf36a009f4c8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30563 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 diff --git a/ios/libs/Webim/Documentation/Images/Screenshots/ChatScreenDark.png b/ios/libs/Webim/Documentation/Images/Screenshots/ChatScreenDark.png deleted file mode 100644 index b050e495695964f9d04eca42d737b7f1801a0b5b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30034 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 LNkvXXu0mjf)G9%} diff --git a/ios/libs/Webim/Documentation/Images/Screenshots/ImageScreenDark.png b/ios/libs/Webim/Documentation/Images/Screenshots/ImageScreenDark.png deleted file mode 100644 index 9e7a868ab898403f091ff4cf543802f7b31c3298..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20412 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 WiEFdeVNPWL0000x16WK< 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 uS7HF%ljV6HLvIn6st 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 aF#iwAL;A$Ey`O~u0000Q;~gyNs0-9Kpx4Wrs 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 aARaK3yzQ)LIQsA3Jizj5a&5}i?lRIcg=DA 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 of contents - -- [Webim class](#webim) - - [Class method newSessionBuilder()](#new-session-builder) - - [Class method parse(remoteNotification:visitorId:)](#parse-remote-notification) - - [Class method isWebim(remoteNotification:)](#is-webim-remote-notification) - - [RemoteNotificationSystem enum](#remote-notification-system) - - [APNS case](#apns) - - [NONE case](#none) -- [SessionBuilder class](#session-builder) - - [Instance method set(accountName:)](#set-account-name) - - [Instance method set(location:)](#set-location) - - [Instance method set(prechat:)](#set-prechat) - - [Instance method set(appVersion:)](#set-app-version) - - [Instance method set(visitorFieldsJSONString:)](#set-visitor-fields-json-string-json-string) - - [Instance method set(visitorFieldsJSONData:)](#set-visitor-fields-json-data-json-data) - - [Instance method set(providedAuthorizationTokenStateListener:providedAuthorizationToken:)](#set-provided-authorization-token-state-listener-provided-authorization-token) - - [Instance method set(pageTitle:)](#set-page-title) - - [Instance method set(fatalErrorHandler:)](#set-fatal-error-handler) - - [Instance method set(remoteNotificationSystem:)](#set-remote-notification-system) - - [Instance method set(deviceToken:)](#set-device-token) - - [Instance method set(isLocalHistoryStoragingEnabled:)](#set-is-local-history-storaging-enabled) - - [Instance method set(isVisitorDataClearingEnabled:)](#set-is-visitor-data-clearing-enabled) - - [Instance method set(webimLogger:verbosityLevel:)](#set-webim-logger-verbosity-level) - - [Instance method build()](#build) - - [WebimLoggerVerbosityLevel enum](#webim-logger-verbosity-level) - - [VERBOSE case](#verbose) - - [DEBUG case](#debug) - - [INFO](#info) - - [WARNING case](#warning) - - [ERROR case](#error) - - [SessionBuilderError enum](#session-builder-error) - - [NIL_ACCOUNT_NAME case](#nil-account-name) - - [NIL_LOCATION case](#nil-location) - - [INVALID_AUTHENTICATION_PARAMETERS](#invalid-authentication-parameters) - - [INVALID_REMOTE_NOTIFICATION_CONFIGURATION case](#invalid-remote-notification-configuration) -- [ProvidedAuthorizationTokenStateListener protocol](#provided-authorization-token-state-listener) - - [update(providedAuthorizationToken:) method](#update-provided-authorization-token) -- [WebimSession protocol](#webim-session) - - [resume() method](#resume) - - [pause() method](#pause) - - [destroy() method](#destroy) - - [destroyWithClearVisitorData() method](#destroy-with-clear-visitor-data) - - [getStream() method](#get-stream) - - [change(location:) method](#change-location) - - [set(deviceToken:) method](#set-device-token) -- [MessageStream protocol](#message-stream) - - [getVisitSessionState() method](#get-visit-session-state) - - [getChatState() method](#get-chat-state) - - [getUnreadByOperatorTimestamp() method](#get-unread-by-operator-timestamp) - - [getUnreadByVisitorMessageCount() method](#get-unread-by-visitor-message-count) - - [getUnreadByVisitorTimestamp() method](#get-unread-by-visitor-timestamp) - - [getDepartmentList() method](#get-department-list) - - [getLocationSettings() method](#get-location-settings) - - [getCurrentOperator() method](#get-current-operator) - - [getLastRatingOfOperatorWith(id:) method](#get-last-rating-of-operator-with-id) - - [rateOperatorWith(id:byRating:completionHandler:) method](#rate-operator-with-id-by-rating-rating) - - [respondSentryCall(id:) method](#respond-sentry-call) - - [startChat() method](#start-chat) - - [startChat(firstQuestion:) method](#start-chat-first-question) - - [startChat(customFields:) method](#start-chat-custom-fields) - - [startChat(departmentKey:) method](#start-chat-department-key) - - [startChat(departmentKey:firstQuestion:) method](#start-chat-department-key-first-question) - - [startChat(firstQuestion:customFields) method](#start-chat-first-question-custom-fields) - - [startChat(departmentKey:customFields) method](#start-chat-department-key-custom-fields) - - [startChat(departmentKey:firstQuestion:customFields) method](#start-chat-department-key-first-question-custom-fields) - - [closeChat() method](#close-chat) - - [send(message:) method](#send-message) - - [setVisitorTyping(draftMessage:) method](#set-visitor-typing-draft-message) - - [send(message:data:completionHandler:) method](#send-message-data) - - [send(message:isHintQuestion:) method](#send-message-is-hint-question) - - [send(file:filename:mimeType:completionHandler:) method](#send-file-filename-mime-type-completion-handler) - - [udpateWidgetStatus(data:) method](#update-widget-status) - - [edit(message:text:completionHandler:) method](#edit-message) - - [delete(message:completionHandler:) method](#delete-message) - - [setChatRead() method](#set-chat-read) - - [set(prechatFields:) method](#set-prechat-fields) - - [newMessageTracker(messageListener:) method](#new-message-tracker-message-listener) - - [set(visitSessionStateListener:)](#set-visit-session-state-listener) - - [set(chatStateListener:) method](#set-chat-state-listener) - - [set(currentOperatorChangeListener:) method](#set-current-operator-change-listener) - - [set(departmentListChangeListener:)](#set-department-list-change-listener) - - [set(operatorTypingListener:) method](#set-operator-typing-listener) - - [set(locationSettingsChangeListener:) method](#set-location-settings-change-listener) - - [set(onlineStatusChangeListener:) method](#set-online-status-change-listener) - - [set(unreadByOperatorTimestampChangeListener:) method](#set-unread-by-operator-timestamp-change-listener) - - [set(unreadByVisitorMessageCountChangeListener:) method](#set-unread-by-visitor-message-count-change-listener) - - [set(unreadByVisitorTimestampChangeListener:) method](#set-unread-by-visitor-timestamp-change-listener) -- [DataMessageCompletionHandler protocol](#data-message-completion-handler) - - [onSuccess(messageID:) method](#on-success-message-id-data-message-completion-handler) - - [onFailure(messageID:,error:) method](#on-failure-message-id-error-data-message-completion-handler) -- [EditMessageCompletionHandler protocol](#edit-message-completion-handler) - - [onSuccess(messageID:) method](#on-success-message-id-edit-message-completion-handler) - - [onFailure(messageID:,error:) method](#on-failure-message-id-error-edit-message-completion-handler) -- [DeleteMessageCompletionHandler protocol](#delete-message-completion-handler) - - [onSuccess(messageID:) method](#on-success-message-id-delete-message-completion-handler) - - [onFailure(messageID:,error:) method](#on-failure-message-id-error-delete-message-completion-handler) -- [SendFileCompletionHandler protocol](#send-file-completion-handler) - - [onSuccess(messageID:) method](#on-success-message-id) - - [onFailure(messageID:,error:) method](#on-failure-message-id-error) -- [RateOperatorCompletionHandler protocol](#rate-operator-completion-handler) - - [onSuccess() method](#on-success) - - [onFailure(error:) method](#on-failure-error) -- [VisitSessionStateListener protocol](#visit-session-state-listener) - - [changed(state:to:)](#changed-state-previous-state-to-new-state-visit-session-state-listener) -- [DepartmentListChangeListener protocol](#department-list-change-listener) - - [received(departmentList:) method](#received-department-list) -- [LocationSettings protocol](#location-settings) - - [areHintsEnabled() method](#are-hints-enabled) -- [ChatStateListener protocol](#chat-state-listener) - - [changed(state:to:) method](#changed-state-previous-state-to-new-state) -- [CurrentOperatorChangeListener protocol](#current-operator-change-listener) - - [changed(operator:to:) method](#changed-operator-previous-operator-to-new-operator) -- [OperatorTypingListener protocol](#operator-typing-listener) - - [onOperatorTypingStateChanged(isTyping:) method](#on-operator-typing-state-changed-is-typing) -- [LocationSettingsChangeListener protocol](#location-settings-shange-listener) - - [changed(locationSettings:to:) method](#changed-location-settings-previous-location-settings-to-new-location-settings) -- [OnlineStatusChangeListener protocol](#online-status-change-listener) - - [changed(onlineStatus:to:) method](#changed-session-online-status-previous-session-online-status-to-new-session-online-status) -- [UnreadByOperatorTimestampChangeListener protocol](#unread-by-operator-timestamp-change-listener) - - [changedUnreadByOperatorTimestampTo(newValue:) method](#changed-unread-by-operator-timestamp-to-new-value) -- [UnreadByVisitorMessageCountChangeListener protocol](#unread-by-visitor-message-count-change-listener) - - [changedUnreadByVisitorMessageCountTo(newValue:) method](#changed-unread-by-visitor-message-count-to-new-value) -- [UnreadByVisitorTimestampChangeListener protocol](#unread-by-visitor-timestamp-change-listener) - - [changedUnreadByVisitorTimestampTo(newValue:) method](#changed-unread-by-visitor-timestamp-to-new-value) -- [ChatState enum](#chat-state) - - [CHATTING case](#chatting) - - [CHATTING_WITH_ROBOT](#chatting-with-robot) - - [CLOSED_BY_OPERATOR case](#closed-by-operator) - - [CLOSED_BY_VISITOR case](#closed-by-visitor) - - [INVITATION case](#invitation) - - [NONE case](#none-chat-state) - - [QUEUE case](#queue) - - [UNKNOWN case](#unknown) -- [OnlineStatus enum](#session-online-status) - - [BUSY_OFFLINE case](#busy-offline) - - [BUSY_ONLINE case](#busy-online) - - [OFFLINE case](#offline) - - [ONLINE case](#online) - - [UNKNOWN case](#unknown-session-online-status) -- [VisitSessionState enum](#visit-session-state) - - [CHAT case](#chat-visit-session-state) - - [DEPARTMENT_SELECTION case](#department-selection) - - [IDLE case](#idle) - - [IDLE_AFTER_CHAT case](#idle-after-chat) - - [OFFLINE_MESSAGE case](#offline-message) - - [UNKNOWN case](#unknown-visit-session-state) -- [DataMessageError enum](#data-message-error) - - [UNKNOWN case](#unknown-data-message-error) - - [QUOTED_MESSAGE_CANNOT_BE_REPLIED case](#quoted-message-cannot-be-replied) - - [QUOTED_MESSAGE_FROM_ANOTHER_VISITOR case](#quoted-message-from-another-visitor) - - [QUOTED_MESSAGE_MULTIPLE_IDS case](#quoted-message-multiple-ids) - - [QUOTED_MESSAGE_REQUIRED_ARGUMENTS_MISSING case](#quoted-message-required-arguments-missing) - - [QUOTED_MESSAGE_WRONG_ID case](#quoted-message-wrong-id) -- [EditMessageError enum](#edit-message-error) - - [UNKNOWN case](#unknown-edit-message-error) - - [NOT_ALLOWED case](#not-allowed-edit-message-error) - - [MESSAGE_EMPTY case](#message_empty-edit-message-error) - - [MESSAGE_NOT_OWNED case](#message-not-owned-edit-message-error) - - [MAX_LENGTH_EXCEEDED case](#max-length-exceeded-edit-message-error) - - [WRONG_MESSAGE_KIND case](#wrong-message-kind-edit-message-error) -- [DeleteMessageError enum](#delete-message-error) - - [UNKNOWN case](#unknown-delete-message-error) - - [NOT_ALLOWED case](#not-allowed-delete-message-error) - - [MESSAGE_NOT_OWNED case](#message-not-owned-delete-message-error) - - [MESSAGE_NOT_FOUND](#message-not-found-delete-message-error) -- [SendFileError enum](#send-file-error) - - [FILE_SIZE_EXCEEDED case](#file-size-exceeded) - - [FILE_TYPE_NOT_ALLOWED case](#file-type-not-allowed) - - [UPLOADED_FILE_NOT_FOUND case](#uploaded-file-not-found) - - [UNKNOWN case](#file-sending-unknown) -- [RateOperatorError enum](#rate-operator-error) - - [NO_CHAT case](#no-chat) - - [WRONG_OPERATOR_ID case](#wrong-operator-id) -- [MessageTracker protocol](#message-tracker) -- [getLastMessages(byLimit:completion:) method](#get-last-messages-by-limit-limit-of-messages-completion) -- [getNextMessages(byLimit:completion:) method](#get-next-nessages-by-limit-limit-of-messages-completion) - - [getAllMessages(completion:) method](#get-all-messages-completion) - - [resetTo(message:) method](#reset-to-message) - - [destroy() method](#destroy-message-tracker) -- [MessageListener protocol](#message-listener) - - [added(message:after:) method](#added-message-new-message-after-previous-message) - - [removed(message:) method](#removed-message) - - [removedAllMessages() method](#removed-all-messages) - - [changed(message:to:) method](#changed-message-old-version-to-new-version) -- [Message protocol](#message) - - [getAttachment() method](#get-attachment) - - [getData() method](#get-data) - - [getID() method](#get-id) - - [getOperatorID() method](#get-operator-id) - - [getSenderAvatarFullURL() method](#get-sender-avatar-full-url) - - [getSenderName() method](#get-sender-name) - - [getSendStatus() method](#get-send-status) - - [getText() method](#get-text) - - [getTime() method](#get-time) - - [getType() method](#get-type) - - [isEqual(to:) method](#is-equal-to-message) - - [isReadByOperator() method](#is-read-by-operator) - - [canBeEdited() method](#can-be-edited) -- [MessageAttachment protocol](#message-attachment) - - [getContentType() method](#get-content-type) - - [getFileName() method](#get-file-name) - - [getImageInfo() method](#get-image-info) - - [getSize() method](#get-size) - - [getURL() method](#get-url-string) -- [ImageInfo protocol](#image-info) - - [getThumbURL() method](#get-thumb-url-string) - - [getHeight() method](#get-height) - - [getWidth() method](#get-width) -- [MessageType enum](#message-type) - - [ACTION_REQUEST case](#action-request) - - [CONTACTS_REQUEST case](#contacts-request) - - [FILE_FROM_OPERATOR case](#file-from-operator) - - [FILE_FROM_VISITOR case](#file-from-visitor) - - [INFO case](#info) - - [OPERATOR case](#operator) - - [OPERATOR_BUSY case](#operator-busy) - - [VISITOR case](#visitor) -- [MessageSendStatus enum](#message-send-status) - - [SENDING case](#sending) - - [SENT case](#sent) -- [Department protocol](#department) - - [getKey() method](#get-key) - - [getName() method](#get-name-department) - - [getDepartmentOnlineStatus() method](#get-department-online-status) - - [getOrder() method](#get-order) - - [getLocalizedNames() method](#get-localized-names) - - [getLogo() method](#get-logo) -- [DepartmentOnlineStatus enum](#department-online-status) - - [BUSY_OFFLINE case](#busy-offline-department-online-status) - - [BUSY_ONLINE case](#busy-online-department-online-status) - - [OFFLINE case](#offline-department-online-status) - - [ONLINE case](#online-department-online-status) - - [UNKNOWN case](#unknown-department-online-status) -- [Operator protocol](#operator-protocol) - - [getID() method](#get-id-operator) - - [getName() method](#get-name) - - [getAvatarURL() method](#get-avatar-url) -- [WebimRemoteNotification protocol](#webim-remote-notification) - - [getType() method](#get-type-webim-remote-notification) - - [getEvent() method](#get-event) - - [getParameters() method](#get-parameters) -- [NotificationType enum](#notification-type) - - [CONTACT_INFORMATION_REQUEST](#contact-information-request) - - [OPERATOR_ACCEPTED case](#operator-accepted) - - [OPERATOR_FILE case](#operator-file) - - [OPERATOR_MESSAGE case](#operator-message) - - [WIDGET case](#widget) -- [NotificationEvent enum](#notification-event) - - [ADD case](#add) - - [DELETE case](#delete) -- [FatalErrorHandler protocol](#fatal-error-handler) - - [on(error:) method](#on-error) -- [FatalErrorType enum](#fatal-error-type) - - [ACCOUNT_BLOCKED case](#account-blocked) - - [NO_CHAT case](#no-chat) - - [PROVIDED_VISITOR_FIELDS_EXPIRED case](#provided-visitor-fields-expired) - - [UNKNOWN case](#unknown-fatal-error-type) - - [VISITOR_BANNED case](#visitor-banned) - - [WRONG_PROVIDED_VISITOR_HASH case](#wrong-provided-visitor-hash) -- [WebimError protocol](#webim-error) - - [getErrorType() method](#get-error-type) - - [getErrorString() method](#get-error-string) -- [AccessError enum](#access-error) - - [INVALID_THREAD case](#invalid-thread) - - [INVALID_SESSION case](#invalid-session) -- [WebimLogger protocol](#webim-logger) - - [log(entry:) method](#log-entry) - -

Webim class

- -Set of static methods which are used for session object creating and working with remote notifications that are sent by _Webim_ service. - -

Class method newSessionBuilder()

- -Returns [SessionBuilder class](#session-builder) instance that is necessary to create `WebimSession` class instance. - -

Class method parse(remoteNotification:visitorId)

- -Converts _iOS_ remote notification object into [WebimRemoteNotification](#webim-remote-notification) object. -`remoteNotification` parameter takes `[AnyHashable: Any]` dictionary (which can be taken inside `application(_ application:,didReceiveRemoteNotification userInfo:)` `AppDelegate` class method from `userInfo` parameter). -Method can return `nil` if `remoteNotification` parameter value doesn't fit to _Webim_ service remote notification format or if it doesn't contain any useful payload or visitor ID from notification doesn't equals `visitorId `. -Preliminarily you can call [method isWebim(remoteNotification:)](#is-webim-remote-notification) on this value to know if this notification is send by _Webim_ service. - -

Class method isWebim(remoteNotification:)

- -Allows to know if particular remote notification object represents Webim service remote notification. -`remoteNotification` parameter takes `[AnyHashable: Any]` dictionary (which can be taken inside `application(_ application:,didReceiveRemoteNotification userInfo:)` `AppDelegate` class method from `userInfo` parameter). -Returns `true` or `false`. - -

RemoteNotificationSystem enum

- -Enumerates push notifications systems that can be used with _WebimClientLibrary_. Enum values are used to be passed to [method set(remoteNotificationSystem:)](#set-remote-notification-system) [SessionBuilder class](#session-builder) instance method. - -

APNS case

- -_Apple Push Notification System_. - -

NONE case

- -App does not receive remote notification from _Webim_ service. - -[Go to table of contents](#table-of-contents) - -

SessionBuilder class

- -Instance of this class is used to get [WebimSession](#webim-session) object. [SessionBuilder class](#session-builder) instance can be retreived with [newSessionBuilder()](#new-session-builder) [Webim class](#webim) method. - -

Instance method set(accountName:)

- -Sets _Webim_ service account name. -`accountName` parameter – `String`-typed account name. Usually is represented by server URL (e.g. "https://demo.webim.ru"), but also can be just one word (e.g. "demo") -Returns `self` with account name set. -Method is mandatory to create [WebimSession](#webim-session) object. - -

Instance method set(location:)

- -Sets [location](https://webim.ru/help/help-terms/) name for the session. -`location` parameter – `String`-typed location name. Usually default available location names are "mobile" and "default". To create any other one you can contact service support. -Returns `self` with location name set. -Method is mandatory to create [WebimSession](#webim-session) object. - -

Instance method set(prechat:)

-Sets prechat fields for the session. -`prechat` parameter – `String`-typed prechat fields in JSON format. -Returns `self` with location name set. -Method is mandatory to create [WebimSession](#webim-session) object. - -

Instance method set(appVersion:)

- -Sets app version number if it is necessary to differentiate its values inside _Webim_ service. -`appVersion` parameter – optional `String`-typed app version. -Returns `self` with app version set. When passed `nil` it does nothing. -Method is not mandatory to create [WebimSession](#webim-session) object. - -

Instance method set(visitorFieldsJSONString:)

- -Sets visitor authorization data. -Without this method calling a visitor is anonymous, with randomly generated ID. This ID is saved inside app UserDefaults and can be lost (e.g. when app is uninstalled), thereby message history is lost too. -Authorized visitor data are saved by server and available with any device. -`jsonString` parameter – _JSON_-formatted `String`-typed [visitor fields](https://webim.ru/help/identification/). -Returns `self` with visitor authorization data set. -Method is not mandatory to create [WebimSession](#webim-session) object. -Can't be used simultanously with [set(providedAuthorizationTokenStateListener:,providedAuthorizationToken:) method](#set-provided-authorization-token-state-listener-provided-authorization-token). - -

Instance method set(visitorFieldsJSONData:)

- -Absolutely similar to [method set(visitorFieldsJSONString jsonString:)](#set-visitor-fields-json-string-json-string). -`jsonData` parameter – _JSON_-formatted `Data`-typed [visitor fields](https://webim.ru/help/identification/). - -

Instance method set(providedAuthorizationTokenStateListener:providedAuthorizationToken:)

- -When client provides custom visitor authorization mechanism, it can be realised by providing custom authorization token which is used instead of visitor fields. -Method sets [ProvidedAuthorizationTokenStateListener](#provided-authorization-token-state-listener) object and provided authorization token. Setting custom token is optional, if is not set, library generates its own. -Returns `self` with visitor authorization data set. -Method is not mandatory to create [WebimSession](#webim-session) object. -Can't be used simultaneously with [set(visitorFieldsJSONString:)](#set-visitor-fields-json-string-json-string) or [set(visitorFieldsJSONString:)](#set-visitor-fields-json-data-json-data). - -

Instance method set(pageTitle:)

- -Sets chat title which is visible by an operator. Default value is "iOS Client" -`pageTitle` – `String`-typed chat title. -Returns `self` with chat title set. -Method is not mandatory to create [WebimSession](#webim-session) object. - -

Instance method set(fatalErrorHandler:)

- -Sets [FatalErrorHandler](#fatal-error-handler) object for session. -`fatalErrorHandler` parameter – any object of a class or struct that conforms to `FatalErrorHandler` protocol (or `nil`). -Returns `self` with `FatalErrorHandler` set. When `nil` passed it does nothing. -Method is not mandatory to create [WebimSession](#webim-session) object. - -

Instance method set(remoteNotificationSystem:)

- -Sets remote notification system to use for receiving push notifications from _Webim_ service. -`remoteNotificationSystem` parameter – [RemoteNotificationSystem](#remote-notification-system) enum value. If parameter value is not [NONE](#none), [set(deviceToken:)](#set-device-token) method is mandatory to be called too. With [NONE](#none) value passed it does nothing. -Method is not mandatory to create [WebimSession](#webim-session) object. - -

Instance method set(deviceToken:)

- -Sets device token for push notification receiving. -`deviceToken` parameter – `String`-typed device token in hexadecimal format and without any spaces and service symbols. -Code example to convert device token to the right format: -```` -let deviceToken = deviceToken.map { String(format: "%02.2hhx", $0) }.joined() -```` -Returns `self` with device token set. -For the proper remote notifications configuration this method call is not sufficient. You have to call `set(remoteNotificationSystem:)` method too. -Method is not mandatory to create [WebimSession](#webim-session) object. - -

Instance method set(isLocalHistoryStoragingEnabled:)

- -By default session saves message history inside SQLite DB file. To deactivate this functionality you can use this method with false parameter isLocalHistoryStoragingEnabled value (with true value passed it does nothing). -Returns `self` with the functionality activation setting. -Method is not mandatory to create [WebimSession](#webim-session) object. - -

Instance method set(isVisitorDataClearingEnabled:)

- -Sets necesarity to clear all visitor data before session is created. -With false `isVisitorDataClearingEnabled` parameter value passed it does nothing. -Returns `self` with the functionality activation setting. -Method is not mandatory to create [WebimSession](#webim-session) object. - -

Instance method set(webimLogger:verbosityLevel:)

- -Method to pass [WebimLogger](#webim-logger) object. -Parameter `verbosityLevel` – [WebimLoggerVerbosityLevel](#webim-logger-verbosity-level) case (can be skipped). -Returns `self` with the functionality activation setting. -Method is not mandatory to create [WebimSession](#webim-session) object. - -

Instance method build()

- -Final method that returns [WebimSession](#webim-session) object. -Can throw errors of [SessionBuilderError](#session-builder-error) type. -The only two mandatory method to call preliminarily are [set(accountName:)](#set-account-name) and [set(location:)](#set-location). - -

WebimLoggerVerbosityLevel enum

- -Verbosity level of [WebimLogger](#webim-logger). - -

VERBOSE case

- -All available information will be delivered to [WebimLogger](#webim-logger) instance with maximum verbosity level: -* session network setup parameters; -* network requests' URLs, HTTP method and parameters; -* network responses' HTTP codes, received data and errors; -* SQL queries and errors; -* full debug information and additional notes. - -

DEBUG case

- -All information which is useful when debugging will be delivered to [WebimLogger](#webim-logger) instance with necessary verbosity level: -* session network setup parameters; -* network requests' URLs, HTTP method and parameters; -* network responses' HTTP codes, received data and errors; -* SQL queries and errors; -* moderate debug information. - -

INFO case

- -Reference information and all warnings and errors will be delivered to [WebimLogger](#webim-logger) instance: -* network requests' URLS, HTTP method and parameters; -* HTTP codes and errors descriptions of failed requests. -* SQL errors. - -

WARNING case

- -Errors and warnings only will be delivered to [WebimLogger](#webim-logger) instance: -* network requests' URLs, HTTP method, parameters, HTTP code and error description. -* SQL errors. - -

ERROR case

- -Only errors will be delivered to [WebimLogger](#webim-logger) instance: -* network requests' URLs, HTTP method, parameters, HTTP code and error description. - -

SessionBuilderError enum

- -Error types that can be throwed by [SessionBuilder](#session-builder) [method build()](#build). - -

NIL_ACCOUNT_NAME case

- -Error that is thrown when trying to create session object with `nil` account name. - -

NIL_LOCATION case

- -Error that is thrown when trying to create session object with `nil` location name. - -

INVALID_AUTHENTICATION_PARAMETERS case

- -Error that is thrown when trying to use standard and custom visitor fields authentication simultaneously. - -

INVALID_REMOTE_NOTIFICATION_CONFIGURATION case

- -Error that is thrown when trying to create session object with invalid remote notifications configuration. - -[Go to table of contents](#table-of-contents) - -

ProvidedAuthorizationTokenStateListener protocol

- -When client provides custom visitor authorization mechanism, it can be realised by providing custom authorization token which is used instead of visitor fields. -When provided authorization token is generated (or passed to session by client app), `update(providedAuthorizationToken:)` method is called. This method call indicates that client app must send provided authorisation token to its server which is responsible to send it to Webim service. -This mechanism can't be used as is. It requires that client server to support this mecahnism. - -

update(providedAuthorizationToken:) method

- -Method is called in two cases: -1. Provided authorization token is genrated (or set by client app) and must be sent to client server which is responsible to send it to Webim service. -2. Passed provided authorization token is not valid. Provided authorization token can be invalid if Webim service did not receive it from client server yet. -When this method is called, client server must send provided authorization token to Webim service. -`providedAuthorizationToken` parameter contains provided authentication token which is set and which must be sent to _Webim_ service by client server. - -[Go to table of contents](#table-of-contents) - -

WebimSession protocol

- -Provides methods to manipulate with [WebimSession](#webim-session) object. - -

resume() method

- -Resumes session networking -Session is created as paused. To start using it firstly you should call this method. -Can throw errors of [AccessError](#access-error) type. - -

pause() method

- -Pauses session networking. If is already paused the method does nothing. -Can throw errors of [AccessError](#access-error) type. - -

destroy() method

- -Deactivates session. After that any session methods are not available. -Can throw errors of [AccessError](#access-error) type. - -

destroyWithClearVisitorData() method

- -Deactivates session, performing a cleanup. After that any session methods are not available. -Can throw errors of [AccessError](#access-error) type. - - -

getStream() method

- -Returns [MessageStream](#message-stream) object attached to this session. Each invocation of this method returns the same object. - -

change(location:) method

- -Changes [location](https://webim.ru/help/help-terms/) without creating a new session. -`location` parameter – new location name of `String` type. -Can throw errors of [AccessError](#access-error) type. - -

set(deviceToken:) method

- -Sets device token. - -[Go to table of contents](#table-of-contents) - -

MessageStream protocol

- -Provides methods to interact with _Webim_ service. - -

getVisitSessionState() method

- -Returns current session state ([VisitSessionState type](#visit-session-state). - -

getChatState() method

- -Returns current chat state of [ChatState](#chat-state) type. - -

getUnreadByOperatorTimestamp() method

- -Returns timestamp (of type `Date`) after which all chat messages are unread by operator (at the moment of last server update recieved). - -

getUnreadByVisitorMessageCount() method

- -Returns unread by visitor message count. - -

getUnreadByVisitorTimestamp() method

- -Returns timestamp (of type `Date`) after which all chat messages are unread by visitor (at the moment of last server update recieved) or `nil` if there's no unread by visitor messages. - -

getDepartmentList() method

- -Returns array of departments ([Department](#department)) or `nil` if there're any or department list is not recieved yet. - -

getLocationSettings() method

- -Returns current [LocationSettings](#location-settings) object. - -

getCurrentOperator() method

- -Returns [Operator](#operator-protocol) object of the current chat or `nil` if one does not exist. - -

getLastRatingOfOperatorWith(id:) method

- -Returns previous rating of the operator or `0` if it was not rated before. -`id` parameter – `String`-typed ID of operator. - -

rateOperatorWith(id:byRating:completionHandler:) method

- -Rates an operator. -To get an ID of the current operator call [getCurrentOperator()](#get-current-operator). -`id` parameter – String-typed ID of the operator to be rated. Optional: if `nil` is passed, current chat operator will be rated. -`rating` parameter – a number in range (1...5) that represents an operator rating. If the number is out of range, rating will not be sent to a server. -`completionHandler` parameter – [RateOperatorCompletionHandler](#rate-operator-completion-handler) object. -Can throw errors of [AccessError](#access-error) type. - -

respondSentryCall(id:) method

- -Respond sentry call. -`id` parameter – String-typed ID of redirect to sentry message. -Can throw errors of [AccessError](#access-error) type. - -

startChat() method

- -Changes [ChatState](#chat-state) to [QUEUE](#queue). -Method call is not mandatory, send message or send file methods start chat automatically. If account settings provide automatic complimentary message it won't be sent before any "startChat" method or first sent message. -Can throw errors of [AccessError](#access-error) type. - -

startChat(firstQuestion:) method

- -Changes [ChatState](#chat-state) to [QUEUE](#queue). Starts chat and sends first message simultaneously. -Method call is not mandatory, send message or send file methods start chat automatically. If account settings provide automatic complimentary message it won't be sent before any "startChat" method or first sent message. -Can throw errors of [AccessError](#access-error) type. - -

startChat(customFields:) method

- -Changes [ChatState](#chat-state) to [QUEUE](#queue). Starts chat with custom fields. -Method call is not mandatory. Starts chat with custom fields. -`customFields` paramater – String-typed custom fields in JSON format. -Can throw errors of [AccessError](#access-error) type. - -

startChat(departmentKey:) method

- -Starts chat with particular department. Department is identified by `departmentKey` parameter (see [getKey()](#get-key) of [Department](#department) protocol) -Changes [ChatState](#chat-state) to [QUEUE](#queue). -In most cases method call is not mandatory, send message or send file methods start chat automatically. But it is mandatory when [VisitSessionState](#visit-session-state) is in [DEPARTMENT_SELECTION state](#department-selection). -If account settings provide automatic complimentary message it won't be sent before any "startChat" method or first sent message. -Can throw errors of [AccessError](#access-error) type. - -

startChat(departmentKey:firstQuestion:) method

- -Starts chat with particular department and sends first message simultaneously. Department is identified by `departmentKey` parameter (see [getKey()](#get-key) of [Department](#department) protocol) -Changes [ChatState](#chat-state) to [QUEUE](#queue). -In most cases method call is not mandatory, send message or send file methods start chat automatically. But it is mandatory when [VisitSessionState](#visit-session-state) is in [DEPARTMENT_SELECTION state](#department-selection). -If account settings provide automatic complimentary message it won't be sent before any "startChat" method or first sent message. -Can throw errors of [AccessError](#access-error) type. - -

startChat(firstQuestion:customFields:) method

- -Starts chat with custom fields and sends first message simultaneously. -Changes [ChatState](#chat-state) to [QUEUE](#queue). -If account settings provide automatic complimentary message it won't be sent before any "startChat" method or first sent message. -Can throw errors of [AccessError](#access-error) type. - -

startChat(departmentKey:customFields:) method

- -Starts chat with particular department and custom fields. Department is identified by `departmentKey` parameter (see [getKey()](#get-key) of [Department](#department) protocol) -Changes [ChatState](#chat-state) to [QUEUE](#queue). -In most cases method call is not mandatory, send message or send file methods start chat automatically. But it is mandatory when [VisitSessionState](#visit-session-state) is in [DEPARTMENT_SELECTION state](#department-selection). -If account settings provide automatic complimentary message it won't be sent before any "startChat" method or first sent message. -Can throw errors of [AccessError](#access-error) type. - -

startChat(departmentKey:firstQuestion:customFields:) method

- -Starts chat with particular department and customFields and sends first message simultaneously. Department is identified by `departmentKey` parameter (see [getKey()](#get-key) of [Department](#department) protocol) -Changes [ChatState](#chat-state) to [QUEUE](#queue). -In most cases method call is not mandatory, send message or send file methods start chat automatically. But it is mandatory when [VisitSessionState](#visit-session-state) is in [DEPARTMENT_SELECTION state](#department-selection). -If account settings provide automatic complimentary message it won't be sent before any "startChat" method or first sent message. -Can throw errors of [AccessError](#access-error) type. - -

closeChat() method

- -Changes [ChatState](#chat-state) to [CLOSED_BY_VISITOR](#closed-by-visitor). -Can throw errors of [AccessError](#access-error) type. - -

setVisitorTyping(draftMessage:) method

- -This method must be called whenever there is a change of the input field of a message transferring current content of a message as a parameter. When `nil` value passed it means that visitor stopped to type a message or deleted it. -When there's multiple calls of this method occured, draft message is sending to service one time per second. -Can throw errors of [AccessError](#access-error) type. - -

send(message:data:completionHandler:) method

- -Sends a text message. -When calling this method, if there is an active [MessageTracker](#message-tracker) object. [added(message newMessage:,after previousMessage:) method](#added-message-new-message-after-previous-message)) with a message [SENDING case](#sending) in the status is also called. -`message` parameter – `String`-typed message text. -`data` parameter is optional, custom message parameters dictionary. Note that this functionality does not work as is – server version must support it. -`completionHandler` parameter – optional [DataMessageCompletionHandler](#data-message-completion-handler) object. -Returns randomly generated `String`-typed ID of the message. -Can throw errors of [AccessError](#access-error) type. - -

send(message:isHintQuestion:) method

- -Sends a text message. -When calling this method, if there is an active [MessageTracker](#message-tracker) object. [added(message newMessage:,after previousMessage:) method](#added-message-new-message-after-previous-message)) with a message [SENDING case](#sending) in the status is also called. -`message` parameter – `String`-typed message text. -`isHintQuestion` parameter shows to server if a visitor chose a hint (true value) or wrote his own text (`false`). Optional to use. -Returns randomly generated `String`-typed ID of the message. -Can throw errors of [AccessError](#access-error) type. - -

send(file:filename:mimeType:completionHandler:) method

- -Sends a file message. -When calling this method, if there is an active [MessageTracker](#message-tracker) object. [added(message newMessage:,after previousMessage:) method](#added-message-new-message-after-previous-message)) with a message [SENDING case](#sending) in the status is also called. -`file` parameter – file represented in `Data` type. -`filename` parameter – file name of `String` type. -`mimeType` parameter – MIME type of the file to send of `String` type. -`completionHandler` parameter – optional [SendFileCompletionHandler](#send-file-completion-handler) object. -Returns randomly generated `String`-typed ID of the message. -Can throw errors of [AccessError](#access-error) type. - -

updateWidgetStatus(data:) method

- -Update widget status. The change is displayed by the operator.. -`data` parameter – JSON string with new widget status. -Can throw errors of [AccessError](#access-error) type. - -

edit(message:text:completionHandler:) method

- -Edits a text message. -Before calling this method recommended to find out the possibility of editing the message using [canBeEdited() method](#can-be-edited). -When calling this method, if there is an active [MessageTracker](#message-tracker) object. [changed(message:,to:) method](changed-message-old-version-to-new-version) with a message [SENDING case](#sending) in the status is also called. -`message` parameter – message in `Message` type. -`text` parameter – new message text of `String` type. -`completionHandler` parameter – optional [EditMessageCompletionHandler](#edit-message-completion-handler) object. -Returns true if message can be edited. -Can throw errors of [AccessError](#access-error) type. - -

edit(message:text:completionHandler:) method

- -Deletes a text message. -Before calling this method recommended to find out the possibility of editing the message using [canBeEdited() method](#can-be-edited). -When calling this method, if there is an active [MessageTracker](#message-tracker) object. [removed(message:) method](#removed-message) with a message [SENT case](#sent) in the status is also called. -`message` parameter – message in `Message` type. -`completionHandler` parameter – optional [DeleteMessageCompletionHandler](#delete-message-completion-handler) object. -Returns true if message can be deleted. -Can throw errors of [AccessError](#access-error) type. - -

setChatRead() method

- -Set chat has been read by visitor. -Can throw errors of [AccessError](#access-error) type. - -

set(prechatFields:) method

- -Sends prechat fields to server. -Can throw errors of [AccessError](#access-error) type. - -

newMessageTracker(messageListener:) method

- -Returns [MessageTracker](#message-tracker) object wich (via [getNextMessages(byLimit limitOfMessages:,completion:)](#get-next-nessages-by-limit-limit-of-messages-completion)) allows to request the messages from above in the history. Each next call [getNextMessages(byLimit limitOfMessages:,completion:)](#get-next-nessages-by-limit-limit-of-messages-completion) returns earlier messages in relation to the already requested ones. -Changes of user-visible messages (e.g. ever requested from [MessageTracker](#message-tracker)) are transmitted to [MessageListener](#message-listener). That is why [MessageListener](#message-listener) object is needed when creating [MessageTracker](#message-tracker). -For each [MessageStream](#message-stream) at every single moment can exist the only one active [MessageTracker](#message-tracker). When creating a new one at the previous there will be automatically called [destroy()](#destroy-message-tracker). -Can throw errors of [AccessError](#access-error) type. - -

set(visitSessionStateListener:) method

- -Sets [VisitSessionStateListener](#visit-session-state-listener) object to track changes of [VisitSessionState](#visit-session-state). - -

set(chatStateListener:) method

- -Sets [ChatStateListener](#chat-state-listener) object. - -

set(currentOperatorChangeListener:) method

- -Sets [CurrentOperatorChangeListener](#current-operator-change-listener) object. - -

set(departmentListChangeListener:) method

- -Sets [DepartmentListChangeListener](#department-list-change-listener) object to track changes of department list. - -

set(operatorTypingListener:) method

- -Sets [OperatorTypingListener](#operator-typing-listener) object. - -

set(locationSettingsChangeListener:) method

- -Sets [LocationSettingsChangeListener](#location-settings-shange-listener) object. - -

set(onlineStatusChangeListener:) method

- -Sets [OnlineStatusChangeListener](#session-online-status-change-listener) object. - -

set(unreadByOperatorTimestampChangeListener:) method

- -Sets [UnreadByOperatorTimestampChangeListener](#unread-by-operator-timestamp-change-listener) object. - -

set(unreadByVisitorMessageCountChangeListener:) method

- -Sets [UnreadByVisitorMessageCountChangeListener](#unread-by-visitor-message-count-change-listener) object. - -

set(unreadByVisitorTimestampChangeListener:) method

- -Sets [UnreadByVisitorTimestampChangeListener](#unread-by-visitor-timestamp-change-listener) object. - -[Go to table of contents](#table-of-contents) - -

DataMessageCompletionHandler protocol

- -Protocol which methods are called after [send(message:data:completionHandler:)](#send-message-data) method is finished. Must be adopted. - -

onSuccess(messageID:) method

- -Executed when operation is done successfully. -`messageID` parameter – ID of the appropriate message of `String` type. - -

onFailure(messageID:error:) method

- -Executed when operation is failed. -`messageID` parameter – ID of the appropriate message of `String` type. -`error` parameter – appropriate [DataMessageError](#data-message-error) value. - -[Go to table of contents](#table-of-contents) - -

EditMessageCompletionHandler protocol

- -Protocol which methods are called after [edit(message:text:completionHandler:)](#edit-message) method is finished. Must be adopted. - -

onSuccess(messageID:) method

- -Executed when operation is done successfully. -`messageID` parameter – ID of the appropriate message of `String` type. - -

onFailure(messageID:error:) method

- -Executed when operation is failed. -`messageID` parameter – ID of the appropriate message of `String` type. -`error` parameter – appropriate [EditMessageError](#edit-message-error) value. - -[Go to table of contents](#table-of-contents) - -

DeleteMessageCompletionHandler protocol

- -Protocol which methods are called after [delete(message:completionHandler:)](#delete-message) method is finished. Must be adopted. - -

onSuccess(messageID:) method

- -Executed when operation is done successfully. -`messageID` parameter – ID of the appropriate message of `String` type. - -

onFailure(messageID:error:) method

- -Executed when operation is failed. -`messageID` parameter – ID of the appropriate message of `String` type. -`error` parameter – appropriate [DeleteMessageError](#delete-message-error) value. - -[Go to table of contents](#table-of-contents) - -

SendFileCompletionHandler protocol

- -Protocol which methods are called after [send(file:filename:mimeType:completionHandler:)](#send-file-filename-mime-type-completion-handler) method is finished. Must be adopted. - -

onSuccess(messageID:) method

- -Executed when operation is done successfully. -`messageID` parameter – ID of the appropriate message of `String` type. - -

onFailure(messageID:error:) method

- -Executed when operation is failed. -`messageID` parameter – ID of the appropriate message of `String` type. -`error` parameter – appropriate [SendFileError](#send-file-error) value. - -[Go to table of contents](#table-of-contents) - -

RateOperatorCompletionHandler protocol

- -Protocol which methods are called after [rateOperatorWith(id:byRating:completionHandler:)](#rate-operator-with-id-by-rating-rating) method is finished. Must be adopted. - -

onSuccess() method

- -Executed when operation is done successfully. - -

onFailure(error:) method

- -Executed when operation is failed. -`error` parameter – appropriate [RateOperatorError](#rate-operator-error) value. - -[Go to table of contents](#table-of-contents) - -

VisitSessionStateListener protocol

- -Provides methods to track changes of [VisitSessionState](#visit-session-state) status. - -

changed(state:to:) method

- -Called when [VisitSessionState](#visit-session-state) status is changed. Parameters contain its previous and new values. - -[Go to table of contents](#table-of-contents) - -

DepartmentListChangeListener protocol

- -Provides methods to track changes in departments list. - -

received(departmentList:) method

- -Called when department list is received. Current department list passed inside `departmentList` parameter and presents array of [Department](#department) objects. - -[Go to table of contents](#table-of-contents) - -

LocationSettings protocol

- -Interface that provides methods for handling [LocationSettings](#location-settings) which are received from server. - -

areHintsEnabled() method

- -This method shows to an app if it should show hint questions to visitor. Returns `true` if an app should show hint questions to visitor, `false` otherwise. - -[Go to table of contents](#table-of-contents) - -

ChatStateListener protocol

- -Protocol that is to be adopted to track [ChatState](#chat-state) changes. - -

changed(state:to:) method

- -Called during [ChatState](#chat-state)transition. Parameters are of [ChatState](#chat-state) type. - -[Go to table of contents](#table-of-contents) - -

CurrentOperatorChangeListener protocol

- -Protocol that is to be adopted to track if current [Operator](#operator-protocol) object is changed. - -

changed(operator:to:) method

- -Called when [Operator](#operator-protocol) object of the current chat changed. Values can be `nil` (if an operator leaved the chat or there was no operator before). - -[Go to table of contents](#table-of-contents) - -

OperatorTypingListener protocol

- -Protocol that is to be adopted to track if the operator started or ended to type a message. - -

onOperatorTypingStateChanged(isTyping:) method

- -Called when operator typing state changed. -Parameter `isTyping` is `true` if operator is typing, `false` otherwise. - -[Go to table of contents](#table-of-contents) - -

LocationSettingsChangeListener protocol

- -Interface that provides methods for handling changes in [LocationSettings](#location-settings). - -

changed(locationSettings:to:) method

- -Method called by an app when new [LocationSettings](#location-settings) object is received with parameters that represent previous and new [LocationSettings](#location-settings) objects. - -[Go to table of contents](#table-of-contents) - -

OnlineStatusChangeListener protocol

- -Interface that provides methods for handling changes of session status. - -

changed(onlineStatus:to:) method

- -Called when new session status is received with parameters that represent previous and new [OnlineStatus](#session-online-status) values. - -[Go to table of contents](#table-of-contents) - -

UnreadByOperatorTimestampChangeListener protocol

- -Interface that provides methods for handling changes of parameter that is to be returned by [getUnreadByOperatorTimestamp() method](#get-unread-by-operator-timestamp). -Can be set by [set(unreadByOperatorTimestampChangeListener:) method](#set-unread-by-operator-timestamp-change-listener). - -

changedUnreadByOperatorTimestampTo(newValue:) method

- -Method to be called when parameter that is to be returned by [getUnreadByOperatorTimestamp() method](#get-unread-by-operator-timestamp) method is changed. - -[Go to table of contents](#table-of-contents) - -

UnreadByVisitorMessageCountChangeListener protocol

- -Interface that provides methods for handling changes of parameter that is to be returned by [getUnreadByVisitorMessageCount() method](#get-unread-by-visitor-message-count). -Can be set by [set(unreadByVisitorMessageCountChangeListener:) method](#set-unread-by-visitor-message-count-change-listener). - -

changedUnreadByVisitorMessageCountTo(newValue:) method

- -Method to be called when parameter that is to be returned by [getUnreadByVisitorMessageCount() method](#get-unread-by-visitor-message-count) method is changed. - -[Go to table of contents](#table-of-contents) - -

UnreadByVisitorTimestampChangeListener protocol

- -Interface that provides methods for handling changes of parameter that is to be returned by [getUnreadByVisitorTimestamp() method](#get-unread-by-visitor-timestamp). -Can be set by [set(unreadByVisitorTimestampChangeListener:) method](#set-unread-by-visitor-timestamp-change-listener). - -

changedUnreadByVisitorTimestampTo(newValue:) method

- -Method to be called when parameter that is to be returned by [getUnreadByVisitorTimestamp() method](#get-unread-by-visitor-timestamp) method is changed. - -[Go to table of contents](#table-of-contents) - -

ChatState enum

- -A chat is seen in different ways by an operator depending on ChatState. -The initial state is [NONE](#none-chat-state). -Then if a visitor sends a message ([send(message:isHintQuestion:)](#send-message-is-hint-question)), the chat changes it's state to [QUEUE](#queue). The chat can be turned into this state by calling [startChat() method](#start-chat). -After that, if an operator takes the chat to process, the state changes to [CHATTING](#chatting). The chat is being in this state until the visitor or the operator closes it. -When closing a chat by the visitor [closeChat() method](#close-chat) it turns into the state [CLOSED_BY_VISITOR](#closed-by-visitor), by the operator - [CLOSED_BY_OPERATOR](#closed-by-operator). -When both the visitor and the operator close the chat, it's state changes to the initial – [NONE](#none-chat-state). A chat can also automatically turn into the initial state during long-term absence of activity in it. -Furthermore, the first message can be sent not only by a visitor but also by an operator. In this case the state will change from the initial to [INVITATION](#invitation), and then, after the first message of the visitor, it changes to [CHATTING](#chatting). - -

CHATTING case

- -Means that an operator has taken a chat for processing. -From this state a chat can be turned into: -* [CHATTING](#chatting), if an operator intercepted the chat; -* [CLOSED_BY_VISITOR](#closed-by-visitor), if a visitor closes the chat ([closeChat() method](#close-chat)); -* [NONE](#none-chat-state), automatically during long-term absence of activity. - -

CHATTING_WITH_ROBOT case

- -Means that chat is picked up by a bot. -From this state a chat can be turned into: -* [CLOSED_BY_OPERATOR](#closed-by-operator), if an operator closes the chat; -* [CLOSED_BY_VISITOR](#closed-by-visitor), if a visitor closes the chat ([closeChat() method](#close-chat)); -* [NONE](#none-chat-state), automatically during long-term absence of activity. - -

CLOSED_BY_OPERATOR case

- -Means that an operator has closed the chat. -From this state a chat can be turned into: -* [NONE](#none-chat-state), if the chat is also closed by a visitor ([closeChat() method](#close-chat)), or automatically during long-term absence of activity; -* [QUEUE](#queue), if a visitor sends a new message ([send(message:isHintQuestion:) method](#send-message-is-hint-question)). - -

CLOSED_BY_VISITOR case

- -Means that a visitor has closed the chat. -From this state a chat can be turned into: -* [NONE](#none-chat-state), if the chat is also closed by an operator or automatically during long-term absence of activity; -* [QUEUE](#queue), if a visitor sends a new message ([send(message:isHintQuestion:) method](#send-message-is-hint-question)). - -

INVITATION case

- -Means that a chat has been started by an operator and at this moment is waiting for a visitor's response. -From this state a chat can be turned into: -* [CHATTING](#chatting), if a visitor sends a message ([send(message:isHintQuestion:) method](#send-message-is-hint-question)); -* [NONE](#none-chat-state), if an operator or a visitor closes the chat ([closeChat() method](#close-chat)). - -

NONE case

- -Means the absence of a chat as such, e.g. a chat has not been started by a visitor nor by an operator. -From this state a chat can be turned into: -* [QUEUE](#queue), if the chat is started by a visitor (by the first message or by calling [startChat() method](#start-chat)); -* [INVITATION](#invitation), if the chat is started by an operator. - -

QUEUE case

- -Means that a chat has been started by a visitor and at this moment is being in the queue for processing by an operator. -From this state a chat can be turned into: -* [CHATTING](#chatting), if an operator takes the chat for processing; -* [NONE](#none-chat-state), if a visitor closes the chat (by calling ([closeChat() method](#close-chat)) before it is taken for processing; -* [CLOSED_BY_OPERATOR](#closed-by-operator), if an operator closes the chat without taking it for processing. - -

UNKNOWN case

- -The state is undefined. -This state is set as the initial when creating a new session, until the first response of the server containing the actual state is got. This state is also used as a fallback if _WebimClientLibrary_ can not identify the server state (e.g. if the server has been updated to a version that contains new states). - -[Go to table of contents](#table-of-contents) - -

OnlineStatus enum

- -Online state possible cases. - -

BUSY_OFFLINE case

- -Offline state with chats' count limit exceeded. -Means that visitor is not able to send messages at all. - -

BUSY_ONLINE case

- -Online state with chats' count limit exceeded. -Visitor is able send offline messages, but the server can reject it. - -

OFFLINE case

- -Visitor is able send offline messages. - -

ONLINE case

- -Visitor is able to send both online and offline messages. - -

UNKNOWN case

- -Session has not received first session status yet or session status is not supported by this version of the library. - -[Go to table of contents](#table-of-contents) - -

VisitSessionState enum

- -Session possible states. - -

CHAT case

- -Chat in progress. - -

DEPARTMENT_SELECTION case

- -Chat must be started with department selected (there was a try to start chat without department selected). - -

IDLE case

- -Session is active but no chat is occuring (chat was not started yet). - -

IDLE_AFTER_CHAT case

- -Session is active but no chat is occuring (chat was closed recently). - -

OFFLINE_MESSAGE case

- -Offline state. - -

UNKNOWN case

- -First status is not recieved yet or status is not supported by this version of the library. - -[Go to table of contents](#table-of-contents) - -

DataMessageError enum

- -Error types that could be passed in [onFailure(messageID:error:) method](#on-failure-message-id-error-data-message-completion-handler). - -

UNKNOWN case

- -Received error is not supported by current WebimClientLibrary version. - -

Quoted message errors.

- -

QUOTED_MESSAGE_CANNOT_BE_REPLIED case

- -To be raised when quoted message ID belongs to a message without `canBeReplied` flag set to `true` (this flag is to be set on the server-side). - -

QUOTED_MESSAGE_FROM_ANOTHER_VISITOR case

- -To be raised when quoted message ID belongs to another visitor chat. - -

QUOTED_MESSAGE_MULTIPLE_IDS case

- -To be raised when quoted message ID belongs to multiple messages (server data base error). - -

QUOTED_MESSAGE_REQUIRED_ARGUMENTS_MISSING case

- -To be raised when one or more required arguments of quoting mechanism are missing. - -

QUOTED_MESSAGE_WRONG_ID case

- -To be raised when wrong quoted message ID is sent. - -[Go to table of contents](#table-of-contents) - -

EditMessageError enum

- -Error types that could be passed in [onFailure(messageID:error:) method](#on-failure-message-id-error-edit-message-completion-handler). - -

UNKNOWN case

- -Received error is not supported by current WebimClientLibrary version. - -

NOT_ALLOWED case

- -Editing messages by visitor is turned off on the server. - -

MESSAGE_EMPTY case

- -Editing message is empty. - -

MESSAGE_NOT_OWNED case

- -Visitor can edit only his messages. The specified id belongs to someone else's message. - -

MAX_LENGTH_EXCEEDED case

- -The server may deny a request if the message size exceeds a limit. The maximum size of a message is configured on the server. - -

WRONG_MESSAGE_KIND case

- -Visitor can edit only text messages. - -[Go to table of contents](#table-of-contents) - -

DeleteMessageError enum

- -Error types that could be passed in [onFailure(messageID:error:) method](#on-failure-message-id-error-delete-message-completion-handler). - -

UNKNOWN case

- -Received error is not supported by current WebimClientLibrary version. - -

NOT_ALLOWED case

- -Editing messages by visitor is turned off on the server. - -

MESSAGE_NOT_OWNED case

- -Visitor can edit only his messages. The specified id belongs to someone else's message. - -

MESSAGE_NOT_FOUND case

- -Message with the specified id is not found in history. - -[Go to table of contents](#table-of-contents) - -

SendFileError enum

- -Error types that could be passed in [onFailure(messageID:error:) method](#on-failure-message-id-error). - -

FILE_SIZE_EXCEEDED case

- -The server may deny a request if the file size exceeds a limit. -The maximum size of a file is configured on the server. - -

FILE_TYPE_NOT_ALLOWED case

- -The server may deny a request if the file type is not allowed. -The list of allowed file types is configured on the server. - -

UPLOADED_FILE_NOT_FOUND case

- -Sending files in body is not supported. Use multipart form only. - -

UNKNOWN case

- -Received error is not supported by current WebimClientLibrary version. - -[Go to table of contents](#table-of-contents) - -

RateOperatorError enum

- -Error types that could be passed in [onFailure(error:) method](#on-failure-error). - -

NO_CHAT case

- -Arised when trying to send operator rating request if no chat is exists. - -

WRONG_OPERATOR_ID case

- -Arised when trying to send operator rating request if passed operator ID doesn't belong to existing chat operator (or, in the same place, chat doesn't have an operator at all). - -[Go to table of contents](#table-of-contents) - -

MessageTracker protocol

- -[MessageTracker](#message-tracker) object has two purposes: -- it allows to request the messages which are above in the history; -- it defines an interval within which message changes are transmitted to the listener (see [newMessageTracker(messageListener:) method](#new-message-tracker-message-listener)). - -

getLastMessages(byLimit:completion:) method

- -Requests last messages from history. Returns not more than `limitOfMessages` of messages. If an empty list is passed inside completion, there no messages in history yet. -If there is any previous [MessageTracker](#message-tracker) request that is not completed, or limit of messages is less than 1, or current [MessageTracker](#message-tracker) has been destroyed, this method will do nothing. -Following history request can be fulfilled by [getLastMessages(byLimit:completion:)](#get-last-messages-by-limit-limit-of-messages-completion) method. -Completion is called with received array of [Message](#message) objects as the parameter. It is guaranteed that completion will be called with empty or not result if call didn't throw an error. If current `MessageTracker` is destroyed completion will be called on empty result. -Can throw errors of [AccessError](#access-error) type. - -

getNextMessages(byLimit:completion:) method

- -Requests the messages above in history. Returns not more than `limitOfMessages` of messages. If an empty list is passed inside completion, the end of the message history is reached. -If there is any previous [MessageTracker](#message-tracker) request that is not completed, or limit of messages is less than 1, or current [MessageTracker](#message-tracker) has been destroyed, this method will do nothing. -Notice that this method can not be called again until the callback for the previous call will be invoked. -Completion is called with received array of [Message](#message) objects as the parameter. It is guaranteed that completion will be called with empty or not result if call didn't throw an error. If current `MessageTracker` is destroyed completion will be called on empty result. -Can throw errors of [AccessError](#access-error) type. - -

getAllMessages(completion:) method

- -Requests all messages from history. If an empty list is passed inside completion, there no messages in history yet. -If there is any previous [MessageTracker](#message-tracker) request that is not completed, or current [MessageTracker](#message-tracker) has been destroyed, this method will do nothing. -This method is totally independent on [getLastMessages(byLimit:completion:)](#get-last-messages-by-limit-limit-of-messages-completion) and [getNextMessages(byLimit:completion:)](#get-next-nessages-by-limit-limit-of-messages-completion) methods calls. -Completion is called with received array of [Message](#message) objects as the parameter. It is guaranteed that completion will be called with empty or not result if call didn't throw an error. If current `MessageTracker` is destroyed completion will be called on empty result. -Can throw errors of [AccessError](#access-error) type. - -

resetTo(message:) method

- -[MessageTracker](#message-tracker) retains some range of messages. By using this method one can move the upper limit of this range to another message. -If there is any previous [MessageTracker](#message-tracker) request that is not completed, this method will do nothing. -Notice that this method can not be used unless the previous call [getNextMessages(byLimit:completion:)](#get-next-nessages-by-limit-limit-of-messages-completion) was finished (completion handler was invoked). -Parameter `message` – [Message](#message) object reset to. -Can throw errors of [AccessError](#access-error) type. - -

destroy() method

- -Destroys the [MessageTracker](#message-tracker). It is impossible to use any [MessageTracker](#message-tracker) methods after it was destroyed. -Isn't mandatory to be called. - -[Go to table of contents](#table-of-contents) - -

MessageListener protocol

- -Should be adopted. Provides methods to track changes inside message stream. - -

added(message:after:) method

- -Called when added a new message. -If `previousMessage == nil` then it should be added to the end of message history (the lowest message is added), in other cases the message should be inserted before the message (i.e. above in history) which was given as a parameter `previousMessage`. -Notice that this is a logical insertion of a message. I.e. calling this method does not necessarily mean receiving a new (unread) message. Moreover, at the first call [getNextMessages(byLimit:completion:)](#get-next-nessages-by-limit-limit-of-messages-completion) most often the last messages of a local history (i.e. which is stored on a user's device) are returned, and this method will be called for each message received from a server after a successful connection. -Parameters are of type [Message](#message). `previousMessage` represents a message after which it is needed to make a message insert. If `nil` then an insert is performed at the end of the list. - -

removed(message:) method

- -Called when removing a message. -`message` parameter is of type [Message](#message). - -

removedAllMessages() method

- -Called when removed all the messages. - -

changed(message:to:) method

- -Called when changing a message. -[Message](#message) is an immutable type and field values can not be changed. That is why message changing occurs as replacing one object with another. Thereby you can find out, for example, which certain message fields have changed by comparing an old and a new object values. -Parameters are of type [Message](#message). - -[Go to table of contents](#table-of-contents) - -

Message protocol

- -Abstracts a single message in the message history. -A message is an immutable object. It means that changing some of the message fields creates a new object. Messages can be compared by using [isEqual(to:)](#is-equal-to-message) method for searching messages with the same set of fields or by ID (`message1.getID() == message2.getID()`) for searching logically identical messages. ID is formed on the client side when sending a message ([send(message:isHintQuestion:)](#send-message-is-hint-question) or [send(file:filename:mimeType:completionHandler:)](#send-file-filename-mime-type-completion-handler)). - -

getAttachment() method

- -Messages of the types [FILE_FROM_OPERATOR](#file-from-operator) and [FILE_FROM_VISITOR](#file-from-visitor) can contain attachments. -Returns [MessageAttachment](#message-attachment) object. Notice that this method may return nil even in the case of previously listed types of messages. E.g. if a file is being sent. - -

getData() method

- -Messages of type [ACTION_REQUEST](#action-request) contain custom dictionary. -Returns dictionary which contains custom fields or `nil` if there's no such custom fields. - -

getID() method

- -Every message can be uniquefied by its ID. Messages also can be lined up by its IDs. ID doesn’t change while changing the content of a message. -Returns unique ID of the message of type `String`. - -

getOperatorID() method

- -Returns ID of a message sender, if the sender is an operator, of type `String`. - -

getSenderAvatarFullURL() method

- -Returns `URL` of a sender's avatar or `nil` if one does not exist. - -

getSenderName() method

- -Returns name of a message sender of type `String`. - -

getSendStatus() method

- -Returns [SENT](#sent) if a message had been sent to the server, was received by the server and was delivered to all the clients; [SENDING](#sending) if not. - -

getText() method

- -Returns text of the message of type `String`. - -

getTime() method

- -Returns `Date` the message was processed by the server. - -

getType() method

- -Returns type of a message of [MessageType](#message-type) type. - -

isEqual(to:) method

- -Method which can be used to compare if two [Message](#message) objects have identical contents. -Returns `true` if two [Message](#message) objects are identical and `false` otherwise. - -Example code: -```` -if messageOne.isEqual(to: messageTwo) { /* … */ } -```` -Where `messageOne` and `messageTwo` are any `Message` objects. - -

isReadByOperator() method

- -Returns true if visitor message read by operator or this message is not by visitor and false otherwise. - -[Go to table of contents](#table-of-contents) - -

canBeEdited() method

- -Returns true if message can be edited and false otherwise. - -[Go to table of contents](#table-of-contents) - -

MessageAttachment protocol

- -Contains information about an attachment file. - -

getContentType() method

- -Returns MIME-type of an attachment file of optional `String` type. - -

getFileName() method

- -Returns name of an attachment file of optional `String` type. - -

getImageInfo() method

- -If a file is an image, returns [ImageInfo](#image-info) object; in other cases returns nil. - -

getSize() method

- -Returns attachment file size in bytes of `Int64` type. - -

getURLString() method

- -Returns `URL` of the file or `nil`. -Notice that this URL is short-living and is tied to a session. - -[Go to table of contents](#table-of-contents) - -

ImageInfo protocol

- -Provides information about an image. - -

getThumbURL() method

- -Returns a URL of an image thumbnail. -The maximum width and height is usually 300 px but it can be adjusted at server settings. -To get an actual preview size before file uploading is completed, use the following code: -```` -let THUMB_SIZE = 300 -var width = imageInfo.getWidth() -var height = imageInfo.getHeight() -if (height > width) { - width = (THUMB_SIZE * width) / height - height = THUMB_SIZE -} else { - height = (THUMB_SIZE * height) / width - width = THUMB_SIZE -} -```` -Notice that this URL is short-living and is tied to a session. - -

getHeight() method

- -Returns height of an image in pixels of `Int` type or `nil`. - -

getWidth() method

- -Returns width of an image in pixels of `Int` type or `nil`. - -[Go to table of contents](#table-of-contents) - -

MessageType enum

- -Message type representation. - -

ACTION_REQUEST case

- -A message from operator which requests some actions from a visitor. -E.g. choose an operator group by clicking on a button in this message. - -

CONTACTS_REQUEST case

-Message type that is received after operator clicked contacts request button. -There's no this functionality automatic support yet. All payload is transfered inside standard text field. - -

FILE_FROM_OPERATOR case

- -A message sent by an operator which contains an attachment. - -

FILE_FROM_VISITOR case

- -A message sent by a visitor which contains an attachment. - -

INFO case

- -A system information message. -Messages of this type are automatically sent at specific events. E.g. when starting a chat, closing a chat or when an operator joins a chat. - -

OPERATOR case

- -A text message sent by an operator. - -

OPERATOR_BUSY case

- -A system information message which indicates that an operator is busy and can't reply to a visitor at the moment. - -

VISITOR case

- -A text message sent by a visitor. - -[Go to table of contents](#table-of-contents) - -

MessageSendStatus enum

- -Until a message is sent to the server, is received by the server and is spreaded among clients, message can be seen as "being send"; at the same time `Message.getSendStatus()` will return [SENDING](#sending). In other cases - [SENT](#sent). - -

SENDING case

- -A message is being sent. - -

SENT case

- -A message had been sent to the server, received by the server and was spreaded among clients. - -[Go to table of contents](#table-of-contents) - -

Department protocol

- -Single department entity. Provides methods to get department information. -Department objects can be received through [DepartmentListChangeListener protocol](#department-list-change-listener) methods and [getDepartmentList() method](#get-department-list) of [MessageStream protocol](#message-stream). - -

getKey() method

- -Department key is used to start chat with some department. Presented by `String` object. -Used for [startChat(departmentKey:) method](#start-chat-department-key) of [MessageStream protocol](#message-stream) call. - -

getName() method

- -Returns department public name. Presented by `String` object. - -

getDepartmentOnlineStatus() method

- -Returns department online status. Presented by [DepartmentOnlineStatus](#department-online-status) object. - -

getOrder() method

- -Returns order number. -Presented by `Int` value. Higher numbers match higher priority. - -

getLocalizedNames() method

- -Returns dictionary of department localized names (if exists). -Presented by `[String: String]` dictonary. Key is custom locale descriptor, value is matching name. - - - -Returns department logo _URL_ (if exists). -Presented by `URL` object. - -[Go to table of contents](#table-of-contents) - -

DepartmentOnlineStatus enum

- -Possible department online statuses. -Can be retreived by [getDepartmentOnlineStatus() method](#get-department-online-status) of [Department protocol](#department). - -

BUSY_OFFLINE case

- -Offline state with chats' count limit exceeded. - -

BUSY_ONLINE case

- -Online state with chats' count limit exceeded. - -

OFFLINE case

- -Visitor is able to send offline messages. - -

ONLINE case

- -Visitor is able to send both online and offline messages. - -

UNKNOWN case

- -Any status that is not supported by this version of the library. - -[Go to table of contents](#table-of-contents) - -

Operator protocol

- -Presents chat operator object. - -

getID() method

- -Returns unique ID of the operator of `String` type. - -

getName() method

- -Returns display name of the operator of `String` type. - -

getAvatarURL() method

- -Returns `URL` of the operator’s avatar or `nil` if does not exist. - -[Go to table of contents](#table-of-contents) - -

WebimRemoteNotification protocol

- -Abstracts a remote notifications from _Webim_ service. - -

getType() method

- -Returns type of this remote notification of [NotificationType](#notification-type) type. - -

getEvent() method

- -Returns event of this remote notification of [NotificationEvent](#notification-event) type or `nil`. - -

getParameters() method

- -Returns parameters of this remote notification of array of type `String` type. Each [NotificationType](#notification-type) has specific list of parameters. - -[Go to table of contents](#table-of-contents) - -

NotificationType enum

- -Represents payload type of remote notification. - -

CONTACT_INFORMATION_REQUEST case

- -This notification type indicated that contact information request is sent to a visitor. - -Parameters: empty. - -

OPERATOR_ACCEPTED case

- -This notification type indicated that an operator has connected to a dialogue. - -Parameters: -* Operator's name. - -

OPERATOR_FILE case

- -This notification type indicated that an operator has sent a file. - -Parameters: -* Operator's name; -* File name. - -

OPERATOR_MESSAGE case

- -This notification type indicated that an operator has sent a text message. - -Parameters: -* Operator's name; -* Message text. - -

WIDGET case

- -This notification type indicated that an operator has sent a widget message. -This type can be received only if server supports this functionality. - -Parameters: empty. - -[Go to table of contents](#table-of-contents) - -

NotificationEvent enum

- -Represents meaned type of action when remote notification is received. - -

ADD case

- -Means that a notification should be added by current remote notification. - -

DELETE case

- -Means that a notification should be deleted by current remote notification. - -[Go to table of contents](#table-of-contents) - -

FatalErrorHandler protocol

- -Must be adopted to handle service errors that can occur. - -

on(error:) method

- -This method is to be called when Webim service error is received. -Notice that method called NOT FROM THE MAIN THREAD! - -`error` parameter is of [`WebimError` type](#webim-error). - -[Go to table of contents](#table-of-contents) - -

FatalErrorType enum

- -Webim service error types. -Mind that most of this errors causes session to destroy. - -

ACCOUNT_BLOCKED case

- -Indicates that the account in Webim service has been disabled (e.g. for non-payment). The error is unrelated to the user’s actions. -Recommended response is to show the user an error message with a recommendation to try using the chat later. - -Notice that the session will be destroyed if this error occured. - -

NO_CHAT case

- -Indicates that there was a try to perform action that requires existing chat, but there's no chat. -E.g. see [rateOperatorWith(id:,byRating rating:) method](#rate-operator-with-id-by-rating-rating) of [MessageStream protocol](#message-stream). - -

PROVIDED_VISITOR_FIELDS_EXPIRED case

- -Indicates an expired authorization of a visitor. -The recommended response is to re-authorize it and to re-create session object. - -Notice that the session will be destroyed if this error occured. - -

UNKNOWN case

- -Indicates the occurrence of an unknown error. -Recommended response is to send an automatic bug report and show to a user an error message with the recommendation to try using the chat later. - -Notice that the session will be destroyed if this error occured. - -

VISITOR_BANNED case

- -Indicates that a visitor was banned by an operator and can't send messages to a chat anymore. -Occurs when a user tries to open the chat or write a message after that. -Recommended response is to show the user an error message with the recommendation to try using the chat later or explain to the user that it was blocked for some reason. - -Notice that the session will be destroyed if this error occured. - -

WRONG_PROVIDED_VISITOR_HASH case

- -Indicates a problem of your application authorization mechanism and is unrelated to the user’s actions. -Occurs when trying to authorize a visitor with a non-valid signature. -Recommended response is to send an automatic bug report and show the user an error message with the recommendation to try using the chat later. - -Notice that the session will be destroyed if this error occured. - -[Go to table of contents](#table-of-contents) - -

WebimError protocol

- -Abstracts _Webim_ service possible fatal error. - -

getErrorType() method

- -Returns parsed type of the error of [FatalErrorType](#fatal-error-type) type. - -

getErrorString() method

- -Returns `String` representation of an error. Mostly useful if the error type is unknown. - -[Go to table of contents](#table-of-contents) - -

AccessError enum

- -Error types that can be throwed by [MessageStream](#message-stream) methods. - -

INVALID_THREAD case

- -Error that is thrown if the method was called not from the thread the [WebimSession](#webim-session) object was created in. - -

INVALID_SESSION case

- -Error that is thrown if [WebimSession](#webim-session) object was destroyed. - -[Go to table of contents](#table-of-contents) - -

WebimLogger protocol

- -Protocol that provides methods for implementing custom _WebimClientLibrary_ network requests logging. -It can be useful for debugging production releases if debug logs are not available. - -

log(entry:) method

- -Method which is called after new _WebimClientLibrary_ network request log entry came out. -New log entry passed inside `entry` parameter. diff --git a/ios/libs/Webim/Example/Podfile b/ios/libs/Webim/Example/Podfile deleted file mode 100644 index ff1312f..0000000 --- a/ios/libs/Webim/Example/Podfile +++ /dev/null @@ -1,49 +0,0 @@ -platform :ios, '9.0' - -use_frameworks! - -target 'WebimClientLibrary_Example' do - - pod 'WebimClientLibrary', :path => '../' - - pod 'Cosmos', '~> 16.0.0', :inhibit_warnings => true - pod 'Crashlytics' - pod 'Fabric' - pod 'SlackTextViewController', :inhibit_warnings => true - pod 'SnapKit', :inhibit_warnings => true - pod 'SQLite.swift', '0.11.5', :inhibit_warnings => true # WebimClientLibrary dependency – added to inhibit its warnings. - pod 'PopupDialog', '~> 0.6.2', :inhibit_warnings => true - - - target 'WebimClientLibrary_Tests' do - inherit! :search_paths - end - - post_install do |installer| - installer.pods_project.targets.each do |target| - if target.name =='WebimClientLibrary' - target.build_configurations.each do |config| - config.build_settings['SWIFT_VERSION'] = '4.2' - end - else - if target.name == 'Cosmos' || target.name == 'SnapKit' || target.name == 'WebimClientLibrary' - target.build_configurations.each do |config| - config.build_settings['SWIFT_VERSION'] = '4.0' - end - else - target.build_configurations.each do |config| - config.build_settings['SWIFT_VERSION'] = '3.2' - end - end - end - - target.build_configurations.each do |config| - if config.name == 'Debug' - config.build_settings['OTHER_SWIFT_FLAGS'] = ['$(inherited)', '-Onone'] - config.build_settings['SWIFT_OPTIMIZATION_LEVEL'] = '-Owholemodule' - end - end - end - end - -end diff --git a/ios/libs/Webim/Example/Podfile.lock b/ios/libs/Webim/Example/Podfile.lock deleted file mode 100644 index b25b03c..0000000 --- a/ios/libs/Webim/Example/Podfile.lock +++ /dev/null @@ -1,51 +0,0 @@ -PODS: - - Cosmos (16.0.0) - - Crashlytics (3.13.0): - - Fabric (~> 1.10.0) - - Fabric (1.10.0) - - PopupDialog (0.6.2) - - SlackTextViewController (1.9.6) - - SnapKit (4.2.0) - - SQLite.swift (0.11.5): - - SQLite.swift/standard (= 0.11.5) - - SQLite.swift/standard (0.11.5) - - WebimClientLibrary (3.24.7): - - SQLite.swift (= 0.11.5) - -DEPENDENCIES: - - Cosmos (~> 16.0.0) - - Crashlytics - - Fabric - - PopupDialog (~> 0.6.2) - - SlackTextViewController - - SnapKit - - SQLite.swift (= 0.11.5) - - WebimClientLibrary (from `../`) - -SPEC REPOS: - https://github.com/cocoapods/specs.git: - - Cosmos - - Crashlytics - - Fabric - - PopupDialog - - SlackTextViewController - - SnapKit - - SQLite.swift - -EXTERNAL SOURCES: - WebimClientLibrary: - :path: "../" - -SPEC CHECKSUMS: - Cosmos: 7bcee0fa858a9355a214f2a181be5dffcee42c81 - Crashlytics: 1f5f752c7feac0add0cc1774756f96444fa3b1a7 - Fabric: 09de1e053eb7dc415593166ad3e53d4c88123405 - PopupDialog: d4336d7274a6aa3af4cb26d8b6691510eba90cc3 - SlackTextViewController: b854e62c1c156336bc4fd409c6ca79b5773e8f9d - SnapKit: fe8a619752f3f27075cc9a90244d75c6c3f27e2a - SQLite.swift: 6e5356850bb1791459f8c16d6ee9195b28714a2e - WebimClientLibrary: 70b569ce3f19b21b0e1f2488736d326c4c6cfd6f - -PODFILE CHECKSUM: f54174e617f57584e01671510a3b29c91c213194 - -COCOAPODS: 1.6.1 diff --git a/ios/libs/Webim/Example/Tests/AbstractRequestLoopTests.swift b/ios/libs/Webim/Example/Tests/AbstractRequestLoopTests.swift deleted file mode 100644 index db9e567..0000000 --- a/ios/libs/Webim/Example/Tests/AbstractRequestLoopTests.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// AbstractRequestLoopTests.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 30.01.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -import XCTest -@testable import WebimClientLibrary - -class AbstractRequestLoopTests: XCTestCase { - - // MARK: - Properties - private let abstractRequestLoop = AbstractRequestLoopForTests() - - // MARK: - Tests - - func testResume() { - abstractRequestLoop.resume() - abstractRequestLoop.pause() - abstractRequestLoop.resume() - - XCTAssertFalse(abstractRequestLoop.isPaused()) - } - - func testPause() { - abstractRequestLoop.resume() - abstractRequestLoop.pause() - - XCTAssertTrue(abstractRequestLoop.isPaused()) - } - -} - -// MARK: - Mocking AbstractRequestLoop -fileprivate final class AbstractRequestLoopForTests: AbstractRequestLoop { - - // MARK: - Methods - func isPaused() -> Bool { - return paused - } - -} diff --git a/ios/libs/Webim/Example/Tests/AccessCheckerTests.swift b/ios/libs/Webim/Example/Tests/AccessCheckerTests.swift deleted file mode 100644 index 40796f0..0000000 --- a/ios/libs/Webim/Example/Tests/AccessCheckerTests.swift +++ /dev/null @@ -1,58 +0,0 @@ -// -// AccessCheckerTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 21.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -@available(iOS 10.0, *) -class AccessCheckerTests: XCTestCase { - - func testCheckAccess() { - let thread1 = Thread.current - let sessionDestroyer = SessionDestroyer() - let accessChecker = AccessChecker(thread: thread1, - sessionDestroyer: sessionDestroyer) - - // MARK: Test 1 - let expectation = XCTestExpectation() - func mustThrow2() { - XCTAssertThrowsError(try accessChecker.checkAccess()) - expectation.fulfill() - } - let thread2 = Thread() { - mustThrow2() - } - thread2.start() - wait(for: [expectation], - timeout: 1.0) - - // MARK: Test 2 - sessionDestroyer.destroy() - XCTAssertThrowsError(try accessChecker.checkAccess()) - } - -} diff --git a/ios/libs/Webim/Example/Tests/ActionRequestLoopTests.swift b/ios/libs/Webim/Example/Tests/ActionRequestLoopTests.swift deleted file mode 100644 index c5fd4d6..0000000 --- a/ios/libs/Webim/Example/Tests/ActionRequestLoopTests.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// ActionRequestLoopTests.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 30.01.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class ActionRequestLoopTests: XCTestCase { - - // MARK: - Properties - private let actionRequestLoop = ActionRequestLoopForTests(completionHandlerExecutor: ExecIfNotDestroyedHandlerExecutor(sessionDestroyer: SessionDestroyer(), - queue: DispatchQueue.global()), - internalErrorListener: InternalErrorListenerForTests() as InternalErrorListener) - - // MARK: - Tests - func testStart() { - // MARK: Test 1 - - // When: ActionRequestLoop is started. - actionRequestLoop.start() - - // Then: ActionRequestLoop OperationQueue shouldn't be nil and has to have .userInitiated QoS. - let operationQueue = actionRequestLoop.operationQueue - XCTAssertNotNil(operationQueue) - XCTAssertEqual(operationQueue!.qualityOfService, - QualityOfService.userInitiated) - - // MARK: Test 2 - - // When: ActionRequestLoop is tryed to start again. - actionRequestLoop.start() - - // Then: ActionRequestLoop OperationQueue stays the same. - XCTAssertEqual(operationQueue, - actionRequestLoop.operationQueue) - } - - func testStop() { - // When: ActionRequestLoop is stopped. - actionRequestLoop.stop() - - // Then: ActionRequestLoop OperationQueue should be nil. - XCTAssertNil(actionRequestLoop.operationQueue) - } - -} diff --git a/ios/libs/Webim/Example/Tests/AuthorizationDataTests.swift b/ios/libs/Webim/Example/Tests/AuthorizationDataTests.swift deleted file mode 100644 index 814d43c..0000000 --- a/ios/libs/Webim/Example/Tests/AuthorizationDataTests.swift +++ /dev/null @@ -1,142 +0,0 @@ -// -// AuthorizationDataTests.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 31.01.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -import XCTest -@testable import WebimClientLibrary - -class AuthorizationDataTests: XCTestCase { - - // MARK: - Tests - - func testInitialization() { - // MARK: Test 1 - - // When: Page ID and authorization token are nil. - var pageID: String? = nil - var authorizationToken: String? = nil - var authorizationData = AuthorizationData(pageID: pageID, - authorizationToken: authorizationToken) - - // Then: Authorization data should be nil. - XCTAssertNil(authorizationData) - - // MARK: Test 2 - - // When: Authorization token is nil. - pageID = "page_id" - authorizationToken = nil - authorizationData = AuthorizationData(pageID: pageID, - authorizationToken: authorizationToken) - - // Then: Authorization data should be nil. - XCTAssertNil(authorizationData) - - // MARK: Test 3 - - // When: Authorization token is nil. - pageID = nil - authorizationToken = "auth_token" - authorizationData = AuthorizationData(pageID: pageID, - authorizationToken: authorizationToken) - - // Then: Authorization data should be nil. - XCTAssertNil(authorizationData) - - // MARK: Test 4 - - // When: Page ID and authorization token aren't nil. - pageID = "page_id" - authorizationToken = "auth_token" - authorizationData = AuthorizationData(pageID: pageID, - authorizationToken: authorizationToken) - - // Then: Authorization data shouldn't be nil. - XCTAssertNotNil(authorizationData) - XCTAssertEqual(authorizationData!.getPageID(), - "page_id") - XCTAssertEqual(authorizationData!.getAuthorizationToken(), - "auth_token") - } - - func testEquals() { - // MARK: Test 1 - - // When: Page IDs and authorization tokens are the same. - var pageID = "page_id" - var authorizationToken = "auth_token" - var authorizationData1 = AuthorizationData(pageID: pageID, - authorizationToken: authorizationToken) - var authorizationData2 = AuthorizationData(pageID: pageID, - authorizationToken: authorizationToken) - - // Then: Thwo AuthorizationData objects must be equal. - XCTAssertTrue(authorizationData1 == authorizationData2) - - // MARK: Test 2 - - // When: Page IDs are the same but authorization tokents aren't. - let pageID1 = "page_id1" - let pageID2 = "page_id2" - authorizationToken = "auth_token" - authorizationData1 = AuthorizationData(pageID: pageID1, - authorizationToken: authorizationToken) - authorizationData2 = AuthorizationData(pageID: pageID2, - authorizationToken: authorizationToken) - - // Then: Thwo AuthorizationData objects must be not equal. - XCTAssertTrue(authorizationData1 != authorizationData2) - - // MARK: Test 3 - - // When: Page IDs aren't the same but authorization tokents are. - pageID = "page_id" - let authorizationToken1 = "auth_token1" - let authorizationToken2 = "auth_token2" - authorizationData1 = AuthorizationData(pageID: pageID, - authorizationToken: authorizationToken1) - authorizationData2 = AuthorizationData(pageID: pageID, - authorizationToken: authorizationToken2) - - // Then: Thwo AuthorizationData objects must be not equal. - XCTAssertTrue(authorizationData1 != authorizationData2) - - // MARK: Test 4 - - // When: One AuthorizationData object is nil. - pageID = "page_id" - authorizationToken = "auth_token" - authorizationData1 = AuthorizationData(pageID: pageID, - authorizationToken: authorizationToken) - authorizationData2 = nil - - // Then: Thwo AuthorizationData objects must be not equal. - XCTAssertNotNil(authorizationData1) - XCTAssertNil(authorizationData2) - XCTAssertTrue(authorizationData1 != authorizationData2) - } - -} diff --git a/ios/libs/Webim/Example/Tests/ChatItemTests.swift b/ios/libs/Webim/Example/Tests/ChatItemTests.swift deleted file mode 100644 index 3a39de0..0000000 --- a/ios/libs/Webim/Example/Tests/ChatItemTests.swift +++ /dev/null @@ -1,230 +0,0 @@ -// -// ChatItemTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 15.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class ChatItemTests: XCTestCase { - - // MARK: - Constants - static let CHAT_ITEM_JSON_STRING = """ -{ - "readByVisitor" : true, - "category" : null, - "subject" : null, - "operatorTyping" : false, - "clientSideId" : "95f308d22be1a388c66e875fd71e466c", - "state" : "chatting", - "needToBeClosed" : false, - "visitorTyping" : null, - "messages" : [ - { - "avatar" : null, - "authorId" : null, - "ts" : 1518713140.778348, - "sessionId" : "72b6946234214a24b8d067a406ffcd53", - "id" : "72b6946234214a24b8d067a406ffcd53_2", - "text" : "Текст", - "kind" : "info", - "name" : "" - }, - { - "avatar" : null, - "authorId" : null, - "ts" : 1518713140.7789431, - "sessionId" : "72b6946234214a24b8d067a406ffcd53", - "id" : "72b6946234214a24b8d067a406ffcd53_3", - "text" : "Пожалуйста, подождите немного, к Вам присоединится оператор..", - "clientSideId" : "12af770c26754a5597ecd34b312ba758", - "kind" : "info", - "name" : "" - } - ], - "offline" : false, - "visitorMessageDraft" : null, - "id" : 2530, - "unreadByVisitorSinceTs" : null, - "operatorIdToRate" : { }, - "creationTs" : 1518713140.777204, - "subcategory" : null, - "requestedForm" : null, - "unreadByOperatorSinceTs" : null, - "operator" : { - "avatar" : "/webim/images/avatar/demo_33201.png", - "fullname" : "Administrator", - "id" : 33201, - "robotType" : null, - "departmentKeys" : [ - "telegram", - "test3", - "test2" - ], - "langToFullname" : { }, - "sip" : "10002715000033201" - } -} -""" - private static let MESSAGE_JSON_STRING = """ -{ - "avatar" : null, - "authorId" : null, - "ts" : 1518713140.778348, - "sessionId" : "72b6946234214a24b8d067a406ffcd53", - "id" : "72b6946234214a24b8d067a406ffcd53_2", - "text" : "Текст", - "kind" : "info", - "name" : "" -} -""" - private static let OPERATOR_JSON_STRING = """ -{ - "avatar" : "/webim/images/avatar/demo_33201.png", - "fullname" : "Administrator 2", - "id" : 33201, - "robotType" : null, - "departmentKeys" : [ - "telegram", - "test3", - "test2" - ], - "langToFullname" : { }, - "sip" : "10002715000033201" -} -""" - - // MARK: - Properties - private let chatItemDictionary = try! JSONSerialization.jsonObject(with: ChatItemTests.CHAT_ITEM_JSON_STRING.data(using: .utf8)!, - options: []) as! [String : Any?] - - // MARK: - Tests - - func testInit() { - let chatItem = ChatItem(jsonDictionary: chatItemDictionary) - - XCTAssertFalse(chatItem.isOperatorTyping()) - XCTAssertEqual(chatItem.getState(), - ChatItem.ChatItemState.chatting) - XCTAssertEqual(chatItem.getOperator()!.getID(), - "33201") - XCTAssertTrue(chatItem.getReadByVisitor()!) - XCTAssertTrue(chatItem.getOperatorIDToRate()!.isEmpty) - XCTAssertNil(chatItem.getUnreadByVisitorTimestamp()) - XCTAssertNil(chatItem.getUnreadByOperatorTimestamp()) - XCTAssertTrue(chatItem.getOperatorIDToRate()!.isEmpty) - } - - func testGetSetMessages() { - let chatItem = ChatItem(jsonDictionary: chatItemDictionary) - - let messageDictionary = try! JSONSerialization.jsonObject(with: ChatItemTests.MESSAGE_JSON_STRING.data(using: .utf8)!, - options: []) as! [String: Any?] - let message = MessageItem(jsonDictionary: messageDictionary) - chatItem.set(messages: [message]) - - XCTAssertEqual(chatItem.getMessages(), - [message]) - } - - func testAddMessage() { - let chatItem = ChatItem(jsonDictionary: chatItemDictionary) - let messageDictionary = try! JSONSerialization.jsonObject(with: ChatItemTests.MESSAGE_JSON_STRING.data(using: .utf8)!, - options: []) as! [String: Any?] - let message = MessageItem(jsonDictionary: messageDictionary) - - chatItem.add(message: message, - atPosition: chatItem.getMessages().count) - XCTAssertTrue(message == chatItem.getMessages()[2]) - - chatItem.add(message: message) - XCTAssertTrue(message == chatItem.getMessages().last!) - } - - func testSetOperatorTyping() { - let chatItem = ChatItem(jsonDictionary: chatItemDictionary) - - XCTAssertFalse(chatItem.isOperatorTyping()) - - chatItem.set(operatorTyping: true) - XCTAssertTrue(chatItem.isOperatorTyping()) - } - - func testSetChatState() { - let chatItem = ChatItem(jsonDictionary: chatItemDictionary) - - XCTAssertEqual(chatItem.getState(), - ChatItem.ChatItemState.chatting) - - chatItem.set(state: .closed) - XCTAssertEqual(chatItem.getState(), - ChatItem.ChatItemState.closed) - } - - func testSetOperator() { - let chatItem = ChatItem(jsonDictionary: chatItemDictionary) - - XCTAssertEqual(chatItem.getOperator()?.getFullName(), - "Administrator") - - let operatorDictionary = try! JSONSerialization.jsonObject(with: ChatItemTests.OPERATOR_JSON_STRING.data(using: .utf8)!, - options: []) as! [String: Any?] - let operatorItem = OperatorItem(jsonDictionary: operatorDictionary)! - chatItem.set(operator: operatorItem) - XCTAssertEqual(chatItem.getOperator()?.getFullName(), - "Administrator 2") - } - - func testSetReadByVisitor() { - let chatItem = ChatItem(jsonDictionary: chatItemDictionary) - - XCTAssertTrue(chatItem.getReadByVisitor()!) - - chatItem.set(readByVisitor: false) - XCTAssertFalse(chatItem.getReadByVisitor()!) - } - - func testSetUnreadByOperatorTimestamp() { - let chatItem = ChatItem(jsonDictionary: chatItemDictionary) - chatItem.set(unreadByOperatorTimestamp: 1.0) - - XCTAssertEqual(chatItem.getUnreadByOperatorTimestamp(), - 1.0) - } - - // MARK: ChatItemState tests - - func testInitChatItemState() { - XCTAssertEqual(ChatItem.ChatItemState(withType: "new_state").rawValue, - "unknown") // Some unsupported value. - } - - func testIsClosed() { - let chatItemState = ChatItem.ChatItemState(withType: "chatting") - - XCTAssertFalse(chatItemState.isClosed()) - } - -} diff --git a/ios/libs/Webim/Example/Tests/ClientSideIDTests.swift b/ios/libs/Webim/Example/Tests/ClientSideIDTests.swift deleted file mode 100644 index 09ddcd6..0000000 --- a/ios/libs/Webim/Example/Tests/ClientSideIDTests.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// ClientSideIDTests.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 31.01.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -import XCTest -@testable import WebimClientLibrary - -class ClientSideIDTests: XCTestCase { - - // MARK: - Tests - - func testLength() { - let length = 10 - - XCTAssertEqual(ClientSideID.generateRandomString(ofCharactersNumber: length).count, - length) - } - - func testCorrectSymbols() { - var clientSideID = ClientSideID.generateClientSideID() - let letters = "abcdef0123456789" - for letter in letters { - clientSideID = clientSideID.replacingOccurrences(of: String(letter), - with: "", - options: [], - range: nil) - } - - XCTAssertTrue(clientSideID.count == 0) - } - -} diff --git a/ios/libs/Webim/Example/Tests/DeltaItemTests.swift b/ios/libs/Webim/Example/Tests/DeltaItemTests.swift deleted file mode 100644 index 1e260e0..0000000 --- a/ios/libs/Webim/Example/Tests/DeltaItemTests.swift +++ /dev/null @@ -1,91 +0,0 @@ -// -// DeltaItemTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 19.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class DeltaItemTests: XCTestCase { - - // MARK: - Tests - - func testInit() { - let deltaItemJSONString = """ -{ - "id" : "80a332f6fced40f290a5e8ace4a6d11c_5", - "data" : { - "avatar" : null, - "authorId" : null, - "ts" : 1519043833.694463, - "sessionId" : "80a332f6fced40f290a5e8ace4a6d11c", - "id" : "80a332f6fced40f290a5e8ace4a6d11c_5", - "text" : "10", - "clientSideId" : "fbaa9bb54d47008b5bf56a5830510c64", - "kind" : "visitor", - "name" : "Никита" - }, - "event" : "add", - "objectType" : "CHAT_MESSAGE" -} -""" - let deltaItemDictionary = try! JSONSerialization.jsonObject(with: deltaItemJSONString.data(using: .utf8)!, - options: []) as! [String : Any?] - let deltaItem = DeltaItem(jsonDictionary: deltaItemDictionary)! - - XCTAssertEqual(deltaItem.getDeltaType(), - DeltaItem.DeltaType.chatMessage) - XCTAssertEqual(deltaItem.getEvent(), - DeltaItem.Event.add) - XCTAssertEqual(deltaItem.getID(), - "80a332f6fced40f290a5e8ace4a6d11c_5") - XCTAssertNotNil(deltaItem.getData()) - } - - func testInitFails() { - let deltaItemJSONString = """ -{ - "id" : "80a332f6fced40f290a5e8ace4a6d11c_5", - "data" : { - "avatar" : null, - "authorId" : null, - "ts" : 1519043833.694463, - "sessionId" : "80a332f6fced40f290a5e8ace4a6d11c", - "id" : "80a332f6fced40f290a5e8ace4a6d11c_5", - "text" : "10", - "clientSideId" : "fbaa9bb54d47008b5bf56a5830510c64", - "kind" : "visitor", - "name" : "Никита" - }, - "objectType" : "CHAT_MESSAGE" -} -""" - let deltaItemDictionary = try! JSONSerialization.jsonObject(with: deltaItemJSONString.data(using: .utf8)!, - options: []) as! [String : Any?] - - XCTAssertNil(DeltaItem(jsonDictionary: deltaItemDictionary)) - } - -} diff --git a/ios/libs/Webim/Example/Tests/DeltaRequestLoopTests.swift b/ios/libs/Webim/Example/Tests/DeltaRequestLoopTests.swift deleted file mode 100644 index 12a649b..0000000 --- a/ios/libs/Webim/Example/Tests/DeltaRequestLoopTests.swift +++ /dev/null @@ -1,147 +0,0 @@ -// -// DeltaRequestLoopTests.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 31.01.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -import XCTest -@testable import WebimClientLibrary - -class DeltaRequestLoopTests: XCTestCase { - - // MARK: - Properties - private var deltaRequestLoop: DeltaRequestLoopForTests? - - // MARK: - Methods - - override func setUp() { - super.setUp() - - deltaRequestLoop = DeltaRequestLoopForTests(deltaCallback: DeltaCallback(currentChatMessageMapper: CurrentChatMessageMapper(withServerURLString: "https://demo.webim.ru")), - completionHandlerExecutor: ExecIfNotDestroyedHandlerExecutor(sessionDestroyer: SessionDestroyer(), - queue: DispatchQueue.global()), - sessionParametersListener: nil, - internalErrorListener: InternalErrorListenerForTests() as InternalErrorListener, - baseURL: "https://demo.webim.ru", - title: "Page Title", - location: "mobile", - appVersion: "1.0.0", - visitorFieldsJSONString: nil, - providedAuthenticationTokenStateListener: nil, - providedAuthenticationToken: nil, - deviceID: "device_id", - deviceToken: nil, - visitorJSONString: nil, - sessionID: nil, - authorizationData: nil) - } - - override func tearDown() { - deltaRequestLoop = nil - - super.tearDown() - } - - // MARK: - Tests - - func testStart() { - // MARK: Test 1 - - // When: DeltaRequestLoop is started. - deltaRequestLoop!.start() - let queue = deltaRequestLoop!.queue - - // Then: Queue shouldn't be nil. - XCTAssertNotNil(queue) - - // MARK: Test 2 - - // When: DeltaRequestLoop is started again. - deltaRequestLoop!.start() - - // Then: Queue should remain the same. - XCTAssertEqual(deltaRequestLoop!.queue, - queue) - } - - func testStop() { - deltaRequestLoop!.start() - deltaRequestLoop!.stop() - - XCTAssertNil(deltaRequestLoop!.queue) - } - - func testChangeLocation() { - try? deltaRequestLoop?.change(location: "location") - - XCTAssertNil(deltaRequestLoop?.getAuthorizationData()) - XCTAssertEqual(deltaRequestLoop!.since, - 0) - XCTAssertTrue(deltaRequestLoop!.initializationRunned) - } - - func testRunMethod() { - // MARK: Test 1 - - // When: DeltaRequestLoop started without AuthorizationData. - deltaRequestLoop?.start() - usleep(1_000_000) - - // Then: Initialization should be requested, but delta should not. - XCTAssertNil(deltaRequestLoop?.getAuthorizationData()) - XCTAssertTrue(deltaRequestLoop!.initializationRunned) - XCTAssertFalse(deltaRequestLoop!.deltaRequestingRunned) - - // MARK: Test 2 - - // When: AuthorizationData is setted. - deltaRequestLoop?.authorizationData = AuthorizationData(pageID: "page_id", - authorizationToken: "auth_token") - usleep(1_000_000) - - // Then: Delta should be requested. - XCTAssertNotNil(deltaRequestLoop?.getAuthorizationData()) - XCTAssertTrue(deltaRequestLoop!.initializationRunned) - } - -} - -// MARK: Mocking DeltaRequestLoop -final fileprivate class DeltaRequestLoopForTests: DeltaRequestLoop { - - // MARK: - Properties - var initializationRunned = false - var deltaRequestingRunned = false - - // MARK: - Methods - - override func requestInitialization() { - initializationRunned = true - } - - override func requestDelta() { - deltaRequestingRunned = true - } - -} diff --git a/ios/libs/Webim/Example/Tests/DeltaResponseTests.swift b/ios/libs/Webim/Example/Tests/DeltaResponseTests.swift deleted file mode 100644 index 1fab76a..0000000 --- a/ios/libs/Webim/Example/Tests/DeltaResponseTests.swift +++ /dev/null @@ -1,85 +0,0 @@ -// -// DeltaResponseTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 19.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class DeltaResponseTests: XCTestCase { - - // MARK: - Constants - private static let DELTA_RESPONSE_JSON_STRING = """ -{ - "revision" : 12, - "deltaList" : [ - { - "id" : "80a332f6fced40f290a5e8ace4a6d11c", - "data" : null, - "event" : "upd", - "objectType" : "CHAT_OPERATOR" - }, - { - "id" : "80a332f6fced40f290a5e8ace4a6d11c", - "data" : "queue", - "event" : "upd", - "objectType" : "CHAT_STATE" - }, - { - "id" : "80a332f6fced40f290a5e8ace4a6d11c_8", - "data" : { - "avatar" : null, - "authorId" : null, - "ts" : 1519046868.2501681, - "sessionId" : "80a332f6fced40f290a5e8ace4a6d11c", - "id" : "80a332f6fced40f290a5e8ace4a6d11c_8", - "text" : "11", - "clientSideId" : "578150796321959ef8b445866738381b", - "kind" : "visitor", - "name" : "Никита" - }, - "event" : "add", - "objectType" : "CHAT_MESSAGE" - } - ] -} -""" - - // MARK: - Properties - private let deltaResponseDictionary = try! JSONSerialization.jsonObject(with: DeltaResponseTests.DELTA_RESPONSE_JSON_STRING.data(using: .utf8)!, - options: []) as! [String : Any?] - - // MARK: - Tests - func testInit() { - let deltaResponseItem = DeltaResponse(jsonDictionary: deltaResponseDictionary) - - XCTAssertEqual(deltaResponseItem.getRevision(), - 12) - XCTAssertNil(deltaResponseItem.getFullUpdate()) - XCTAssertEqual(deltaResponseItem.getDeltaList()!.count, - 3) - } - -} diff --git a/ios/libs/Webim/Example/Tests/DepartmentFactoryTests.swift b/ios/libs/Webim/Example/Tests/DepartmentFactoryTests.swift deleted file mode 100644 index f2eab30..0000000 --- a/ios/libs/Webim/Example/Tests/DepartmentFactoryTests.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// DepartmentFactoryTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 20.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class DepartmentFactoryTests: XCTestCase { - - // MARK: - Constants - private static let SERVER_URL_STRING = "https://demo.webim.ru" - - // MARK: - Properties - private let departmentFactory = DepartmentFactory(serverURLString: DepartmentFactoryTests.SERVER_URL_STRING) - private let departmentItemDictionary = try! JSONSerialization.jsonObject(with: DEPARTMENT_ITEM_JSON_STRING.data(using: .utf8)!, - options: []) as! [String : Any?] - - // MARK: - Tests - func testConvert() { - let departmentItem = DepartmentItem(jsonDictionary: departmentItemDictionary)! - let department = departmentFactory.convert(departmentItem: departmentItem) - - XCTAssertEqual(department.getDepartmentOnlineStatus(), - DepartmentOnlineStatus.OFFLINE) - XCTAssertEqual(department.getKey(), - "mobile_test_1") - XCTAssertEqual(department.getLocalizedNames()!.count, - 1) - XCTAssertEqual(department.getLogoURL()!, - URL(string: DepartmentFactoryTests.SERVER_URL_STRING + "/webim/images/department_logo/wmtest2_1.png")!) - XCTAssertEqual(department.getName(), - "Mobile Test 1") - XCTAssertEqual(department.getOrder(), - 100) - } - -} diff --git a/ios/libs/Webim/Example/Tests/DepartmentItemTests.swift b/ios/libs/Webim/Example/Tests/DepartmentItemTests.swift deleted file mode 100644 index 36a9b06..0000000 --- a/ios/libs/Webim/Example/Tests/DepartmentItemTests.swift +++ /dev/null @@ -1,107 +0,0 @@ -// -// DepartmentItemTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 16.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -// MARK: - Global constants -let DEPARTMENT_ITEM_JSON_STRING = """ -{ - "localeToName" : { - "ru" : "Mobile Test 1" - }, - "key" : "mobile_test_1", - "online" : "offline", - "name" : "Mobile Test 1", - "order" : 100, - "logo" : "/webim/images/department_logo/wmtest2_1.png" -} -""" -let DEPARTMENT_ITEM_WITH_UNKNOWN_ONLINE_STATUS_JSON_STRING = """ -{ - "localeToName" : { - "ru" : "Mobile Test 1" - }, - "key" : "mobile_test_1", - "online" : "new_status", - "name" : "Mobile Test 1", - "order" : 100, - "logo" : "/webim/images/department_logo/wmtest2_1.png" -} -""" -let INCORRECT_DEPARTMENT_ITEM_JSON_STRING = """ -{ - "localeToName" : { - "ru" : "Mobile Test 1" - }, - "online" : "offline", - "name" : "Mobile Test 1", - "order" : 100, - "logo" : "/webim/images/department_logo/wmtest2_1.png" -} -""" - -class DepartmentItemTests: XCTestCase { - - // MARK: - Tests - - func testInit() { - let departmentItemDictionary = try! JSONSerialization.jsonObject(with: DEPARTMENT_ITEM_JSON_STRING.data(using: .utf8)!, - options: []) as! [String : Any?] - let departmentItem = DepartmentItem(jsonDictionary: departmentItemDictionary) - - XCTAssertEqual(departmentItem!.getKey(), - "mobile_test_1") - XCTAssertEqual(departmentItem!.getName(), - "Mobile Test 1") - XCTAssertEqual(departmentItem!.getOnlineStatus(), - DepartmentItem.InternalDepartmentOnlineStatus.offline) - XCTAssertEqual(departmentItem!.getOrder(), - 100) - XCTAssertEqual(departmentItem!.getLocalizedNames()!, - ["ru" : "Mobile Test 1"]) - XCTAssertEqual(departmentItem!.getLogoURLString()!, - "/webim/images/department_logo/wmtest2_1.png") - } - - func testUnknownOnlineStatus() { - let departmentItemDictionary = try! JSONSerialization.jsonObject(with: DEPARTMENT_ITEM_WITH_UNKNOWN_ONLINE_STATUS_JSON_STRING.data(using: .utf8)!, - options: []) as! [String : Any?] - let departmentItem = DepartmentItem(jsonDictionary: departmentItemDictionary) - - XCTAssertEqual(departmentItem!.getOnlineStatus(), - DepartmentItem.InternalDepartmentOnlineStatus.unknown) - } - - func testInitFails() { - let departmentItemDictionary = try! JSONSerialization.jsonObject(with: INCORRECT_DEPARTMENT_ITEM_JSON_STRING.data(using: .utf8)!, - options: []) as! [String : Any?] - - XCTAssertNil(DepartmentItem(jsonDictionary: departmentItemDictionary)) - } - -} diff --git a/ios/libs/Webim/Example/Tests/ExampleTests/ChatViewControllerTests.swift b/ios/libs/Webim/Example/Tests/ExampleTests/ChatViewControllerTests.swift deleted file mode 100644 index 9156447..0000000 --- a/ios/libs/Webim/Example/Tests/ExampleTests/ChatViewControllerTests.swift +++ /dev/null @@ -1,87 +0,0 @@ -// -// ChatViewControllerTests.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 15.01.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import UIKit -import XCTest -@testable import WebimClientLibrary -@testable import WebimClientLibrary_Example - -class ChatViewControllerTests: XCTestCase { - - // MARK: - Properties - var chatViewController: ChatViewController! - - // MARK: - Methods - override func setUp() { - super.setUp() - - let storyboard = UIStoryboard(name: "Main", - bundle: nil) - chatViewController = storyboard.instantiateViewController(withIdentifier: "ChatViewController") as! ChatViewController - } - - // MARK: - Tests - - func testBackgroundViewNotEmpty() { - // When: Table view is empty. - let tableView = chatViewController.tableView! - tableView.reloadData() - - // Then: Table view background has the message. - let label = tableView.backgroundView as! UILabel - XCTAssertEqual(label.attributedText?.string, - "Send first message to start chat.") - } - - func testBackgroundViewEmpty() { - // MARK: Set up - var messages = [Message]() - for index in 0 ... 2 { - let message = MessageImpl(serverURLString: "http://demo.webim.ru/", - id: String(index), - operatorID: nil, - senderAvatarURLString: nil, - senderName: "Sender name", - type: .VISITOR, - data: nil, - text: "Text", - timeInMicrosecond: Int64(index), - attachment: nil, - historyMessage: false, - internalID: nil, - rawText: nil) - messages.append(message as Message) - } - - // When: Table view is not empty. - chatViewController.set(messages: messages) - chatViewController.tableView?.reloadData() - - // Then: Table view background view is empty. - XCTAssertNil(chatViewController.tableView!.backgroundView) - } - -} diff --git a/ios/libs/Webim/Example/Tests/ExampleTests/DecodePercentEscapedLinksIfPresentTests.swift b/ios/libs/Webim/Example/Tests/ExampleTests/DecodePercentEscapedLinksIfPresentTests.swift deleted file mode 100644 index fd1d10e..0000000 --- a/ios/libs/Webim/Example/Tests/ExampleTests/DecodePercentEscapedLinksIfPresentTests.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// DecodePercentEscapedLinksIfPresentTests.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 31.01.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -import WebimClientLibrary_Example -import XCTest - -class DecodePercentEscapedLinksIfPresentTests: XCTestCase { - - // MARK: - Tests - - func testNormalString() { - let initialString = "Normal string" - let expectedString = initialString - - XCTAssertEqual(initialString.decodePercentEscapedLinksIfPresent(), - expectedString) - } - - func testOneLinkWithoutPercentEscapingOnlyString() { - let initialString = "https://www.webim.ru/" - let expectedString = initialString - - XCTAssertEqual(initialString.decodePercentEscapedLinksIfPresent(), - expectedString) - } - - func testOneLinkWithPercentEscapingOnlyString() { - let initialString = "https://www.webim.ru/%D1%82%D0%B5%D1%81%D1%82/" - let expectedString = "https://www.webim.ru/тест/" - - XCTAssertEqual(initialString.decodePercentEscapedLinksIfPresent(), - expectedString) - } - - func testOneLinkWithPercentEscapingAndStartingTextString() { - let initialString = "Link: https://www.webim.ru/%D1%82%D0%B5%D1%81%D1%82/" - let expectedString = "Link: https://www.webim.ru/тест/" - - XCTAssertEqual(initialString.decodePercentEscapedLinksIfPresent(), - expectedString) - } - - func testOneLinkWithPercentEscapingAndClosingTextString() { - let initialString = "https://www.webim.ru/%D1%82%D0%B5%D1%81%D1%82/ – link" - let expectedString = "https://www.webim.ru/тест/ – link" - - XCTAssertEqual(initialString.decodePercentEscapedLinksIfPresent(), - expectedString) - } - - func testOneLinkWithPercentEscapingInsideTextString() { - let initialString = "Link: https://www.webim.ru/%D1%82%D0%B5%D1%81%D1%82/ – check it!" - let expectedString = "Link: https://www.webim.ru/тест/ – check it!" - - XCTAssertEqual(initialString.decodePercentEscapedLinksIfPresent(), - expectedString) - } - - func testMultipleLinksWithPercentEscapingString() { - let initialString = "https://www.webim.ru/%D1%82%D0%B5%D1%81%D1%821/ https://www.webim.ru/%D1%82%D0%B5%D1%81%D1%822/" - let expectedString = "https://www.webim.ru/тест1/ https://www.webim.ru/тест2/" - - XCTAssertEqual(initialString.decodePercentEscapedLinksIfPresent(), - expectedString) - } - - func testMultipleLinksWithPercentEscapingInsideComplexTextString() { - let initialString = "First link: https://www.webim.ru/%D1%82%D0%B5%D1%81%D1%821/ Second link: https://www.webim.ru/%D1%82%D0%B5%D1%81%D1%822/ That's it!" - let expectedString = "First link: https://www.webim.ru/тест1/ Second link: https://www.webim.ru/тест2/ That's it!" - - XCTAssertEqual(initialString.decodePercentEscapedLinksIfPresent(), - expectedString) - } - -} diff --git a/ios/libs/Webim/Example/Tests/ExampleTests/MimeTypeTests.swift b/ios/libs/Webim/Example/Tests/ExampleTests/MimeTypeTests.swift deleted file mode 100644 index 4c7ec76..0000000 --- a/ios/libs/Webim/Example/Tests/ExampleTests/MimeTypeTests.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// MimeTypeTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 12.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -@testable import WebimClientLibrary_Example -import Foundation -import XCTest - -class MimeTypeTests: XCTestCase { - - func testValue() { - // MARK: Test 1 - - var urlString = "/image.jpg" - var url = URL(string: urlString)! - - XCTAssertEqual(MimeType(url: url).value, - "image/jpeg") - XCTAssertTrue(isImage(contentType: MimeType(url: url).value)) - - // MARK: Test 2 - // Unknown extension - - urlString = "/db.db" - url = URL(string: urlString)! - - XCTAssertEqual(MimeType(url: url).value, - "application/octet-stream") - XCTAssertFalse(isImage(contentType: MimeType(url: url).value)) - - // MARK: Test 3 - // No extension - - urlString = "/unknown" - url = URL(string: urlString)! - - XCTAssertEqual(MimeType(url: url).value, - "application/octet-stream") - } - -} diff --git a/ios/libs/Webim/Example/Tests/ExecIfNotDestroyedHandlerExecutorTests.swift b/ios/libs/Webim/Example/Tests/ExecIfNotDestroyedHandlerExecutorTests.swift deleted file mode 100644 index 1fbb98d..0000000 --- a/ios/libs/Webim/Example/Tests/ExecIfNotDestroyedHandlerExecutorTests.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// ExecIfNotDestroyedHandlerExecutorTests.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 01.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -import XCTest -@testable import WebimClientLibrary - -class ExecIfNotDestroyedHandlerExecutorTests: XCTestCase { - - // MARK: - Properties - let execIfNotDestroyedHandlerExecutor = ExecIfNotDestroyedHandlerExecutor(sessionDestroyer: SessionDestroyer(), - queue: DispatchQueue.global()) - - // MARK: - Tests - func testExecuteTask() { - let expectationToBeCalled = XCTestExpectation() - execIfNotDestroyedHandlerExecutor.execute(task: DispatchWorkItem { - expectationToBeCalled.fulfill() - }) - - wait(for: [expectationToBeCalled], - timeout: 1.0) - } - -} diff --git a/ios/libs/Webim/Example/Tests/FileParametersItemTests.swift b/ios/libs/Webim/Example/Tests/FileParametersItemTests.swift deleted file mode 100644 index be6b634..0000000 --- a/ios/libs/Webim/Example/Tests/FileParametersItemTests.swift +++ /dev/null @@ -1,73 +0,0 @@ -// -// FileParametersItemTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 16.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class FileParametersItemTests: XCTestCase { - - // MARK: - Constants - static let FILE_PARAMETERS_JSON_STRING = """ -{ - "client_content_type" : "image/jpeg", - "image" : { - "size" : { - "width" : 700, - "height" : 501 - } - }, - "visitor_id" : "877a920ede7082412656ac1cdec7ecde", - "filename" : "asset.JPG", - "content_type" : "image/png", - "guid" : "010a56da72ee41e2a78d0509155de755", - "size" : 758611 -} -""" - - // MARK: - Properties - private let fileParametersItemDictionary = try! JSONSerialization.jsonObject(with: FileParametersItemTests.FILE_PARAMETERS_JSON_STRING.data(using: .utf8)!, - options: []) as! [String : Any?] - - // MARK: - Tests - func testInit() { - let fileParametersItem = FileParametersItem(jsonDictionary: fileParametersItemDictionary) - - XCTAssertEqual(fileParametersItem.getSize(), - 758611) - XCTAssertEqual(fileParametersItem.getGUID(), - "010a56da72ee41e2a78d0509155de755") - XCTAssertEqual(fileParametersItem.getContentType(), - "image/png") - XCTAssertEqual(fileParametersItem.getFilename(), - "asset.JPG") - XCTAssertEqual(fileParametersItem.getImageParameters()!.getSize()!.getWidth(), - 700) - XCTAssertEqual(fileParametersItem.getImageParameters()!.getSize()!.getHeight(), - 501) - } - -} diff --git a/ios/libs/Webim/Example/Tests/FullUpdateTests.swift b/ios/libs/Webim/Example/Tests/FullUpdateTests.swift deleted file mode 100644 index f79223c..0000000 --- a/ios/libs/Webim/Example/Tests/FullUpdateTests.swift +++ /dev/null @@ -1,195 +0,0 @@ -// -// FullUpdateTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 19.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class FullUpdateTests: XCTestCase { - - // MARK: - Constants - private static let FULL_UPDATE_JSON_STRING = """ -{ - "state" : "chat", - "authToken" : "17778d49ecf342b5aef702479a99bb65", - "visitorNumber" : null, - "visitor" : { - "fields" : { - "name" : "Посетитель" - }, - "channelType" : null, - "channelId" : null, - "id" : "877a920ede7082412656ac1cdec7ecde", - "icon" : { - "color" : "#5fa0ea", - "shape" : "rhombus" - }, - "modificationTs" : 1518790888.5528669, - "creationTs" : 1518790888.5528669, - "hasProvidedFields" : true, - "channelUserName" : null, - "tags" : [ ], - "channelUserId" : null - }, - "pageId" : "fc59d2b80f1742da805e1f93548b3a29", - "onlineStatus" : "offline", - "visitSessionId" : "80a332f6fced40f290a5e8ace4a6d11c", - "pollingPeriod" : 2, - "onlineOperators" : false, - "currentTime" : 1519044952, - "cobrowsingSession" : null, - "normalPollingPeriod" : 10, - "chat" : { - "readByVisitor" : true, - "category" : "Прочее", - "subject" : null, - "operatorTyping" : false, - "clientSideId" : "0134e9d90e0eb95884d880860382c8ab", - "state" : "closed_by_operator", - "needToBeClosed" : false, - "visitorTyping" : null, - "messages" : [ - { - "avatar" : null, - "authorId" : null, - "ts" : 1519040829.056972, - "sessionId" : "80a332f6fced40f290a5e8ace4a6d11c", - "id" : "80a332f6fced40f290a5e8ace4a6d11c_2", - "text" : "Text", - "clientSideId" : "381e483f39e041a68b965da7f767c438", - "kind" : "info", - "name" : "" - } - ], - "offline" : false, - "visitorMessageDraft" : null, - "id" : 2547, - "unreadByVisitorSinceTs" : null, - "operatorIdToRate" : { }, - "creationTs" : 1519040829.056129, - "subcategory" : null, - "requestedForm" : null, - "unreadByOperatorSinceTs" : null, - "operator" : { - "avatar" : "/webim/images/avatar/demo_33201.png", - "fullname" : "Administrator", - "id" : 33201, - "robotType" : null, - "departmentKeys" : [ - "telegram", - "test3", - "test2" - ], - "langToFullname" : { }, - "sip" : "10002715000033201" - } - } -} -""" - - // MARK: - Properties - private let fullUpdateDictionary = try! JSONSerialization.jsonObject(with: FullUpdateTests.FULL_UPDATE_JSON_STRING.data(using: .utf8)!, - options: []) as! [String : Any?] - - // MARK: - Tests - func testInit() { - let fullUpdateItem = FullUpdate(jsonDictionary: fullUpdateDictionary) - - XCTAssertEqual(fullUpdateItem.getAuthorizationToken(), - "17778d49ecf342b5aef702479a99bb65") - - let chatItemString = """ -{ - "readByVisitor" : true, - "category" : "Прочее", - "subject" : null, - "operatorTyping" : false, - "clientSideId" : "0134e9d90e0eb95884d880860382c8ab", - "state" : "closed_by_operator", - "needToBeClosed" : false, - "visitorTyping" : null, - "messages" : [ - { - "avatar" : null, - "authorId" : null, - "ts" : 1519040829.056972, - "sessionId" : "80a332f6fced40f290a5e8ace4a6d11c", - "id" : "80a332f6fced40f290a5e8ace4a6d11c_2", - "text" : "Text", - "clientSideId" : "381e483f39e041a68b965da7f767c438", - "kind" : "info", - "name" : "" - } - ], - "offline" : false, - "visitorMessageDraft" : null, - "id" : 2547, - "unreadByVisitorSinceTs" : null, - "operatorIdToRate" : { }, - "creationTs" : 1519040829.056129, - "subcategory" : null, - "requestedForm" : null, - "unreadByOperatorSinceTs" : null, - "operator" : { - "avatar" : "/webim/images/avatar/demo_33201.png", - "fullname" : "Administrator", - "id" : 33201, - "robotType" : null, - "departmentKeys" : [ - "telegram", - "test3", - "test2" - ], - "langToFullname" : { }, - "sip" : "10002715000033201" - } -} -""" - let chatItemDictonary = try! JSONSerialization.jsonObject(with: chatItemString.data(using: .utf8)!, - options: []) as! [String : Any?] - XCTAssertEqual(fullUpdateItem.getChat(), - ChatItem(jsonDictionary: chatItemDictonary)) - - XCTAssertNil(fullUpdateItem.getDepartments()) - - XCTAssertFalse(fullUpdateItem.getHintsEnabled()) - - XCTAssertEqual(fullUpdateItem.getOnlineStatus(), - "offline") - - XCTAssertEqual(fullUpdateItem.getPageID(), - "fc59d2b80f1742da805e1f93548b3a29") - - XCTAssertEqual(fullUpdateItem.getSessionID(), - "80a332f6fced40f290a5e8ace4a6d11c") - - XCTAssertEqual(fullUpdateItem.getState(), - "chat") - - XCTAssertNotNil(fullUpdateItem.getVisitorJSONString()) - } - -} diff --git a/ios/libs/Webim/Example/Tests/HMACsha256Tests.swift b/ios/libs/Webim/Example/Tests/HMACsha256Tests.swift deleted file mode 100644 index 893d6ae..0000000 --- a/ios/libs/Webim/Example/Tests/HMACsha256Tests.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// HMACSha256Tests.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 17.01.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -import XCTest -@testable import WebimClientLibrary - -class HMACSha256Tests: XCTestCase { - - func testHMACsha256() { - // Setup. - // Example is taken from Wikipedia. - let string = "The quick brown fox jumps over the lazy dog" - let key = "key" - let expectedResult = "f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8" - - let result = string.hmacSHA256(withKey: key) - XCTAssertEqual(result, expectedResult) - } - -} diff --git a/ios/libs/Webim/Example/Tests/HistoryBeforeResponseTests.swift b/ios/libs/Webim/Example/Tests/HistoryBeforeResponseTests.swift deleted file mode 100644 index be744c4..0000000 --- a/ios/libs/Webim/Example/Tests/HistoryBeforeResponseTests.swift +++ /dev/null @@ -1,82 +0,0 @@ -// -// HistoryBeforeResponseTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 19.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class HistoryBeforeResponseTests: XCTestCase { - - // MARK: - Constants - private static let HISTORY_BEFORE_RESPONSE_JSON_STRING = """ -{ - "result" : "ok", - "data" : { - "hasMore" : true, - "messages" : [ - { - "avatar" : "/webim/images/avatar/demo_33201.png", - "chatId" : "2470", - "authorId" : 33201, - "data" : null, - "id" : "26066", - "ts_m" : 1518178864048925, - "text" : "5", - "clientSideId" : "2b29154364e14cf8b3823267740ac090", - "kind" : "operator", - "name" : "Administrator" - }, - { - "avatar" : null, - "chatId" : "2470", - "authorId" : null, - "data" : null, - "id" : "26068", - "ts_m" : 1518181740640531, - "text" : "Text", - "clientSideId" : "b91d616953a4d05c3df82f63359ebb58", - "kind" : "file_visitor", - "name" : "Никита" - } - ] - } -} -""" - - // MARK: - Properties - private let historyBeforeResponseDictionary = try! JSONSerialization.jsonObject(with: HistoryBeforeResponseTests.HISTORY_BEFORE_RESPONSE_JSON_STRING.data(using: .utf8)!, - options: []) as! [String : Any?] - - // MARK: - Tests - func testInit() { - let historyBeforeItem = HistoryBeforeResponse(jsonDictionary: historyBeforeResponseDictionary) - - XCTAssertTrue(historyBeforeItem.getData()!.isHasMore()) - XCTAssertEqual(historyBeforeItem.getData()!.getMessages()!.count, - 2) - } - -} diff --git a/ios/libs/Webim/Example/Tests/HistoryIDTests.swift b/ios/libs/Webim/Example/Tests/HistoryIDTests.swift deleted file mode 100644 index 387f4e0..0000000 --- a/ios/libs/Webim/Example/Tests/HistoryIDTests.swift +++ /dev/null @@ -1,76 +0,0 @@ -// -// HistoryIDTests.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 01.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -import XCTest -@testable import WebimClientLibrary - -class HistoryIDTests: XCTestCase { - - // MARK: - Tests - func testEquals() { - let dbID = "db_id" - let timeInMicrosecond: Int64 = 1 - - // MARK: Test 1 - // Two different normal HistoryID objects. - - var historyID1: HistoryID? = HistoryID(dbID: "db_id1", - timeInMicrosecond: 1) - var historyID2: HistoryID? = HistoryID(dbID: "db_id2", - timeInMicrosecond: 2) - - XCTAssertFalse(historyID1 == historyID2) - - // MARK: Test 2 - // Two same normal HistoryID objects. - - historyID1 = HistoryID(dbID: dbID, - timeInMicrosecond: timeInMicrosecond) - historyID2 = HistoryID(dbID: dbID, - timeInMicrosecond: timeInMicrosecond) - - XCTAssertTrue(historyID1 == historyID2) - - // MARK: Test 3 - // One normal HistoryID object and one nil. - - historyID1 = HistoryID(dbID: dbID, - timeInMicrosecond: timeInMicrosecond) - historyID2 = nil - - XCTAssertFalse(historyID1 == historyID2) - - // MARK: Test 4 - // Two nil objects. - - historyID1 = nil - historyID2 = nil - - XCTAssertTrue(historyID1 == historyID2) - } - -} diff --git a/ios/libs/Webim/Example/Tests/HistorySinceResponseTests.swift b/ios/libs/Webim/Example/Tests/HistorySinceResponseTests.swift deleted file mode 100644 index d9c9e15..0000000 --- a/ios/libs/Webim/Example/Tests/HistorySinceResponseTests.swift +++ /dev/null @@ -1,85 +0,0 @@ -// -// HistorySinceResponseTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 19.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class HistorySinceResponseTests: XCTestCase { - - // MARK: - Constants - private static let HISTORY_SINCE_RESPONSE_JSON_STRING = """ -{ - "result" : "ok", - "data" : { - "hasMore" : true, - "revision" : "1519046942029554", - "messages" : [ - { - "avatar" : null, - "chatId" : "2489", - "authorId" : null, - "data" : null, - "id" : "26886", - "ts_m" : 1518610821878678, - "text" : "5", - "clientSideId" : "4855e5fb4cf72970fd1ee6d055db165f", - "kind" : "visitor", - "name" : "Никита" - }, - { - "avatar" : null, - "chatId" : "2489", - "authorId" : null, - "data" : null, - "id" : "26887", - "ts_m" : 1518610834493789, - "text" : "Посетитель закрыл диалог", - "clientSideId" : "f90565d2ae724a5f969f72687af7fd49", - "kind" : "info", - "name" : "" - } - ] - } -} -""" - - // MARK: - Properties - private let historySinceResponseDictionary = try! JSONSerialization.jsonObject(with: HistorySinceResponseTests.HISTORY_SINCE_RESPONSE_JSON_STRING.data(using: .utf8)!, - options: []) as! [String : Any?] - - // MARK: - Methods - func testInit() { - let historySinceResponse = HistorySinceResponse(jsonDictionary: historySinceResponseDictionary) - - XCTAssertEqual(historySinceResponse.getData()!.getMessages()!.count, - 2) - XCTAssertTrue(historySinceResponse.getData()!.isHasMore()!) - XCTAssertEqual(historySinceResponse.getData()!.getRevision(), - "1519046942029554") - } - -} diff --git a/ios/libs/Webim/Example/Tests/Info.plist b/ios/libs/Webim/Example/Tests/Info.plist deleted file mode 100644 index ba72822..0000000 --- a/ios/libs/Webim/Example/Tests/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - - diff --git a/ios/libs/Webim/Example/Tests/InternalUtilsTests.swift b/ios/libs/Webim/Example/Tests/InternalUtilsTests.swift deleted file mode 100644 index 3474672..0000000 --- a/ios/libs/Webim/Example/Tests/InternalUtilsTests.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// InternalUtilsTests.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 02.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -import XCTest -@testable import WebimClientLibrary - -class InternalUtilsTests: XCTestCase { - - func testCreateServerURLString() { - let expectedServerURLString = "https://demo.webim.ru" - - // MARK: Test 1 - var accountName = "demo" - XCTAssertEqual(InternalUtils.createServerURLStringBy(accountName: accountName), - expectedServerURLString) - - // MARK: Test 2 - accountName = "https://demo.webim.ru" - XCTAssertEqual(InternalUtils.createServerURLStringBy(accountName: accountName), - expectedServerURLString) - - // MARK: Test 3 - accountName = "https://demo.webim.ru/" - XCTAssertEqual(InternalUtils.createServerURLStringBy(accountName: accountName), - expectedServerURLString) - } - -} diff --git a/ios/libs/Webim/Example/Tests/LocationSettingsHolderTests.swift b/ios/libs/Webim/Example/Tests/LocationSettingsHolderTests.swift deleted file mode 100644 index e1d617b..0000000 --- a/ios/libs/Webim/Example/Tests/LocationSettingsHolderTests.swift +++ /dev/null @@ -1,67 +0,0 @@ -// -// LocationSettingsHolderTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 21.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class LocationSettingsHolderTests: XCTestCase { - - // MARK: - Constants - private static let USER_DEFAULTS_KEY = "mock" - - // MARK: - Methods - - override func setUp() { - super.setUp() - - UserDefaults.standard.removeObject(forKey: LocationSettingsHolderTests.USER_DEFAULTS_KEY) - } - - override func tearDown() { - UserDefaults.standard.removeObject(forKey: LocationSettingsHolderTests.USER_DEFAULTS_KEY) - - super.tearDown() - } - - // MARK: - Tests - - func testInit() { - let locationSettingsHolder = LocationSettingsHolder(userDefaultsKey: LocationSettingsHolderTests.USER_DEFAULTS_KEY) - - XCTAssertFalse(locationSettingsHolder.getLocationSettings().areHintsEnabled()) - } - - func testReceiving() { - let locationSettingsHolder = LocationSettingsHolder(userDefaultsKey: LocationSettingsHolderTests.USER_DEFAULTS_KEY) - - XCTAssertFalse(locationSettingsHolder.receiving(locationSettings: locationSettingsHolder.getLocationSettings())) - - let newLocationSettings = LocationSettingsImpl(hintsEnabled: true) - XCTAssertTrue(locationSettingsHolder.receiving(locationSettings: newLocationSettings)) - } - -} diff --git a/ios/libs/Webim/Example/Tests/LocationSettingsImplTests.swift b/ios/libs/Webim/Example/Tests/LocationSettingsImplTests.swift deleted file mode 100644 index 916acd9..0000000 --- a/ios/libs/Webim/Example/Tests/LocationSettingsImplTests.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// LocationSettingsImplTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 20.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -import XCTest -@testable import WebimClientLibrary - -class LocationSettingsImplTests: XCTestCase { - - // MARK: - Constants - private static let USER_DEFAULTS_KEY = "mock" - - // MARK: - Methods - - override func setUp() { - super.setUp() - - UserDefaults.standard.removeObject(forKey: LocationSettingsImplTests.USER_DEFAULTS_KEY) - } - - override func tearDown() { - UserDefaults.standard.removeObject(forKey: LocationSettingsImplTests.USER_DEFAULTS_KEY) - - super.tearDown() - } - - // MARK: - Tests - - func testInit() { - let locationSettings = LocationSettingsImpl(hintsEnabled: true) - - XCTAssertTrue(locationSettings.areHintsEnabled()) - } - - func testGetSave() { - let USER_DEFAULTS_KEY = "test" - - let locationSettings = LocationSettingsImpl(hintsEnabled: true) - locationSettings.saveTo(userDefaults: USER_DEFAULTS_KEY) - - let restoredLocationSettings = LocationSettingsImpl.getFrom(userDefaults: USER_DEFAULTS_KEY) - - XCTAssertEqual(locationSettings.areHintsEnabled(), - restoredLocationSettings.areHintsEnabled()) - } - -} diff --git a/ios/libs/Webim/Example/Tests/MemoryHistoryMetaInformationStorageTests.swift b/ios/libs/Webim/Example/Tests/MemoryHistoryMetaInformationStorageTests.swift deleted file mode 100644 index 9c61b39..0000000 --- a/ios/libs/Webim/Example/Tests/MemoryHistoryMetaInformationStorageTests.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// MemoryHistoryMetaInformationStorageTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 15.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class MemoryHistoryMetaInformationStorageTests: XCTestCase { - - // MARK: - Tests - func testIsHistoryEnded() { - let memoryHistoryMetaInformationStorage = MemoryHistoryMetaInformationStorage() - - XCTAssertFalse(memoryHistoryMetaInformationStorage.isHistoryEnded()) - - memoryHistoryMetaInformationStorage.set(historyEnded: true) - XCTAssertTrue(memoryHistoryMetaInformationStorage.isHistoryEnded()) - } - -} diff --git a/ios/libs/Webim/Example/Tests/MemoryHistoryStorageTests.swift b/ios/libs/Webim/Example/Tests/MemoryHistoryStorageTests.swift deleted file mode 100644 index 29e5d49..0000000 --- a/ios/libs/Webim/Example/Tests/MemoryHistoryStorageTests.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// MemoryHistoryStorageTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 20.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class MemoryHistoryStorageTests: XCTestCase { - - // MARK: - Constants - private static let SERVER_URL_STRING = "http://demo.webim.ru" - - // MARK: - Methods - // MARK: Private methods - private static func generateMessages(ofCount numberOfMessages: Int) -> [MessageImpl] { - var messages = [MessageImpl]() - - for index in 1 ... numberOfMessages { - messages.append(MessageImpl(serverURLString: MemoryHistoryStorageTests.SERVER_URL_STRING, - id: String(index), - operatorID: "1", - senderAvatarURLString: nil, - senderName: "Name", - type: MessageType.OPERATOR, - data: nil, - text: "Text", - timeInMicrosecond: Int64(index), - attachment: nil, - historyMessage: true, - internalID: String(index), - rawText: nil)) - } - - return messages - } - - // MARK: - Tests - func testGetFullHistory() { - let memoryHistoryStorage = MemoryHistoryStorage() - let messagesCount = 10 - memoryHistoryStorage.receiveHistoryBefore(messages: MemoryHistoryStorageTests.generateMessages(ofCount: messagesCount), - hasMoreMessages: false) - - let expectation = XCTestExpectation() - var gettedMessages = [Message]() - memoryHistoryStorage.getFullHistory() { messages in - gettedMessages = messages - - expectation.fulfill() - } - wait(for: [expectation], - timeout: 1.0) - - XCTAssertEqual(gettedMessages.count, - messagesCount) - } - -} diff --git a/ios/libs/Webim/Example/Tests/MessageFactoriesTests.swift b/ios/libs/Webim/Example/Tests/MessageFactoriesTests.swift deleted file mode 100644 index 713016f..0000000 --- a/ios/libs/Webim/Example/Tests/MessageFactoriesTests.swift +++ /dev/null @@ -1,143 +0,0 @@ -// -// MessageFactoriesTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 19.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -// MARK: - Global constants -fileprivate let MESSAGE_ITEM_JSON_STRING = """ -{ - "avatar" : "/webim/images/avatar/demo_33202.png", - "chatId" : "2489", - "authorId" : 33202, - "data" : null, - "id" : "26871", - "ts_m" : 1518609964579372, - "text" : "42", - "clientSideId" : "84e51d5638524ee7833a1fe19a1f2448", - "kind" : "operator", - "name" : "Евгения Техподдержка" -} -""" -fileprivate let MESSAGE_ITEM_DICTIONARY = try! JSONSerialization.jsonObject(with: MESSAGE_ITEM_JSON_STRING.data(using: .utf8)!, - options: []) as! [String : Any?] -fileprivate let MESSAGE_ITEM = MessageItem(jsonDictionary: MESSAGE_ITEM_DICTIONARY) - -class CurrentChatMapperTests: XCTestCase { - - // MARK: - Properties - let currentChatMapper = CurrentChatMessageMapper(withServerURLString: "http://demo.webim.ru") - - // MARK: - Tests - - func testMap() { - let message = currentChatMapper.map(message: MESSAGE_ITEM)! - - XCTAssertEqual(message.getType(), - MessageType.OPERATOR) - XCTAssertNil(message.getAttachment()) - XCTAssertEqual(message.getText(), - "42") - XCTAssertNil(message.getRawText()) - XCTAssertEqual(message.getOperatorID(), - "33202") - XCTAssertEqual(message.getSenderAvatarURLString(), - "/webim/images/avatar/demo_33202.png") - XCTAssertEqual(message.getSenderName(), - "Евгения Техподдержка") - XCTAssertEqual(message.getTimeInMicrosecond(), - 1518609964579372) - XCTAssertFalse(message.hasHistoryComponent()) - } - - func testMapAll() { - XCTAssertEqual(currentChatMapper.mapAll(messages: [MESSAGE_ITEM]).count, - 1) - } - -} - -class HistoryMapperTests: XCTestCase { - - // MARK: - Properties - let historyMapper = HistoryMessageMapper(withServerURLString: "http://demo.webim.ru") - - // MARK: - Tests - func testMap() { - let message = historyMapper.map(message: MESSAGE_ITEM)! - - XCTAssertEqual(message.getType(), - MessageType.OPERATOR) - XCTAssertNil(message.getAttachment()) - XCTAssertEqual(message.getText(), - "42") - XCTAssertNil(message.getRawText()) - XCTAssertEqual(message.getOperatorID(), - "33202") - XCTAssertEqual(message.getSenderAvatarURLString(), - "/webim/images/avatar/demo_33202.png") - XCTAssertEqual(message.getSenderName(), - "Евгения Техподдержка") - XCTAssertEqual(message.getTimeInMicrosecond(), - 1518609964579372) - XCTAssertTrue(message.hasHistoryComponent()) - } - -} - -class SendingFactoryTests: XCTestCase { - - // MARK: - Properties - let sendingFactory = SendingFactory(withServerURLString: "http://demo.webim.ru") - - // MARK: - Tests - - func testCreateTextMessage() { - let message = sendingFactory.createTextMessageToSendWith(id: "1", - text: "Text") - - XCTAssertEqual(message.getID(), - "1") - XCTAssertTrue(message.getSenderName().isEmpty) - XCTAssertEqual(message.getType(), - MessageType.VISITOR) - XCTAssertEqual(message.getText(), - "Text") - } - - func testCreateFileMessage() { - let message = sendingFactory.createFileMessageToSendWith(id: "1") - - XCTAssertEqual(message.getID(), - "1") - XCTAssertTrue(message.getSenderName().isEmpty) - XCTAssertEqual(message.getType(), - MessageType.FILE_FROM_VISITOR) - XCTAssertTrue(message.getText().isEmpty) - } - -} diff --git a/ios/libs/Webim/Example/Tests/MessageHolderTests.swift b/ios/libs/Webim/Example/Tests/MessageHolderTests.swift deleted file mode 100644 index 332c063..0000000 --- a/ios/libs/Webim/Example/Tests/MessageHolderTests.swift +++ /dev/null @@ -1,1713 +0,0 @@ -// -// MessageHolderTests.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 01.09.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import UIKit -import XCTest -@testable import WebimClientLibrary - -class MessageHolderTests: XCTestCase { - - // MARK: - Constants - private enum MessageImplMockData: String { - case serverURLString = "https://demo.webim.ru/" - case operatorID = "operatorID" - case avatarURLString = "image.jpg" - case senderName = "Sender Name" - case text = "Text." - } - - // MARK: - Properties - private var lastAddedMessage: MessageImpl? - private var lastMessageBeforeAdded: MessageImpl? - private var lastRemovedMessage: MessageImpl? - private var lastNewVersionChangedMessage: MessageImpl? - private var lastOldVersionChangedMessage: MessageImpl? - private var messagesCount = 0 - - // MARK: - Methods - // MARK: Private methods - - private func generateHistory(ofCount numberOfMessages: Int) -> [MessageImpl] { - var history = [MessageImpl]() - - for index in messagesCount ..< (messagesCount + numberOfMessages) { - history.append(MessageImpl(serverURLString: MessageImplMockData.serverURLString.rawValue, - id: String(index), - operatorID: MessageImplMockData.operatorID.rawValue, - senderAvatarURLString: MessageImplMockData.avatarURLString.rawValue, - senderName: MessageImplMockData.senderName.rawValue, - type: MessageType.OPERATOR, - data: nil, - text: MessageImplMockData.text.rawValue, - timeInMicrosecond: Int64(index), - attachment: nil, - historyMessage: true, - internalID: String(index), - rawText: nil)) - } - - messagesCount = messagesCount + numberOfMessages - - return history - } - - private func generateCurrentChat(ofCount numberOfMessages: Int) -> [MessageImpl] { - var currentChat = [MessageImpl]() - - for index in messagesCount ..< (messagesCount + numberOfMessages) { - currentChat.append(MessageImpl(serverURLString: MessageImplMockData.serverURLString.rawValue, - id: String(index), - operatorID: MessageImplMockData.operatorID.rawValue, - senderAvatarURLString: MessageImplMockData.avatarURLString.rawValue, - senderName: MessageImplMockData.senderName.rawValue, - type: MessageType.OPERATOR, - data: nil, - text: MessageImplMockData.text.rawValue, - timeInMicrosecond: Int64(index), - attachment: nil, - historyMessage: false, - internalID: String(index), - rawText: nil)) - } - - messagesCount = messagesCount + numberOfMessages - - return currentChat - } - - private func generateHistoryFrom(currentChat: [MessageImpl]) -> [MessageImpl] { - var result = [MessageImpl]() - - for message in currentChat { - let newMessage = MessageImpl(serverURLString: MessageImplMockData.serverURLString.rawValue, - id: message.getID(), - operatorID: message.getOperatorID(), - senderAvatarURLString: message.getSenderAvatarURLString(), - senderName: message.getSenderName(), - type: message.getType(), - data: message.getData(), - text: message.getText(), - timeInMicrosecond: message.getTimeInMicrosecond(), - attachment: message.getAttachment(), - historyMessage: true, - internalID: String(message.getTimeInMicrosecond()), - rawText: message.getRawText()) - result.append(newMessage) - } - - return result - } - - private func newCurrentChat() -> MessageImpl { - messagesCount = messagesCount + messagesCount - - return MessageImpl(serverURLString: MessageImplMockData.serverURLString.rawValue, - id: String(messagesCount), - operatorID: MessageImplMockData.operatorID.rawValue, - senderAvatarURLString: MessageImplMockData.avatarURLString.rawValue, - senderName: MessageImplMockData.senderName.rawValue, - type: MessageType.OPERATOR, - data: nil, - text: MessageImplMockData.text.rawValue, - timeInMicrosecond: Int64(messagesCount), - attachment: nil, - historyMessage: false, - internalID: String(messagesCount), - rawText: nil) - } - - private func newEdited(currentChatMessage: MessageImpl) -> MessageImpl { - return MessageImpl(serverURLString: MessageImplMockData.serverURLString.rawValue, - id: currentChatMessage.getID(), - operatorID: currentChatMessage.getOperatorID(), - senderAvatarURLString: currentChatMessage.getSenderAvatarURLString(), - senderName: currentChatMessage.getSenderName(), - type: currentChatMessage.getType(), - data: nil, - text: (currentChatMessage.getText() + " One more thing."), - timeInMicrosecond: currentChatMessage.getTimeInMicrosecond(), - attachment: nil, - historyMessage: false, - internalID: currentChatMessage.getCurrentChatID(), - rawText: nil) - } - - private func newEdited(historyMessage: MessageImpl) -> MessageImpl { - return MessageImpl(serverURLString: MessageImplMockData.serverURLString.rawValue, - id: historyMessage.getID(), - operatorID: historyMessage.getOperatorID(), - senderAvatarURLString: historyMessage.getSenderAvatarURLString(), - senderName: historyMessage.getSenderName(), - type: historyMessage.getType(), - data: nil, - text: (historyMessage.getText() + " One more thing."), - timeInMicrosecond: historyMessage.getTimeInMicrosecond(), - attachment: nil, - historyMessage: true, - internalID: historyMessage.getHistoryID()?.getDBid(), - rawText: nil) - } - - private func newMessageHolder(withHistory history: [MessageImpl] = [MessageImpl]()) -> MessageHolder { - let sessionDestroyer = SessionDestroyer() - let accessChecker = AccessChecker(thread: Thread.current, - sessionDestroyer: sessionDestroyer) - let execIfNotDestroyedHandlerExecutor = ExecIfNotDestroyedHandlerExecutor(sessionDestroyer: sessionDestroyer, - queue: DispatchQueue.global(qos: .userInteractive)) - let actionRequestLoop = ActionRequestLoop(completionHandlerExecutor: execIfNotDestroyedHandlerExecutor, - internalErrorListener: InternalErrorListenerForTests()) - let webimActions = WebimActions(baseURL: MessageImplMockData.serverURLString.rawValue, - actionRequestLoop: actionRequestLoop) - let remoteHistoryProvider = RemoteHistoryProviderForTests(withWebimActions: webimActions, - historyMessageMapper: HistoryMessageMapper(withServerURLString: MessageImplMockData.serverURLString.rawValue), - historyMetaInformation: MemoryHistoryMetaInformationStorage(), - history: history) - - return MessageHolder(accessChecker: accessChecker, - remoteHistoryProvider: remoteHistoryProvider, - historyStorage: MemoryHistoryStorage(), - reachedEndOfRemoteHistory: false) - } - - private func newMessageHolder(withHistory history: [MessageImpl], - localHistory: [MessageImpl]) -> MessageHolder { - let sessionDestroyer = SessionDestroyer() - let accessChecker = AccessChecker(thread: Thread.current, - sessionDestroyer: sessionDestroyer) - let execIfNotDestroyedHandlerExecutor = ExecIfNotDestroyedHandlerExecutor(sessionDestroyer: sessionDestroyer, - queue: DispatchQueue.global(qos: .userInteractive)) - let actionRequestLoop = ActionRequestLoop(completionHandlerExecutor: execIfNotDestroyedHandlerExecutor, - internalErrorListener: InternalErrorListenerForTests()) - let webimActions = WebimActions(baseURL: MessageImplMockData.serverURLString.rawValue, - actionRequestLoop: actionRequestLoop) - let remoteHistoryProvider = RemoteHistoryProviderForTests(withWebimActions: webimActions, - historyMessageMapper: HistoryMessageMapper(withServerURLString: MessageImplMockData.serverURLString.rawValue), - historyMetaInformation: MemoryHistoryMetaInformationStorage(), - history: history) - let memoryHistoryStorage = MemoryHistoryStorage(messagesToAdd: localHistory) - - return MessageHolder(accessChecker: accessChecker, - remoteHistoryProvider: remoteHistoryProvider, - historyStorage: memoryHistoryStorage, - reachedEndOfRemoteHistory: false) - } - - // MARK: - Tests - - func testGenerateHistory() { - // MARK: Model set up - let history1 = generateHistory(ofCount: 10) - _ = generateCurrentChat(ofCount: 10) - let history2 = generateHistory(ofCount: 10) - - // MARK: Test 1 - var index = 0 - for message in history1 { - XCTAssertEqual(message.getPrimaryID(), String(index)) - index = index + 1 - } - - // MARK: Test 2 - index = 20 - for message in history2 { - XCTAssertEqual(message.getPrimaryID(), String(index)) - index = index + 1 - } - } - - func testMessageTrackerRespondsImmediatelyOnNewCurrentChatMessages() throws { - // MARK: Model set up - let currentChat = generateCurrentChat(ofCount: 10) - let messageHolder = newMessageHolder() - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - - // MARK: Test - // When: Request next 10 messages (which are of current chat). - messageHolder.set(currentChatMessages: currentChat) - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion should be called on current chat. When requesting messages current chat receives it immediately. - XCTAssertEqual(completionHandlerMessages!, currentChat) - } - - func testMessageTrackerAwaitsForHistoryResponse() throws { - // MARK: Model set up - let history1 = generateHistory(ofCount: 10) - let history2 = generateHistory(ofCount: 10) - let messageHolder = newMessageHolder(withHistory: (history1 + history2)) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - - // MARK: Test 1 - // When: Requesting next 10 messages (which are of history). - let expectationNotToBeCalled = XCTestExpectation() - expectationNotToBeCalled.isInverted = true - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - expectationNotToBeCalled.fulfill() - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion shouldn't be called. It was cached and will be called after history is received. - wait(for: [expectationNotToBeCalled], - timeout: 0.0) - - // MARK: Test 2 - // When: History is received. - messageHolder.receiveHistoryUpdateWith(messages: history2, - deleted: Set()) { - // No need to do anything when testing. - } - // Then: Previously cached completion should be called. - XCTAssertEqual(completionHandlerMessages!, history2) - - // MARK: Test 3 - // When: Requesting next 10 messages. - completionHandlerMessages = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion should be called on history1. - XCTAssertEqual(completionHandlerMessages!, history1) - } - - func testMessageTrackerAwaitsForHistoryResponseWithCurrentChat() throws { - // MARK: Model set up - let history1 = generateHistory(ofCount: 10) - let history2 = generateHistory(ofCount: 10) - let currentChat = generateCurrentChat(ofCount: 10) - let messageHolder = newMessageHolder(withHistory: (history1 + history2)) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - - // MARK: Test 1 - // When: Requesting all messages that are of current chat. - messageHolder.set(currentChatMessages: currentChat) - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion should be called on current chat messages. - XCTAssertEqual(completionHandlerMessages!, currentChat) - - // MARK: Test 2 - // When: Requesting next 10 messages (which are of history). - let expectationNotToBeCalled = XCTestExpectation() - expectationNotToBeCalled.isInverted = true - try messageTracker.getNextMessages(byLimit: 10) { messages in - expectationNotToBeCalled.fulfill() - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion should not be called. It was cached and will be called after history is received. - wait(for: [expectationNotToBeCalled], - timeout: 1.0) - - // MARK: Test 3 - // When: History is received. - messageHolder.receiveHistoryUpdateWith(messages: history2, - deleted: Set(), completion: { - // No need to do anything when testing. - }) - // Then: Cached completion should be called on history2. - XCTAssertEqual(completionHandlerMessages!, history2) - - // MARK: Test 4 - // When: Requesting next 10 messages (which are of received history). - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on history1. - XCTAssertEqual(completionHandlerMessages!, history1) - } - - func testRemoteHistoryProviderStopsRequesting() throws { - // MARK: Model set up - let history1 = generateHistory(ofCount: 10) - let history2 = generateHistory(ofCount: 10) - let messageHolder = newMessageHolder(withHistory: (history1 + history2)) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - - // MARK: Test 1 - // When: Request all messages. - messageHolder.receiveHistoryUpdateWith(messages: history2, - deleted: Set()) { - // No need to do anything when testing. - } - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 100) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: 10 previously received messages should be received and no history requests should be performed. - XCTAssertEqual(completionHandlerMessages!, history2) - XCTAssertEqual((messageHolder.getRemoteHistoryProvider() as! RemoteHistoryProviderForTests).numberOfCalls, 0) - - // MARK: Test 2 - // When: Requesting all messages. - try messageTracker.getNextMessages(byLimit: 100) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Next 10 messages should be received and history request for more should be performed. - XCTAssertEqual(completionHandlerMessages!, history1) - XCTAssertEqual((messageHolder.getRemoteHistoryProvider() as! RemoteHistoryProviderForTests).numberOfCalls, 1) - - // MARK: Test 3 - // When: Requesting more messages. - try messageTracker.getNextMessages(byLimit: 100) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: No messages should be received and no history requests should be performed. - XCTAssertEqual(completionHandlerMessages!, [MessageImpl]()) - XCTAssertEqual((messageHolder.getRemoteHistoryProvider() as! RemoteHistoryProviderForTests).numberOfCalls, 1) - - // MARK: Test 4 - // When: Resetting 15 messages back and requesting for all messages. - try messageTracker.resetTo(message: history2[5]) - try messageTracker.getNextMessages(byLimit: 100) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: 15 messages should be received and no history requests should be preformed. - XCTAssertEqual(completionHandlerMessages!, (history1 + Array(history2[0 ... 4]))) - XCTAssertEqual((messageHolder.getRemoteHistoryProvider() as! RemoteHistoryProviderForTests).numberOfCalls, 1) - } - - func testInsertMessagesBetweenOlderHistoryAndCurrentChat() throws { - // MARK: Model set up - let history1 = generateHistory(ofCount: 10) - let history2 = generateHistory(ofCount: 2) - let currentChat = generateCurrentChat(ofCount: 10) - let messageHolder = newMessageHolder(withHistory: (history1 + history2)) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - messageHolder.receiveHistoryUpdateWith(messages: history1, - deleted: Set()) { - // No need to do anything when testing. - } - messageHolder.receiving(newChat: ChatItem(), - previousChat: nil, - newMessages: currentChat) - - // MARK: Test 1 - // When: Requesting 10 messages (which are of current chat). - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on this 10 messages. - XCTAssertEqual(completionHandlerMessages!, currentChat) - - // MARK: Test 2 - // When: Requesting 10 messages (which are history). - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on this 10 messages. - XCTAssertEqual(completionHandlerMessages!, history1) - - // MARK: Test 3 - // When: Receiving history between current chat and receiver older history. - messageHolder.receiveHistoryUpdateWith(messages: history2, - deleted: Set()) { - // No need to do anything when testing. - } - // Then: First history message should be inserted before first current chat message. - XCTAssertEqual(lastAddedMessage, history2[1]) - XCTAssertEqual(lastMessageBeforeAdded, currentChat.last!) - } - - func testReceiveHistoryPartOfCurrentChat() throws { - // MARK: Model set up - let history1 = generateHistory(ofCount: 10) - let currentChat = generateCurrentChat(ofCount: 10) - let history2 = generateHistoryFrom(currentChat: currentChat) - let messageHolder = newMessageHolder(withHistory: (history1 + history2)) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - messageHolder.receiveHistoryUpdateWith(messages: history1, - deleted: Set()) { - // No need to do anything when testing. - } - messageHolder.receiving(newChat: ChatItem(), - previousChat: nil, - newMessages: currentChat) - - // MARK: Test 1 - // When: Requesting current chat. - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Receiving current chat completion should be called. - XCTAssertEqual(completionHandlerMessages!, currentChat) - - // MARK: Test 2 - // When: Requesting history part. - var numberOfCalls = 0 - try messageTracker.getNextMessages(byLimit: 5) { messages in - numberOfCalls = numberOfCalls + 1 - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Receiving history completion handler should be called. - XCTAssertEqual(numberOfCalls, 1) - XCTAssertEqual(completionHandlerMessages!, Array(history1[5 ... 9])) - - // MARK: Test 3 - // When: Receiving history part of current chat. - messageHolder.receiveHistoryUpdateWith(messages: Array(history2[0 ..< 5]), - deleted: Set()) { - // No need to do anything when testing. - } - // Then: No completion handlers should be called. - XCTAssertEqual(numberOfCalls, 1) - - // MARK: Test 4 - // When: Requesting remaining history. - try messageTracker.getNextMessages(byLimit: 5) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Receiving remaining history completion handler should be called. - XCTAssertEqual(completionHandlerMessages!, Array(history1[0 ... 4])) - } - - func testReceiveFullHistoryOfCurrentChat() throws { - // MARK: Model set up - let history1 = generateHistory(ofCount: 10) - let currentChat = generateCurrentChat(ofCount: 10) - let history2 = generateHistoryFrom(currentChat: currentChat) - let messageHolder = newMessageHolder(withHistory: (history1 + history2)) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - messageHolder.receiveHistoryUpdateWith(messages: history1, - deleted: Set()) { - // No need to do anything when testing. - } - messageHolder.receiving(newChat: ChatItem(), - previousChat: nil, - newMessages: currentChat) - - // MARK: Test 1 - // When: Requesting next 10 messages. - var numberOfCalls = 0 - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - numberOfCalls = numberOfCalls + 1 - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Receiving current chat completion handler should be called. - XCTAssertEqual(numberOfCalls, 1) - XCTAssertEqual(completionHandlerMessages!, currentChat) - - // MARK: Test 2 - // When: Receiving history part of current chat. - messageHolder.receiveHistoryUpdateWith(messages: Array(history2[0 ... 5]), - deleted: Set()) { - // No need to do anything when testing. - } - // Then: Completion handler should not be called and receiving method too. - XCTAssertEqual(numberOfCalls, 1) - XCTAssertNil(lastAddedMessage) - XCTAssertNil(lastMessageBeforeAdded) - - // MARK: Test 3 - // When: Requesting for more messages. - try messageTracker.getNextMessages(byLimit: 10) { messages in - numberOfCalls = numberOfCalls + 1 - } - // Then: History part before current chat completion handler should be called. - XCTAssertEqual(numberOfCalls, 2) - } - - func testReceiveLastHistoryPartOfCurrentChat() throws { - // MARK: Model set up - let history1 = generateHistory(ofCount: 10) - let currentChat = generateCurrentChat(ofCount: 10) - let history2 = generateHistoryFrom(currentChat: currentChat) - let messageHolder = newMessageHolder(withHistory: (history1 + history2)) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - messageHolder.receiveHistoryUpdateWith(messages: Array(history2[5 ... 9]), - deleted: Set()) { - // No need to do anything when testing. - } - messageHolder.receiving(newChat: ChatItem(), - previousChat: nil, - newMessages: currentChat) - - // MARK: Test 1 - // When: Requesting 10 messages. - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Current chat receiving completion handler should be called. - XCTAssertEqual(completionHandlerMessages!, currentChat) - - // MARK: Test 2 - // When: Requesting next 10 messages. - let expectationToBeCalled2 = XCTestExpectation() - try messageTracker.getNextMessages(byLimit: 10) { _ in - expectationToBeCalled2.fulfill() - } - // Then: History part before current chat receiving completion handler should be called. - wait(for: [expectationToBeCalled2], - timeout: 1.0) - - // MARK: Test 3 - // When: Resetting current chat and requesting next messages. - messageTracker.set(messagesLoading: false) - try messageTracker.resetTo(message: currentChat[9]) - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handlers should be called on next 9 current chat messages. - XCTAssertEqual(completionHandlerMessages!, Array(currentChat[0 ... 8])) - - // MARK: Test 4 - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handlers should be called first on received history messages. - XCTAssertEqual(completionHandlerMessages!, history1) - } - - func testRequestAsManyMessagesAsReceivedWithHistoryForCurrentChat() throws { - // MARK: Model set up - let history1 = generateHistory(ofCount: 10) - let currentChat = generateCurrentChat(ofCount: 10) - let history2 = generateHistoryFrom(currentChat: currentChat) - let messageHolder = newMessageHolder(withHistory: (history1 + history2)) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - messageHolder.receiveHistoryUpdateWith(messages: history1, - deleted: Set()) { - // No need to do anything when testing. - } - messageHolder.receiving(newChat: ChatItem(), - previousChat: nil, - newMessages: Array(currentChat[0 ... 5])) - - // MARK: Test 1 - // When: Requesting 10 messages. - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: First 5 messages of current chat receiving completion should be called. - XCTAssertEqual(completionHandlerMessages!, Array(currentChat[0 ... 5])) - - // MARK: Test 2 - // When: Received 5 messaged of history (which is part of current chat). - messageHolder.receiveHistoryUpdateWith(messages: Array(history2[0 ... 5]), - deleted: Set()) { - // No need to do anything when testing. - } - // Then: Receiving method should not be called. - XCTAssertNil(lastAddedMessage) - XCTAssertNil(lastMessageBeforeAdded) - - // MARK: Test 3 - // When: Receiving history which is not a part of current chat. - messageHolder.receiveHistoryUpdateWith(messages: [history2[6]], - deleted: Set()) { - // No need to do anything when testing. - } - // Then: Receiving method should not be called. - XCTAssertNil(lastAddedMessage) - XCTAssertNil(lastMessageBeforeAdded) - - // MARK: Test 4 - // When: Receiving current chat message (which is part of history). - messageHolder.receive(newMessage: currentChat[6]) - // Then: Message should be inserted in the end. - XCTAssertEqual(lastAddedMessage, currentChat[6]) - XCTAssertNil(lastMessageBeforeAdded) - - // MARK: Test 5 - // When: Requesting more messages. - let expectationToBeCalled = XCTestExpectation() - try messageTracker.getNextMessages(byLimit: 5) { messages in - expectationToBeCalled.fulfill() - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on history part before current chat. - wait(for: [expectationToBeCalled], - timeout: 1.0) - } - - func testReceiveCurrentChatWhenHistoryFullyTracked() throws { - // MARK: Model set up - let history1 = generateHistory(ofCount: 10) - let currentChat = generateCurrentChat(ofCount: 10) - let history2 = generateHistoryFrom(currentChat: currentChat) - let messageHolder = newMessageHolder(withHistory: (history1 + history2)) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - messageHolder.receiveHistoryUpdateWith(messages: (history1 + history2), - deleted: Set()) { - // No need to do anything when testing. - } - - // MARK: Test 1 - // When: Requesting 10 messages. - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Receiving completion handler should be called on history part of current chat. - XCTAssertEqual(completionHandlerMessages!, history2) - - // MARK: Test 2 - // When: Receiving chat of 7/10 messages. - messageHolder.receiving(newChat: ChatItem(), - previousChat: nil, - newMessages: Array(currentChat[0 ..< 8])) - // Then: Receiving method should not be called. - XCTAssertNil(lastAddedMessage) - XCTAssertNil(lastMessageBeforeAdded) - - // MARK: Test 3 - // When: Receiving next current chat message. - messageHolder.receive(newMessage: currentChat[9]) - // Then: Receiving method should not be called. - XCTAssertNil(lastAddedMessage) - XCTAssertNil(lastMessageBeforeAdded) - - // MARK: Test 4 - // When: Requesting more messages. - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on the older history. - XCTAssertEqual(completionHandlerMessages!, history1) - } - - func testReceiveLocalHistoryRemoteHistoryCurrentChat() throws { - // MARK: Model set up - let history1 = generateHistory(ofCount: 10) - let currentChat = generateCurrentChat(ofCount: 10) - let history2 = generateHistoryFrom(currentChat: currentChat) - let messageHolder = newMessageHolder(withHistory: (history1 + history2), - localHistory: (history1 + Array(history2[0 ... 7]))) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - - // MARK: Test 1 - // When: Requesting next 8 messages. - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 8) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on 8 history messages of current chat. - XCTAssertEqual(completionHandlerMessages!, Array(history2[0 ... 7])) - - // MARK: Test 2 - // When: Receiving history and 1 message of current chat history. - messageHolder.receiveHistoryUpdateWith(messages: (history1 + [history2[8]]), - deleted: Set()) { - // No need to do anything when testing. - } - // Then: Receiving method should be called on that message. - XCTAssertEqual(lastAddedMessage, history2[8]) - XCTAssertNil(lastMessageBeforeAdded) - - // MARK: Test 3 - // When: Receiving current chat. - messageHolder.receiving(newChat: ChatItem(), - previousChat: nil, - newMessages: currentChat) - // Then: Current chat messages should be added in the end. - XCTAssertEqual(lastAddedMessage, currentChat[9]) - XCTAssertNil(lastMessageBeforeAdded) - - // MARK: Test 4 - // When: Requesting more messages. - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion should be called on the older history. - XCTAssertEqual(completionHandlerMessages!, history1) - } - - func testReceiveCurrentChatWhenHistoryLastPartTracked() throws { - // MARK: Model set up - let currentChat = generateCurrentChat(ofCount: 10) - let history = generateHistoryFrom(currentChat: currentChat) - let messageHolder = newMessageHolder(withHistory: history) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - messageHolder.receiveHistoryUpdateWith(messages: Array(history[1 ... 9]), - deleted: Set()) { - // No need to do anything when testing. - } - - // MARK: Test 1 - // When: Requesting messages. - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion should be called on received history. - XCTAssertEqual(completionHandlerMessages!, Array(history[1 ... 9])) - - // MARK: Test 2 - // When: Receiving chat. - messageHolder.receiving(newChat: ChatItem(), - previousChat: nil, - newMessages: currentChat) - // Then: Receiving method should not be called. - XCTAssertNil(lastAddedMessage) - XCTAssertNil(lastMessageBeforeAdded) - - // MARK: Test 3 - // When: Requesting more messages. - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on last history part message. - XCTAssertEqual(completionHandlerMessages!, [currentChat[0]]) - } - - func testMergeChat() throws { - // MARK: Model set up - let messageHolder = newMessageHolder() - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - let chat = ChatItem() - let messages = generateCurrentChat(ofCount: 10) - - // MARK: Test 1 - // When: Requesting some messages - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should not be called because there's no messages received. - XCTAssertNil(completionHandlerMessages) - - // MARK: Test 2 - // When: Receiving chat with 2 messages. - messageHolder.receiving(newChat: nil, - previousChat: chat, - newMessages: Array(messages[0 ... 1])) - // Then: Completion should be called on this messages. Receiving method should not be called. - XCTAssertEqual(completionHandlerMessages!, Array(messages[0 ... 1])) - XCTAssertNil(lastAddedMessage) - XCTAssertNil(lastMessageBeforeAdded) - - // MARK: Test 3 - // When: Receiving chat with the same messages. - messageHolder.receiving(newChat: chat, - previousChat: chat, - newMessages: Array(messages[0 ... 1])) - // Then: Receiving method should not be called. - XCTAssertNil(lastAddedMessage) - XCTAssertNil(lastMessageBeforeAdded) - - // MARK: Test 4 - // When: Receiving chat with more messages. - messageHolder.receiving(newChat: chat, - previousChat: chat, - newMessages: Array(messages[0 ... 3])) - // Then: New message should be inserted in the end. Changing or removing messages methods should not be called. - XCTAssertEqual(lastAddedMessage, messages[3]) - XCTAssertNil(lastMessageBeforeAdded) - XCTAssertNil(lastRemovedMessage) - XCTAssertNil(lastOldVersionChangedMessage) - XCTAssertNil(lastNewVersionChangedMessage) - - // MARK: Test 5 - // When: Receiving some non-running messages. - messageHolder.receiving(newChat: chat, - previousChat: chat, - newMessages: (Array(messages[0 ... 1]) + Array(messages[3 ... 4]))) - // Then: Message out of range should be removed, new messages should be added in the end. - XCTAssertEqual(lastRemovedMessage, messages[2]) - XCTAssertEqual(lastAddedMessage, messages[4]) - XCTAssertNil(lastMessageBeforeAdded) - } - - func testReplaceCurrentChat() throws { - // MARK: Model set up - let messageHolder = newMessageHolder() - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - let firstChat = ChatItem(id: "1") - let secondChat = ChatItem(id: "2") - let messages = generateCurrentChat(ofCount: 10) - - // MARK: Test 1 - // When: Requesting some messages. - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion shouldn't be called. It was cached and will be called after messages are received. - XCTAssertNil(completionHandlerMessages) - - // MARK: Test 2 - // When: Receiving first chat with 2 messages. - messageHolder.receiving(newChat: firstChat, - previousChat: nil, - newMessages: Array(messages[0 ... 1])) - // Then: Completion handler should be called. Receiving method should not. - XCTAssertEqual(completionHandlerMessages!, Array(messages[0 ... 1])) - XCTAssertNil(lastAddedMessage) - XCTAssertNil(lastMessageBeforeAdded) - - // MARK: Test 3 - // When: Receiving second chat with 3 messages. - messageHolder.receiving(newChat: secondChat, - previousChat: firstChat, - newMessages: Array(messages[2 ... 4])) - // Then: This messages should be added. - XCTAssertEqual(lastAddedMessage, messages[4]) - XCTAssertNil(lastMessageBeforeAdded) - - // MARK: Test 4 - // When: Resetting to last message, requesting messages. - try messageTracker.resetTo(message: messages[4]) - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on messages [0 ... 3]. - XCTAssertEqual(completionHandlerMessages!, Array(messages[0 ... 3])) - - // MARK: Test 5 - // When: Receiving second chat with non-running messages. - messageHolder.receiving(newChat: secondChat, - previousChat: secondChat, - newMessages: ([messages[2]] + Array(messages[4 ... 5]))) - // Then: One message should be deleted. One message should be added. - XCTAssertEqual(lastRemovedMessage, messages[3]) - XCTAssertEqual(lastAddedMessage, messages[5]) - - // MARK: Test 6 - // When: Resetting to the last messages and requesting messages. - try messageTracker.resetTo(message: messages[5]) - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on messages except the last one. - XCTAssertEqual(completionHandlerMessages!, (Array(messages[0 ... 2]) + [messages[4]])) - } - - func testReplaceCurrentChatWhenPreviousHistoryReceived() throws { - // MARK: Model set up - let history1 = generateHistory(ofCount: 10) - let messages = generateCurrentChat(ofCount: 10) - let history2 = generateHistoryFrom(currentChat: messages) - let messageHolder = newMessageHolder(withHistory: (history1 + history2)) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - let firstChat = ChatItem(id: "1") - let secondChat = ChatItem(id: "2") - - // MARK: Test 1 - // When: Requesting messages. - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion shouldn't be called. It was cached and will be called after messages are received. - XCTAssertNil(completionHandlerMessages) - - // MARK: Test 2 - // When: Receiving first chat with 2 messages. - messageHolder.receiving(newChat: firstChat, - previousChat: nil, - newMessages: Array(messages[0 ... 1])) - // Then: Completion handler should be called on this messages. Message listener methods should not be called. - XCTAssertEqual(completionHandlerMessages!, Array(messages[0 ... 1])) - XCTAssertNil(lastAddedMessage) - XCTAssertNil(lastMessageBeforeAdded) - XCTAssertNil(lastRemovedMessage) - XCTAssertNil(lastOldVersionChangedMessage) - XCTAssertNil(lastNewVersionChangedMessage) - - // MARK: Test 3 - // When: Receiving history part of current chat. - messageHolder.receiveHistoryUpdateWith(messages: Array(history2[0 ... 1]), - deleted: Set()) { - // No need to do anything when testing. - } - // Then: Message listener methods should not be called. - XCTAssertNil(lastAddedMessage) - XCTAssertNil(lastMessageBeforeAdded) - XCTAssertNil(lastRemovedMessage) - XCTAssertNil(lastOldVersionChangedMessage) - XCTAssertNil(lastNewVersionChangedMessage) - - // MARK: Test 4 - // When: Requesting all messages. - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on full history. - XCTAssertEqual(completionHandlerMessages!, history1) - - // MARK: Test 5 - // When: Receiving second chat with next 3 messages. - messageHolder.receiving(newChat: secondChat, - previousChat: firstChat, - newMessages: Array(messages[2 ... 4])) - // Then: Receiving method should be called on all this messages. All current chat messages should be historified. - XCTAssertEqual(lastAddedMessage, messages[4]) - XCTAssertNil(lastMessageBeforeAdded) - XCTAssertEqual(messageHolder.getLastChatMessageIndex(), 0) - - // MARK: Test 6 - // When: Resetting to the last message. Requesting latest messages. - try messageTracker.resetTo(message: messages[4]) - try messageTracker.getNextMessages(byLimit: 20) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on previous two messages. - XCTAssertEqual(completionHandlerMessages!, Array(messages[2 ... 3])) - - // MARK: Test 7 - // When: Requesting all messages. - try messageTracker.getNextMessages(byLimit: 20) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion should be called on full history. - XCTAssertEqual(completionHandlerMessages!, (history1 + Array(history2[0 ... 1]))) - - // MARK: Test 8 - // When: Receiving second chat with one message deleted and one added. - messageHolder.receiving(newChat: secondChat, - previousChat: secondChat, - newMessages: ([messages[2]] + Array(messages[4 ... 5]))) - // Then: One message deleted. One message added. - XCTAssertEqual(lastRemovedMessage, messages[3]) - XCTAssertEqual(lastAddedMessage, messages[5]) - XCTAssertNil(lastMessageBeforeAdded) - - // MARK: Test 9 - // When: Resetting to last message. Requesting more messages. - try messageTracker.resetTo(message: messages[5]) - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion should be called on missing messages. - XCTAssertEqual(completionHandlerMessages!, ([messages[2], messages[4]])) - } - - func testReplaceCurrentChatWhenPreviousHistoryStoredLocally() throws { - // MARK: Model set up - let history1 = generateHistory(ofCount: 10) - let messages = generateCurrentChat(ofCount: 10) - let history2 = generateHistoryFrom(currentChat: messages) - let messageHolder = newMessageHolder(withHistory: (history1 + history2), - localHistory: Array(history2[0 ... 1])) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - let firstChat = ChatItem(id: "1") - let secondChat = ChatItem(id: "2") - - // MARK: Test 1 - // When: Requesting messages. - var numberOfCalls = 0 - var completionHandlerMessages: [MessageImpl]? - try messageTracker.getNextMessages(byLimit: 10) { messages in - numberOfCalls = numberOfCalls + 1 - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on stored locally history. - XCTAssertEqual(completionHandlerMessages!, Array(history2[0 ... 1])) - - // MARK: Test 2 - // When: Receiving first chat with 2 messages. - messageHolder.receiving(newChat: firstChat, - previousChat: nil, - newMessages: Array(messages[0 ... 1])) - // Then: Completion handler should not be called. Message listener methods should not be called. - XCTAssertEqual(numberOfCalls, 1) - XCTAssertNil(lastAddedMessage) - XCTAssertNil(lastMessageBeforeAdded) - XCTAssertNil(lastRemovedMessage) - XCTAssertNil(lastOldVersionChangedMessage) - XCTAssertNil(lastNewVersionChangedMessage) - - // MARK: Test 3 - // When: Requesting all messages. - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on full history. - XCTAssertEqual(completionHandlerMessages!, history1) - - // MARK: Test 4 - // When: Receiving second chat with next 3 messages. All current chat messages should be historified. - messageHolder.receiving(newChat: secondChat, - previousChat: firstChat, - newMessages: Array(messages[2 ... 4])) - // Then: This messages should be added. - XCTAssertEqual(lastAddedMessage, messages[4]) - XCTAssertNil(lastMessageBeforeAdded) - XCTAssertEqual(messageHolder.getLastChatMessageIndex(), 0) - - // MARK: Test 5 - // When: Resetting to the last message. Requesting latest messages. - try messageTracker.resetTo(message: messages[4]) - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on missing messages. - XCTAssertEqual(completionHandlerMessages!, Array(messages[2 ... 3])) - - // MARK: Test 6 - // When: Requesting all messages. - try messageTracker.getNextMessages(byLimit: 20) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on full history. - XCTAssertEqual(completionHandlerMessages!, (history1 + Array(history2[0 ... 1]))) - - // MARK: Test 7 - // When: Receiving second chat again with one message deleted and one added. - messageHolder.receiving(newChat: secondChat, - previousChat: secondChat, - newMessages: ([messages[2]] + Array(messages[4 ... 5]))) - // Then: One message deleted. One message added. - XCTAssertEqual(lastRemovedMessage, messages[3]) - XCTAssertEqual(lastAddedMessage, messages[5]) - XCTAssertNil(lastMessageBeforeAdded) - - // MARK: Test 8 - // When: Resetting to the last messages. Requesting missing messages. - try messageTracker.resetTo(message: messages[5]) - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on missing messages. - XCTAssertEqual(completionHandlerMessages!, ([messages[2], messages[4]])) - } - - func testResetMixedCurrentChatAndHistory() throws { - // MARK: Model set up - let history1 = generateHistory(ofCount: 10) - let history2 = generateHistory(ofCount: 10) - let currentChat = generateCurrentChat(ofCount: 10) - let nextCurrentChat = newCurrentChat() - let messageHolder = newMessageHolder(withHistory: (history1 + history2)) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - messageHolder.receiveHistoryUpdateWith(messages: history2, - deleted: Set()) { - // No need to do anything when testing. - } - messageHolder.receiving(newChat: ChatItem(), - previousChat: nil, - newMessages: currentChat) - - // MARK: Test 1 - // When: Requesting next 10 messages. - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on current chat. - XCTAssertEqual(completionHandlerMessages!, currentChat) - - // MARK: Test 2 - // When: Requesting next 10 messages. - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on history2. - XCTAssertEqual(completionHandlerMessages!, history2) - - // MARK: Test 3 - // When: Requesting next 10 messages. - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on history1. - XCTAssertEqual(completionHandlerMessages!, history1) - - // MARK: Test 4 - // When: Receiving next current chat message. - messageHolder.receive(newMessage: nextCurrentChat) - // Then: This message should be added in the end. - XCTAssertEqual(lastAddedMessage, nextCurrentChat) - XCTAssertNil(lastMessageBeforeAdded) - - // MARK: Test 5 - // When: Resetting to the last message. Requesting next 10 messages - try messageTracker.resetTo(message: nextCurrentChat) - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on current chat. - XCTAssertEqual(completionHandlerMessages!, currentChat) - - // MARK: Test 6 - // When: Requesting next 10 messages. - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on history2. - XCTAssertEqual(completionHandlerMessages!, history2) - - // MARK: Test 7 - // When: Requesting next 10 messages. - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on history1. - XCTAssertEqual(completionHandlerMessages!, history1) - } - - func testReceiveNewMessageWhenHistoryIsEmpty() throws { - // MARK: Model set up - let nextCurrentChat = newCurrentChat() - let messageHolder = newMessageHolder() - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - messageHolder.receiveHistoryUpdateWith(messages: [MessageImpl](), - deleted: Set()) { - // No need to do anything when testing. - } - messageHolder.set(endOfHistoryReached: true) - - // MARK: Test 1 - // When: Requesting next messages. - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on empty history. - XCTAssertEqual(completionHandlerMessages!, [MessageImpl]()) - - // MARK: Test 2 - // When: Receiving next current chat message. - messageHolder.receive(newMessage: nextCurrentChat) - // Then: This message should be added in the end. - XCTAssertEqual(lastAddedMessage, nextCurrentChat) - XCTAssertNil(lastMessageBeforeAdded) - } - - func testEditCurrentChatMessage() throws { - // MARK: Model set up - let nextCurrentChat = newCurrentChat() - let editedCurrentChat = newEdited(currentChatMessage: nextCurrentChat) - let messageHolder = newMessageHolder() - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - messageHolder.receiveHistoryUpdateWith(messages: [MessageImpl](), - deleted: Set()) { - // No need to do anything when testing. - } - messageHolder.set(reachedEndOfLocalHistory: true) - - // MARK: Test 1 - // When: Requesting next messages. - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on empty history. - XCTAssertEqual(completionHandlerMessages!, [MessageImpl]()) - - // MARK: Test 2 - // When: Receiving next current chat message. - messageHolder.receive(newMessage: nextCurrentChat) - // Then: This message should be added in the end. - XCTAssertEqual(lastAddedMessage, nextCurrentChat) - XCTAssertNil(lastMessageBeforeAdded) - - // MARK: Test 3 - // When: Changing message. - messageHolder.changed(message: editedCurrentChat) - // Then: Changing message listener method should be called on this message. - XCTAssertEqual(lastOldVersionChangedMessage, nextCurrentChat) - XCTAssertEqual(lastNewVersionChangedMessage, editedCurrentChat) - } - - func testEditCurrentChatMessageReceivedWithFullUpdate() throws { - // MARK: Model set up - var currentChat = generateCurrentChat(ofCount: 10) - let editedCurrentChat = currentChat - currentChat[9] = newEdited(currentChatMessage: currentChat[9]) - let messageHolder = newMessageHolder() - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - let chat = ChatItem() - messageHolder.receiveHistoryUpdateWith(messages: [MessageImpl](), - deleted: Set()) { - // No need to do anything when testing. - } - messageHolder.set(endOfHistoryReached: true) - messageHolder.receiving(newChat: chat, - previousChat: nil, - newMessages: currentChat) - - // MARK: Test 1 - // When: Requesting next messages. - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on current chat. - XCTAssertEqual(completionHandlerMessages!, currentChat) - - // MARK: Test 2 - // When: Receiving new messages (one is different). - messageHolder.receiving(newChat: chat, - previousChat: chat, - newMessages: editedCurrentChat) - // Then: That message should be changed. Other message listener methods should not be called. - XCTAssertNil(lastAddedMessage) - XCTAssertNil(lastMessageBeforeAdded) - XCTAssertNil(lastRemovedMessage) - XCTAssertEqual(lastOldVersionChangedMessage, currentChat[9]) - XCTAssertEqual(lastNewVersionChangedMessage, editedCurrentChat[9]) - } - - func testEditHistoryMessage() throws { - // MARK: Model set up - let history = generateHistory(ofCount: 10) - let editedHistoryMessage = newEdited(historyMessage: history[9]) - let messageHolder = newMessageHolder(withHistory: history) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - messageHolder.receiveHistoryUpdateWith(messages: history, - deleted: Set()) { - // No need to do anything when testing. - } - - // MARK: Test 1 - // When: Requesting next messages. - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on history. - XCTAssertEqual(completionHandlerMessages!, history) - - // MARK: Test 2 - // When: Receiving changed history message. - messageHolder.receiveHistoryUpdateWith(messages: [editedHistoryMessage], - deleted: Set()) { - // No need to do anything when testing. - } - // Then: This message should be changed. - XCTAssertEqual(lastOldVersionChangedMessage, history[9]) - XCTAssertEqual(lastNewVersionChangedMessage, editedHistoryMessage) - } - - func testReplaceHistoryMessageWithEditedCurrentChatMessage() throws { - // MARK: Model set up - var currentChat = generateCurrentChat(ofCount: 10) - let history = generateHistoryFrom(currentChat: currentChat) - currentChat[9] = newEdited(currentChatMessage: currentChat[9]) - let messageHolder = newMessageHolder(withHistory: history) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - messageHolder.receiveHistoryUpdateWith(messages: history, - deleted: Set()) { - // No need to do anything when testing. - } - - // MARK: Test 1 - // When: Requesting next messages. - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on history. - XCTAssertEqual(completionHandlerMessages!, history) - - // MARK: Test 2 - // When: Receiving current chat with one changed message. - messageHolder.receiving(newChat: ChatItem(), - previousChat: nil, - newMessages: currentChat) - // Then: This message should be changed. - XCTAssertEqual(lastOldVersionChangedMessage, history[9]) - XCTAssertEqual(lastNewVersionChangedMessage, currentChat[9]) - } - - func testReplaceCurrentChatMessageWithEditedHistoryMessageInClosedChat() throws { - // MARK: Model set up - let currentChat = generateCurrentChat(ofCount: 10) - let history = generateHistoryFrom(currentChat: currentChat) - let editedHistoryMessage = newEdited(historyMessage: history[9]) - let messageHolder = newMessageHolder(withHistory: history) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - let chat = ChatItem() - messageHolder.receiving(newChat: chat, - previousChat: nil, - newMessages: currentChat) - - // MARK: Test 1 - // When: Requesting next messages. - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on current chat. - XCTAssertEqual(completionHandlerMessages!, currentChat) - - // MARK: Test 2 - // When: Receiving chat without messages and history messages. - messageHolder.receiving(newChat: nil, - previousChat: chat, - newMessages: [MessageImpl]()) - messageHolder.receiveHistoryUpdateWith(messages: history, - deleted: Set()) { - // No need to do anything when testing. - } - // Then: Message listener methods should not be called. - XCTAssertNil(lastAddedMessage) - XCTAssertNil(lastMessageBeforeAdded) - XCTAssertNil(lastRemovedMessage) - XCTAssertNil(lastOldVersionChangedMessage) - XCTAssertNil(lastNewVersionChangedMessage) - - // MARK: Test 3 - // When: Receiving changed history message. - messageHolder.receiveHistoryUpdateWith(messages: [editedHistoryMessage], - deleted: Set()) { - // No need to do anything when testing. - } - // Then: This message should be changed. - XCTAssertEqual(lastOldVersionChangedMessage, currentChat[9]) - XCTAssertEqual(lastNewVersionChangedMessage, editedHistoryMessage) - } - - func testReplaceCurrentChatMessageWithEditedHistoryMessageInOpenChat() throws { - // MARK: Model set up - let currentChat = generateCurrentChat(ofCount: 10) - let history = generateHistoryFrom(currentChat: currentChat) - let editedHistoryMessage = newEdited(historyMessage: history[9]) - let messageHolder = newMessageHolder(withHistory: history) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - messageHolder.receiving(newChat: ChatItem(), - previousChat: nil, - newMessages: currentChat) - - // MARK: Test 1 - // When: Requesting messages. - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on current chat. - XCTAssertEqual(completionHandlerMessages!, currentChat) - - // MARK: Test 2 - // When: Receiving history. - messageHolder.receiveHistoryUpdateWith(messages: history, - deleted: Set()) { - // No need to do anything when testing. - } - // Then: Message listener methods should not be called. - XCTAssertNil(lastAddedMessage) - XCTAssertNil(lastMessageBeforeAdded) - XCTAssertNil(lastRemovedMessage) - XCTAssertNil(lastOldVersionChangedMessage) - XCTAssertNil(lastNewVersionChangedMessage) - - // MARK: Test 3 - // When: Receiving edited history message. - messageHolder.receiveHistoryUpdateWith(messages: [editedHistoryMessage], - deleted: Set()) { - // No need to do anything when testing. - } - // Then: While current chat exists changes in history should not have an effect.. - XCTAssertNil(lastAddedMessage) - XCTAssertNil(lastMessageBeforeAdded) - XCTAssertNil(lastRemovedMessage) - XCTAssertNil(lastOldVersionChangedMessage) - XCTAssertNil(lastNewVersionChangedMessage) - } - - func testReceiveEditedHistoryInClosedChat() throws { - // MARK: Model set up - let currentChat = generateCurrentChat(ofCount: 10) - var history = generateHistoryFrom(currentChat: currentChat) - history[9] = newEdited(historyMessage: history[9]) - let messageHolder = newMessageHolder(withHistory: history) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - let chat = ChatItem() - messageHolder.receiving(newChat: chat, - previousChat: nil, - newMessages: currentChat) - - // MARK: Test 1 - // When: Requesting messages. - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on current chat. - XCTAssertEqual(completionHandlerMessages!, currentChat) - - // MARK: Test 2 - // When: Receiving empty chat. - messageHolder.receiving(newChat: nil, - previousChat: chat, - newMessages: [MessageImpl]()) - // Then: Message listener methods should not be called. - XCTAssertNil(lastAddedMessage) - XCTAssertNil(lastMessageBeforeAdded) - XCTAssertNil(lastRemovedMessage) - XCTAssertNil(lastOldVersionChangedMessage) - XCTAssertNil(lastNewVersionChangedMessage) - - // MARK: Test 3 - // When: Receiving history. - messageHolder.receiveHistoryUpdateWith(messages: history, - deleted: Set()) { - // No need to do anything when testing. - } - // Then: Edited message should be changed. - XCTAssertEqual(lastOldVersionChangedMessage, currentChat[9]) - XCTAssertEqual(lastNewVersionChangedMessage, history[9]) - } - - func testReceiveEditedHistoryAndCloseChat() throws { - // MARK: Set up - let currentChat = generateCurrentChat(ofCount: 10) - var history = generateHistoryFrom(currentChat: currentChat) - history[9] = newEdited(historyMessage: history[9]) - let messageHolder = newMessageHolder(withHistory: history) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - let chat = ChatItem() - messageHolder.receiving(newChat: chat, - previousChat: nil, - newMessages: currentChat) - - // MARK: Test 1 - // When: Requesting messages. - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on current chat. - XCTAssertEqual(completionHandlerMessages!, currentChat) - - // MARK: Test 2 - // When: receiving history. - messageHolder.receiveHistoryUpdateWith(messages: history, - deleted: Set()) { - // No need to do anything when testing. - } - // Then: Message listener methods should not be called. - XCTAssertNil(lastAddedMessage) - XCTAssertNil(lastMessageBeforeAdded) - XCTAssertNil(lastRemovedMessage) - XCTAssertNil(lastOldVersionChangedMessage) - XCTAssertNil(lastNewVersionChangedMessage) - - // MARK: Test 3 - // When: Receiving empty chat. - messageHolder.receiving(newChat: nil, - previousChat: chat, - newMessages: [MessageImpl]()) - // Then: Edited message should be changed. - XCTAssertEqual(lastOldVersionChangedMessage, currentChat[9]) - XCTAssertEqual(lastNewVersionChangedMessage, history[9]) - } - - func testReceiveCurrentChatWhenItHoldedAsHistory() throws { - // MARK: Model set up - let currentChat = generateCurrentChat(ofCount: 10) - let history = generateHistoryFrom(currentChat: currentChat) - let messageHolder = newMessageHolder(withHistory: history) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - messageHolder.receiveHistoryUpdateWith(messages: history, - deleted: Set()) { - // No need to do anything when testing. - } - - // MARK: Test 1 - // When: Requesting messages. - var completionHandlerMessages: [MessageImpl]? = nil - var numberOfCalls = 0 - try messageTracker.getNextMessages(byLimit: 10) { messages in - completionHandlerMessages = messages as? [MessageImpl] - numberOfCalls = numberOfCalls + 1 - } - // Then: Completion handler should be called on history. - XCTAssertEqual(completionHandlerMessages!, history) - XCTAssertEqual(numberOfCalls, 1) - - // MARK: Test 2 - // When: Received current chat message twice which is holded as local history. - messageHolder.receive(newMessage: currentChat[9]) - messageHolder.receive(newMessage: currentChat[9]) - // Then: Message shouldn't be received as new. - XCTAssertEqual(numberOfCalls, 1) - } - - func testReplacingHistoryWithCurrentChat() throws { - // MARK: Model set up - let currentChat = generateCurrentChat(ofCount: 1) - let history = generateHistoryFrom(currentChat: currentChat) - let messageHolder = newMessageHolder(withHistory: history) - let messageTracker = try messageHolder.newMessageTracker(withMessageListener: self) - let chat = ChatItem() - messageHolder.receiveHistoryUpdateWith(messages: history, - deleted: Set()) { - // No need to do anything when testing. - } - - // MARK: Test 1 - // When: Requesting messages. - var completionHandlerMessages: [MessageImpl]? = nil - try messageTracker.getNextMessages(byLimit: 1) { messages in - completionHandlerMessages = messages as? [MessageImpl] - } - // Then: Completion handler should be called on history. - XCTAssertEqual(completionHandlerMessages!, history) - - // MARK: Test 2 - // When: Receiving chat with history. - messageHolder.receiving(newChat: nil, - previousChat: chat, - newMessages: currentChat) - // Then: No messages should be changed. - XCTAssertNil(lastOldVersionChangedMessage) - XCTAssertNil(lastNewVersionChangedMessage) - - // MARK: Test 3 - // When: Deleting current chat message. - messageHolder.deletedMessageWith(id: currentChat[0].getCurrentChatID()!) - // Then: Message should be deleted. - XCTAssertEqual(lastRemovedMessage, currentChat[0]) - - // MARK: Test 4 - // When: Receiving chat again. - messageHolder.receiving(newChat: chat, - previousChat: chat, - newMessages: currentChat) - // Then: Message should be added. - XCTAssertNil(lastMessageBeforeAdded) - XCTAssertEqual(lastAddedMessage, currentChat[0]) - } - - func testSetMessagesToSend() { - let messageToSend = MessageToSend(serverURLString: "http://demo.webim.ru", - id: "1", - senderName: "Sender", - type: .OPERATOR, - text: "Text", - timeInMicrosecond: 1) - let messageHolder = newMessageHolder() - messageHolder.set(messagesToSend: [messageToSend]) - - XCTAssertEqual([messageToSend], - messageHolder.getMessagesToSend()) - } - - func testSendingMessage() { - let messageToSend = MessageToSend(serverURLString: "http://demo.webim.ru", - id: "1", - senderName: "Sender", - type: .OPERATOR, - text: "Text", - timeInMicrosecond: 1) - let messageHolder = newMessageHolder() - messageHolder.sending(message: messageToSend) - - XCTAssertEqual([messageToSend], - messageHolder.getMessagesToSend()) - } - - func testSendingCancelled() { - let messageID = "1" - let messageToSend = MessageToSend(serverURLString: "http://demo.webim.ru", - id: messageID, - senderName: "Sender", - type: .OPERATOR, - text: "Text", - timeInMicrosecond: 1) - let messageHolder = newMessageHolder() - messageHolder.sending(message: messageToSend) - messageHolder.sendingCancelledWith(messageID: messageID) - - XCTAssertTrue(messageHolder.getMessagesToSend().isEmpty) - } - - // MARK: - Mocking RemoteHistoryProvider - final class RemoteHistoryProviderForTests: RemoteHistoryProvider { - - // MARK: - Properties - var history: [MessageImpl] - var numberOfCalls = 0 - - // MARK: - Initialization - init(withWebimActions webimActions: WebimActions, - historyMessageMapper: MessageMapper, - historyMetaInformation: HistoryMetaInformationStorage, - history: [MessageImpl] = [MessageImpl]()) { - self.history = history - - super.init(webimActions: webimActions, - historyMessageMapper: historyMessageMapper, - historyMetaInformationStorage: historyMetaInformation) - } - - // MARK: - Methods - override func requestHistory(beforeTimestamp: Int64, - completion: @escaping ([MessageImpl], Bool) -> ()) { - var beforeIndex = 0 - for (messageIndex, message) in history.enumerated() { - if message.getTimeInMicrosecond() <= beforeTimestamp { - beforeIndex = messageIndex - - continue - } else { - break - } - } - - let afterIndex = max(0, (beforeIndex - 100)) - - numberOfCalls = numberOfCalls + 1 - - completion((beforeIndex <= 0) ? [MessageImpl]() : Array(history[afterIndex ..< beforeIndex]), (afterIndex != 0)) - } - - } - -} - -// MARK: - MessageListener -extension MessageHolderTests: MessageListener { - - func added(message newMessage: Message, - after previousMessage: Message?) { - lastAddedMessage = newMessage as? MessageImpl - lastMessageBeforeAdded = previousMessage as? MessageImpl - } - - func removed(message: Message) { - lastRemovedMessage = message as? MessageImpl - } - - func removedAllMessages() { - // No need to do anything when testing. - } - - func changed(message oldVersion: Message, to newVersion: Message) { - lastOldVersionChangedMessage = oldVersion as? MessageImpl - lastNewVersionChangedMessage = newVersion as? MessageImpl - } - -} - - -// MARK: - -extension MessageImpl { - - func getPrimaryID() -> String! { - return (getSource().isHistoryMessage() ? getHistoryID()!.getDBid() : getCurrentChatID()) - } - -} diff --git a/ios/libs/Webim/Example/Tests/MessageImplTests.swift b/ios/libs/Webim/Example/Tests/MessageImplTests.swift deleted file mode 100644 index 457e689..0000000 --- a/ios/libs/Webim/Example/Tests/MessageImplTests.swift +++ /dev/null @@ -1,350 +0,0 @@ -// -// MessageImplTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 20.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class MessageImplTests: XCTestCase { - - // MARK: - Tests - func testToString() { - let message = MessageImpl(serverURLString: "http://demo.webim.ru", - id: "id", - operatorID: nil, - senderAvatarURLString: nil, - senderName: "Name", - sendStatus: .SENT, - type: .VISITOR, - data: nil, - text: "Text", - timeInMicrosecond: 0, - attachment: nil, - historyMessage: false, - internalID: nil, - rawText: nil) - let expectedString = """ -MessageImpl { - serverURLString = http://demo.webim.ru, - ID = id, - operatorID = nil, - senderAvatarURLString = nil, - senderName = Name, - type = VISITOR, - text = Text, - timeInMicrosecond = 0, - attachment = nil, - historyMessage = false, - currentChatID = nil, - historyID = nil, - rawText = nil -} -""" - - XCTAssertEqual(message.toString(), - expectedString) - } - - func testGetSenderAvatarURL() { - let message = MessageImpl(serverURLString: "http://demo.webim.ru", - id: "id", - operatorID: nil, - senderAvatarURLString: nil, - senderName: "Name", - sendStatus: .SENT, - type: .VISITOR, - data: nil, - text: "Text", - timeInMicrosecond: 0, - attachment: nil, - historyMessage: false, - internalID: nil, - rawText: nil) - - XCTAssertNil(message.getSenderAvatarFullURL()) - } - - func testGetSendStatus() { - let message = MessageImpl(serverURLString: "http://demo.webim.ru", - id: "id", - operatorID: nil, - senderAvatarURLString: nil, - senderName: "Name", - sendStatus: .SENT, - type: .VISITOR, - data: nil, - text: "Text", - timeInMicrosecond: 0, - attachment: nil, - historyMessage: false, - internalID: nil, - rawText: nil) - - XCTAssertEqual(message.getSendStatus(), - MessageSendStatus.SENT) - } - - func testIsEqual() { - let message = MessageImpl(serverURLString: "http://demo.webim.ru", - id: "id", - operatorID: nil, - senderAvatarURLString: nil, - senderName: "Name", - sendStatus: .SENT, - type: .VISITOR, - data: nil, - text: "Text", - timeInMicrosecond: 0, - attachment: nil, - historyMessage: false, - internalID: nil, - rawText: nil) - - let message1 = MessageImpl(serverURLString: "http://demo.webim.ru", - id: "id1", - operatorID: nil, - senderAvatarURLString: nil, - senderName: "Name", - sendStatus: .SENT, - type: .VISITOR, - data: nil, - text: "Text", - timeInMicrosecond: 0, - attachment: nil, - historyMessage: false, - internalID: nil, - rawText: nil) - let message2 = MessageImpl(serverURLString: "http://demo.webim.ru", - id: "id", - operatorID: nil, - senderAvatarURLString: nil, - senderName: "Name1", - sendStatus: .SENT, - type: .VISITOR, - data: nil, - text: "Text", - timeInMicrosecond: 0, - attachment: nil, - historyMessage: false, - internalID: nil, - rawText: nil) - let message3 = MessageImpl(serverURLString: "http://demo.webim.ru", - id: "id", - operatorID: nil, - senderAvatarURLString: nil, - senderName: "Name", - sendStatus: .SENT, - type: .VISITOR, - data: nil, - text: "Text1", - timeInMicrosecond: 0, - attachment: nil, - historyMessage: false, - internalID: nil, - rawText: nil) - let message4 = MessageImpl(serverURLString: "http://demo.webim.ru", - id: "id", - operatorID: nil, - senderAvatarURLString: nil, - senderName: "Name", - sendStatus: .SENT, - type: .OPERATOR, - data: nil, - text: "Text", - timeInMicrosecond: 0, - attachment: nil, - historyMessage: false, - internalID: nil, - rawText: nil) - let message5 = MessageImpl(serverURLString: "http://demo.webim.ru", - id: "id", - operatorID: nil, - senderAvatarURLString: nil, - senderName: "Name", - sendStatus: .SENT, - type: .VISITOR, - data: nil, - text: "Text", - timeInMicrosecond: 0, - attachment: nil, - historyMessage: false, - internalID: nil, - rawText: nil) - - XCTAssertFalse(message.isEqual(to: message1)) - XCTAssertFalse(message.isEqual(to: message2)) - XCTAssertFalse(message.isEqual(to: message3)) - XCTAssertFalse(message.isEqual(to: message4)) - XCTAssertTrue(message.isEqual(to: message5)) - } - - // MARK: MessageSource tests - - func testAssertIsCurrentChat() { - let message = MessageImpl(serverURLString: "http://demo.webim.ru", - id: "id", - operatorID: nil, - senderAvatarURLString: nil, - senderName: "Name", - sendStatus: .SENT, - type: .VISITOR, - data: nil, - text: "Text", - timeInMicrosecond: 0, - attachment: nil, - historyMessage: false, - internalID: nil, - rawText: nil) - - XCTAssertNoThrow(try message.getSource().assertIsCurrentChat()) - } - - func testAssertIsHistory() { - let message = MessageImpl(serverURLString: "http://demo.webim.ru", - id: "id", - operatorID: nil, - senderAvatarURLString: nil, - senderName: "Name", - sendStatus: .SENT, - type: .VISITOR, - data: nil, - text: "Text", - timeInMicrosecond: 0, - attachment: nil, - historyMessage: false, - internalID: nil, - rawText: nil) - - XCTAssertThrowsError(try message.getSource().assertIsHistory()) - } - - func testGetHistoryID() { - let message = MessageImpl(serverURLString: "http://demo.webim.ru", - id: "id", - operatorID: nil, - senderAvatarURLString: nil, - senderName: "Name", - sendStatus: .SENT, - type: .VISITOR, - data: nil, - text: "Text", - timeInMicrosecond: 0, - attachment: nil, - historyMessage: false, - internalID: nil, - rawText: nil) - - XCTAssertNil(message.getHistoryID()) - } - - func testGetCurrentChatID() { - let currentChatID = "id" - let message = MessageImpl(serverURLString: "http://demo.webim.ru", - id: "id", - operatorID: nil, - senderAvatarURLString: nil, - senderName: "Name", - sendStatus: .SENT, - type: .VISITOR, - data: nil, - text: "Text", - timeInMicrosecond: 0, - attachment: nil, - historyMessage: false, - internalID: currentChatID, - rawText: nil) - - XCTAssertEqual(currentChatID, - message.getCurrentChatID()) - } - - func testGetSenderAvatarFullURL() { - let baseURLString = "http://demo.webim.ru" - let avatarURLString = "/image.jpg" - let message = MessageImpl(serverURLString: baseURLString, - id: "id", - operatorID: nil, - senderAvatarURLString: avatarURLString, - senderName: "Name", - sendStatus: .SENT, - type: .VISITOR, - data: nil, - text: "Text", - timeInMicrosecond: 0, - attachment: nil, - historyMessage: false, - internalID: nil, - rawText: nil) - - XCTAssertEqual(URL(string: (baseURLString + avatarURLString)), - message.getSenderAvatarFullURL()) - } - -} - -// MARK: - -class MessageAttachmentTests: XCTestCase { - - // MARK: - Tests - func testInit() { - let messageAttachment = MessageAttachmentImpl(urlString: "/image.jpg", - size: 1, - filename: "image", - contentType: "image/jpeg", - imageInfo: nil) - - XCTAssertEqual(messageAttachment.getContentType(), - "image/jpeg") - XCTAssertEqual(messageAttachment.getFileName(), - "image") - XCTAssertNil(messageAttachment.getImageInfo()) - XCTAssertEqual(messageAttachment.getSize(), - 1) - XCTAssertEqual(messageAttachment.getURL(), - URL(string: "/image.jpg")!) - } - -} - -// MARK: - -class ImageInfoImplTests: XCTestCase { - - // MARK: - Tests - func testInit() { - let imageInfo = ImageInfoImpl(withThumbURLString: "https://demo.webim.ru/thumb.jpg", - width: 100, - height: 200) - - - XCTAssertEqual(imageInfo.getThumbURL(), - URL(string: "https://demo.webim.ru/thumb.jpg")) - XCTAssertEqual(imageInfo.getWidth(), - 100) - XCTAssertEqual(imageInfo.getHeight(), - 200) - } - -} diff --git a/ios/libs/Webim/Example/Tests/MessageItemTests.swift b/ios/libs/Webim/Example/Tests/MessageItemTests.swift deleted file mode 100644 index dfd075a..0000000 --- a/ios/libs/Webim/Example/Tests/MessageItemTests.swift +++ /dev/null @@ -1,149 +0,0 @@ -// -// MessageItemTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 16.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class MessageItemTests: XCTestCase { - - // MARK: - Constants - private static let MESSAGE_ITEM_JSON_STRING = """ -{ - "avatar" : "/webim/images/avatar/demo_33202.png", - "chatId" : "2489", - "authorId" : 33202, - "data" : null, - "id" : "26871", - "ts_m" : 1518609964579372, - "text" : "42", - "clientSideId" : "84e51d5638524ee7833a1fe19a1f2448", - "kind" : "operator", - "name" : "Евгения Техподдержка" -} -""" - private static let MESSAGE_ITEM_TO_COMPARE_JSON_STRING_1 = """ -{ - "avatar" : "/webim/images/avatar/demo_33202.png", - "chatId" : "2489", - "authorId" : 33202, - "data" : null, - "id" : "26871", - "ts_m" : 1518609964579372, - "text" : "42", - "clientSideId" : "84e51d5638524ee7833a1fe19a1f2448", - "kind" : "operator", - "name" : "Евгения Техподдержка" -} -""" // Same. - private static let MESSAGE_ITEM_TO_COMPARE_JSON_STRING_2 = """ -{ - "avatar" : "/webim/images/avatar/demo_33202.png", - "chatId" : "2489", - "authorId" : 33202, - "data" : null, - "id" : "26872", - "ts_m" : 1518609964579372, - "text" : "42", - "clientSideId" : "84e51d5638524ee7833a1fe19a1f2448", - "kind" : "operator", - "name" : "Евгения Техподдержка" -} -""" // Different IDs. - private static let MESSAGE_ITEM_TO_COMPARE_JSON_STRING_3 = """ -{ - "avatar" : "/webim/images/avatar/demo_33202.png", - "chatId" : "2489", - "authorId" : 33202, - "data" : null, - "id" : "26871", - "ts_m" : 1518609964579372, - "text" : "42", - "clientSideId" : "84e51d5638524ee7833a1fe19a1f2449", - "kind" : "operator", - "name" : "Евгения Техподдержка" -} -""" // Different client side IDs. - private static let MESSAGE_ITEM_TO_COMPARE_JSON_STRING_4 = """ -{ - "avatar" : "/webim/images/avatar/demo_33202.png", - "chatId" : "2489", - "authorId" : 33202, - "data" : null, - "id" : "26871", - "ts_m" : 1518609964579372, - "text" : "43", - "clientSideId" : "84e51d5638524ee7833a1fe19a1f2448", - "kind" : "operator", - "name" : "Евгения Техподдержка" -} -""" // Different texts. - - // MARK: - Properties - private let messageItemDictionary = try! JSONSerialization.jsonObject(with: MessageItemTests.MESSAGE_ITEM_JSON_STRING.data(using: .utf8)!, - options: []) as! [String : Any?] - - // MARK: - Tests - func testInit() { - let messageItem = MessageItem(jsonDictionary: messageItemDictionary) - - XCTAssertEqual(messageItem.getClientSideID(), - "84e51d5638524ee7833a1fe19a1f2448") - XCTAssertEqual(messageItem.getID(), - "26871") - XCTAssertEqual(messageItem.getText(), - "42") - XCTAssertEqual(messageItem.getSenderID(), - "33202") - XCTAssertEqual(messageItem.getSenderAvatarURLString(), - "/webim/images/avatar/demo_33202.png") - XCTAssertNil(messageItem.getData()) - XCTAssertFalse(messageItem.isDeleted()) - XCTAssertEqual(messageItem.getKind(), - MessageItem.MessageKind.operatorMessage) - XCTAssertEqual(messageItem.getSenderName(), - "Евгения Техподдержка") - XCTAssertEqual(messageItem.getTimeInMicrosecond(), - 1518609964579372) - } - - func testEquals() { - let messageItemDictionary1 = try! JSONSerialization.jsonObject(with: MessageItemTests.MESSAGE_ITEM_TO_COMPARE_JSON_STRING_1.data(using: .utf8)!, - options: []) as! [String : Any?] - let messageItemDictionary2 = try! JSONSerialization.jsonObject(with: MessageItemTests.MESSAGE_ITEM_TO_COMPARE_JSON_STRING_2.data(using: .utf8)!, - options: []) as! [String : Any?] - let messageItemDictionary3 = try! JSONSerialization.jsonObject(with: MessageItemTests.MESSAGE_ITEM_TO_COMPARE_JSON_STRING_3.data(using: .utf8)!, - options: []) as! [String : Any?] - let messageItemDictionary4 = try! JSONSerialization.jsonObject(with: MessageItemTests.MESSAGE_ITEM_TO_COMPARE_JSON_STRING_4.data(using: .utf8)!, - options: []) as! [String : Any?] - - XCTAssertTrue(MessageItem(jsonDictionary: messageItemDictionary) == MessageItem(jsonDictionary: messageItemDictionary1)) - XCTAssertTrue(MessageItem(jsonDictionary: messageItemDictionary) != MessageItem(jsonDictionary: messageItemDictionary2)) - XCTAssertTrue(MessageItem(jsonDictionary: messageItemDictionary) != MessageItem(jsonDictionary: messageItemDictionary3)) - XCTAssertTrue(MessageItem(jsonDictionary: messageItemDictionary) != MessageItem(jsonDictionary: messageItemDictionary4)) - } - -} diff --git a/ios/libs/Webim/Example/Tests/MessageStreamImplTests.swift b/ios/libs/Webim/Example/Tests/MessageStreamImplTests.swift deleted file mode 100644 index b8afd40..0000000 --- a/ios/libs/Webim/Example/Tests/MessageStreamImplTests.swift +++ /dev/null @@ -1,202 +0,0 @@ -// -// MessageStreamImplTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 22.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class MessageStreamImplTests: XCTestCase { - - // MARK: - Properties - var messageStream: MessageStreamImpl? - var webimActions: WebimActions? - - // MARK: - Methods - override func setUp() { - super.setUp() - - let serverURLString = "https://demo.webim.ru" - let sessionDestroyer = SessionDestroyer() - let accessChecker = AccessChecker(thread: Thread.current, - sessionDestroyer: sessionDestroyer) - let queue = DispatchQueue.main - webimActions = WebimActions(baseURL: serverURLString, - actionRequestLoop: ActionRequestLoopForTests(completionHandlerExecutor: ExecIfNotDestroyedHandlerExecutor(sessionDestroyer: sessionDestroyer, - queue: queue), - internalErrorListener: InternalErrorListenerForTests())) - messageStream = MessageStreamImpl(serverURLString: serverURLString, - currentChatMessageFactoriesMapper: CurrentChatMessageMapper(withServerURLString: serverURLString), - sendingMessageFactory: SendingFactory(withServerURLString: serverURLString), - operatorFactory: OperatorFactory(withServerURLString: serverURLString), - accessChecker: accessChecker, - webimActions: webimActions!, - messageHolder: MessageHolder(accessChecker: accessChecker, - remoteHistoryProvider: RemoteHistoryProvider(webimActions: webimActions!, - historyMessageMapper: HistoryMessageMapper(withServerURLString: serverURLString), - historyMetaInformationStorage: MemoryHistoryMetaInformationStorage()), - historyStorage: MemoryHistoryStorage(), - reachedEndOfRemoteHistory: true), - messageComposingHandler: MessageComposingHandler(webimActions: webimActions!, - queue: queue), - locationSettingsHolder: LocationSettingsHolder(userDefaultsKey: "key")) - } - - // MARK: - Tests - - func testSetVisitSessionState() { - messageStream!.set(visitSessionState: .chat) - - XCTAssertEqual(messageStream!.getVisitSessionState(), - VisitSessionState.CHAT) - } - - func testSetUnreadByOperatorTimestamp() { - let date = Date() - messageStream!.set(unreadByOperatorTimestamp: date) - - XCTAssertEqual(messageStream!.getUnreadByOperatorTimestamp(), - date) - } - - func testSetUnreadByVisitorTimestamp() { - let date = Date() - messageStream!.set(unreadByVisitorTimestamp: date) - - XCTAssertEqual(messageStream!.getUnreadByVisitorTimestamp(), - date) - } - - func testOnReceivingDepartmentList() { - let departmentItemDictionary = try! JSONSerialization.jsonObject(with: DEPARTMENT_ITEM_JSON_STRING.data(using: .utf8)!, - options: []) as! [String : Any?] - let departmentItem = DepartmentItem(jsonDictionary: departmentItemDictionary)! - messageStream!.onReceiving(departmentItemList: [departmentItem]) - - XCTAssertEqual(messageStream!.getDepartmentList()![0].getKey(), - "mobile_test_1") - XCTAssertEqual(messageStream!.getDepartmentList()![0].getName(), - "Mobile Test 1") - XCTAssertEqual(messageStream!.getDepartmentList()![0].getDepartmentOnlineStatus(), - DepartmentOnlineStatus.OFFLINE) - XCTAssertEqual(messageStream!.getDepartmentList()![0].getOrder(), - 100) - XCTAssertEqual(messageStream!.getDepartmentList()![0].getLocalizedNames()!, - ["ru" : "Mobile Test 1"]) - XCTAssertEqual(messageStream!.getDepartmentList()![0].getLogoURL()!, - URL(string: "https://demo.webim.ru/webim/images/department_logo/wmtest2_1.png")!) - } - - func testGetChatState() { - XCTAssertEqual(messageStream!.getChatState(), - ChatState.UNKNOWN) - } - - func testGetLocationSettings() { - XCTAssertFalse(messageStream!.getLocationSettings().areHintsEnabled()) // Initial value must be false. - } - - func testGetCurrentOperator() { - XCTAssertNil(messageStream!.getCurrentOperator()) // Initially operator does not exist. - } - - func testSetVisitSessionStateListener() { - let visitSessionStateListener = VisitSessionStateListenerForTests() - messageStream!.set(visitSessionStateListener: visitSessionStateListener) - - messageStream!.set(visitSessionState: .chat) - - XCTAssertTrue(visitSessionStateListener.called) - XCTAssertEqual(visitSessionStateListener.state!, - VisitSessionState.CHAT) - } - - func testSetOnlineStatusChangeListener() { - let onlineStatusChangeListener = OnlineStatusChangeListenerForTests() - messageStream!.set(onlineStatusChangeListener: onlineStatusChangeListener) - - messageStream!.set(onlineStatus: .busyOnline) - XCTAssertFalse(onlineStatusChangeListener.called) - - messageStream!.onOnlineStatusChanged(to: .busyOffline) - - XCTAssertTrue(onlineStatusChangeListener.called) - XCTAssertEqual(onlineStatusChangeListener.status!, - OnlineStatus.BUSY_OFFLINE) - } - - func testChangingChatState() { - let chatItemDictionary = try! JSONSerialization.jsonObject(with: ChatItemTests.CHAT_ITEM_JSON_STRING.data(using: .utf8)!, - options: []) as! [String : Any?] - let chatItem = ChatItem(jsonDictionary: chatItemDictionary) - messageStream!.changingChatStateOf(chat: chatItem) - - XCTAssertEqual(messageStream!.getChatState(), - ChatState.CHATTING) - XCTAssertNil(messageStream!.getUnreadByOperatorTimestamp()) - XCTAssertNil(messageStream!.getUnreadByVisitorTimestamp()) - XCTAssertEqual(messageStream!.getCurrentOperator()!.getID(), "33201") - } - - func testGetWebimActions() { - XCTAssertTrue(webimActions! === messageStream!.getWebimActions()) - } - -} - -// MARK: - -fileprivate class VisitSessionStateListenerForTests: VisitSessionStateListener { - - // MARK: - Properties - var called = false - var state: VisitSessionState? - - // MARK: - Methods - // MARK: VisitSessionStateListener protocol methods - func changed(state previousState: VisitSessionState, - to newState: VisitSessionState) { - called = true - state = newState - } - -} - -// MARK: - -fileprivate class OnlineStatusChangeListenerForTests: OnlineStatusChangeListener { - - // MARK: - Properties - var called = false - var status: OnlineStatus? - - // MARK: - Methods - // MARK: OnlineStatusChangeListener protocol methods - func changed(onlineStatus previousOnlineStatus: OnlineStatus, - to newOnlineStatus: OnlineStatus) { - called = true - status = newOnlineStatus - } - - -} diff --git a/ios/libs/Webim/Example/Tests/Mocks/ActionRequestLoopMock.swift b/ios/libs/Webim/Example/Tests/Mocks/ActionRequestLoopMock.swift deleted file mode 100644 index 5b9abd4..0000000 --- a/ios/libs/Webim/Example/Tests/Mocks/ActionRequestLoopMock.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// ActionRequestLoop.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 30.01.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary - -final class ActionRequestLoopForTests: ActionRequestLoop { - - // MARK: - Properties - var webimRequest: WebimRequest? - - // MARK: - Methods - override func enqueue(request: WebimRequest) { - webimRequest = request - } - -} diff --git a/ios/libs/Webim/Example/Tests/Mocks/InternalErrorListenerMock.swift b/ios/libs/Webim/Example/Tests/Mocks/InternalErrorListenerMock.swift deleted file mode 100644 index efffa64..0000000 --- a/ios/libs/Webim/Example/Tests/Mocks/InternalErrorListenerMock.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// InternalErrorListener.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 29.01.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary - -final class InternalErrorListenerForTests: InternalErrorListener { - - func on(error: String) { - // No need to do anything when testing. - } - -} diff --git a/ios/libs/Webim/Example/Tests/OperatorFactoryTests.swift b/ios/libs/Webim/Example/Tests/OperatorFactoryTests.swift deleted file mode 100644 index edc07e5..0000000 --- a/ios/libs/Webim/Example/Tests/OperatorFactoryTests.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// OperatorFactoryTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 19.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class OperatorFactoryTests: XCTestCase { - - // MARK: - Constants - private static let serverURLString = "http://demo.webim.ru" - - // MARK: - Properties - private let operatorFactory = OperatorFactory(withServerURLString: serverURLString) - - // MARK: - Tests - func testCreateOperator() { - let operatorItemDictionary = try! JSONSerialization.jsonObject(with: OPERATOR_ITEM_JSON_STRING.data(using: .utf8)!, - options: []) as! [String : Any?] - var operatorItem = OperatorItem(jsonDictionary: operatorItemDictionary) - let `operator` = operatorFactory.createOperatorFrom(operatorItem: operatorItem) - - XCTAssertEqual(`operator`!.getID(), - operatorItem!.getID()) - XCTAssertEqual(`operator`!.getName(), - operatorItem!.getFullName()) - XCTAssertEqual(URL(string: (OperatorFactoryTests.serverURLString + operatorItem!.getAvatarURLString()!)), - `operator`!.getAvatarURL()!) - - operatorItem = nil - XCTAssertNil(operatorFactory.createOperatorFrom(operatorItem: operatorItem)) - } - -} diff --git a/ios/libs/Webim/Example/Tests/OperatorImplTests.swift b/ios/libs/Webim/Example/Tests/OperatorImplTests.swift deleted file mode 100644 index 41ee156..0000000 --- a/ios/libs/Webim/Example/Tests/OperatorImplTests.swift +++ /dev/null @@ -1,87 +0,0 @@ -// -// OperatorImplTests.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 02.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -import XCTest -@testable import WebimClientLibrary - -class OperatorImplTests: XCTestCase { - - // MARK: - Tests - - func testInit() { - let `operator` = OperatorImpl(id: "id", - name: "name", - avatarURLString: nil) - - XCTAssertEqual(`operator`.getID(), - "id") - XCTAssertEqual(`operator`.getName(), - "name") - XCTAssertNil(`operator`.getAvatarURL()) - } - - func testEquals() { - var operator1: OperatorImpl? = OperatorImpl(id: "id1", - name: "name1", - avatarURLString: "avatar1.jpg") - var operator2: OperatorImpl? = OperatorImpl(id: "id1", - name: "name1", - avatarURLString: "avatar1.jpg") - XCTAssertTrue(operator1 == operator2) - - operator1 = OperatorImpl(id: "id1", - name: "name1", - avatarURLString: "avatar1.jpg") - operator2 = OperatorImpl(id: "id2", - name: "name2", - avatarURLString: "avatar2.jpg") - XCTAssertFalse(operator1 == operator2) - - operator1 = OperatorImpl(id: "id1", - name: "name1", - avatarURLString: "avatar1.jpg") - operator2 = OperatorImpl(id: "id2", - name: "name1", - avatarURLString: "avatar1.jpg") - XCTAssertFalse(operator1 == operator2) - - operator1 = OperatorImpl(id: "id1", - name: "name1", - avatarURLString: "avatar1.jpg") - operator2 = OperatorImpl(id: "id1", - name: "name1", - avatarURLString: nil) - XCTAssertFalse(operator1 == operator2) - - operator1 = OperatorImpl(id: "id1", - name: "name1", - avatarURLString: "avatar1.jpg") - operator2 = nil - XCTAssertFalse(operator1 == operator2) - } - -} diff --git a/ios/libs/Webim/Example/Tests/OperatorItemTests.swift b/ios/libs/Webim/Example/Tests/OperatorItemTests.swift deleted file mode 100644 index 9cb064d..0000000 --- a/ios/libs/Webim/Example/Tests/OperatorItemTests.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// OperatorItemTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 16.02.18. -// Copyright © 2018 CocoaPods. All rights reserved. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -// MARK: - Global constants -let OPERATOR_ITEM_JSON_STRING = """ -{ - "avatar" : "/webim/images/avatar/demo_33201.png", - "fullname" : "Administrator", - "id" : 33201, - "robotType" : null, - "departmentKeys" : [ - "telegram", - "test3", - "test2" - ], - "langToFullname" : { }, - "sip" : "10002715000033201" -} -""" - -class OperatorItemTests: XCTestCase { - - // MARK: - Tests - - func testInit() { - let operatorItemDictionary = try! JSONSerialization.jsonObject(with: OPERATOR_ITEM_JSON_STRING.data(using: .utf8)!, - options: []) as! [String : Any?] - let operatorItem = OperatorItem(jsonDictionary: operatorItemDictionary)! - - XCTAssertEqual(operatorItem.getID(), - "33201") - XCTAssertEqual(operatorItem.getFullName(), - "Administrator") - XCTAssertEqual(operatorItem.getAvatarURLString(), - "/webim/images/avatar/demo_33201.png") - } - - func testInitFails() { - let incorrectOperatorJSONString = """ -{ - "avatar" : "/webim/images/avatar/demo_33201.png", - "fullname" : "Administrator", - "robotType" : null, - "departmentKeys" : [ - "telegram", - "test3", - "test2" - ], - "langToFullname" : { }, - "sip" : "10002715000033201" -} -""" - let operatorItemDictionary = try! JSONSerialization.jsonObject(with: incorrectOperatorJSONString.data(using: .utf8)!, - options: []) as! [String : Any?] - - XCTAssertNil(OperatorItem(jsonDictionary: operatorItemDictionary)) - } - -} diff --git a/ios/libs/Webim/Example/Tests/ProvidedVisitorFieldsTests.swift b/ios/libs/Webim/Example/Tests/ProvidedVisitorFieldsTests.swift deleted file mode 100644 index aca9966..0000000 --- a/ios/libs/Webim/Example/Tests/ProvidedVisitorFieldsTests.swift +++ /dev/null @@ -1,73 +0,0 @@ -// -// ProvidedVisitorFieldsTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 20.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class ProvidedVisitorFieldsTests: XCTestCase { - - // MARK: - Constants - private static let PROVIDED_VISITOR_FIELDS_JSON_STRING = """ -{ - "id" : "1234567890987654321", - "display_name" : "Никита", - "crc" : "ffadeb6aa3c788200824e311b9aa44cb" -} -""" - private static let PROVIDED_VISITOR_FIELDS_JSON_DATA = ProvidedVisitorFieldsTests.PROVIDED_VISITOR_FIELDS_JSON_STRING.data(using: .utf8)! - private static let WRONG_PROVIDED_VISITOR_FIELDS_JSON_STRING = """ -{ - "display_name" : "Никита", - "crc" : "ffadeb6aa3c788200824e311b9aa44cb" -} -""" - - // MARK: - Tests - - func testInitWithString() { - let providedVisitorFields = ProvidedVisitorFields(withJSONString: ProvidedVisitorFieldsTests.PROVIDED_VISITOR_FIELDS_JSON_STRING)! - - XCTAssertEqual(ProvidedVisitorFieldsTests.PROVIDED_VISITOR_FIELDS_JSON_STRING, - providedVisitorFields.getJSONString()) - XCTAssertEqual("1234567890987654321", - providedVisitorFields.getID()) - } - - func testInitWithData() { - let providedVisitorFields = ProvidedVisitorFields(withJSONObject: ProvidedVisitorFieldsTests.PROVIDED_VISITOR_FIELDS_JSON_DATA)! - - XCTAssertEqual(ProvidedVisitorFieldsTests.PROVIDED_VISITOR_FIELDS_JSON_STRING, - providedVisitorFields.getJSONString()) - XCTAssertEqual("1234567890987654321", - providedVisitorFields.getID()) - } - - func testInitFailed() { - XCTAssertNil(ProvidedVisitorFields(withJSONString: ProvidedVisitorFieldsTests.WRONG_PROVIDED_VISITOR_FIELDS_JSON_STRING)) - } - -} diff --git a/ios/libs/Webim/Example/Tests/RatingItemTests.swift b/ios/libs/Webim/Example/Tests/RatingItemTests.swift deleted file mode 100644 index 71b021d..0000000 --- a/ios/libs/Webim/Example/Tests/RatingItemTests.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// RatingItemTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 19.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class RatingItemTests: XCTestCase { - - // MARK: - Tests - - func testInit() { - let ratingItemJSONString = """ -{ - "operatorId" : 33201, - "rating" : 2 -} -""" - let ratingItemDictionary = try! JSONSerialization.jsonObject(with: ratingItemJSONString.data(using: .utf8)!, - options: []) as! [String : Any?] - let ratingItem = RatingItem(jsonDictionary: ratingItemDictionary) - - XCTAssertEqual(ratingItem!.getOperatorID(), - "33201") - XCTAssertEqual(ratingItem!.getRating(), - 2) - } - - func testInitFails() { - let ratingItemJSONString = """ -{ - "operatorId" : 33201 -} -""" - let ratingItemDictionary = try! JSONSerialization.jsonObject(with: ratingItemJSONString.data(using: .utf8)!, - options: []) as! [String : Any?] - - XCTAssertNil(RatingItem(jsonDictionary: ratingItemDictionary)) - } - -} diff --git a/ios/libs/Webim/Example/Tests/SQLiteHistoryStorageTests.swift b/ios/libs/Webim/Example/Tests/SQLiteHistoryStorageTests.swift deleted file mode 100644 index 136505a..0000000 --- a/ios/libs/Webim/Example/Tests/SQLiteHistoryStorageTests.swift +++ /dev/null @@ -1,196 +0,0 @@ -// -// SQLiteHistoryStorageTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 20.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class SQLiteHistoryStorageTests: XCTestCase { - - // MARK: - Constants - private static let DB_NAME = "test" - private static let SERVER_URL_STRING = "https://demo.webim.ru" - - // MARK: - Properties - var sqLiteHistoryStorage: SQLiteHistoryStorage? - - // MARK: - Methods - override func setUp() { - super.setUp() - - let queue = DispatchQueue.main - let exeIfNotDestroyedHandlerExecutor = ExecIfNotDestroyedHandlerExecutor(sessionDestroyer: SessionDestroyer(), - queue: queue) - let internalErrorListener = InternalErrorListenerForTests() - let actionRequestLoop = ActionRequestLoopForTests(completionHandlerExecutor: exeIfNotDestroyedHandlerExecutor, - internalErrorListener: internalErrorListener) - sqLiteHistoryStorage = SQLiteHistoryStorage(dbName: SQLiteHistoryStorageTests.DB_NAME, - serverURL: SQLiteHistoryStorageTests.DB_NAME, - webimClient: WebimClient(withActionRequestLoop: actionRequestLoop, - deltaRequestLoop: DeltaRequestLoop(deltaCallback: DeltaCallback(currentChatMessageMapper: CurrentChatMessageMapper(withServerURLString: SQLiteHistoryStorageTests.SERVER_URL_STRING)), - completionHandlerExecutor: exeIfNotDestroyedHandlerExecutor, - sessionParametersListener: nil, - internalErrorListener: internalErrorListener, - baseURL: SQLiteHistoryStorageTests.SERVER_URL_STRING, - title: "Title", - location: "mobile", - appVersion: nil, - visitorFieldsJSONString: nil, - providedAuthenticationTokenStateListener: nil, - providedAuthenticationToken: nil, - deviceID: "ID", - deviceToken: nil, - visitorJSONString: nil, - sessionID: nil, - authorizationData: nil), - webimActions: WebimActions(baseURL: SQLiteHistoryStorageTests.SERVER_URL_STRING, - actionRequestLoop: actionRequestLoop)), - reachedHistoryEnd: true, - queue: queue) - } - - override func tearDown() { - let fileManager = FileManager.default - let documentsPath = try! fileManager.url(for: .documentDirectory, - in: .userDomainMask, - appropriateFor: nil, - create: false) - let dbPath = "\(documentsPath)/\(SQLiteHistoryStorageTests.DB_NAME)" - do { - try fileManager.removeItem(at: URL(string: dbPath)!) - } catch let error { - print("DB file deletion failed with error: " + error.localizedDescription) - } - - super.tearDown() - } - - // MARK: Private methods - private static func generateMessages(ofCount numberOfMessages: Int) -> [MessageImpl] { - var messages = [MessageImpl]() - - for index in 1 ... numberOfMessages { - messages.append(MessageImpl(serverURLString: SQLiteHistoryStorageTests.SERVER_URL_STRING, - id: String(index), - operatorID: "1", - senderAvatarURLString: nil, - senderName: "Name", - type: MessageType.OPERATOR, - data: nil, - text: "Text", - timeInMicrosecond: Int64(index * 1_000_000_000_000), - attachment: nil, - historyMessage: true, - internalID: String(index), - rawText: nil)) - } - - return messages - } - - // MARK: - Tests - - func testGetMajorVersion() { - XCTAssertEqual(sqLiteHistoryStorage!.getMajorVersion(), - 1) - } - - func testGetFullHistory() { - let messagesCount = 10 - sqLiteHistoryStorage!.receiveHistoryBefore(messages: SQLiteHistoryStorageTests.generateMessages(ofCount: messagesCount), - hasMoreMessages: false) - - let expectation = XCTestExpectation() - var gettedMessages = [Message]() - sqLiteHistoryStorage!.getFullHistory() { messages in - gettedMessages = messages - - expectation.fulfill() - } - wait(for: [expectation], - timeout: 1.0) - - XCTAssertEqual(gettedMessages.count, - messagesCount) - } - - func testGetLatestHistory() { - let messagesCount = 10 - sqLiteHistoryStorage!.receiveHistoryBefore(messages: SQLiteHistoryStorageTests.generateMessages(ofCount: messagesCount), - hasMoreMessages: false) - - let messagesLimit = 3 - let expectation = XCTestExpectation() - var gettedMessages = [Message]() - sqLiteHistoryStorage!.getLatestHistory(byLimit: messagesLimit) { messages in - expectation.fulfill() - gettedMessages = messages - } - wait(for: [expectation], - timeout: 1.0) - - XCTAssertEqual(gettedMessages.count, - messagesLimit) - - let timestampArray = gettedMessages.map() { $0.getTime() } - let thresholdTimestamp = Date(timeIntervalSince1970: TimeInterval((messagesCount - messagesLimit) * 1_000_000)) - for timestamp in timestampArray { - XCTAssertTrue(timestamp > thresholdTimestamp) - } - } - - func testGetHistoryBefore() { - let messagesCount = 10 - sqLiteHistoryStorage!.receiveHistoryBefore(messages: SQLiteHistoryStorageTests.generateMessages(ofCount: messagesCount), - hasMoreMessages: false) - - let messagesLimit = 3 - let beforeID = 5 - let expectation = XCTestExpectation() - var gettedMessages = [Message]() - sqLiteHistoryStorage!.getHistoryBefore(id: HistoryID(dbID: String(beforeID), - timeInMicrosecond: Int64(beforeID * 1_000_000_000_000)), - limitOfMessages: messagesLimit) { messages in - gettedMessages = messages - - expectation.fulfill() - } - wait(for: [expectation], - timeout: 1.0) - - XCTAssertEqual(gettedMessages.count, - messagesLimit) - - let timestampArray = gettedMessages.map() { $0.getTime() } - let lowerThresholdTimestamp = Date(timeIntervalSince1970: TimeInterval((beforeID - messagesLimit - 1)) * 1_000_000) - let upperThresholdTimestamp = Date(timeIntervalSince1970: TimeInterval(beforeID * 1_000_000)) - for timestamp in timestampArray { - XCTAssertTrue(timestamp > lowerThresholdTimestamp) - XCTAssertTrue(timestamp < upperThresholdTimestamp) - } - } - -} diff --git a/ios/libs/Webim/Example/Tests/SessionBuilderTests.swift b/ios/libs/Webim/Example/Tests/SessionBuilderTests.swift deleted file mode 100644 index f8fa88f..0000000 --- a/ios/libs/Webim/Example/Tests/SessionBuilderTests.swift +++ /dev/null @@ -1,129 +0,0 @@ -// -// SessionBuilderTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 02.03.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class SessionBuilderTests: XCTestCase { - - // MARK: - Tests - func testBuild() { - let visitorFieldsJSONString = "{\"id\":\"1234567890987654321\",\"display_name\":\"Никита\",\"crc\":\"ffadeb6aa3c788200824e311b9aa44cb\"}" - - XCTAssertThrowsError(try Webim - .newSessionBuilder() - .set(location: "location") - .build()) - XCTAssertThrowsError(try Webim - .newSessionBuilder() - .set(accountName: "account") - .build()) - - XCTAssertThrowsError(try Webim - .newSessionBuilder() - .set(accountName: "account") - .set(location: "location") - .set(deviceToken: "token") - .build()) - XCTAssertNoThrow(try Webim - .newSessionBuilder() - .set(accountName: "account") - .set(location: "location") - .set(deviceToken: "token") - .set(remoteNotificationSystem: .APNS) - .build()) - - XCTAssertThrowsError(try Webim - .newSessionBuilder() - .set(accountName: "account") - .set(location: "location") - .set(visitorFieldsJSONString: visitorFieldsJSONString) - .set(providedAuthorizationTokenStateListener: self) - .build()) - XCTAssertNoThrow(try Webim - .newSessionBuilder() - .set(accountName: "account") - .set(location: "location") - .set(visitorFieldsJSONString: visitorFieldsJSONString) - .build()) - XCTAssertNoThrow(try Webim - .newSessionBuilder() - .set(accountName: "account") - .set(location: "location") - .set(providedAuthorizationTokenStateListener: self) - .build()) - - XCTAssertNoThrow(try Webim - .newSessionBuilder() - .set(accountName: "account") - .set(location: "location") - .set(appVersion: "version") - .set(visitorFieldsJSONData: visitorFieldsJSONString.data(using: .utf8)!) - .set(pageTitle: "title") - .set(fatalErrorHandler: self) - .set(remoteNotificationSystem: .APNS) - .set(deviceToken: "token") - .set(isLocalHistoryStoragingEnabled: true) - .set(isVisitorDataClearingEnabled: false) - .set(webimLogger: self) - .build()) - } - -} - -// MARK: - -extension SessionBuilderTests: ProvidedAuthorizationTokenStateListener { - - // MARK: - Methods - // MARK: ProvidedAuthorizationTokenStateListener protocol methods - func update(providedAuthorizationToken: String) { - // No need to do anything while testing. - } - -} - -// MARK: - -extension SessionBuilderTests: FatalErrorHandler { - - // MARK: - Methods - // MARK: FatalErrorHandler protocol methods - func on(error: WebimError) { - // No need to do anything when testing. - } - -} - -// MARK: - -extension SessionBuilderTests: WebimLogger { - - // MARK: - Methods - // MARK: WebimLogger protocol methods - func log(entry: String) { - // No need to do anything when testing. - } - -} diff --git a/ios/libs/Webim/Example/Tests/SessionDestroyerTests.swift b/ios/libs/Webim/Example/Tests/SessionDestroyerTests.swift deleted file mode 100644 index 2ce03fa..0000000 --- a/ios/libs/Webim/Example/Tests/SessionDestroyerTests.swift +++ /dev/null @@ -1,66 +0,0 @@ -// -// SessionDestroyerTests.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 01.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class SessionDestroyerTests: XCTestCase { - - // MARK: - Tests - func testDestroy() { - // Setup. - - let sessionDestroyer = SessionDestroyer() - - let expectation1 = XCTestExpectation() - let expectation2 = XCTestExpectation() - let expectation3 = XCTestExpectation() - - sessionDestroyer.add { - expectation1.fulfill() - } - sessionDestroyer.add { - expectation2.fulfill() - } - sessionDestroyer.add { - expectation3.fulfill() - } - - // When: Session is destroyed. - sessionDestroyer.destroy() - - // Then: All passed actions should be executed. - XCTAssertTrue(sessionDestroyer.isDestroyed()) - wait(for: [expectation1], - timeout: 1.0) - wait(for: [expectation2], - timeout: 1.0) - wait(for: [expectation3], - timeout: 1.0) - } - -} diff --git a/ios/libs/Webim/Example/Tests/StringFromHTTPParametersTests.swift b/ios/libs/Webim/Example/Tests/StringFromHTTPParametersTests.swift deleted file mode 100644 index 39b29b9..0000000 --- a/ios/libs/Webim/Example/Tests/StringFromHTTPParametersTests.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// StringFromHTTPParametersTests.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 02.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -import XCTest -@testable import WebimClientLibrary - -class StringFromHTTPParametersTests: XCTestCase { - - // MARK: - Tests - func testStringFromHTTPParameters() { - let dictionary = ["parameter1" : "value1", - "parameter2" : "1"] as [String : Any] - let expectedString = "parameter1=value1¶meter2=1" - - XCTAssertEqual(dictionary.stringFromHTTPParameters(), - expectedString) - } - -} diff --git a/ios/libs/Webim/Example/Tests/UIColorHexStringTests.swift b/ios/libs/Webim/Example/Tests/UIColorHexStringTests.swift deleted file mode 100644 index cd46d62..0000000 --- a/ios/libs/Webim/Example/Tests/UIColorHexStringTests.swift +++ /dev/null @@ -1,58 +0,0 @@ -// -// UIColorHexStringTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 19.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import UIKit -@testable import WebimClientLibrary -import XCTest - -class UIColorHexStringTests: XCTestCase { - - // MARK: - Methods - func testUIColorHexString() { - let colorHexString1 = "000000" - let colorHexString2 = "#000000" - let colorHexString3 = "#ffffff" - let colorHexString4 = "0000000" - - XCTAssertEqual(UIColor(hexString: colorHexString1)!, - UIColor(red: (0.0 / 255.0), - green: (0.0 / 255.0), - blue: (0.0 / 255.0), - alpha: 1.0)) - XCTAssertEqual(UIColor(hexString: colorHexString2)!, - UIColor(red: (0.0 / 255.0), - green: (0.0 / 255.0), - blue: (0.0 / 255.0), - alpha: 1.0)) - XCTAssertEqual(UIColor(hexString: colorHexString3)!, - UIColor(red: (255.0 / 255.0), - green: (255.0 / 255.0), - blue: (255.0 / 255.0), - alpha: 1.0)) - XCTAssertNil(UIColor(hexString: colorHexString4)) - } - -} diff --git a/ios/libs/Webim/Example/Tests/VisitorItemTests.swift b/ios/libs/Webim/Example/Tests/VisitorItemTests.swift deleted file mode 100644 index 609609b..0000000 --- a/ios/libs/Webim/Example/Tests/VisitorItemTests.swift +++ /dev/null @@ -1,151 +0,0 @@ -// -// VisitorItemTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 19.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import UIKit -@testable import WebimClientLibrary -import XCTest - -class VisitorItemTests: XCTestCase { - - // MARK: - Tests - - func testInit() { - let visitorItemJSONString = """ -{ - "fields" : { - "name" : "Посетитель" - }, - "channelType" : null, - "channelId" : null, - "id" : "877a920ede7082412656ac1cdec7ecde", - "icon" : { - "color" : "#5fa0ea", - "shape" : "rhombus" - }, - "modificationTs" : 1518790888.5528669, - "creationTs" : 1518790888.5528669, - "hasProvidedFields" : true, - "channelUserName" : null, - "tags" : [ ], - "channelUserId" : null -} -""" - let visitorItemDictionary = try! JSONSerialization.jsonObject(with: visitorItemJSONString.data(using: .utf8)!, - options: []) as! [String : Any?] - let visitorItem = VisitorItem(jsonDictionary: visitorItemDictionary)! - - XCTAssertEqual(visitorItem.getID(), - "877a920ede7082412656ac1cdec7ecde") - - XCTAssertEqual(visitorItem.getIcon()!.getColor(), - UIColor(hexString: "#5fa0ea")!) - XCTAssertEqual(visitorItem.getIcon()!.getShape(), - "rhombus") - - XCTAssertEqual(visitorItem.getVisitorFields().getName(), - "Посетитель") - XCTAssertNil(visitorItem.getVisitorFields().getEmail()) - XCTAssertNil(visitorItem.getVisitorFields().getPhone()) - } - - func testInitFails() { - let visitorItemJSONString = """ -{ - "fields" : { - "name" : "Посетитель" - }, - "channelType" : null, - "channelId" : null, - "icon" : { - "color" : "#5fa0ea", - "shape" : "rhombus" - }, - "modificationTs" : 1518790888.5528669, - "creationTs" : 1518790888.5528669, - "hasProvidedFields" : true, - "channelUserName" : null, - "tags" : [ ], - "channelUserId" : null -} -""" - let visitorItemDictionary = try! JSONSerialization.jsonObject(with: visitorItemJSONString.data(using: .utf8)!, - options: []) as! [String : Any?] - - XCTAssertNil(VisitorItem(jsonDictionary: visitorItemDictionary)) - } - - func testNilIcon() { - let visitorItemJSONString = """ -{ - "fields" : { - "name" : "Посетитель" - }, - "channelType" : null, - "channelId" : null, - "id" : "877a920ede7082412656ac1cdec7ecde", - "icon" : { - "shape" : "rhombus" - }, - "modificationTs" : 1518790888.5528669, - "creationTs" : 1518790888.5528669, - "hasProvidedFields" : true, - "channelUserName" : null, - "tags" : [ ], - "channelUserId" : null -} -""" - let visitorItemDictionary = try! JSONSerialization.jsonObject(with: visitorItemJSONString.data(using: .utf8)!, - options: []) as! [String : Any?] - let visitorItem = VisitorItem(jsonDictionary: visitorItemDictionary)! - - XCTAssertNil(visitorItem.getIcon()) - } - - func testNilFields() { - let visitorItemJSONString = """ -{ - "fields" : { }, - "channelType" : null, - "channelId" : null, - "id" : "877a920ede7082412656ac1cdec7ecde", - "icon" : { - "shape" : "rhombus" - }, - "modificationTs" : 1518790888.5528669, - "creationTs" : 1518790888.5528669, - "hasProvidedFields" : true, - "channelUserName" : null, - "tags" : [ ], - "channelUserId" : null -} -""" - let visitorItemDictionary = try! JSONSerialization.jsonObject(with: visitorItemJSONString.data(using: .utf8)!, - options: []) as! [String : Any?] - - XCTAssertNil(VisitorItem(jsonDictionary: visitorItemDictionary)) - } - -} diff --git a/ios/libs/Webim/Example/Tests/WebimActionsTests.swift b/ios/libs/Webim/Example/Tests/WebimActionsTests.swift deleted file mode 100644 index 6262178..0000000 --- a/ios/libs/Webim/Example/Tests/WebimActionsTests.swift +++ /dev/null @@ -1,445 +0,0 @@ -// -// WebimActionsTests.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 29.01.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -import XCTest -@testable import WebimClientLibrary - -class WebimActionsTests: XCTestCase { - - // MARK: - Properties - private let actionRequestLoop = ActionRequestLoopForTests(completionHandlerExecutor: ExecIfNotDestroyedHandlerExecutor(sessionDestroyer: SessionDestroyer(), - queue: DispatchQueue.global()), - internalErrorListener: InternalErrorListenerForTests() as InternalErrorListener) - private var webimActions: WebimActions? - - // MARK: - Methods - - override func setUp() { - super.setUp() - - webimActions = WebimActions(baseURL: "https://demo.webim.ru", - actionRequestLoop: actionRequestLoop) - } - - override func tearDown() { - actionRequestLoop.webimRequest = nil - - super.tearDown() - } - - // MARK: - Tests - - func testSendMessageRequestFormation() { - // MARK: Test 1 - - // Setup. - var message = "Message" - var clientSideID = "1" - var dataJSONString = "{\"key\":\"value\"}" - var isHintQuestion = true - - // When: Sending message. - webimActions?.send(message: message, - clientSideID: clientSideID, - dataJSONString: dataJSONString, - isHintQuestion: isHintQuestion, - dataMessageCompletionHandler: nil) - - // Then: Request parameters should be like this. - - XCTAssertEqual(actionRequestLoop.webimRequest!.getHTTPMethod(), - AbstractRequestLoop.HTTPMethods.post) - - var expectedParametersDictionary = ["message" : message, - "client-side-id" : clientSideID, - "action" : "chat.message", - "hint_question" : "1", - "data" : dataJSONString] as [String : Any] - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["message"] as! String, - expectedParametersDictionary["message"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["client-side-id"] as! String, - expectedParametersDictionary["client-side-id"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["action"] as! String, - expectedParametersDictionary["action"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["hint_question"] as! String, - expectedParametersDictionary["hint_question"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["data"] as! String, - expectedParametersDictionary["data"] as! String) - - XCTAssertEqual(actionRequestLoop.webimRequest!.getContentType(), - WebimActions.ContentType.urlEncoded.rawValue) - - var expectedBaseURLString = "https://demo.webim.ru/l/v/m/action" - XCTAssertEqual(actionRequestLoop.webimRequest!.getBaseURLString(), - expectedBaseURLString) - XCTAssertNil(actionRequestLoop.webimRequest!.getDataMessageCompletionHandler()) - - // MARK: Test 1 - - // Setup. - message = "Message" - clientSideID = "1" - dataJSONString = "{\"key\":\"value\"}" - isHintQuestion = false - - // When: Sending message. - webimActions?.send(message: message, - clientSideID: clientSideID, - dataJSONString: dataJSONString, - isHintQuestion: isHintQuestion, - dataMessageCompletionHandler: nil) - - // Then: Request parameters should be like this. - - XCTAssertEqual(actionRequestLoop.webimRequest!.getHTTPMethod(), - AbstractRequestLoop.HTTPMethods.post) - - expectedParametersDictionary = ["message" : message, - "client-side-id" : clientSideID, - "action" : "chat.message", - "hint_question" : "0", - "data" : dataJSONString] as [String : Any] - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["message"] as! String, - expectedParametersDictionary["message"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["client-side-id"] as! String, - expectedParametersDictionary["client-side-id"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["action"] as! String, - expectedParametersDictionary["action"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["hint_question"] as! String, - expectedParametersDictionary["hint_question"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["data"] as! String, - expectedParametersDictionary["data"] as! String) - - XCTAssertEqual(actionRequestLoop.webimRequest!.getContentType(), - WebimActions.ContentType.urlEncoded.rawValue) - - expectedBaseURLString = "https://demo.webim.ru/l/v/m/action" - XCTAssertEqual(actionRequestLoop.webimRequest!.getBaseURLString(), - expectedBaseURLString) - } - - func testSendFileRequestFormation() { - // Setup. - let data = "1010".data(using: .utf8)! - let fileName = "file.jpg" - let mimeType = "image/jpeg" - let clientSideID = "1" - - // When: Sending file. - webimActions?.send(file: data, - filename: fileName, - mimeType: mimeType, - clientSideID: clientSideID, - completionHandler: nil) - - // Then: Request parameters should be like this. - - let boundaryString = actionRequestLoop.webimRequest!.getContentType()!.replacingOccurrences(of: "multipart/form-data; boundary=", - with: "") - let expectedHTTPBody = "--\(boundaryString)\r\n" - + "Content-Disposition: form-data; name=\"webim_upload_file\"; filename=\"\(fileName)\"\r\n" - + "Content-Type: \(mimeType)\r\n\r\n" - + "1010\r\n" - + "--\(boundaryString)--\r\n" - XCTAssertEqual(String(data: actionRequestLoop.webimRequest!.getHTTPBody()!, - encoding: .utf8), - expectedHTTPBody) - - XCTAssertEqual(actionRequestLoop.webimRequest!.getHTTPMethod(), - AbstractRequestLoop.HTTPMethods.post) - - let expectedParametersDictionary = ["chat-mode" : "online", - "client-side-id" : clientSideID] as [String : Any] - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["chat-mode"] as! String, - expectedParametersDictionary["chat-mode"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["client-side-id"] as! String, - expectedParametersDictionary["client-side-id"] as! String) - - XCTAssertEqual(actionRequestLoop.webimRequest!.getMessageID(), - clientSideID) - - let expectedBaseURLString = "https://demo.webim.ru/l/v/m/upload" - XCTAssertEqual(actionRequestLoop.webimRequest!.getBaseURLString(), - expectedBaseURLString) - - XCTAssertNil(actionRequestLoop.webimRequest!.getSendFileCompletionHandler()) - } - - func testStartChatRequestFormation() { - // Setup. - let message = "Message" - let clientSideID = "1" - let departmentKey = "Department" - - // When: Starting chat. - webimActions?.startChat(withClientSideID: clientSideID, - firstQuestion: message, - departmentKey: departmentKey) - - // Then: Request parameters should be like this. - - XCTAssertEqual(actionRequestLoop.webimRequest!.getHTTPMethod(), - AbstractRequestLoop.HTTPMethods.post) - - let expectedParametersDictionary = ["first-question" : message, - "client-side-id" : clientSideID, - "action" : "chat.start", - "force-online" : "1", - "department-key" : departmentKey] as [String : Any] - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["first-question"] as! String, - expectedParametersDictionary["first-question"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["client-side-id"] as! String, - expectedParametersDictionary["client-side-id"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["action"] as! String, - expectedParametersDictionary["action"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["force-online"] as! String, - expectedParametersDictionary["force-online"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["department-key"] as! String, - expectedParametersDictionary["department-key"] as! String) - - XCTAssertEqual(actionRequestLoop.webimRequest!.getContentType(), - WebimActions.ContentType.urlEncoded.rawValue) - - let expectedBaseURLString = "https://demo.webim.ru/l/v/m/action" - XCTAssertEqual(actionRequestLoop.webimRequest!.getBaseURLString(), - expectedBaseURLString) - } - - func testCloseChatRequestFormation() { - // When: Closing chat. - webimActions?.closeChat() - - // Then: Request parameters should be like this. - - XCTAssertEqual(actionRequestLoop.webimRequest!.getHTTPMethod(), - AbstractRequestLoop.HTTPMethods.post) - - let expectedParametersDictionary = ["action" : "chat.close"] as [String : Any] - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["action"] as! String, - expectedParametersDictionary["action"] as! String) - - XCTAssertEqual(actionRequestLoop.webimRequest!.getContentType(), - WebimActions.ContentType.urlEncoded.rawValue) - - let expectedBaseURLString = "https://demo.webim.ru/l/v/m/action" - XCTAssertEqual(actionRequestLoop.webimRequest!.getBaseURLString(), - expectedBaseURLString) - } - - func testSetVisitorTypingRequestFormation() { - // Setup. - let message = "Message" - let visitorTyping = true - let deleteDraft = false - - // When: Setting visitor is typing a draft. - webimActions?.set(visitorTyping: visitorTyping, - draft: message, - deleteDraft: deleteDraft) - - // Then: Request parameters should be like this. - - XCTAssertEqual(actionRequestLoop.webimRequest!.getHTTPMethod(), - AbstractRequestLoop.HTTPMethods.post) - - let expectedParametersDictionary = ["message-draft" : message, - "action" : "chat.visitor_typing", - "del-message-draft" : "0", - "typing" : "1"] as [String : Any] - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["message-draft"] as! String, - expectedParametersDictionary["message-draft"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["action"] as! String, - expectedParametersDictionary["action"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["del-message-draft"] as! String, - expectedParametersDictionary["del-message-draft"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["typing"] as! String, - expectedParametersDictionary["typing"] as! String) - - XCTAssertEqual(actionRequestLoop.webimRequest!.getContentType(), - WebimActions.ContentType.urlEncoded.rawValue) - - let expectedBaseURLString = "https://demo.webim.ru/l/v/m/action" - XCTAssertEqual(actionRequestLoop.webimRequest!.getBaseURLString(), - expectedBaseURLString) - } - - func testSetVisitorTypingEndRequestFormation() { - // Setup. - let visitorTyping = false - let deleteDraft = true - - // When: Setting visitor is typing a draft. - webimActions?.set(visitorTyping: visitorTyping, - draft: nil, - deleteDraft: deleteDraft) - - // Then: Request parameters should be like this. - - XCTAssertEqual(actionRequestLoop.webimRequest!.getHTTPMethod(), - AbstractRequestLoop.HTTPMethods.post) - - let expectedParametersDictionary = ["action" : "chat.visitor_typing", - "del-message-draft" : "1", - "typing" : "0"] as [String : Any] - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["action"] as! String, - expectedParametersDictionary["action"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["del-message-draft"] as! String, - expectedParametersDictionary["del-message-draft"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["typing"] as! String, - expectedParametersDictionary["typing"] as! String) - - XCTAssertEqual(actionRequestLoop.webimRequest!.getContentType(), - WebimActions.ContentType.urlEncoded.rawValue) - - let expectedBaseURLString = "https://demo.webim.ru/l/v/m/action" - XCTAssertEqual(actionRequestLoop.webimRequest!.getBaseURLString(), - expectedBaseURLString) - } - - func testRequestHistorySinceFormation() { - // Setup. - let since = "1" - - // When: Requesting history since. - let expectaion = XCTestExpectation() - webimActions?.requestHistory(since: since) { data in - expectaion.fulfill() - } - - // Then: Request parameters should be like this. - - try! actionRequestLoop.webimRequest!.getCompletionHandler()!(nil) - wait(for: [expectaion], - timeout: 1.0) - - XCTAssertEqual(actionRequestLoop.webimRequest!.getHTTPMethod(), - AbstractRequestLoop.HTTPMethods.get) - - let expectedParametersDictionary = ["since" : since] as [String : Any] - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["since"] as! String, - expectedParametersDictionary["since"] as! String) - - XCTAssertNil(actionRequestLoop.webimRequest!.getContentType()) - - let expectedBaseURLString = "https://demo.webim.ru/l/v/m/history" - XCTAssertEqual(actionRequestLoop.webimRequest!.getBaseURLString(), - expectedBaseURLString) - } - - func testRequestHistoryBeforeFormation() { - // Setup. - let before = "1" - - // When: Requesting history before. - let expectaion = XCTestExpectation() - webimActions?.requestHistory(beforeMessageTimestamp: Int64(before)!) { data in - expectaion.fulfill() - } - - // Then: Request parameters should be like this. - - try! actionRequestLoop.webimRequest!.getCompletionHandler()!(nil) - wait(for: [expectaion], - timeout: 1.0) - - XCTAssertEqual(actionRequestLoop.webimRequest!.getHTTPMethod(), - AbstractRequestLoop.HTTPMethods.get) - - let expectedParametersDictionary = ["before-ts" : before] as [String : Any] - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["before-ts"] as! String, - expectedParametersDictionary["before-ts"] as! String) - - XCTAssertNil(actionRequestLoop.webimRequest!.getContentType()) - - let expectedBaseURLString = "https://demo.webim.ru/l/v/m/history" - XCTAssertEqual(actionRequestLoop.webimRequest!.getBaseURLString(), - expectedBaseURLString) - } - - func testRateOperatorRequestFormation() { - // Setup. - let operatorID = "1" - let rating = "2" - - // When: Rating an operator. - webimActions?.rateOperatorWith(id: operatorID, - rating: Int(rating)!, - completionHandler: nil) - - // Then: Request parameters should be like this. - - XCTAssertEqual(actionRequestLoop.webimRequest!.getHTTPMethod(), - AbstractRequestLoop.HTTPMethods.post) - - let expectedParametersDictionary = ["action" : "chat.operator_rate_select", - "rate" : rating, - "operator_id" : operatorID] as [String : Any] - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["action"] as! String, - expectedParametersDictionary["action"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["rate"] as! String, - expectedParametersDictionary["rate"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["operator_id"] as! String, - expectedParametersDictionary["operator_id"] as! String) - - XCTAssertEqual(actionRequestLoop.webimRequest!.getContentType(), - WebimActions.ContentType.urlEncoded.rawValue) - - let expectedBaseURLString = "https://demo.webim.ru/l/v/m/action" - XCTAssertEqual(actionRequestLoop.webimRequest!.getBaseURLString(), - expectedBaseURLString) - - XCTAssertNil(actionRequestLoop.webimRequest!.getRateOperatorCompletionHandler()) - } - - func testUpdateDeviceTokenRequestFormation() { - // Setup. - let deviceToken = "1" - - // When: Updating device token. - webimActions?.update(deviceToken: deviceToken) - - // Then: Request parameters should be like this. - - XCTAssertEqual(actionRequestLoop.webimRequest!.getHTTPMethod(), - AbstractRequestLoop.HTTPMethods.post) - - let expectedParametersDictionary = ["action" : "set_push_token", - "push-token" : deviceToken] as [String : Any] - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["action"] as! String, - expectedParametersDictionary["action"] as! String) - XCTAssertEqual(actionRequestLoop.webimRequest!.getPrimaryData()["push-token"] as! String, - expectedParametersDictionary["push-token"] as! String) - - XCTAssertEqual(actionRequestLoop.webimRequest!.getContentType(), - WebimActions.ContentType.urlEncoded.rawValue) - - let expectedBaseURLString = "https://demo.webim.ru/l/v/m/action" - XCTAssertEqual(actionRequestLoop.webimRequest!.getBaseURLString(), - expectedBaseURLString) - } - -} diff --git a/ios/libs/Webim/Example/Tests/WebimClientTests.swift b/ios/libs/Webim/Example/Tests/WebimClientTests.swift deleted file mode 100644 index 342d2ca..0000000 --- a/ios/libs/Webim/Example/Tests/WebimClientTests.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// WebimClientTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 12.03.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class WebimClientTests: XCTestCase { - - // MARK: - Tests - - func testGetDeltaRequestLoop() { - let execIfNotDestroyedHandlerExecutor = ExecIfNotDestroyedHandlerExecutor(sessionDestroyer: SessionDestroyer(), - queue: DispatchQueue.main) - let internalErrorListener = InternalErrorListenerForTests() - let actionRequestLoop = ActionRequestLoopForTests(completionHandlerExecutor: execIfNotDestroyedHandlerExecutor, - internalErrorListener: internalErrorListener) - let urlString = "http://webim.ru" - let deltaRequestLoop = DeltaRequestLoop(deltaCallback: DeltaCallback(currentChatMessageMapper: CurrentChatMessageMapper(withServerURLString: urlString)), - completionHandlerExecutor: execIfNotDestroyedHandlerExecutor, - sessionParametersListener: nil, - internalErrorListener: internalErrorListener, - baseURL: urlString, - title: "title", - location: "location", - appVersion: nil, - visitorFieldsJSONString: nil, - providedAuthenticationTokenStateListener: nil, - providedAuthenticationToken: nil, - deviceID: "id", - deviceToken: nil, - visitorJSONString: nil, - sessionID: nil, - authorizationData: nil) - - let webimClient = WebimClient(withActionRequestLoop: actionRequestLoop, - deltaRequestLoop: deltaRequestLoop, - webimActions: WebimActions(baseURL: urlString, - actionRequestLoop: actionRequestLoop)) - - XCTAssertTrue(deltaRequestLoop === webimClient.getDeltaRequestLoop()) - } - - func testGetActions() { - let execIfNotDestroyedHandlerExecutor = ExecIfNotDestroyedHandlerExecutor(sessionDestroyer: SessionDestroyer(), - queue: DispatchQueue.main) - let internalErrorListener = InternalErrorListenerForTests() - let actionRequestLoop = ActionRequestLoopForTests(completionHandlerExecutor: execIfNotDestroyedHandlerExecutor, - internalErrorListener: internalErrorListener) - let urlString = "http://webim.ru" - let webimActions = WebimActions(baseURL: urlString, - actionRequestLoop: actionRequestLoop) - - let webimClient = WebimClient(withActionRequestLoop: actionRequestLoop, - deltaRequestLoop: DeltaRequestLoop(deltaCallback: DeltaCallback(currentChatMessageMapper: CurrentChatMessageMapper(withServerURLString: urlString)), - completionHandlerExecutor: execIfNotDestroyedHandlerExecutor, - sessionParametersListener: nil, - internalErrorListener: internalErrorListener, - baseURL: urlString, - title: "title", - location: "location", - appVersion: nil, - visitorFieldsJSONString: nil, - providedAuthenticationTokenStateListener: nil, - providedAuthenticationToken: nil, - deviceID: "id", - deviceToken: nil, - visitorJSONString: nil, - sessionID: nil, - authorizationData: nil), - webimActions: webimActions) - - XCTAssertTrue(webimActions === webimClient.getActions()) - } - -} diff --git a/ios/libs/Webim/Example/Tests/WebimErrorImplTests.swift b/ios/libs/Webim/Example/Tests/WebimErrorImplTests.swift deleted file mode 100644 index 7a93f63..0000000 --- a/ios/libs/Webim/Example/Tests/WebimErrorImplTests.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// WebimErrorImplTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 20.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -@testable import WebimClientLibrary -import XCTest - -class WebimErrorImplTests: XCTestCase { - - // MARK: - Tests - func testInit() { - var webimError = WebimErrorImpl(errorType: .ACCOUNT_BLOCKED, - errorString: nil) - - XCTAssertEqual(webimError.getErrorType(), - FatalErrorType.ACCOUNT_BLOCKED) - XCTAssertEqual(webimError.getErrorString(), - "ACCOUNT_BLOCKED") - - webimError = WebimErrorImpl(errorType: .UNKNOWN, - errorString: "Error") - - XCTAssertEqual(webimError.getErrorType(), - FatalErrorType.UNKNOWN) - XCTAssertEqual(webimError.getErrorString(), - "Error") - } - -} diff --git a/ios/libs/Webim/Example/Tests/WebimInternalLoggerTests.swift b/ios/libs/Webim/Example/Tests/WebimInternalLoggerTests.swift deleted file mode 100644 index a38d9db..0000000 --- a/ios/libs/Webim/Example/Tests/WebimInternalLoggerTests.swift +++ /dev/null @@ -1,112 +0,0 @@ -// -// WebimInternalLoggerTests.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 16.01.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -import XCTest -@testable import WebimClientLibrary - -class WebimInternalLoggerTests: XCTestCase { - - // MARK: - Properties - let webimInternalLogger = WebimInternalLogger.shared - var logEntry: String? - - // MARK: Methods - override func setUp() { - super.setUp() - - logEntry = nil - } - - // MARK: - Tests - func testSetup() { - // When: Low verbosity level installed and high verbosity level log message is send. - WebimInternalLogger.setup(webimLogger: self, - verbosityLevel: .ERROR) - webimInternalLogger.log(entry: "Test", - verbosityLevel: .VERBOSE) - - // Then: WebimLogger method should not be called. - XCTAssertNil(logEntry) - } - - func testLogWithSameVerbosityLevelIsPassed() { - // Setup. - let verbosityLevel = SessionBuilder.WebimLoggerVerbosityLevel.DEBUG - let logString = "Test" - - // When: Logger installed and log entry passed with the same verbosity level. - WebimInternalLogger.setup(webimLogger: self, - verbosityLevel: verbosityLevel) - webimInternalLogger.log(entry: logString, - verbosityLevel: verbosityLevel) - - // Then: Log entry should be passed to WebimLogger. - XCTAssertNotNil(logEntry) - } - - func testLogWithLowerVerbosityLevelIsPassed() { - // Setup. - let verbosityLevel = SessionBuilder.WebimLoggerVerbosityLevel.DEBUG - let higherVerbosityLevel = SessionBuilder.WebimLoggerVerbosityLevel.VERBOSE - let logString = "Test" - - // When: Logger installed and log entry passed with lower verbosity level. - WebimInternalLogger.setup(webimLogger: self, - verbosityLevel: higherVerbosityLevel) - webimInternalLogger.log(entry: logString, - verbosityLevel: verbosityLevel) - - // Then: Log entry should be passed to WebimLogger. - XCTAssertNotNil(logEntry) - } - - func testLogWithHigherVerbosityLevelIsNotPassed() { - // Setup. - let verbosityLevel = SessionBuilder.WebimLoggerVerbosityLevel.DEBUG - let lowerVerbosityLevel = SessionBuilder.WebimLoggerVerbosityLevel.INFO - let logString = "Test" - - // When: Logger installed and log entry passed with higher verbosity level. - WebimInternalLogger.setup(webimLogger: self, - verbosityLevel: lowerVerbosityLevel) - webimInternalLogger.log(entry: logString, - verbosityLevel: verbosityLevel) - - // Then: Log entry should be passed to WebimLogger. - XCTAssertNil(logEntry) - } - -} - -// MARK: - WebimLogger -extension WebimInternalLoggerTests: WebimLogger { - - func log(entry: String) { - logEntry = entry - } - -} diff --git a/ios/libs/Webim/Example/Tests/WebimRemoteNotificationImplTests.swift b/ios/libs/Webim/Example/Tests/WebimRemoteNotificationImplTests.swift deleted file mode 100644 index 0ee4b50..0000000 --- a/ios/libs/Webim/Example/Tests/WebimRemoteNotificationImplTests.swift +++ /dev/null @@ -1,150 +0,0 @@ -// -// WebimRemoteNotificationImplTests.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 30.01.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -import XCTest -@testable import WebimClientLibrary - -class WebimRemoteNotificationImplTests: XCTestCase { - - // MARK: - Tests - - func testContactRequestNotification() { - // Setup. - let notificationDictionary = ["loc-key" : "P.CR"] as [String : Any] - - // When: Receiving contact request notification. - let webimRemoteNotification = WebimRemoteNotificationImpl(jsonDictionary: notificationDictionary) - - // Then: Parameters should be ruturned like this. - XCTAssertNil(webimRemoteNotification?.getEvent()) - XCTAssertTrue(webimRemoteNotification!.getParameters().isEmpty) - XCTAssertEqual(webimRemoteNotification?.getType(), - NotificationType.CONTACT_INFORMATION_REQUEST) - } - - func testOperatorAcceptedNotification() { - // Setup. - let notificationDictionary = ["loc-key" : "P.OA", - "loc-args" : ["Operator"]] as [String : Any] - - // When: Receiving operator accepted notification. - let webimRemoteNotification = WebimRemoteNotificationImpl(jsonDictionary: notificationDictionary) - - // Then: Parameters should be ruturned like this. - XCTAssertNil(webimRemoteNotification?.getEvent()) - XCTAssertTrue(webimRemoteNotification?.getParameters().count == 1) - XCTAssertEqual(webimRemoteNotification?.getType(), - NotificationType.OPERATOR_ACCEPTED) - } - - func testOperatorFileNotification() { - // Setup. - let notificationDictionary = ["loc-key" : "P.OF", - "loc-args" : ["Operator", - "File"], - "event" : "add"] as [String : Any] - - // When: Receiving operator file adding notification. - let webimRemoteNotification = WebimRemoteNotificationImpl(jsonDictionary: notificationDictionary) - - // Then: Parameters should be ruturned like this. - XCTAssertEqual(webimRemoteNotification?.getEvent(), NotificationEvent.ADD) - XCTAssertTrue(webimRemoteNotification?.getParameters().count == 2) - XCTAssertEqual(webimRemoteNotification?.getType(), - NotificationType.OPERATOR_FILE) - } - - func testOperatorMessageNotification() { - // Setup. - let notificationDictionary = ["loc-key" : "P.OM", - "loc-args" : ["Operator", - "Message"], - "event" : "del"] as [String : Any] - - // When: Receiving operator message deleting notification. - let webimRemoteNotification = WebimRemoteNotificationImpl(jsonDictionary: notificationDictionary) - - // Then: Parameters should be ruturned like this. - XCTAssertEqual(webimRemoteNotification?.getEvent(), NotificationEvent.DELETE) - XCTAssertTrue(webimRemoteNotification?.getParameters().count == 2) - XCTAssertEqual(webimRemoteNotification?.getType(), - NotificationType.OPERATOR_MESSAGE) - } - - func testWidgetNotification() { - // Setup. - let notificationDictionary = ["loc-key" : "P.WM"] as [String : Any] - - // When: Receiving contact request notification. - let webimRemoteNotification = WebimRemoteNotificationImpl(jsonDictionary: notificationDictionary) - - // Then: Parameters should be ruturned like this. - XCTAssertNil(webimRemoteNotification?.getEvent()) - XCTAssertTrue(webimRemoteNotification!.getParameters().isEmpty) - XCTAssertEqual(webimRemoteNotification?.getType(), - NotificationType.WIDGET) - } - - func testUnsupportedType() { - // Setup. - let notificationDictionary = ["loc-key" : "NewType"] as [String : Any] - - // When: Receiving notification of unsupported type. - let webimRemoteNotification = WebimRemoteNotificationImpl(jsonDictionary: notificationDictionary) - - // Then: WebimRemoteNotification object should be nil. - XCTAssertNil(webimRemoteNotification) - } - - func testUnsupportedEvent() { - // Setup. - let notificationDictionary = ["loc-key" : "P.OM", - "loc-args" : ["Operator", - "Message"], - "event" : "NewEvent"] as [String : Any] - - // When: Receiving notification of unsupported type. - let webimRemoteNotification = WebimRemoteNotificationImpl(jsonDictionary: notificationDictionary) - - // Then: Event should be nil. - XCTAssertNil(webimRemoteNotification?.getEvent()) - } - - func testEmptyTypeNotification() { - // Setup. - let notificationDictionary = ["loc-args" : ["Operator", - "Message"], - "event" : "del"] as [String : Any] - - // When: Receiving notification without type. - let webimRemoteNotification = WebimRemoteNotificationImpl(jsonDictionary: notificationDictionary) - - // Then: WebimRemoteNotification object should be nil. - XCTAssertNil(webimRemoteNotification) - } - -} diff --git a/ios/libs/Webim/Example/Tests/WebimTests.swift b/ios/libs/Webim/Example/Tests/WebimTests.swift deleted file mode 100644 index 2f4d459..0000000 --- a/ios/libs/Webim/Example/Tests/WebimTests.swift +++ /dev/null @@ -1,94 +0,0 @@ -// -// WebimTests.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 15.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -import WebimClientLibrary -import XCTest - -class WebimTests: XCTestCase { - - // MARK: - Constants - private static let WEBIM_REMOTE_NOTIFICATION_JSON_STRING = """ -{ - "aps" : { - "alert" : { - "loc-key" : "P.OM", - "loc-args" : ["Имя Оператора", "Сообщение"] - }, - "sound" : "default", - }, - "webim": 1 -} -""" - private static let NOT_WEBIM_REMOTE_NOTIFICATION_JSON_STRING = """ -{ - "aps" : { - "alert" : { - "loc-key" : "P.OM", - "loc-args" : ["Имя Оператора", "Сообщение"] - }, - "sound" : "default", - } -} -""" - private static let INCORRECT_REMOTE_NOTIFICATION_JSON_STRING = """ -{ - "alert" : { - "loc-key" : "P.OM", - "loc-args" : ["Имя Оператора", "Сообщение"] - }, - "sound" : "default", -} -""" - - // MARK: - Properties - let webimRemoteNotification = try! JSONSerialization.jsonObject(with: WebimTests.WEBIM_REMOTE_NOTIFICATION_JSON_STRING.data(using: .utf8)!, - options: []) as! [AnyHashable : Any] - let notWebimRemoteNotification = try! JSONSerialization.jsonObject(with: WebimTests.NOT_WEBIM_REMOTE_NOTIFICATION_JSON_STRING.data(using: .utf8)!, - options: []) as! [AnyHashable : Any] - let incorrectRemoteNotification = try! JSONSerialization.jsonObject(with: WebimTests.INCORRECT_REMOTE_NOTIFICATION_JSON_STRING.data(using: .utf8)!, - options: []) as! [AnyHashable : Any] - - // MARK: - Tests - - func testParseRemoteNotification() { - let webimRemoteNotification = Webim.parse(remoteNotification: self.webimRemoteNotification)! - - XCTAssertNil(webimRemoteNotification.getEvent()) - XCTAssertEqual(webimRemoteNotification.getParameters(), ["Имя Оператора", - "Сообщение"]) - XCTAssertEqual(webimRemoteNotification.getType(), - NotificationType.OPERATOR_MESSAGE) - - XCTAssertNil(Webim.parse(remoteNotification: self.incorrectRemoteNotification)) - } - - func testIsWebimRemoteNotificatin() { - XCTAssertTrue(Webim.isWebim(remoteNotification: webimRemoteNotification)) - XCTAssertFalse(Webim.isWebim(remoteNotification: notWebimRemoteNotification)) - } - -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary.xcodeproj/project.pbxproj b/ios/libs/Webim/Example/WebimClientLibrary.xcodeproj/project.pbxproj deleted file mode 100644 index 648bf24..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary.xcodeproj/project.pbxproj +++ /dev/null @@ -1,1054 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 3BD523E036E5E0145C40A893 /* Pods_WebimClientLibrary_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 75BFCD5FB1955EE77D987E3C /* Pods_WebimClientLibrary_Tests.framework */; }; - 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD51AFB9204008FA782 /* AppDelegate.swift */; }; - 607FACD81AFB9204008FA782 /* StartViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD71AFB9204008FA782 /* StartViewController.swift */; }; - 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; }; - 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; }; - 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; }; - 607FACEC1AFB9204008FA782 /* MessageHolderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACEB1AFB9204008FA782 /* MessageHolderTests.swift */; }; - BDBBA7998D78E4CE2C982C3E /* Pods_WebimClientLibrary_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5A6DD52DA6213CB92530809 /* Pods_WebimClientLibrary_Example.framework */; }; - CE07E9952049794C00E0A0D3 /* SessionBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE07E993204972C600E0A0D3 /* SessionBuilderTests.swift */; }; - CE0CD75A202338FD00719DBE /* HistoryIDTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0CD758202338EE00719DBE /* HistoryIDTests.swift */; }; - CE0CD75D20234BD800719DBE /* SessionDestroyerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0CD75B20234BD500719DBE /* SessionDestroyerTests.swift */; }; - CE0CD7632024561B00719DBE /* InternalUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0CD7622024561B00719DBE /* InternalUtilsTests.swift */; }; - CE0CD765202461FE00719DBE /* StringFromHTTPParametersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0CD764202461FE00719DBE /* StringFromHTTPParametersTests.swift */; }; - CE0CD76720249C3E00719DBE /* OperatorImplTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0CD76620249C3E00719DBE /* OperatorImplTests.swift */; }; - CE18FB9A203DA3890059B9FF /* AccessCheckerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE18FB99203DA3890059B9FF /* AccessCheckerTests.swift */; }; - CE18FB9C203DB32E0059B9FF /* LocationSettingsHolderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE18FB9B203DB32E0059B9FF /* LocationSettingsHolderTests.swift */; }; - CE18FB9E203EBCB00059B9FF /* MessageStreamImplTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE18FB9D203EBCB00059B9FF /* MessageStreamImplTests.swift */; }; - CE1FC99E202333B20090F7E6 /* ExecIfNotDestroyedHandlerExecutorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE1FC99D202333B20090F7E6 /* ExecIfNotDestroyedHandlerExecutorTests.swift */; }; - CE24A00E20372239009EE7E7 /* DepartmentItemTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE24A00D20372239009EE7E7 /* DepartmentItemTests.swift */; }; - CE24A01020372629009EE7E7 /* FileParametersItemTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE24A00F20372629009EE7E7 /* FileParametersItemTests.swift */; }; - CE24A012203730D5009EE7E7 /* MessageItemTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE24A011203730D5009EE7E7 /* MessageItemTests.swift */; }; - CE24A014203735C8009EE7E7 /* OperatorItemTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE24A013203735C8009EE7E7 /* OperatorItemTests.swift */; }; - CE24A019203ADF40009EE7E7 /* RatingItemTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE24A018203ADF40009EE7E7 /* RatingItemTests.swift */; }; - CE2845B82020A891007B1C25 /* AbstractRequestLoopTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2845B62020A88D007B1C25 /* AbstractRequestLoopTests.swift */; }; - CE2845BB2020B6A3007B1C25 /* ActionRequestLoopTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2845B92020B687007B1C25 /* ActionRequestLoopTests.swift */; }; - CE2845BE2020B718007B1C25 /* ActionRequestLoopMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2845BC2020B70A007B1C25 /* ActionRequestLoopMock.swift */; }; - CE2845C22021B9D4007B1C25 /* DecodePercentEscapedLinksIfPresentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2845C02021B9BC007B1C25 /* DecodePercentEscapedLinksIfPresentTests.swift */; }; - CE2845C42021C2BF007B1C25 /* AuthorizationDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2845C32021C2BF007B1C25 /* AuthorizationDataTests.swift */; }; - CE2845C62021CF40007B1C25 /* ClientSideIDTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2845C52021CF40007B1C25 /* ClientSideIDTests.swift */; }; - CE2845C82021DBE5007B1C25 /* DeltaRequestLoopTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2845C72021DBE5007B1C25 /* DeltaRequestLoopTests.swift */; }; - CE2CD5952035DF6E00997628 /* MemoryHistoryMetaInformationStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2CD5942035DF6E00997628 /* MemoryHistoryMetaInformationStorageTests.swift */; }; - CE2CD5972035F12600997628 /* ChatItemTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2CD5962035F12600997628 /* ChatItemTests.swift */; }; - CE324E631FDECBD2004BB116 /* RatingViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE324E651FDECBD2004BB116 /* RatingViewController.xib */; }; - CE380424202B0AC2003032D4 /* SettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE380423202B0AC2003032D4 /* SettingsTableViewController.swift */; }; - CE380426202B3526003032D4 /* ColorScheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE380425202B3526003032D4 /* ColorScheme.swift */; }; - CE44AE651F87CA8E009787E5 /* MessageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE44AE641F87CA8E009787E5 /* MessageTableViewCell.swift */; }; - CE45EDDD1F9108FA00F56319 /* UIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE45EDDC1F9108FA00F56319 /* UIImageView.swift */; }; - CE45EDE01F95F9F700F56319 /* MimeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE45EDDF1F95F95C00F56319 /* MimeType.swift */; }; - CE48362C2031DA5E00E18A20 /* MimeTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE48362B2031DA5E00E18A20 /* MimeTypeTests.swift */; }; - CE48362F2032E3F100E18A20 /* PopupDialogHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE48362D2032E0D900E18A20 /* PopupDialogHandler.swift */; }; - CE591A431FC2F31E004C95EE /* WebimService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE591A421FC2F31E004C95EE /* WebimService.swift */; }; - CE5A03BA1FDEB756009D320A /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = CE5A03BC1FDEB756009D320A /* Localizable.strings */; }; - CE5B7E5C20500A6F00DDA407 /* ProvidedVisitorFieldsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE5B7E5B20500A6F00DDA407 /* ProvidedVisitorFieldsTests.swift */; }; - CE5B7E622056B26C00DDA407 /* WebimClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE5B7E612056B26C00DDA407 /* WebimClientTests.swift */; }; - CE6741C8200F9A600061EEFD /* HMACSha256Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE6741C7200F9A600061EEFD /* HMACSha256Tests.swift */; }; - CE86FA97203AF44700CB9C2D /* VisitorItemTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE86FA96203AF44700CB9C2D /* VisitorItemTests.swift */; }; - CE86FA99203AF6AC00CB9C2D /* UIColorHexStringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE86FA98203AF6AC00CB9C2D /* UIColorHexStringTests.swift */; }; - CE86FA9B203AFBFB00CB9C2D /* DeltaItemTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE86FA9A203AFBFB00CB9C2D /* DeltaItemTests.swift */; }; - CE86FA9D203B009400CB9C2D /* FullUpdateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE86FA9C203B009400CB9C2D /* FullUpdateTests.swift */; }; - CE86FA9F203B07F400CB9C2D /* DeltaResponseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE86FA9E203B07F400CB9C2D /* DeltaResponseTests.swift */; }; - CE86FAA1203B0B1600CB9C2D /* HistoryBeforeResponseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE86FAA0203B0B1600CB9C2D /* HistoryBeforeResponseTests.swift */; }; - CE86FAA3203B122A00CB9C2D /* HistorySinceResponseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE86FAA2203B122A00CB9C2D /* HistorySinceResponseTests.swift */; }; - CE86FAA5203B1B7300CB9C2D /* MessageFactoriesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE86FAA4203B1B7300CB9C2D /* MessageFactoriesTests.swift */; }; - CE86FAAF203B2D1800CB9C2D /* OperatorFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE86FAAE203B2D1800CB9C2D /* OperatorFactoryTests.swift */; }; - CE86FAB1203C18D600CB9C2D /* DepartmentFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE86FAB0203C18D600CB9C2D /* DepartmentFactoryTests.swift */; }; - CE86FAB3203C1E8500CB9C2D /* SQLiteHistoryStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE86FAB2203C1E8500CB9C2D /* SQLiteHistoryStorageTests.swift */; }; - CE86FAB8203C48DA00CB9C2D /* MemoryHistoryStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE86FAB7203C48DA00CB9C2D /* MemoryHistoryStorageTests.swift */; }; - CE86FABC203C664F00CB9C2D /* LocationSettingsImplTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE86FABB203C664F00CB9C2D /* LocationSettingsImplTests.swift */; }; - CE86FABE203C686600CB9C2D /* MessageImplTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE86FABD203C686600CB9C2D /* MessageImplTests.swift */; }; - CE86FAC0203C6FBC00CB9C2D /* WebimErrorImplTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE86FABF203C6FBC00CB9C2D /* WebimErrorImplTests.swift */; }; - CE88BCD11FCD7F9A00A4FA2E /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE88BCD01FCD7F9A00A4FA2E /* SettingsViewController.swift */; }; - CE88BCD31FCD88EA00A4FA2E /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE88BCD21FCD88EA00A4FA2E /* Settings.swift */; }; - CE88BCD51FCDA45C00A4FA2E /* ButtonConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE88BCD41FCDA45C00A4FA2E /* ButtonConstants.swift */; }; - CE995DC32020908F00E27A3C /* WebimRemoteNotificationImplTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE995DC12020904300E27A3C /* WebimRemoteNotificationImplTests.swift */; }; - CEA832681F9906C0004845F0 /* ColorConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA832671F9906BF004845F0 /* ColorConstants.swift */; }; - CEA8326A1F99079A004845F0 /* StringConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA832691F99079A004845F0 /* StringConstants.swift */; }; - CEA849051FFCE29A006CC417 /* UITableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA849041FFCE29A006CC417 /* UITableView.swift */; }; - CEBFB67F2018CB0F00D9E5F6 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEBFB67E2018CB0F00D9E5F6 /* String.swift */; }; - CEBFB6812018E50500D9E5F6 /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEBFB6802018E50500D9E5F6 /* UIViewController.swift */; }; - CED3BA08201F7E100071EC23 /* WebimActionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CED3BA07201F7E100071EC23 /* WebimActionsTests.swift */; }; - CED3BA0B201F87510071EC23 /* InternalErrorListenerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = CED3BA0A201F87510071EC23 /* InternalErrorListenerMock.swift */; }; - CED72596200E20EF00CD1623 /* ChatViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CED72594200E20E500CD1623 /* ChatViewControllerTests.swift */; }; - CED72599200E5B2200CD1623 /* WebimInternalLoggerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CED72597200E5B1C00CD1623 /* WebimInternalLoggerTests.swift */; }; - CEE382C22035D544006C809E /* WebimTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEE382C12035D544006C809E /* WebimTests.swift */; }; - CEF61A391F82A4C700BF7071 /* ChatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEF61A381F82A4C700BF7071 /* ChatViewController.swift */; }; - DDFC632B1F924D41008E1ACC /* UIImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFC632A1F924D41008E1ACC /* UIImage.swift */; }; - DDFC63CB1F93F23E008E1ACC /* RatingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFC63CA1F93F23E008E1ACC /* RatingViewController.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 607FACE61AFB9204008FA782 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 607FACC81AFB9204008FA782 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 607FACCF1AFB9204008FA782; - remoteInfo = WebimClientLibrary; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 188E01CE8A86B2460C60C156 /* Pods-WebimClientLibrary_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WebimClientLibrary_Tests.release.xcconfig"; path = "Target Support Files/Pods-WebimClientLibrary_Tests/Pods-WebimClientLibrary_Tests.release.xcconfig"; sourceTree = ""; }; - 607FACD01AFB9204008FA782 /* WebimClientLibrary_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WebimClientLibrary_Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 607FACD41AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 607FACD51AFB9204008FA782 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 607FACD71AFB9204008FA782 /* StartViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartViewController.swift; sourceTree = ""; }; - 607FACDA1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 607FACDC1AFB9204008FA782 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; - 607FACDF1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; - 607FACE51AFB9204008FA782 /* WebimClientLibrary_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WebimClientLibrary_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 607FACEB1AFB9204008FA782 /* MessageHolderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageHolderTests.swift; sourceTree = ""; }; - 75BFCD5FB1955EE77D987E3C /* Pods_WebimClientLibrary_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_WebimClientLibrary_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 998795E306696F247C099BA2 /* Pods-WebimClientLibrary_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WebimClientLibrary_Tests.debug.xcconfig"; path = "Target Support Files/Pods-WebimClientLibrary_Tests/Pods-WebimClientLibrary_Tests.debug.xcconfig"; sourceTree = ""; }; - 9F85297EB410C96E5341BFCC /* Pods-WebimClientLibrary_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WebimClientLibrary_Example.release.xcconfig"; path = "Target Support Files/Pods-WebimClientLibrary_Example/Pods-WebimClientLibrary_Example.release.xcconfig"; sourceTree = ""; }; - AB52E1C1E0F009A386DC1C6C /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; - C4CD65CA48F80B5A4AD826B3 /* WebimClientLibrary.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = WebimClientLibrary.podspec; path = ../WebimClientLibrary.podspec; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; - CE07E993204972C600E0A0D3 /* SessionBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionBuilderTests.swift; sourceTree = ""; }; - CE0AD26F1F96477500EA9148 /* WebimClientLibrary_Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WebimClientLibrary_Example.entitlements; sourceTree = ""; }; - CE0CD758202338EE00719DBE /* HistoryIDTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryIDTests.swift; sourceTree = ""; }; - CE0CD75B20234BD500719DBE /* SessionDestroyerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionDestroyerTests.swift; sourceTree = ""; }; - CE0CD7622024561B00719DBE /* InternalUtilsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternalUtilsTests.swift; sourceTree = ""; }; - CE0CD764202461FE00719DBE /* StringFromHTTPParametersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringFromHTTPParametersTests.swift; sourceTree = ""; }; - CE0CD76620249C3E00719DBE /* OperatorImplTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperatorImplTests.swift; sourceTree = ""; }; - CE18FB99203DA3890059B9FF /* AccessCheckerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessCheckerTests.swift; sourceTree = ""; }; - CE18FB9B203DB32E0059B9FF /* LocationSettingsHolderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationSettingsHolderTests.swift; sourceTree = ""; }; - CE18FB9D203EBCB00059B9FF /* MessageStreamImplTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageStreamImplTests.swift; sourceTree = ""; }; - CE1FC99D202333B20090F7E6 /* ExecIfNotDestroyedHandlerExecutorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExecIfNotDestroyedHandlerExecutorTests.swift; sourceTree = ""; }; - CE24A00D20372239009EE7E7 /* DepartmentItemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DepartmentItemTests.swift; sourceTree = ""; }; - CE24A00F20372629009EE7E7 /* FileParametersItemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileParametersItemTests.swift; sourceTree = ""; }; - CE24A011203730D5009EE7E7 /* MessageItemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageItemTests.swift; sourceTree = ""; }; - CE24A013203735C8009EE7E7 /* OperatorItemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperatorItemTests.swift; sourceTree = ""; }; - CE24A016203ADC88009EE7E7 /* Logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Logo.png; sourceTree = ""; }; - CE24A018203ADF40009EE7E7 /* RatingItemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RatingItemTests.swift; sourceTree = ""; }; - CE2845B62020A88D007B1C25 /* AbstractRequestLoopTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AbstractRequestLoopTests.swift; sourceTree = ""; }; - CE2845B92020B687007B1C25 /* ActionRequestLoopTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionRequestLoopTests.swift; sourceTree = ""; }; - CE2845BC2020B70A007B1C25 /* ActionRequestLoopMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionRequestLoopMock.swift; sourceTree = ""; }; - CE2845C02021B9BC007B1C25 /* DecodePercentEscapedLinksIfPresentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecodePercentEscapedLinksIfPresentTests.swift; sourceTree = ""; }; - CE2845C32021C2BF007B1C25 /* AuthorizationDataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthorizationDataTests.swift; sourceTree = ""; }; - CE2845C52021CF40007B1C25 /* ClientSideIDTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientSideIDTests.swift; sourceTree = ""; }; - CE2845C72021DBE5007B1C25 /* DeltaRequestLoopTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeltaRequestLoopTests.swift; sourceTree = ""; }; - CE2CD5942035DF6E00997628 /* MemoryHistoryMetaInformationStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryHistoryMetaInformationStorageTests.swift; sourceTree = ""; }; - CE2CD5962035F12600997628 /* ChatItemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemTests.swift; sourceTree = ""; }; - CE324E661FDECBE0004BB116 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/RatingViewController.xib; sourceTree = ""; }; - CE380423202B0AC2003032D4 /* SettingsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableViewController.swift; sourceTree = ""; }; - CE380425202B3526003032D4 /* ColorScheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorScheme.swift; sourceTree = ""; }; - CE44AE641F87CA8E009787E5 /* MessageTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageTableViewCell.swift; sourceTree = ""; }; - CE45EDDC1F9108FA00F56319 /* UIImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIImageView.swift; sourceTree = ""; }; - CE45EDDF1F95F95C00F56319 /* MimeType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MimeType.swift; sourceTree = ""; }; - CE48362B2031DA5E00E18A20 /* MimeTypeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MimeTypeTests.swift; sourceTree = ""; }; - CE48362D2032E0D900E18A20 /* PopupDialogHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopupDialogHandler.swift; sourceTree = ""; }; - CE54B2511FC452B9009C05BD /* Index.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Index.md; sourceTree = ""; }; - CE591A421FC2F31E004C95EE /* WebimService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebimService.swift; sourceTree = ""; }; - CE5A03BB1FDEB756009D320A /* ru-RU */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ru-RU"; path = "ru-RU.lproj/Localizable.strings"; sourceTree = ""; }; - CE5B7E5B20500A6F00DDA407 /* ProvidedVisitorFieldsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProvidedVisitorFieldsTests.swift; sourceTree = ""; }; - CE5B7E612056B26C00DDA407 /* WebimClientTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebimClientTests.swift; sourceTree = ""; }; - CE6741C7200F9A600061EEFD /* HMACSha256Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMACSha256Tests.swift; sourceTree = ""; }; - CE86FA96203AF44700CB9C2D /* VisitorItemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisitorItemTests.swift; sourceTree = ""; }; - CE86FA98203AF6AC00CB9C2D /* UIColorHexStringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIColorHexStringTests.swift; sourceTree = ""; }; - CE86FA9A203AFBFB00CB9C2D /* DeltaItemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeltaItemTests.swift; sourceTree = ""; }; - CE86FA9C203B009400CB9C2D /* FullUpdateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullUpdateTests.swift; sourceTree = ""; }; - CE86FA9E203B07F400CB9C2D /* DeltaResponseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeltaResponseTests.swift; sourceTree = ""; }; - CE86FAA0203B0B1600CB9C2D /* HistoryBeforeResponseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryBeforeResponseTests.swift; sourceTree = ""; }; - CE86FAA2203B122A00CB9C2D /* HistorySinceResponseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistorySinceResponseTests.swift; sourceTree = ""; }; - CE86FAA4203B1B7300CB9C2D /* MessageFactoriesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageFactoriesTests.swift; sourceTree = ""; }; - CE86FAAE203B2D1800CB9C2D /* OperatorFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperatorFactoryTests.swift; sourceTree = ""; }; - CE86FAB0203C18D600CB9C2D /* DepartmentFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DepartmentFactoryTests.swift; sourceTree = ""; }; - CE86FAB2203C1E8500CB9C2D /* SQLiteHistoryStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SQLiteHistoryStorageTests.swift; sourceTree = ""; }; - CE86FAB7203C48DA00CB9C2D /* MemoryHistoryStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryHistoryStorageTests.swift; sourceTree = ""; }; - CE86FABB203C664F00CB9C2D /* LocationSettingsImplTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationSettingsImplTests.swift; sourceTree = ""; }; - CE86FABD203C686600CB9C2D /* MessageImplTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageImplTests.swift; sourceTree = ""; }; - CE86FABF203C6FBC00CB9C2D /* WebimErrorImplTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebimErrorImplTests.swift; sourceTree = ""; }; - CE88BCD01FCD7F9A00A4FA2E /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SettingsViewController.swift; path = WebimClientLibrary/SettingsViewController.swift; sourceTree = SOURCE_ROOT; }; - CE88BCD21FCD88EA00A4FA2E /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = ""; }; - CE88BCD41FCDA45C00A4FA2E /* ButtonConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonConstants.swift; sourceTree = ""; }; - CE9379091FEAADC80057E270 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; - CE995DC12020904300E27A3C /* WebimRemoteNotificationImplTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebimRemoteNotificationImplTests.swift; sourceTree = ""; }; - CEA832671F9906BF004845F0 /* ColorConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorConstants.swift; sourceTree = ""; }; - CEA832691F99079A004845F0 /* StringConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringConstants.swift; sourceTree = ""; }; - CEA849041FFCE29A006CC417 /* UITableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITableView.swift; sourceTree = ""; }; - CEBFB67E2018CB0F00D9E5F6 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; }; - CEBFB6802018E50500D9E5F6 /* UIViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewController.swift; sourceTree = ""; }; - CEC27878202DDB760043899C /* ru-RU */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ru-RU"; path = "ru-RU.lproj/Main.strings"; sourceTree = ""; }; - CEC27879202DDD920043899C /* ru-RU */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ru-RU"; path = "ru-RU.lproj/RatingViewController.strings"; sourceTree = ""; }; - CED02E152031C52E000508C9 /* ChatScreenClassic.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ChatScreenClassic.png; sourceTree = ""; }; - CED02E182031C52E000508C9 /* ChatScreenDark.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ChatScreenDark.png; sourceTree = ""; }; - CED02E242031C5F2000508C9 /* RatingScreenClassic.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = RatingScreenClassic.png; sourceTree = ""; }; - CED02E252031C5F2000508C9 /* SettingsScreenDark.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = SettingsScreenDark.png; sourceTree = ""; }; - CED02E262031C5F2000508C9 /* RatingScreenDark.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = RatingScreenDark.png; sourceTree = ""; }; - CED02E272031C5F3000508C9 /* ImageScreenDark.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ImageScreenDark.png; sourceTree = ""; }; - CED02E282031C5F3000508C9 /* StartScreenDark.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = StartScreenDark.png; sourceTree = ""; }; - CED02E292031C5F3000508C9 /* StartScreenClassic.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = StartScreenClassic.png; sourceTree = ""; }; - CED02E2A2031C5F3000508C9 /* SettingsScreenClassic.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = SettingsScreenClassic.png; sourceTree = ""; }; - CED02E2B2031C5F3000508C9 /* ImageScreenClassic.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ImageScreenClassic.png; sourceTree = ""; }; - CED3BA07201F7E100071EC23 /* WebimActionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebimActionsTests.swift; sourceTree = ""; }; - CED3BA0A201F87510071EC23 /* InternalErrorListenerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternalErrorListenerMock.swift; sourceTree = ""; }; - CED72594200E20E500CD1623 /* ChatViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatViewControllerTests.swift; sourceTree = ""; }; - CED72597200E5B1C00CD1623 /* WebimInternalLoggerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebimInternalLoggerTests.swift; sourceTree = ""; }; - CEE382C12035D544006C809E /* WebimTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebimTests.swift; sourceTree = ""; }; - CEF61A381F82A4C700BF7071 /* ChatViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatViewController.swift; sourceTree = ""; }; - D5A6DD52DA6213CB92530809 /* Pods_WebimClientLibrary_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_WebimClientLibrary_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - DDFC632A1F924D41008E1ACC /* UIImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIImage.swift; sourceTree = ""; }; - DDFC63CA1F93F23E008E1ACC /* RatingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RatingViewController.swift; sourceTree = ""; }; - EB8C258A78F3730770936414 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; - F0808D307D6955C0CC345203 /* Pods-WebimClientLibrary_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WebimClientLibrary_Example.debug.xcconfig"; path = "Target Support Files/Pods-WebimClientLibrary_Example/Pods-WebimClientLibrary_Example.debug.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 607FACCD1AFB9204008FA782 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - BDBBA7998D78E4CE2C982C3E /* Pods_WebimClientLibrary_Example.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 607FACE21AFB9204008FA782 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 3BD523E036E5E0145C40A893 /* Pods_WebimClientLibrary_Tests.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 3C3DB6CF3A0FDD8E0CD44FD9 /* Pods */ = { - isa = PBXGroup; - children = ( - F0808D307D6955C0CC345203 /* Pods-WebimClientLibrary_Example.debug.xcconfig */, - 9F85297EB410C96E5341BFCC /* Pods-WebimClientLibrary_Example.release.xcconfig */, - 998795E306696F247C099BA2 /* Pods-WebimClientLibrary_Tests.debug.xcconfig */, - 188E01CE8A86B2460C60C156 /* Pods-WebimClientLibrary_Tests.release.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; - 607FACC71AFB9204008FA782 = { - isa = PBXGroup; - children = ( - CE54B2501FC45274009C05BD /* Documentation */, - 607FACF51AFB993E008FA782 /* Podspec Metadata */, - CE0AD26F1F96477500EA9148 /* WebimClientLibrary_Example.entitlements */, - 607FACD21AFB9204008FA782 /* Example for WebimClientLibrary */, - 607FACE81AFB9204008FA782 /* Tests */, - 607FACD11AFB9204008FA782 /* Products */, - 3C3DB6CF3A0FDD8E0CD44FD9 /* Pods */, - D6405400012B6906279A6D61 /* Frameworks */, - ); - sourceTree = ""; - }; - 607FACD11AFB9204008FA782 /* Products */ = { - isa = PBXGroup; - children = ( - 607FACD01AFB9204008FA782 /* WebimClientLibrary_Example.app */, - 607FACE51AFB9204008FA782 /* WebimClientLibrary_Tests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 607FACD21AFB9204008FA782 /* Example for WebimClientLibrary */ = { - isa = PBXGroup; - children = ( - CEC2787A2031A0110043899C /* Models */, - CEA832661F990689004845F0 /* AppearanceSettings */, - CE45EDDE1F95F94200F56319 /* Utilities */, - 607FACD51AFB9204008FA782 /* AppDelegate.swift */, - CEF61A381F82A4C700BF7071 /* ChatViewController.swift */, - CE44AE641F87CA8E009787E5 /* MessageTableViewCell.swift */, - DDFC63CA1F93F23E008E1ACC /* RatingViewController.swift */, - CE380423202B0AC2003032D4 /* SettingsTableViewController.swift */, - CE88BCD01FCD7F9A00A4FA2E /* SettingsViewController.swift */, - 607FACD71AFB9204008FA782 /* StartViewController.swift */, - 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */, - 607FACD91AFB9204008FA782 /* Main.storyboard */, - CE324E651FDECBD2004BB116 /* RatingViewController.xib */, - 607FACDC1AFB9204008FA782 /* Images.xcassets */, - 607FACD31AFB9204008FA782 /* Supporting Files */, - CE5A03BC1FDEB756009D320A /* Localizable.strings */, - ); - name = "Example for WebimClientLibrary"; - path = WebimClientLibrary; - sourceTree = ""; - }; - 607FACD31AFB9204008FA782 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 607FACD41AFB9204008FA782 /* Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 607FACE81AFB9204008FA782 /* Tests */ = { - isa = PBXGroup; - children = ( - CE2845BF2021B993007B1C25 /* ExampleTests */, - CED3BA09201F87390071EC23 /* Mocks */, - CE2845B62020A88D007B1C25 /* AbstractRequestLoopTests.swift */, - CE18FB99203DA3890059B9FF /* AccessCheckerTests.swift */, - CE2845B92020B687007B1C25 /* ActionRequestLoopTests.swift */, - CE2845C32021C2BF007B1C25 /* AuthorizationDataTests.swift */, - CE2CD5962035F12600997628 /* ChatItemTests.swift */, - CE2845C52021CF40007B1C25 /* ClientSideIDTests.swift */, - CE86FA9A203AFBFB00CB9C2D /* DeltaItemTests.swift */, - CE2845C72021DBE5007B1C25 /* DeltaRequestLoopTests.swift */, - CE86FA9E203B07F400CB9C2D /* DeltaResponseTests.swift */, - CE86FAB0203C18D600CB9C2D /* DepartmentFactoryTests.swift */, - CE24A00D20372239009EE7E7 /* DepartmentItemTests.swift */, - CE1FC99D202333B20090F7E6 /* ExecIfNotDestroyedHandlerExecutorTests.swift */, - CE24A00F20372629009EE7E7 /* FileParametersItemTests.swift */, - CE86FA9C203B009400CB9C2D /* FullUpdateTests.swift */, - CE86FAA0203B0B1600CB9C2D /* HistoryBeforeResponseTests.swift */, - CE0CD758202338EE00719DBE /* HistoryIDTests.swift */, - CE86FAA2203B122A00CB9C2D /* HistorySinceResponseTests.swift */, - CE6741C7200F9A600061EEFD /* HMACSha256Tests.swift */, - CE0CD7622024561B00719DBE /* InternalUtilsTests.swift */, - CE18FB9B203DB32E0059B9FF /* LocationSettingsHolderTests.swift */, - CE86FABB203C664F00CB9C2D /* LocationSettingsImplTests.swift */, - CE2CD5942035DF6E00997628 /* MemoryHistoryMetaInformationStorageTests.swift */, - CE86FAB7203C48DA00CB9C2D /* MemoryHistoryStorageTests.swift */, - CE86FAA4203B1B7300CB9C2D /* MessageFactoriesTests.swift */, - 607FACEB1AFB9204008FA782 /* MessageHolderTests.swift */, - CE86FABD203C686600CB9C2D /* MessageImplTests.swift */, - CE24A011203730D5009EE7E7 /* MessageItemTests.swift */, - CE18FB9D203EBCB00059B9FF /* MessageStreamImplTests.swift */, - CE86FAAE203B2D1800CB9C2D /* OperatorFactoryTests.swift */, - CE0CD76620249C3E00719DBE /* OperatorImplTests.swift */, - CE24A013203735C8009EE7E7 /* OperatorItemTests.swift */, - CE5B7E5B20500A6F00DDA407 /* ProvidedVisitorFieldsTests.swift */, - CE24A018203ADF40009EE7E7 /* RatingItemTests.swift */, - CE07E993204972C600E0A0D3 /* SessionBuilderTests.swift */, - CE0CD75B20234BD500719DBE /* SessionDestroyerTests.swift */, - CE86FAB2203C1E8500CB9C2D /* SQLiteHistoryStorageTests.swift */, - CE0CD764202461FE00719DBE /* StringFromHTTPParametersTests.swift */, - CE86FA98203AF6AC00CB9C2D /* UIColorHexStringTests.swift */, - CE86FA96203AF44700CB9C2D /* VisitorItemTests.swift */, - CED3BA07201F7E100071EC23 /* WebimActionsTests.swift */, - CE5B7E612056B26C00DDA407 /* WebimClientTests.swift */, - CE86FABF203C6FBC00CB9C2D /* WebimErrorImplTests.swift */, - CED72597200E5B1C00CD1623 /* WebimInternalLoggerTests.swift */, - CE995DC12020904300E27A3C /* WebimRemoteNotificationImplTests.swift */, - CEE382C12035D544006C809E /* WebimTests.swift */, - 607FACE91AFB9204008FA782 /* Supporting Files */, - ); - path = Tests; - sourceTree = ""; - }; - 607FACE91AFB9204008FA782 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 607FACEA1AFB9204008FA782 /* Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 607FACF51AFB993E008FA782 /* Podspec Metadata */ = { - isa = PBXGroup; - children = ( - C4CD65CA48F80B5A4AD826B3 /* WebimClientLibrary.podspec */, - EB8C258A78F3730770936414 /* README.md */, - AB52E1C1E0F009A386DC1C6C /* LICENSE */, - ); - name = "Podspec Metadata"; - sourceTree = ""; - }; - CE24A015203ADC2D009EE7E7 /* Images */ = { - isa = PBXGroup; - children = ( - CE24A016203ADC88009EE7E7 /* Logo.png */, - CE88BCD61FCF05CF00A4FA2E /* Screenshots */, - ); - path = Images; - sourceTree = ""; - }; - CE2845BF2021B993007B1C25 /* ExampleTests */ = { - isa = PBXGroup; - children = ( - CED72594200E20E500CD1623 /* ChatViewControllerTests.swift */, - CE2845C02021B9BC007B1C25 /* DecodePercentEscapedLinksIfPresentTests.swift */, - CE48362B2031DA5E00E18A20 /* MimeTypeTests.swift */, - ); - path = ExampleTests; - sourceTree = ""; - }; - CE45EDDB1F9108E200F56319 /* Extensions */ = { - isa = PBXGroup; - children = ( - CEBFB67E2018CB0F00D9E5F6 /* String.swift */, - DDFC632A1F924D41008E1ACC /* UIImage.swift */, - CE45EDDC1F9108FA00F56319 /* UIImageView.swift */, - CEA849041FFCE29A006CC417 /* UITableView.swift */, - CEBFB6802018E50500D9E5F6 /* UIViewController.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - CE45EDDE1F95F94200F56319 /* Utilities */ = { - isa = PBXGroup; - children = ( - CE45EDDB1F9108E200F56319 /* Extensions */, - CE45EDDF1F95F95C00F56319 /* MimeType.swift */, - CE48362D2032E0D900E18A20 /* PopupDialogHandler.swift */, - CE591A421FC2F31E004C95EE /* WebimService.swift */, - ); - path = Utilities; - sourceTree = ""; - }; - CE54B2501FC45274009C05BD /* Documentation */ = { - isa = PBXGroup; - children = ( - CE24A015203ADC2D009EE7E7 /* Images */, - CE54B2511FC452B9009C05BD /* Index.md */, - ); - name = Documentation; - path = ../Documentation; - sourceTree = ""; - }; - CE88BCD61FCF05CF00A4FA2E /* Screenshots */ = { - isa = PBXGroup; - children = ( - CED02E152031C52E000508C9 /* ChatScreenClassic.png */, - CED02E182031C52E000508C9 /* ChatScreenDark.png */, - CED02E2B2031C5F3000508C9 /* ImageScreenClassic.png */, - CED02E272031C5F3000508C9 /* ImageScreenDark.png */, - CED02E242031C5F2000508C9 /* RatingScreenClassic.png */, - CED02E262031C5F2000508C9 /* RatingScreenDark.png */, - CED02E2A2031C5F3000508C9 /* SettingsScreenClassic.png */, - CED02E252031C5F2000508C9 /* SettingsScreenDark.png */, - CED02E292031C5F3000508C9 /* StartScreenClassic.png */, - CED02E282031C5F3000508C9 /* StartScreenDark.png */, - ); - path = Screenshots; - sourceTree = ""; - }; - CEA832661F990689004845F0 /* AppearanceSettings */ = { - isa = PBXGroup; - children = ( - CE88BCD41FCDA45C00A4FA2E /* ButtonConstants.swift */, - CEA832671F9906BF004845F0 /* ColorConstants.swift */, - CEA832691F99079A004845F0 /* StringConstants.swift */, - ); - path = AppearanceSettings; - sourceTree = ""; - }; - CEC2787A2031A0110043899C /* Models */ = { - isa = PBXGroup; - children = ( - CE380425202B3526003032D4 /* ColorScheme.swift */, - CE88BCD21FCD88EA00A4FA2E /* Settings.swift */, - ); - path = Models; - sourceTree = ""; - }; - CED3BA09201F87390071EC23 /* Mocks */ = { - isa = PBXGroup; - children = ( - CE2845BC2020B70A007B1C25 /* ActionRequestLoopMock.swift */, - CED3BA0A201F87510071EC23 /* InternalErrorListenerMock.swift */, - ); - path = Mocks; - sourceTree = ""; - }; - D6405400012B6906279A6D61 /* Frameworks */ = { - isa = PBXGroup; - children = ( - D5A6DD52DA6213CB92530809 /* Pods_WebimClientLibrary_Example.framework */, - 75BFCD5FB1955EE77D987E3C /* Pods_WebimClientLibrary_Tests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 607FACCF1AFB9204008FA782 /* WebimClientLibrary_Example */ = { - isa = PBXNativeTarget; - buildConfigurationList = 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "WebimClientLibrary_Example" */; - buildPhases = ( - 97DA4630C02562D10912CF16 /* [CP] Check Pods Manifest.lock */, - 8CC584B88D331C1B48D729CB /* [Amimono] Create filelist per architecture */, - 607FACCC1AFB9204008FA782 /* Sources */, - 607FACCD1AFB9204008FA782 /* Frameworks */, - 607FACCE1AFB9204008FA782 /* Resources */, - CE86FAB4203C3E6700CB9C2D /* ShellScript */, - BC0CA950BB03125C2F6377C1 /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = WebimClientLibrary_Example; - productName = WebimClientLibrary; - productReference = 607FACD01AFB9204008FA782 /* WebimClientLibrary_Example.app */; - productType = "com.apple.product-type.application"; - }; - 607FACE41AFB9204008FA782 /* WebimClientLibrary_Tests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 607FACF21AFB9204008FA782 /* Build configuration list for PBXNativeTarget "WebimClientLibrary_Tests" */; - buildPhases = ( - 8B15E7718621B61E40699296 /* [CP] Check Pods Manifest.lock */, - 607FACE11AFB9204008FA782 /* Sources */, - 607FACE21AFB9204008FA782 /* Frameworks */, - 607FACE31AFB9204008FA782 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 607FACE71AFB9204008FA782 /* PBXTargetDependency */, - ); - name = WebimClientLibrary_Tests; - productName = Tests; - productReference = 607FACE51AFB9204008FA782 /* WebimClientLibrary_Tests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 607FACC81AFB9204008FA782 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 1010; - ORGANIZATIONNAME = CocoaPods; - TargetAttributes = { - 607FACCF1AFB9204008FA782 = { - CreatedOnToolsVersion = 6.3.1; - DevelopmentTeam = 574GE9X9L7; - LastSwiftMigration = 0900; - ProvisioningStyle = Automatic; - SystemCapabilities = { - com.apple.Push = { - enabled = 1; - }; - }; - }; - 607FACE41AFB9204008FA782 = { - CreatedOnToolsVersion = 6.3.1; - LastSwiftMigration = 0900; - TestTargetID = 607FACCF1AFB9204008FA782; - }; - }; - }; - buildConfigurationList = 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "WebimClientLibrary" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - "ru-RU", - ); - mainGroup = 607FACC71AFB9204008FA782; - productRefGroup = 607FACD11AFB9204008FA782 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 607FACCF1AFB9204008FA782 /* WebimClientLibrary_Example */, - 607FACE41AFB9204008FA782 /* WebimClientLibrary_Tests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 607FACCE1AFB9204008FA782 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */, - CE5A03BA1FDEB756009D320A /* Localizable.strings in Resources */, - CE324E631FDECBD2004BB116 /* RatingViewController.xib in Resources */, - 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */, - 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 607FACE31AFB9204008FA782 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 8B15E7718621B61E40699296 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-WebimClientLibrary_Tests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 8CC584B88D331C1B48D729CB /* [Amimono] Create filelist per architecture */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[Amimono] Create filelist per architecture"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/bash; - shellScript = "declare -a DEPENDENCIES=('Cosmos' 'PopupDialog' 'SQLite.swift' 'SlackTextViewController' 'SnapKit' 'WebimClientLibrary');\nIFS=\" \" read -r -a SPLIT <<< \"$ARCHS\"\nfor ARCH in \"${SPLIT[@]}\"; do\n cd \"$OBJROOT/Pods.build\"\n filelist=\"\"\n for dependency in \"${DEPENDENCIES[@]}\"; do\n path=\"${CONFIGURATION}${EFFECTIVE_PLATFORM_NAME}/${dependency}.build/Objects-normal/${ARCH}\"\n if [ -d \"$path\" ]; then\n search_path=\"$path/*.o\"\n for obj_file in $search_path; do\n filelist+=\"${OBJROOT}/Pods.build/${obj_file}\"\n filelist+=$'\\n'\n done\n fi\n done\n filelist=${filelist%$'\\n'}\n echo \"$filelist\" > \"${CONFIGURATION}${EFFECTIVE_PLATFORM_NAME}-${TARGET_NAME}-${ARCH}.objects.filelist\"\ndone\n"; - }; - 97DA4630C02562D10912CF16 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-WebimClientLibrary_Example-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - BC0CA950BB03125C2F6377C1 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-WebimClientLibrary_Example/Pods-WebimClientLibrary_Example-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/Cosmos/Cosmos.framework", - "${BUILT_PRODUCTS_DIR}/PopupDialog/PopupDialog.framework", - "${BUILT_PRODUCTS_DIR}/SQLite.swift/SQLite.framework", - "${BUILT_PRODUCTS_DIR}/SlackTextViewController/SlackTextViewController.framework", - "${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework", - "${BUILT_PRODUCTS_DIR}/WebimClientLibrary/WebimClientLibrary.framework", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - ); - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cosmos.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PopupDialog.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SQLite.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SlackTextViewController.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SnapKit.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/WebimClientLibrary.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-WebimClientLibrary_Example/Pods-WebimClientLibrary_Example-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - CE86FAB4203C3E6700CB9C2D /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Fabric/run\" 80055b71f053ff36cce8743fbac5eecae7df7f28 7b5c5723b733cc6cd3e884c6babc2c58039b5f0100489ed510513c1f04df4945"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 607FACCC1AFB9204008FA782 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - CE591A431FC2F31E004C95EE /* WebimService.swift in Sources */, - CE48362F2032E3F100E18A20 /* PopupDialogHandler.swift in Sources */, - CEBFB67F2018CB0F00D9E5F6 /* String.swift in Sources */, - 607FACD81AFB9204008FA782 /* StartViewController.swift in Sources */, - CEA849051FFCE29A006CC417 /* UITableView.swift in Sources */, - CE88BCD31FCD88EA00A4FA2E /* Settings.swift in Sources */, - CE380426202B3526003032D4 /* ColorScheme.swift in Sources */, - CE45EDDD1F9108FA00F56319 /* UIImageView.swift in Sources */, - CE44AE651F87CA8E009787E5 /* MessageTableViewCell.swift in Sources */, - CE45EDE01F95F9F700F56319 /* MimeType.swift in Sources */, - CE380424202B0AC2003032D4 /* SettingsTableViewController.swift in Sources */, - CEBFB6812018E50500D9E5F6 /* UIViewController.swift in Sources */, - DDFC632B1F924D41008E1ACC /* UIImage.swift in Sources */, - CEF61A391F82A4C700BF7071 /* ChatViewController.swift in Sources */, - 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */, - CE88BCD51FCDA45C00A4FA2E /* ButtonConstants.swift in Sources */, - CEA832681F9906C0004845F0 /* ColorConstants.swift in Sources */, - CEA8326A1F99079A004845F0 /* StringConstants.swift in Sources */, - DDFC63CB1F93F23E008E1ACC /* RatingViewController.swift in Sources */, - CE88BCD11FCD7F9A00A4FA2E /* SettingsViewController.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 607FACE11AFB9204008FA782 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - CE24A012203730D5009EE7E7 /* MessageItemTests.swift in Sources */, - CE2CD5972035F12600997628 /* ChatItemTests.swift in Sources */, - CED3BA08201F7E100071EC23 /* WebimActionsTests.swift in Sources */, - CE0CD765202461FE00719DBE /* StringFromHTTPParametersTests.swift in Sources */, - CE0CD75A202338FD00719DBE /* HistoryIDTests.swift in Sources */, - CE995DC32020908F00E27A3C /* WebimRemoteNotificationImplTests.swift in Sources */, - CED72596200E20EF00CD1623 /* ChatViewControllerTests.swift in Sources */, - CE86FA97203AF44700CB9C2D /* VisitorItemTests.swift in Sources */, - CE86FAB8203C48DA00CB9C2D /* MemoryHistoryStorageTests.swift in Sources */, - CE18FB9C203DB32E0059B9FF /* LocationSettingsHolderTests.swift in Sources */, - CE0CD7632024561B00719DBE /* InternalUtilsTests.swift in Sources */, - CEE382C22035D544006C809E /* WebimTests.swift in Sources */, - CE2845C62021CF40007B1C25 /* ClientSideIDTests.swift in Sources */, - CE2845B82020A891007B1C25 /* AbstractRequestLoopTests.swift in Sources */, - CE86FAA3203B122A00CB9C2D /* HistorySinceResponseTests.swift in Sources */, - CE5B7E622056B26C00DDA407 /* WebimClientTests.swift in Sources */, - CE2845C22021B9D4007B1C25 /* DecodePercentEscapedLinksIfPresentTests.swift in Sources */, - CE2CD5952035DF6E00997628 /* MemoryHistoryMetaInformationStorageTests.swift in Sources */, - CE6741C8200F9A600061EEFD /* HMACSha256Tests.swift in Sources */, - CE86FA9F203B07F400CB9C2D /* DeltaResponseTests.swift in Sources */, - CE2845BB2020B6A3007B1C25 /* ActionRequestLoopTests.swift in Sources */, - CE86FAA5203B1B7300CB9C2D /* MessageFactoriesTests.swift in Sources */, - CE86FAC0203C6FBC00CB9C2D /* WebimErrorImplTests.swift in Sources */, - CE07E9952049794C00E0A0D3 /* SessionBuilderTests.swift in Sources */, - CE5B7E5C20500A6F00DDA407 /* ProvidedVisitorFieldsTests.swift in Sources */, - CE0CD75D20234BD800719DBE /* SessionDestroyerTests.swift in Sources */, - CE86FAB1203C18D600CB9C2D /* DepartmentFactoryTests.swift in Sources */, - CE86FAAF203B2D1800CB9C2D /* OperatorFactoryTests.swift in Sources */, - 607FACEC1AFB9204008FA782 /* MessageHolderTests.swift in Sources */, - CE24A019203ADF40009EE7E7 /* RatingItemTests.swift in Sources */, - CE2845BE2020B718007B1C25 /* ActionRequestLoopMock.swift in Sources */, - CE18FB9E203EBCB00059B9FF /* MessageStreamImplTests.swift in Sources */, - CE2845C42021C2BF007B1C25 /* AuthorizationDataTests.swift in Sources */, - CE24A01020372629009EE7E7 /* FileParametersItemTests.swift in Sources */, - CE24A014203735C8009EE7E7 /* OperatorItemTests.swift in Sources */, - CE86FAA1203B0B1600CB9C2D /* HistoryBeforeResponseTests.swift in Sources */, - CE24A00E20372239009EE7E7 /* DepartmentItemTests.swift in Sources */, - CE0CD76720249C3E00719DBE /* OperatorImplTests.swift in Sources */, - CE48362C2031DA5E00E18A20 /* MimeTypeTests.swift in Sources */, - CE86FA99203AF6AC00CB9C2D /* UIColorHexStringTests.swift in Sources */, - CE86FA9B203AFBFB00CB9C2D /* DeltaItemTests.swift in Sources */, - CED72599200E5B2200CD1623 /* WebimInternalLoggerTests.swift in Sources */, - CE1FC99E202333B20090F7E6 /* ExecIfNotDestroyedHandlerExecutorTests.swift in Sources */, - CE86FA9D203B009400CB9C2D /* FullUpdateTests.swift in Sources */, - CE2845C82021DBE5007B1C25 /* DeltaRequestLoopTests.swift in Sources */, - CE86FAB3203C1E8500CB9C2D /* SQLiteHistoryStorageTests.swift in Sources */, - CE86FABC203C664F00CB9C2D /* LocationSettingsImplTests.swift in Sources */, - CED3BA0B201F87510071EC23 /* InternalErrorListenerMock.swift in Sources */, - CE86FABE203C686600CB9C2D /* MessageImplTests.swift in Sources */, - CE18FB9A203DA3890059B9FF /* AccessCheckerTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 607FACE71AFB9204008FA782 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 607FACCF1AFB9204008FA782 /* WebimClientLibrary_Example */; - targetProxy = 607FACE61AFB9204008FA782 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 607FACD91AFB9204008FA782 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 607FACDA1AFB9204008FA782 /* Base */, - CEC27878202DDB760043899C /* ru-RU */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */ = { - isa = PBXVariantGroup; - children = ( - 607FACDF1AFB9204008FA782 /* Base */, - ); - name = LaunchScreen.xib; - sourceTree = ""; - }; - CE324E651FDECBD2004BB116 /* RatingViewController.xib */ = { - isa = PBXVariantGroup; - children = ( - CE324E661FDECBE0004BB116 /* Base */, - CEC27879202DDD920043899C /* ru-RU */, - ); - name = RatingViewController.xib; - sourceTree = ""; - }; - CE5A03BC1FDEB756009D320A /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - CE5A03BB1FDEB756009D320A /* ru-RU */, - CE9379091FEAADC80057E270 /* Base */, - ); - name = Localizable.strings; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 607FACED1AFB9204008FA782 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: hummingbirddj@gmail.com (5AWBA79F9B)"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.3; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 607FACEE1AFB9204008FA782 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.3; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 607FACF01AFB9204008FA782 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = F0808D307D6955C0CC345203 /* Pods-WebimClientLibrary_Example.debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = WebimClientLibrary_Example.entitlements; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 574GE9X9L7; - FRAMEWORK_SEARCH_PATHS = " $(inherited)"; - INFOPLIST_FILE = WebimClientLibrary/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MODULE_NAME = ExampleApp; - OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" -Xfrontend -warn-long-expression-type-checking=100 -Xfrontend -warn-long-function-bodies=200 -Onone"; - PRODUCT_BUNDLE_IDENTIFIER = "ru.webim.Webim-Client"; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.2; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 607FACF11AFB9204008FA782 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9F85297EB410C96E5341BFCC /* Pods-WebimClientLibrary_Example.release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = WebimClientLibrary_Example.entitlements; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 574GE9X9L7; - FRAMEWORK_SEARCH_PATHS = " $(inherited)"; - INFOPLIST_FILE = WebimClientLibrary/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MODULE_NAME = ExampleApp; - PRODUCT_BUNDLE_IDENTIFIER = "ru.webim.Webim-Client"; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.2; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 607FACF31AFB9204008FA782 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 998795E306696F247C099BA2 /* Pods-WebimClientLibrary_Tests.debug.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - DEVELOPMENT_TEAM = ""; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - INFOPLIST_FILE = Tests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.2; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WebimClientLibrary_Example.app/WebimClientLibrary_Example"; - }; - name = Debug; - }; - 607FACF41AFB9204008FA782 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 188E01CE8A86B2460C60C156 /* Pods-WebimClientLibrary_Tests.release.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - DEVELOPMENT_TEAM = ""; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - INFOPLIST_FILE = Tests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.2; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WebimClientLibrary_Example.app/WebimClientLibrary_Example"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "WebimClientLibrary" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 607FACED1AFB9204008FA782 /* Debug */, - 607FACEE1AFB9204008FA782 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "WebimClientLibrary_Example" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 607FACF01AFB9204008FA782 /* Debug */, - 607FACF11AFB9204008FA782 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 607FACF21AFB9204008FA782 /* Build configuration list for PBXNativeTarget "WebimClientLibrary_Tests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 607FACF31AFB9204008FA782 /* Debug */, - 607FACF41AFB9204008FA782 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 607FACC81AFB9204008FA782 /* Project object */; -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary.xcworkspace/contents.xcworkspacedata b/ios/libs/Webim/Example/WebimClientLibrary.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index cf39992..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/ios/libs/Webim/Example/WebimClientLibrary.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/libs/Webim/Example/WebimClientLibrary.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index 3ddf867..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - BuildSystemType - Latest - - diff --git a/ios/libs/Webim/Example/WebimClientLibrary/AppDelegate.swift b/ios/libs/Webim/Example/WebimClientLibrary/AppDelegate.swift deleted file mode 100644 index 461c5bb..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/AppDelegate.swift +++ /dev/null @@ -1,104 +0,0 @@ -// -// AppDelegate.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 01.00.2017. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Crashlytics -import Fabric -import UIKit -import WebimClientLibrary - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate { - - // MARK: - Constants - enum UserDefaultsKey: String { - case deviceToken = "device-token" - } - - // MARK: - Properties - var window: UIWindow? - - // MARK: - Methods - - func application(_ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - Fabric.with([Crashlytics.self]) - - // Remote notifications configuration - let notificationTypes: UIUserNotificationType = [.alert, - .badge, - .sound] - let remoteNotificationSettings = UIUserNotificationSettings(types: notificationTypes, - categories: nil) - application.registerUserNotificationSettings(remoteNotificationSettings) - application.registerForRemoteNotifications() - application.applicationIconBadgeNumber = 0 - - - - return true - } - - func application(_ application: UIApplication, - didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { - let deviceToken = deviceToken.map { String(format: "%02.2hhx", $0) }.joined() - UserDefaults.standard.set(deviceToken, - forKey: UserDefaultsKey.deviceToken.rawValue) - - print("Device token: \(deviceToken)") - } - - func application(_ application: UIApplication, - didFailToRegisterForRemoteNotificationsWithError error: Error) { - print("Remote notification support is unavailable due to error: \(error.localizedDescription)") - } - - func application(_ application: UIApplication, - didReceiveRemoteNotification userInfo: [AnyHashable: Any]) { - print(userInfo) - - // WEBIM: Remote notification handling. - if Webim.isWebim(remoteNotification: userInfo) == true { - _ = Webim.parse(remoteNotification: userInfo) - // Handle Webim remote notification. - } else { - // Handle another type of remote notification. - } - } - - func setStatusBarColor() { - switch ColorScheme.shared.schemeType { - case .light: - UIApplication.shared.statusBarStyle = .default - - break - case .dark: - UIApplication.shared.statusBarStyle = .lightContent - - break - } - } - -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/ButtonConstants.swift b/ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/ButtonConstants.swift deleted file mode 100644 index f4b945f..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/ButtonConstants.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// ButtonConstants.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 28.11.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import UIKit - -//startChatButton -enum Button: CGFloat { - case borderWidth = 0 - case cornerRadius = 8.0 -} - -enum TransparentButton: CGFloat { - case borderWidth = 1.0 - case cornerRadius = 8.0 -} - -// Scroll to bottom button. -enum ScrollToBottomButton: CGFloat { - case margin = 8.0 - case size = 48.0 - case visibilityThreshold = 60.0 -} -enum ScrollToBottomButtonAnimation: Double { - case duration = 0.2 -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/ColorConstants.swift b/ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/ColorConstants.swift deleted file mode 100644 index 741e950..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/ColorConstants.swift +++ /dev/null @@ -1,153 +0,0 @@ -// -// File.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 19.10.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import UIKit - -// MARK: - Colors - -fileprivate let RED_COLOR = UIColor(red: (192.0 / 255.0), - green: (0.0 / 255.0), - blue: (64.0 / 255.0), - alpha: 1.0) - -// MARK: Classic scheme -fileprivate let BACKGROUND_CELL_LIGHT_COLOR_CLASSIC = UIColor.white -//Background main color light(StartVC) -fileprivate let BACKGROUND_MAIN_COLOR_CLASSIC = UIColor.white -fileprivate let BACKGROUND_SECONDARY_COLOR_CLASSIC = BACKGROUND_MAIN_COLOR_CLASSIC -fileprivate let BACKGROUND_TABLE_VIEW_COLOR_CLASSIC = UIColor.white -//cell field(SettingsVC) -fileprivate let BACKGROUND_TEXT_FIELD_COLOR_CLASSIC = UIColor(red: (239.0 / 255.0), - green: (239.0 / 255.0), - blue: (244.0 / 255.0), - alpha: 1.0) -fileprivate let BUTTON_BORDER_COLOR_CLASSIC = UIColor(red: (67.0 / 255.0), - green: (67.0 / 255.0), - blue: (67.0 / 255.0), - alpha: 1.0) -//startChatButton light(StartVC) -fileprivate let BUTTON_COLOR_CLASSIC = UIColor(red: (11 / 255.0), - green: (180.0 / 255.0), - blue: (168.0 / 255.0), - alpha: 1.0) -//separation_light between light and dark(SettingsVC) -fileprivate let DELIMITER_COLOR_CLASSIC = BACKGROUND_MAIN_COLOR_CLASSIC -//startChatButton_light text(StartVC) -fileprivate let TEXT_BUTTON_COLOR_CLASSIC = BACKGROUND_MAIN_COLOR_CLASSIC -//settingsButton_light text and border(StartVC) -fileprivate let TEXT_BUTTON_TRANSPARENT_COLOR_CLASSIC = BACKGROUND_MAIN_COLOR_DARK -fileprivate let TEXT_BUTTON_TRANSPARENT_HIGHLIGHTED_COLOR_CLASSIC = UIColor.lightGray -//text in separation light(SettingsVC) -fileprivate let TEXT_CELL_LIGHT_COLOR_CLASSIC = BACKGROUND_MAIN_COLOR_DARK -//start_text_main_light color(StartVC) -fileprivate let TEXT_MAIN_COLOR_CLASSIC = BACKGROUND_MAIN_COLOR_DARK -fileprivate let TEXT_NAME_OPERATOR_COLOR_CLASSIC = RED_COLOR -fileprivate let TEXT_NAME_VISITOR_COLOR_CLASSIC = UIColor(red: (0.0 / 255.0), - green: (152.0 / 255.0), - blue: (79.0 / 255.0), - alpha: 1.0) -fileprivate let TEXT_SECONDARY_COLOR_CLASSIC = UIColor.darkGray -//cell text light(SettingsVC) -fileprivate let TEXT_TEXT_FIELD_COLOR_CLASSIC = BACKGROUND_MAIN_COLOR_DARK -fileprivate let TEXT_TEXT_FIELD_ERROR_COLOR_CLASSIC = RED_COLOR -//start_text_tint_main_light color(StartVC) -fileprivate let TEXT_TINT_COLOR_CLASSIC = BUTTON_COLOR_CLASSIC - -// MARK: Dark theme -//(SettingsVC) -fileprivate let BACKGROUND_CELL_LIGHT_COLOR_DARK = BACKGROUND_MAIN_COLOR_DARK -//Background main color dark(StartVC) -fileprivate let BACKGROUND_MAIN_COLOR_DARK = UIColor(red: (47.0 / 255.0), - green: (49.0 / 255.0), - blue: (95.0 / 255.0), - alpha: 1.0) -//top of the screen dark(StartVC) -fileprivate let BACKGROUND_SECONDARY_COLOR_DARK = BACKGROUND_MAIN_COLOR_DARK -//(ChatVC) -fileprivate let BACKGROUND_TABLE_VIEW_COLOR_DARK = BACKGROUND_MAIN_COLOR_DARK -//cell field(SettingsVC) -fileprivate let BACKGROUND_TEXT_FIELD_COLOR_DARK = BACKGROUND_TEXT_FIELD_COLOR_CLASSIC -fileprivate let BUTTON_BORDER_COLOR_DARK = BUTTON_BORDER_COLOR_CLASSIC -//startChatButton light(StartVC) -fileprivate let BUTTON_COLOR_DARK = BUTTON_COLOR_CLASSIC -//separation_dark between light and dark(SettingsVC) -fileprivate let DELIMITER_COLOR_DARK = BACKGROUND_MAIN_COLOR_DARK -//startChatButton_light text(StartVC) -fileprivate let TEXT_BUTTON_COLOR_DARK = UIColor.white -//settingsButton_dark text and border(StartVC) -fileprivate let TEXT_BUTTON_TRANSPARENT_COLOR_DARK = UIColor.white -fileprivate let TEXT_BUTTON_TRANSPARENT_HIGHLIGHTED_COLOR_DARK = UIColor.white -//text in separation light(SettingsVC) -fileprivate let TEXT_CELL_LIGHT_COLOR_DARK = UIColor.white -fileprivate let TEXT_MAIN_COLOR_DARK = UIColor.white -fileprivate let TEXT_NAME_OPERATOR_COLOR_DARK = TEXT_NAME_OPERATOR_COLOR_CLASSIC -fileprivate let TEXT_NAME_VISITOR_COLOR_DARK = TEXT_NAME_VISITOR_COLOR_CLASSIC -fileprivate let TEXT_SECONDARY_COLOR_DARK = UIColor.lightGray -//cell text dark(SettingsVC) -fileprivate let TEXT_TEXT_FIELD_COLOR_DARK = BACKGROUND_MAIN_COLOR_DARK -fileprivate let TEXT_TEXT_FIELD_ERROR_COLOR_DARK = TEXT_TEXT_FIELD_ERROR_COLOR_CLASSIC -//start_text_tint_main_dark color(StartVC) -fileprivate let TEXT_TINT_COLOR_DARK = BUTTON_COLOR_CLASSIC - -// MARK: - Model -let backgroundCellLightColor = SchemeColor(classic: BACKGROUND_CELL_LIGHT_COLOR_CLASSIC, - dark: BACKGROUND_CELL_LIGHT_COLOR_DARK) -let backgroundMainColor = SchemeColor(classic: BACKGROUND_MAIN_COLOR_CLASSIC, - dark: BACKGROUND_MAIN_COLOR_DARK) -let backgroundSecondaryColor = SchemeColor(classic: BACKGROUND_SECONDARY_COLOR_CLASSIC, - dark: BACKGROUND_SECONDARY_COLOR_DARK) -let backgroundTableViewColor = SchemeColor(classic: BACKGROUND_TABLE_VIEW_COLOR_CLASSIC, - dark: BACKGROUND_TABLE_VIEW_COLOR_DARK) -let backgroundTextFieldColor = SchemeColor(classic: BACKGROUND_TEXT_FIELD_COLOR_CLASSIC, - dark: BACKGROUND_TEXT_FIELD_COLOR_DARK) -let buttonBorderColor = SchemeColor(classic: BUTTON_BORDER_COLOR_CLASSIC, - dark: BUTTON_BORDER_COLOR_DARK) -let buttonColor = SchemeColor(classic: BUTTON_COLOR_CLASSIC, - dark: BUTTON_COLOR_DARK) -let delimiterColor = SchemeColor(classic: DELIMITER_COLOR_CLASSIC, - dark: DELIMITER_COLOR_DARK) -let textButtonColor = SchemeColor(classic: TEXT_BUTTON_COLOR_CLASSIC, - dark: TEXT_BUTTON_COLOR_DARK) -let textButtonTransparentColor = SchemeColor(classic: TEXT_BUTTON_TRANSPARENT_COLOR_CLASSIC, - dark: TEXT_BUTTON_TRANSPARENT_COLOR_DARK) -let textButtonTransparentHighlightedColor = SchemeColor(classic: TEXT_BUTTON_TRANSPARENT_HIGHLIGHTED_COLOR_CLASSIC, - dark: TEXT_BUTTON_TRANSPARENT_HIGHLIGHTED_COLOR_DARK) -let textCellLightColor = SchemeColor(classic: TEXT_CELL_LIGHT_COLOR_CLASSIC, - dark: TEXT_CELL_LIGHT_COLOR_DARK) -let textMainColor = SchemeColor(classic: TEXT_MAIN_COLOR_CLASSIC, - dark: TEXT_MAIN_COLOR_DARK) -let textNameOperatorColor = SchemeColor(classic: TEXT_NAME_OPERATOR_COLOR_CLASSIC, - dark: TEXT_NAME_OPERATOR_COLOR_DARK) -let textNameVisitorColor = SchemeColor(classic: TEXT_NAME_VISITOR_COLOR_CLASSIC, - dark: TEXT_NAME_VISITOR_COLOR_DARK) -let textSecondaryColor = SchemeColor(classic: TEXT_SECONDARY_COLOR_CLASSIC, - dark: TEXT_SECONDARY_COLOR_DARK) -let textTextFieldColor = SchemeColor(classic: TEXT_TEXT_FIELD_COLOR_CLASSIC, - dark: TEXT_TEXT_FIELD_COLOR_DARK) -let textTextFieldErrorColor = SchemeColor(classic: TEXT_TEXT_FIELD_ERROR_COLOR_CLASSIC, - dark: TEXT_TEXT_FIELD_ERROR_COLOR_CLASSIC) -let textTintColor = SchemeColor(classic: TEXT_TINT_COLOR_CLASSIC, - dark: TEXT_TINT_COLOR_DARK) diff --git a/ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/StringConstants.swift b/ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/StringConstants.swift deleted file mode 100644 index 65e0cb7..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/AppearanceSettings/StringConstants.swift +++ /dev/null @@ -1,139 +0,0 @@ -// -// StringConstants.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 19.10.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -enum Avatar: String { - case accessibilityLabel = "SenderAvatarImage" - case accessibilityHintOperator = "ShowsRatingDialog" -} - -enum BackButton: String { - case accessibilityLabel = "Back" - case accessibilityHint = "ClosesScreen" -} - -enum ChatClosedDialog: String { - case message = "ChatClosed" - - case buttonTitle = "OK" - case buttonAccessibilityHint = "ClosesDialog" -} - -enum CloseChatButton: String { - case accessibilityLabel = "CloseChat" - case accessibilityHint = "ClosesChat" -} - -enum DepartmentListDialog: String { - case title = "ContactTopic" - - case buttonAccessibilityHint = "ChoosesTopic" - - case cancelButtonTitle = "Cancel" - case cancelButtonAccessibilityHint = "ClosesDialog" -} - -enum FileMessage: String { - case fileUnavailable = "FileUnavailable" -} - -enum LeftButton: String { - case accessibilityLabel = "ChooseFile" - case accessibilityHint = "ShowsImagePicker" -} - -enum RateOperatorErrorMessage: String { - case title = "OperatorRatingFailed" - - case buttonTitle = "OK" - case buttonAccessibilityHint = "ClosesRateOperatorError" - - case message = "RateOperatorErrorMessage" -} - -enum RatingDialog: String { - case actionButtonAccessibilityHint = "RatesOperator" - case actionButtonTitle = "Rate" - - case cancelButtonAccessibilityHint = "ClosesRatingDialog" - case cancelButtonTitle = "Cancel" -} - -enum SendFileErrorMessage: String { - case title = "FileSendingFailed" - - case buttonTitle = "OK" - case buttonAccessibilityHint = "ClosesSendFileError" - - // Error messages - case fileSizeExceeded = "FileTooLarge" - case fileTypeNotAllowed = "FileTypeNotSupported" - case fileNotFound = "FileNotFound" - case unknownError = "FileSendingUnknownError" -} - -enum SessionCreationErrorDialog: String { - case buttonTitle = "OK" - case buttonAccessibilityHint = "ClosesSessionError" - - case title = "SessionCreationFailed" - - // Error messages - case accountBlocked = "AccountBlocked" - case visitorBanned = "VisitorBanned" -} - -enum SettingsErrorDialog: String { - case buttonTitle = "OK" - case buttonAccessibilityHint = "ClosesSettingsError" - - case title = "InvalidSettings" - - // Error messages - case wrongAccountName = "AccountNameEmpty" - case wrongLocation = "LocationEmpty" -} - -enum ShowFileDialog: String { - case buttonTitle = "OK" - - // Error messages - case imageFormatInvalid = "ImageFormatInvalid" - case imageLinkInvalid = "ImageLinkInvalid" - case notImage = "PreviewUnavailable" - - case accessibilityHint = "ClosesFilePreview" -} - -enum StartView: String { - case welcomeText = "Welcome to the WebimClientLibrary demo app!\n\nTo start a chat tap on the button below.\n\nOperator can answer to your chat at:\nhttps://demo.webim.ru/\nLogin: o@webim.ru\nPassword: password\n\nThis app source code can be found at:\nhttps://github.com/webim/webim-client-sdk-ios" -} - -enum TableView: String { - case refreshControlText = "LoadingMessages" - case emptyTableViewText = "EmptyChat" -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/LaunchScreen.xib b/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/LaunchScreen.xib deleted file mode 100644 index e0de33c..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/LaunchScreen.xib +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/Localizable.strings b/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/Localizable.strings deleted file mode 100644 index 031fed8..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/Localizable.strings +++ /dev/null @@ -1,109 +0,0 @@ -/* - Localizable.strings - WebimClientLibrary - - Created by Nikita Lazarev-Zubov on 11.12.17. - Copyright © 2017 Webim. All rights reserved. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - -// MARK: - Remote notifications - -"P.OA" = "Operator assigned to your appeal: %@."; -"P.OF" = "%@ has sent file: %@."; -"P.OM" = "%@ has sent message: %@."; - - -// MARK: - StringConstants.swift - -// EMPTY_TABLE_VIEW_TEXT -"EmptyChat" = "Send first message to start chat."; - -// REFRESH_CONTROL_TEXT -"LoadingMessages" = "Loading messages..."; - -// Avatar -"SenderAvatarImage" = "Sender avatar image"; -"ShowsRatingDialog" = "Shows rating dialog."; - -// BackButton -"Back" = "Close screen"; -"ClosesScreen" = "Closes screen for returning to previous screen."; - -// ChatClosedDialog -"ChatClosed" = "Chat finished."; -"OK" = "OK"; -"ClosesRateOperatorError" = "Closes dialog."; - -// CloseChatButton -"CloseChat" = "Close chat"; -"ClosesChat" = "Closes chat without closing this screen."; - -// DepartmentListDialog -"ContactTopic" = "Contact topic"; -"ChoosesTopic" = "Chooses this topic for contacting."; -"Cancel" = "Cancel"; -"ClosesDialog" = "Closes dialog."; - -// FileMessage -"FileUnavailable" = "File is unavailable."; - -// LeftButton -"ChooseFile" = "Choose file"; -"ShowsImagePicker" = "Shows image picker to choose an image to send."; - -// RateOperatorErrorMessage -"OperatorRatingFailed" = "Operator rating failed"; -"OK" = "OK"; -"ClosesRateOperatorError" = "Closes dialog."; -"RateOperatorErrorMessage" = "Unknown error occured."; - -// RatingDialog -"Rate" = "Rate"; -"Cancel" = "Cancel"; -"RatesOperator" = "Rates operator with chosen rating."; -"ClosesRatingDialog" = "Closes rating dialog."; - -// SendFileErrorMessage -"FileSendingFailed" = "File sending failed"; -"ClosesSendFileError" = "Closes dialog."; -"FileTooLarge" = "File is too large."; -"FileTypeNotSupported" = "File type is not supported."; -"FileNotFound" = "Sending files in body is not supported."; -"FileSendingUnknownError" = "Find sending unknown error."; - -// SessionCreationErrorDialog -"ClosesSessionError" = "Closes dialog."; -"SessionCreationFailed" = "Session creation failed"; -"AccountBlocked" = "Account that is used to create session is blocked. Please contact Webim support or use another one."; -"VisitorBanned" = "Your visitor account is in the black list."; - -// SettingsErrorDialog -"ClosesSettingsError" = "Closes dialog."; -"InvalidSettings" = "Invalid account settings"; -"AccountNameEmpty" = "Account name can't be empty."; -"LocationEmpty" = "Location can't be empty."; - -// ShowFileDialog -"ImageFormatInvalid" = "Image format is not valid."; -"ImageLinkInvalid" = "Image link is not valid."; -"PreviewUnavailable" = "Preview is not available."; -"ClosesFilePreview" = "Closes file preview."; diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/Main.storyboard b/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/Main.storyboard deleted file mode 100644 index 3252b8a..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/Main.storyboard +++ /dev/null @@ -1,422 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - Welcome to the WebimClientLibrary demo app! - -To start a chat tap on the button below. - -Operator can answer to your chat at: -https://demo.webim.ru/ -Login: o@webim.ru -Password: password - -This app source code can be found at: -https://github.com/webim/webim-client-sdk-ios - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/RatingViewController.xib b/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/RatingViewController.xib deleted file mode 100644 index 34e260e..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Base.lproj/RatingViewController.xib +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ios/libs/Webim/Example/WebimClientLibrary/ChatViewController.swift b/ios/libs/Webim/Example/WebimClientLibrary/ChatViewController.swift deleted file mode 100644 index 2ac89b5..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/ChatViewController.swift +++ /dev/null @@ -1,637 +0,0 @@ -// -// ChatViewController.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 02.10.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import SlackTextViewController -import UIKit -import WebimClientLibrary - -final class ChatViewController: SLKTextViewController { - - // MARK: - Properties - private let imagePicker = UIImagePickerController() - private let refreshControl = UIRefreshControl() - private lazy var alreadyRated = [String: Bool]() - private var lastOperatorID: String? - private lazy var messages = [Message]() - private var popupDialogHandler: PopupDialogHandler? - private var scrollToBottomButton: UIButton? - private var webimService: WebimService? - - - // MARK: - Methods - - override func viewDidLoad() { - super.viewDidLoad() - - webimService = WebimService(fatalErrorHandlerDelegate: self, - departmentListHandlerDelegate: self) - popupDialogHandler = PopupDialogHandler(delegate: self) - - imagePicker.delegate = self - - setupNavigationItem() - setupRefreshControl() - setupSlackTextViewController() - setupWebimSession() - } - - override func viewWillLayoutSubviews() { - super.viewWillLayoutSubviews() - - setupTableView() - - scrollToBottomButton?.removeFromSuperview() // Need for redrawing after device is rotated. - setupScrollToBottomButton() - } - - // For testing purposes. - func set(messages: [Message]) { - self.messages = messages - } - - // MARK: SlackTextViewController methods - - override func textViewDidChange(_ textView: UITextView) { - webimService!.setVisitorTyping(draft: textView.text) - } - - override func didPressRightButton(_ sender: Any?) { // Send message button - textView.refreshFirstResponder() - - if let text = textView.text, - !text.isEmpty { - webimService!.send(message: text) { [weak self] in - self?.textView.text = "" - self?.webimService!.setVisitorTyping(draft: nil) // Delete visitor typing draft after message is sent. - } - } - } - - override func didPressLeftButton(_ sender: Any?) { // Send file buton - dismissKeyboard(true) - - imagePicker.allowsEditing = false - imagePicker.sourceType = .photoLibrary - present(imagePicker, - animated: true, - completion: nil) - } - - // MARK: UICollectionViewDataSource methods - override func numberOfSections(in tableView: UITableView) -> Int { - if messages.count > 0 { - tableView.backgroundView = nil - - return 1 - } else { - tableView.emptyTableView(message: TableView.emptyTableViewText.rawValue.localized) - - return 0 - } - } - - - // MARK: UITableViewDelegate methods - - override func tableView(_ tableView: UITableView, - numberOfRowsInSection section: Int) -> Int { - return messages.count - } - - override func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { - guard let cell = tableView.dequeueReusableCell(withIdentifier: "MessageCell", - for: indexPath) as? MessageTableViewCell else { - fatalError("The dequeued cell is not an instance of MessageTableViewCell.") - } - - let message = messages[indexPath.row] - cell.setContent(withMessage: message) - - if let operatorID = message.getOperatorID() { - lastOperatorID = operatorID // For using on chat closing. - let gestureRecognizer = UITapGestureRecognizer(target: self, - action: #selector(ChatViewController.rateOperator(_:))) - cell.avatarImageView.addGestureRecognizer(gestureRecognizer) - } - - if (message.getType() == .FILE_FROM_OPERATOR) - || (message.getType() == .FILE_FROM_VISITOR) { - let gestureRecognizer = UITapGestureRecognizer(target: self, - action: #selector(ChatViewController.showFile(_:))) - cell.bodyLabel.addGestureRecognizer(gestureRecognizer) - } - - return cell - } - - // MARK: UIScrollViewDelegate protocol methods - override func scrollViewDidScroll(_ scrollView: UIScrollView) { - if tableView!.contentOffset.y >= (tableView!.contentSize.height - tableView!.frame.size.height - ScrollToBottomButton.visibilityThreshold.rawValue) { - UIView.animate(withDuration: ScrollToBottomButtonAnimation.duration.rawValue, - delay: 0.1, - options: [], - animations: { [weak self] in - self?.scrollToBottomButton?.alpha = 0.0 - } - , completion: nil) - } else { - UIView.animate(withDuration: ScrollToBottomButtonAnimation.duration.rawValue, - delay: 0.1, - options: [], - animations: { [weak self] in - self?.scrollToBottomButton?.alpha = 1.0 - } - , completion: nil) - } - } - - // MARK: Private methods - - private func setupTableView() { - tableView?.backgroundColor = backgroundTableViewColor.color() - - tableView?.estimatedRowHeight = 64.0 - tableView?.rowHeight = UITableView.automaticDimension - tableView?.separatorStyle = .none - tableView?.register(MessageTableViewCell.self, - forCellReuseIdentifier: "MessageCell") - } - - private func setupRefreshControl() { - if #available(iOS 10.0, *) { - tableView?.refreshControl = refreshControl - } else { - tableView?.addSubview(refreshControl) - } - refreshControl.addTarget(self, - action: #selector(requestMessages), - for: .valueChanged) - refreshControl.tintColor = textMainColor.color() - refreshControl.attributedTitle = NSAttributedString(string: TableView.refreshControlText.rawValue.localized, - attributes: [.foregroundColor : textMainColor.color()]) - } - - private func setupSlackTextViewController() { - isInverted = false - - leftButton.setImage(#imageLiteral(resourceName: "Clip"), - for: .normal) - leftButton.accessibilityLabel = LeftButton.accessibilityLabel.rawValue.localized - leftButton.accessibilityHint = LeftButton.accessibilityHint.rawValue.localized - - rightButton.setImage(#imageLiteral(resourceName: "SendMessage"), - for: .normal) - rightButton.setTitle(nil, - for: .normal) - - textInputbar.tintColor = textTintColor.color() - textInputbar.backgroundColor = backgroundSecondaryColor.color() - textInputbar.textView.textInputView.layer.backgroundColor = backgroundTextFieldColor.color().cgColor - textInputbar.textView.textColor = textTextFieldColor.color() - textInputbar.textView.tintColor = textTextFieldColor.color() - textInputbar.textView.keyboardAppearance = ColorScheme.shared.keyboardAppearance() - textInputbar.textView.layer.cornerRadius = 15.0 - } - - private func setupNavigationItem() { - setupLeftBarButtonItem() - setupRightBarButtonItem() - setupTitleView() - } - - private func setupLeftBarButtonItem() { - let backButton = UIButton(type: .custom) - backButton.setImage(ColorScheme.shared.backButtonImage(), - for: .normal) - backButton.imageView?.contentMode = .scaleAspectFit - backButton.accessibilityLabel = BackButton.accessibilityLabel.rawValue.localized - backButton.accessibilityHint = BackButton.accessibilityHint.rawValue.localized - backButton.addTarget(self, - action: #selector(onBackButtonClick(sender:)), - for: .touchUpInside) - let leftBarButtonItem = UIBarButtonItem(customView: backButton) - navigationItem.leftBarButtonItem = leftBarButtonItem - } - - @objc - private func onBackButtonClick(sender: UIButton) { - webimService!.stopSession() - - navigationController?.popViewController(animated: true) - } - - private func setupRightBarButtonItem() { - let closeChatButton = UIButton(type: .custom) - closeChatButton.setImage(ColorScheme.shared.closeChatButtonImage(), - for: .normal) - closeChatButton.imageView?.contentMode = .scaleAspectFit - closeChatButton.accessibilityLabel = CloseChatButton.accessibilityLabel.rawValue.localized - closeChatButton.accessibilityHint = CloseChatButton.accessibilityHint.rawValue.localized - closeChatButton.addTarget(self, - action: #selector(endChat), - for: .touchUpInside) - navigationItem.rightBarButtonItem = UIBarButtonItem(customView: closeChatButton) - } - - @objc - private func endChat() { - webimService!.closeChat() - - if let operatorID = lastOperatorID { - if alreadyRated[operatorID] != true { // Don't offer to rate an operator if a visitor already did it independently. - if showRatingDialog(forOperator: operatorID) { - return - } - } - } - - popupDialogHandler?.showChatClosedDialog() - } - - private func setupTitleView() { - let navigationItemImageView = UIImageView(image: ColorScheme.shared.navigationItemImage()) - navigationItemImageView.contentMode = .scaleAspectFit - navigationItem.titleView = navigationItemImageView - } - - private func setupScrollToBottomButton() { - let xPosition = view.frame.size.width - ScrollToBottomButton.size.rawValue - ScrollToBottomButton.margin.rawValue - let yPosition = UIApplication.shared.statusBarFrame.height + navigationController!.navigationBar.frame.size.height + ScrollToBottomButton.margin.rawValue - scrollToBottomButton = UIButton(frame: CGRect(x: xPosition, - y: yPosition, - width: ScrollToBottomButton.size.rawValue, - height: ScrollToBottomButton.size.rawValue)) - scrollToBottomButton!.setImage(ColorScheme.shared.scrollToBottomButtonImage(), - for: .normal) - scrollToBottomButton!.addTarget(self, - action: #selector(scrollToBottom), - for: .touchUpInside) - scrollToBottomButton!.alpha = 0.0 - view.addSubview(scrollToBottomButton!) - } - - private func setupWebimSession() { - webimService!.createSession() - webimService!.startSession() - - webimService!.setMessageStream() - webimService!.setMessageTracker(withMessageListener: self) - webimService!.getLastMessages() { [weak self] messages in - self?.messages.insert(contentsOf: messages, - at: 0) - DispatchQueue.main.async() { - self?.tableView?.reloadData() - self?.scrollToBottom() - self?.webimService?.setChatRead() - } - } - } - - @objc - private func requestMessages() { - webimService!.getNextMessages() { [weak self] messages in - self?.messages.insert(contentsOf: messages, - at: 0) - DispatchQueue.main.async() { - self?.tableView?.reloadData() - self?.refreshControl.endRefreshing() - self?.webimService?.setChatRead() - } - } - } - - @objc - private func rateOperator(_ recognizer: UITapGestureRecognizer) { - guard recognizer.state == .ended else { - return - } - - let tapLocation = recognizer.location(in: tableView) - if let tapIndexPath = tableView?.indexPathForRow(at: tapLocation) { - let message = messages[tapIndexPath.row] - if let operatorID = message.getOperatorID() { - _ = showRatingDialog(forOperator: operatorID) - } - } - } - - private func showRatingDialog(forOperator operatorID: String) -> Bool { - guard webimService!.isChatExist() else { - return false - } - - popupDialogHandler?.showRatingDialog(forOperator: operatorID) { [weak self] rating in - self?.alreadyRated[operatorID] = true - - self?.webimService!.rateOperator(withID: operatorID, - byRating: rating, - completionHandler: self) - } - - return true - } - - @objc - private func showFile(_ recognizer: UITapGestureRecognizer) { - guard recognizer.state == .ended else { - return - } - - let tapLocation = recognizer.location(in: tableView) - guard let tapIndexPath = tableView?.indexPathForRow(at: tapLocation) else { - return - } - - let message = messages[tapIndexPath.row] - guard let attachment = message.getAttachment() else { - return - } - - let attachmentURL = attachment.getURL() - - var popupMessage: String? - var image: UIImage? - - if isImage(contentType: attachment.getContentType()) { - let semaphore = DispatchSemaphore(value: 0) - let request = URLRequest(url: attachmentURL) - - print("Requesting file: \(attachmentURL.absoluteString)") - - URLSession.shared.dataTask(with: request, - completionHandler: { data, _, _ in - if let data = data { - if let downloadedImage = UIImage(data: data) { - image = downloadedImage - } else { - popupMessage = ShowFileDialog.imageFormatInvalid.rawValue.localized - } - } else { - popupMessage = ShowFileDialog.imageLinkInvalid.rawValue.localized - } - - semaphore.signal() - }).resume() - - _ = semaphore.wait(timeout: .distantFuture) - } else { - popupMessage = ShowFileDialog.notImage.rawValue - } - - popupDialogHandler?.showFileDialog(withMessage: popupMessage, - title: attachment.getFileName(), - image: image) - } - - @objc - private func scrollToBottom() { - if messages.isEmpty { - return - } - - let bottomMessageIndex = IndexPath(row: (tableView?.numberOfRows(inSection: 0))! - 1, - section: 0) - tableView?.scrollToRow(at: bottomMessageIndex, - at: .bottom, - animated: true) - } - -} - -// MARK: - UIImagePickerControllerDelegate -extension ChatViewController: UIImagePickerControllerDelegate { - - // MARK: - Methods - - func imagePickerController(_ picker: UIImagePickerController, - didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { - if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage { - if let imageURL = info[UIImagePickerController.InfoKey.referenceURL] as? URL { - let imageData: Data - let imageExtension = imageURL.pathExtension.lowercased() - if imageExtension == "jpg" || imageExtension == "jpeg" { - imageData = image.jpegData(compressionQuality: 1.0)! - } else { - imageData = image.pngData()! - } - let imageName = imageURL.lastPathComponent - let mimeType = MimeType(url: imageURL as URL) - - webimService!.send(file: imageData, - fileName: imageName, - mimeType: mimeType.value, - completionHandler: self) - } - } - - dismiss(animated: true, - completion: nil) - } - - func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { - dismiss(animated: true, - completion: nil) - } - -} - -// MARK: - UINavigationControllerDelegate -extension ChatViewController: UINavigationControllerDelegate { - // For image picker. -} - -// MARK: - WEBIM: MessageListener -extension ChatViewController: MessageListener { - - // MARK: - Methods - - func added(message newMessage: Message, - after previousMessage: Message?) { - var inserted = false - - if let previousMessage = previousMessage { - for (index, message) in messages.enumerated() { - if previousMessage.isEqual(to: message) { - messages.insert(newMessage, - at: (index == 0) ? index : (index - 1)) - inserted = true - - break - } - } - } - - if !inserted { - messages.append(newMessage) - } - - DispatchQueue.main.async() { - self.tableView?.reloadData() - self.scrollToBottom() - } - } - - func removed(message: Message) { - var toUpdate = false - - for (messageIndex, iteratedMessage) in messages.enumerated() { - if iteratedMessage.getID() == message.getID() { - messages.remove(at: messageIndex) - toUpdate = true - - break - } - } - - if toUpdate { - DispatchQueue.main.async() { - self.tableView?.reloadData() - self.scrollToBottom() - } - } - } - - func removedAllMessages() { - messages.removeAll() - - DispatchQueue.main.async() { - self.tableView?.reloadData() - } - } - - func changed(message oldVersion: Message, - to newVersion: Message) { - var toUpdate = false - - for (messageIndex, iteratedMessage) in messages.enumerated() { - if iteratedMessage.getID() == oldVersion.getID() { - messages[messageIndex] = newVersion - toUpdate = true - - break - } - } - - if toUpdate { - DispatchQueue.main.async() { - self.tableView?.reloadData() - self.scrollToBottom() - } - } - } - -} - -// MARK: - SendFileCompletionHandler -extension ChatViewController: SendFileCompletionHandler { - - // MARK: - Methods - - func onSuccess(messageID: String) { - // Ignored. - } - - func onFailure(messageID: String, - error: SendFileError) { - DispatchQueue.main.sync { - var message: String? - switch error { - case .FILE_SIZE_EXCEEDED: - message = SendFileErrorMessage.fileSizeExceeded.rawValue.localized - - break - case .FILE_TYPE_NOT_ALLOWED: - message = SendFileErrorMessage.fileTypeNotAllowed.rawValue.localized - - break - case .UNKNOWN: - message = SendFileErrorMessage.unknownError.rawValue.localized - - break - case .UPLOADED_FILE_NOT_FOUND: - message = SendFileErrorMessage.fileNotFound.rawValue.localized - - break - } - - popupDialogHandler?.showFileSendFailureDialog(withMessage: message!) { [weak self] in - guard let `self` = self else { - return - } - - for (index, message) in self.messages.enumerated() { - if message.getID() == messageID { - self.messages.remove(at: index) - DispatchQueue.main.async() { - self.tableView?.reloadData() - } - - return - } - } - } - } - } - -} - -// MARK: - RateOperatorCompletionHandler -extension ChatViewController: RateOperatorCompletionHandler { - - // MARK: - Methods - - func onSuccess() { - // Ignored. - } - - func onFailure(error: RateOperatorError) { - popupDialogHandler?.showRatingFailureDialog() - } - -} - -// MARK: - FatalErrorHandler -extension ChatViewController: FatalErrorHandlerDelegate { - - // MARK: - Methods - func showErrorDialog(withMessage message: String) { - popupDialogHandler?.showCreatingSessionFailureDialog(withMessage: message) - } - -} - -// MARK: - DepartmentListHandlerDelegate -extension ChatViewController: DepartmentListHandlerDelegate { - - // MARK: - Methods - func show(departmentList: [Department], - action: @escaping (String) -> ()) { - popupDialogHandler?.showDepartmentListDialog(withDepartmentList: departmentList, - action: action) - } - -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-1.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-1.png deleted file mode 100644 index 2c3f9c1b931bcf2c8997b56d1533dcddd95e5dcd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11731 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 F{|g0)0HDy;Qa8dK1Ah+^ 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 Q@Bf&!HT2ans&*0o0pBF3@c;k- diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-3.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-3.png deleted file mode 100644 index 86b33ada5ab7bd36ae881c15019c9247e0152a15..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8195 zcmc(EcT`hfn{}uny$Xmx=$#Nk4ZTSdLX|Ex^kzt?LXeIHM5K3+E&)VAx_}5s(a@0& z(wj0)0HDy;Qa8dK1Ah+^ zeB5_EaX~ZyfG6#yre>hxz`tDPR9?|PcQbbL;erX>rCk7J^A$Q~Q7LpO#sWbEA|umiJu zO0zcJefz5Q5PhjYGqDf%&eJ4O7FJ-iPzfv$MVm6oC2u+O_%c)O*$10AHB0+8;E^?G z)LTaXydh7C2E6|WyVy5Y>cug6-B-)P4*(#e`#tagnb}ML08y=*i8<0-?+(<_$4k`y zH@~8RUcNXq03fdv=xguj0Y?HI;4W_73Y>e*?VLb2Ck0M3Nj)(=Up2U^n^rIaZXB#{ z;u!4VDC@+jqzIG`gyIZ%!IAdBKrc^kKWLx==O1>VxcTqPAWq;P5Tu6!=bwU_>lpym zd=PM;q^OjLBUnNVC@m`rmJ*YY1PcSj#lX@aF-ee^l!zD@DkcLJ2Lu25aN@inoSdOX z>bL*$g*#K=bVVY4p&(E|K!9ifMAQf20>TxGEJ#coBrYz3Lx}hVc_ZxuMZEpE{0{>|NT-_cCSK!2{CWF&U1T1a>mV$yIP)Uf87z8RN_9s-&$H~n(=wCu* z{tFIQFHZJI`+tvga)dhjAiV5xsk(XDyTC!d-Y%TLe+Y!C`FQ#ua4vCiLH_Wsrw7&c z_CwlxJHoZq6*zI(in_TuL8YA>;a~}fn24;Tth0!Ov=mrG1}^3(A|~nJB{GH z`g^^)k0a{0rhl(@!mWomI6FDnJ3EQUih=D#B*2nVBKFb_;vx`S`N_b=!7^eF|M-U? z+;Dr!-t+%#=l4$gT?|kyH$R+AL4WN9WBC2QW}a@qKlF#%JN~X~1y0A`g2Hhb{CU~! zUoh~$%iz!T0j_YI(SIZKpD;fkXJmjq0=}k9+^A@B9tNHM8H-f4V5{t2GNN_s*dP@|TrJ0hB+CJkwO*5Y7D~lWKlX$gpMEyXn=;|8bzTtJ{9`l}C!>&VZ z)tj4}7@_LpwhON2ipt80#7zul1AOr~VYeb}Z{=(b)PCN&$C{xx@Wjhg@xz$Z!aP}h zyf@ANhXF`zS3K>lW1KL%>w^(c>i$)?mvg#pmUnynWE3?2v-k>`rax-%<8APPMyYS% zGw+#}JldCJLyYW-@$bs_wtj7)!&dmrZk9MysiXPiQ1dHkLvkm#g???k*D4V!rS>9= zrl4S@`JD7L*S<=9p4p9xbZ7CT?+-wEl0~36t%R^9Z`W;2`N?(Wah(IXfk~UB566B2 zS*ArO2_hmM+W}{`JUs;^X}KL45zIy3NRfdc6E((!)vKVb-nVW2hL_Kdi@AqO*+Xy1 zWVDpuM$gGXD0T>C(H!;wj#$qt(d6^8;tv#!)jHRKU9BClx@O?58Cwt{ooo0Kw|C-V zpJoJ2A2|W@-8{A!SV;D~DZ3@VKu%KqtR6XFCwEb~=9*eyp zCfRrAIbOIjA$9sfO%qSj11E>2%Cu_F3Z6A1i*;4%7e=>x*S*LHzNc7_Jl7elR#Cpm z60s+xdJz-!@l%^+x^3DZ#X{n|d=@(>Mu7vR4#n?~iez4(odpm?tozCzDS>j?h3Ta} zKOf<8V``#)Q3v-Ce~>R%!krePtVWkABoe@Y=k{cMx+}iR897 ze8GNOR7q0Lp2i(w;7&_py}DJH#ICQ`o}N2Pt{Vf1Mq;mDL*Xw3pUFAKh*}c~YM{tn zBhqDks_5}0xd@0>uj`p=bpXw-|odqXOifI4~8xCUxltCBmk6~dO zgAL9I`Vl1cb-;(HvVtCp< zkb*AMn4gU<6L_lP9Lz;wjz`tzuK|{zX0jtu?KrwE-Z+0*%+h{;@5izJ?Q4)AT{CDD zh@;+!VDXC|WTUh+YhJfqMus9nG>V5u;(or|YUx?1I9{70oz{qY$MgPH;X?bu=EL_@ zi|Sf&6Mp-j2c*&8#pP`u{Cc`LXWol$CxS3Zh)Z5=1hAca1zioq?oJ&u?lqkxPGg!K z7+CoYH=mO~C0wi)z2}Yrr}BY@7zTU|z>n$~$=4^2dBTap+zP6JocJmv&lg^q+8Rzk zexT)tS08%arP6!q^^zI&qpD6#V|s^#h=JfqIPY!eed)c8)8Sa3!PT6OzL_UpXivL^ zRxC!y+mOov{~^7jrp$r0;Kk~L`uLC8Z2jb=`|&j#7L7(ck+;QZzf+yigPJ4&?|}## zw-8iG{1GE- zHc*1z(`<~tH#m-sB!)7BhN>pz^eldnLaKxolvw<^`1LH!ND?Uk%=@~#HOK3iZ4*Rq zZ9_*+C;?uvxYkvB{1%niSby(1RpQuC%}Hc@Io4qWb5Tjh97m)$b?7}aB^vh#^Q!RO zdGz(0H0h-NsOon^l3lj0dwtr~R#b{mg$(yO&#q)MUKcWdWx6nFlKf`@ia`(1qoX54 zu{R1`w3G!7e;lzwu`Msc)GObEyOT2^WL$SPIE9e3*463G>Z#JYL{hV2)P-RlApR)1!=j ziV>2!TtEI>A!aR(!*#lr+T`5i%Sp9A;AfY&#h_;IvWGMxp%3YS_#ZJxBmlv@W_ADg zrEVv^{Pn;Tu5=V_&gfytS16xCvklexeC=Y3XP{f@jWo!KON@~=q?cTbT<^{hgE#v+ zba*;-XsSu{obp~cp`oDwwc>bfB;Yy`KA35SPTY2I;9~j?U1tF#+0U<@PLcv&*v$XK zVAt&Z{IAjFxVVhL>Vz?-G!I{)n>#-9K;yA=IU%I!LbIHOx6 zn7v;-nYdbEonF@DGfEgFY|{t?Ztn4tTZ-^sg;Cdev6MLi|Fl=sXP5&8a;VR%}Tx0cC>qadQ$@5QDbW_Mw;HtCUdY| zK6CeRj5X{b-YT-A$pvj|HjphOW3nL(hjTyAZECKn8zFIexptQBpibe~`I;?n^2>V^ zrlaNhEptjx(0#79kI_?w%k5Ak>tIB?$ysWpC zg0t^X%GKHMspk861ts^Jne1yGsxL{8aua@i-rYcWmU}$DpfG*&5D?2izpIPP$b7aC zZQ-6jP2MI32@%b*YEUTUTe}5wj{wlKGE=yoH9M>n={hv?ya93F6`iC_+Uk3{+j^#c zrH}Xer9Ac1^PPn+eRrH$`GP_P_dgW(wZ(1pu-xRxsoRzNGLcN;@+jeU;dbYnHx$J2 z5nHo2blDQrOXYijoOr}bcwL4+u@r=(iMH8d_{4bXCI_RtN9zgoV(A*%^ah#B`8us- zn>_u;lOLsJ=W@1XXcH1F@2X0Z1TJi6ZOQa0W#2>=yF&;rYveo{0T-vWt>JscW9JTw zxjZT+c5Z|p6uf3-H)@q+xB#xw1h6~$)u8;`Pt&D*klOs+3HPA6f;lJt{HfffVnOSA z=Z$R5zRsU6?jOB}6Ze?3`!nF@LI0m;Q>!=W7BU(q80gRi0`6yGM?XoV_fz0Q8;COp8V zgF4Hl1Yk@GZ$}H+ypuZOCn_E#EZp1Mk)w~NWPD8QYRi4z4O#ohlHnEjeKe(i!`g*^ zJ=J-{tN&tMubBv&y(0Ql+Wi*G7ZTZx9rEY|jitKW<}a$sT!@SbX|;>xe!5pC+;(Cr z;t_ZkuD1B^mw2n7F~W!Iq}Pv?q#n9Pt_S$Dei^*2Z>LK>VqoHDu3_*&g&#+J);>^Yn~Lv&b=3<9$;7y5n-PZJ381 zP49e5@Q=>X8D;q;AKot#nYlveON*?t_aRnDq~2(-J{(CDt{kBi^Z*tzAqsh6n0p)W zup_5qVa58gC;2JSXf@1vF1ycPQx8^)!M3byYsWM%l{~*=vh&vDqFAs~l+}Ga;VPW^ z3VwB|J?;NuSXpy=DNiBj6uW53IfeCHgyqRXp2gvBe`eNmsj6{%aGKC%XL4$vLPiG^ zOp}U36r;SyQve%*BasUF;t-$mr}0TDdtne(^KVaze5_ zvv5s?F<^It_Sz5f8S+!;iM^Oh%Gg1^zH7o`_XeaT3i2N(EwR8%A=zyk)O!0 zvzKt^Rqb_%##yZ{-3|ud`l^4cYrZhF0`gn?^*kC9A2*0AbRyEQjT`9F`~%hu~*qv zr|FPJRK$Tq&hGAddRi|3ECp#C@tYpLiJRXPq@QQ@GA47N?Vlkq@-wV^kE6|hR0vvo zjTuRt*cX6qwO(p28@sI4#d2W_`L1ym#Fd1uPEE9-!oC$v?8uL&;QDjO`poxZkp3}^|RD_TT1R@y?#7yBg=0b0&lIOdOG%S9SI1nPuhMIa|d zrJS%J=cCkwZxu&MKgY{T;-6ux5(qo|Tdr!VuMtk0mW_ZWZkj(uTunI@QmCL&`+9pJ zOH<4}+UqeZ!Co=<)x^UDQ)Fe65?F#u7L*rVHLU>&rRjZN_;VUkzE#hot*KXpC-w%% z^=qk~_TFFVFh7V1JU_`eXtSF%qK$f2AoN`=lB<$7r#^eF$2pj@q=#G?oE78WvnvXC z#33k>U(t?IHb=N+US%(O<@8;lwm**4?GwRna^LE++fL9p`oIOAon(Eyt*efA#0^nn ztWl7aPdZWBYhOv2&GEC)-0$(16tq5pHx^SoW*`hJC~D4sNp^3YHsegKfbV0ei&+S8 zIW~>=b7|d9LAb*>AzXN^Y3P?tvz%d1_^F^F?RV(Is}lJyCmv@37Y$w4Y;*OejfkQQ z$h+@^b3_4+KC#=^a%hR?v1DFW$x)&=e|30bQ$D!1P-4fv9oIbw5Q;IUf3(sP*b%)&Hc+A|m46-akHsVaknQ-%KWLnH!F&Wc0?2Tf>tWp=BZWVLyhfp5j`FF0$F$}4QFnoDlF~!l5dFOSFyJ5C3!&#HQ3vCQII`+q~&nqfHa~qmCRnXIi zo>;w@NF{U`JDKqeN|_+!(Pvd`8#eW+qAH{<>2so_PlxR>~ z^!wavYG`l9bj-_3zaS@);G_a@cugN~Z%olp33aDPreZuoL(6n3?#u`mUblO?_H%dF z;2Volz}Ch_BcEnzPaRQe9MOTJLf_fZA&tG_Uf@7xJvT4LTiGVnZKK+#5a4+i`r%s0 zS(upYN*NKhA>}Irg_4rO{`R+l90gX>aYZSKlO^?Fn8XtQO30g?K&9qVmhk2BPu@jC zuV!zW6Dwz(!unn;O=Z)4Q5SYHDSzSBAF*|^bQjJfa$=lg#A0FkHs|3pOj7=_{MC$I z+ZT4RVke#yN@&*5+}GS+L#+XKr%vX4@&erhH&4|Ee$WdHSS37{`4J!D&(oQ@eBDsf zZbH?YN9tITR@H#}<+M>T*^%c^?q|8Fh~&PhI@xCaV%{mM%u{@XfH8Cd#M z?2GuT6#JW*1vE?%T6oV@A|z_5ML-t*Hun=hSl(UxWELKu{~deDde*u4Vv9-j*V)<~ zy>0T?%Z2EPl2_40AyySiGCwReWtgy%=w$u5!*#ZJeCX;_EX4bP$@we`g%PuctdI? zpOipyqT--5dq}zW3nDjQVubG&?1(U8*s(aBVJlx~|HPlmPLrO>{(NHJhH{;_Fj; z!|62VpZ$WDRjnZj4Gp%!-y$=2tvU%|ms{1BaZQ~Y?-^M-n5-S}}rB4kIg z9v<9kytI?d%_JEuz+Go_o)LM5MjgM`-FQOmy0WDW$R{&eFs6g#HSc^6IX)6?TuTMJ zi-=mUkcvEl3MMtk6JgGlQYC-rqLjwvVCAIFgebhuo;>skJBX@XgblVytn1t@98_p$ zlb(6@4ZGEL|8teyJ0lv?yz3rZ0d5bAH>&u)CR+=C=1kcs+lMnVVg_xqieng@2`TUv z9vb^RI2qK%l;Q(<8rOS)@mIlJ4?oW$2*ZU;y(m0h29_^M#$rAx*)`nS&@LX!V64*g z7I0fR8qcYHC5-#gjRVjEP74k6-FA@Dq>cSr$UaxM-&9Wmm@rP^o609Mb7>Y-7jo`D zy3sd9$aoJENBzaU1SH>QJr}!~W|Ku)ZDi5iQK=>Y&=j0VQ8i!{vA+@R1!9>dyiF6oFEV+3?&z-_gGrUdT1tUhB81AiZ7t@+Ob_E#K?xfBcd?9DR z^fn>}`)8?yRxwt_7ul$vHiHd2?h(kRPHr?W1q54eKbm+}w|ZV#{{2%1rbM#~?K@(4 zNr+&OD(gh)z8Q|L^i7#(*9*rKETQno;@^)IyemACT(h1Ydv^-j9G5J3VKhJnVLto< zjd#r@GlNgjR_9KjY@@cCJy9mFKbcUP&e3{gA6T5f4j!_6d{@y;U~$tO$(-vTkhaHA zO~im1G|KQjEbfZs&36*wzb8DR&VcDN(%h<#(^^)wySge8VcrTO5xaO@xzHKM|opnW(-Pf2r##{D?oz!V>v5J8M9^{srnRFn;cdr09K$s+X$Vf){e#BrkI$x)vbsjDm435AA|29RJSo%cpu47 z;V&VQSKZgu$m^i1$!cmoJ}k1)Y5I=%r6Z3u8U5M2)Hq&2*~7P8KFn9_qms}Zq?AF@ Q@Bf&!HT2ans&*0o0pBF3@c;k- diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-4.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/AppIcon-4.png deleted file mode 100644 index d4011627c1b8b4a915c56325ce8f9fa9d37acfce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6264 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 X;If)?WqJ@&00000NkvXXu0mjf)+x!I diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-40.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-40.png deleted file mode 100644 index 7697ffea51fbc1f8ca449fdf06278a35f0e7fe00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1541 zcmV+g2KxDlP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1)51jK~z{r?UsFL zQ&$+q%V5k2Zn!bo7);m)7IhgStH{_y24jw~eR1cHVo>ZEu>}G&LRUk3PvmI4Ad> z{PKP!dHA1e9xzwU1LmrEz+5#Cn5*UivyryNfqqYruTqr;SQqrbDTMjzzgHgv%lr6G z6j{3YPO8!XO#wH~_*{IIy-tk|;PWm!iU<1mPIkKV&j9j1D~A4>lkcP|4bYnq@Z)ed z5`3MFP6r0D_D&<-Xt(0!1``hV+~e=etitLWc=XHDxbAQx7#5IB@;A6tYjC&gHd=!| zzRIj_w;#)ktDq^bMS-mj>#tc+P;WuIFT49U7FqD(uJai3hT!o>;b)LasRC*}F6`-7 zuZgMJX>7;Bouyc@_X2*kcH;dTSF!4f8DHDm`4!VE8c!g9Zv{3SG9nU@&qErD%+qye&q`!x+)Me@!#*>9wXbx1O+vUTUFA5h+)u!t$ zSbo`v!p<&!rMgPndXcy7B#t+*Y%wANlO19aB~1%x^xVh#s}1nSr3=;cz0r<`cb8(T zwh7^IT&$yrU%=6x9%$-Jc)Q+;@mOk2DYZk_ibuXJL0$JS66|BfLoxWtVd*uVNKOwJ zW9{@-vlR#L-sL-~3JGznEvmudJ!Lp&cOb$5M|@$7vl{Aj`|zgCij_4+R1OUBJ5og{ zT=z#UUii5JPInMdRxSb7Amm^~GDUG(KvJ=@4=W5t^aj(X{Q0haJYHCi*M6@NBj;sc zqvH{{nIoY%c64+gzt(`STJ8LfRNeLXvE(N$-aTQ0z?vcyi7UV)xbRGX0hZo%=6Y

UBvaaF1SD<0YR8gOI&9F@;{&}F zOONRA)c$iQz1}O178z_TD2)g**t4*!3(Kkv*vvAZjK4P$!z)KGVc9`F9G(D@Z0yNU zA{eXhC`&szD?mSs+^6OiJaa;aCk~&-bB8YAfc2J`T7ntlP(IdqawjHZNwkc5#d)Z? zXn<|R%}-G9430nu zjG#m?HXh_oq@owtHCwK=;ibwNd|_+jCjp!Fjd*N-IgYj75!WeT3`$TqYd}#{f-I$R z7M%$w=Ctv^JCXizRJn$rVdF+~!2sjn2&x=ISbAI!O;Ht`W72ep#ghz%EQ2M*8JKYn zs)-JgBc_bjR4};{V=U@)&nL~TSgALlpyD!Cml^QvF&(}$OWivi*aHEQXcSP_1~`-m zrkGokBSJEDM~BykHPt5MpR306r!QhnsR7P$DSFd^CCIEmXAMY2trjgMl(OK-Bx;h) zmL_~;Y(m?JSKP}4CVSR^B>L83#2Cobxs_7zWS%}zidmBhikuXk;m^WMA_%o;#aQP` zMK9MCGY6p$B&$J9Joq*AW$5LB0qM}l1XOCYCOsJ?*_om>VRk;5^uT~5iVT6x1f>R+ z21RCPl9kE{kd$+@$m|@lnsNrD4@iTW0ybMHrE&%&F`jfN@i7TR3;r@I%?TiBE~2HT rIRg|SWFXmmKNrmzAZf0kCI$Qp!`}U^J9(t*00000NkvXXu0mjf#yZCs diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-41.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-41.png deleted file mode 100644 index 7697ffea51fbc1f8ca449fdf06278a35f0e7fe00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1541 zcmV+g2KxDlP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1)51jK~z{r?UsFL zQ&$+q%V5k2Zn!bo7);m)7IhgStH{_y24jw~eR1cHVo>ZEu>}G&LRUk3PvmI4Ad> z{PKP!dHA1e9xzwU1LmrEz+5#Cn5*UivyryNfqqYruTqr;SQqrbDTMjzzgHgv%lr6G z6j{3YPO8!XO#wH~_*{IIy-tk|;PWm!iU<1mPIkKV&j9j1D~A4>lkcP|4bYnq@Z)ed z5`3MFP6r0D_D&<-Xt(0!1``hV+~e=etitLWc=XHDxbAQx7#5IB@;A6tYjC&gHd=!| zzRIj_w;#)ktDq^bMS-mj>#tc+P;WuIFT49U7FqD(uJai3hT!o>;b)LasRC*}F6`-7 zuZgMJX>7;Bouyc@_X2*kcH;dTSF!4f8DHDm`4!VE8c!g9Zv{3SG9nU@&qErD%+qye&q`!x+)Me@!#*>9wXbx1O+vUTUFA5h+)u!t$ zSbo`v!p<&!rMgPndXcy7B#t+*Y%wANlO19aB~1%x^xVh#s}1nSr3=;cz0r<`cb8(T zwh7^IT&$yrU%=6x9%$-Jc)Q+;@mOk2DYZk_ibuXJL0$JS66|BfLoxWtVd*uVNKOwJ zW9{@-vlR#L-sL-~3JGznEvmudJ!Lp&cOb$5M|@$7vl{Aj`|zgCij_4+R1OUBJ5og{ zT=z#UUii5JPInMdRxSb7Amm^~GDUG(KvJ=@4=W5t^aj(X{Q0haJYHCi*M6@NBj;sc zqvH{{nIoY%c64+gzt(`STJ8LfRNeLXvE(N$-aTQ0z?vcyi7UV)xbRGX0hZo%=6Y

UBvaaF1SD<0YR8gOI&9F@;{&}F zOONRA)c$iQz1}O178z_TD2)g**t4*!3(Kkv*vvAZjK4P$!z)KGVc9`F9G(D@Z0yNU zA{eXhC`&szD?mSs+^6OiJaa;aCk~&-bB8YAfc2J`T7ntlP(IdqawjHZNwkc5#d)Z? zXn<|R%}-G9430nu zjG#m?HXh_oq@owtHCwK=;ibwNd|_+jCjp!Fjd*N-IgYj75!WeT3`$TqYd}#{f-I$R z7M%$w=Ctv^JCXizRJn$rVdF+~!2sjn2&x=ISbAI!O;Ht`W72ep#ghz%EQ2M*8JKYn zs)-JgBc_bjR4};{V=U@)&nL~TSgALlpyD!Cml^QvF&(}$OWivi*aHEQXcSP_1~`-m zrkGokBSJEDM~BykHPt5MpR306r!QhnsR7P$DSFd^CCIEmXAMY2trjgMl(OK-Bx;h) zmL_~;Y(m?JSKP}4CVSR^B>L83#2Cobxs_7zWS%}zidmBhikuXk;m^WMA_%o;#aQP` zMK9MCGY6p$B&$J9Joq*AW$5LB0qM}l1XOCYCOsJ?*_om>VRk;5^uT~5iVT6x1f>R+ z21RCPl9kE{kd$+@$m|@lnsNrD4@iTW0ybMHrE&%&F`jfN@i7TR3;r@I%?TiBE~2HT rIRg|SWFXmmKNrmzAZf0kCI$Qp!`}U^J9(t*00000NkvXXu0mjf#yZCs diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-58.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-58.png deleted file mode 100644 index f7855236f08d3c88f2ef83bb665bbbe8c0e3a63d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2667 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 Z{saBDpbvIt#mE2v002ovPDHLkV1lZb^=<$F diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-76.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-76.png deleted file mode 100644 index f748437c0810c22d597b5e1faa2fc21212e9c8c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3753 zcmbtX_dgVl|98f@?2$dn?5u1~M#wtOkzK@bwj&oZ$~dFT87F(wSs~-BE)=qpOXxro>yf9CFQT#o0w*bYjei?9aOEK7eckU#(=p?jg zy}%(Z%1VL)Rz}%rCHeoLi^rJhcVz!>yfT?sA2dc#%DSVoK|0CE&zGg>pZ}kv1M1rI z?xzk%J>MWH!NwXh9p^NeGf!E~ruZ@MK0MMm>>iVPrGGl^^mNfyo^Cozg4<%!m+-%pewTG>W-K{SYB$QHJp7??SGWe zcCftubh%DF$)8;m_;n0*4_RF@T3HFo#=`eQj#%3r0<1I?APtaty9N`iz3MH*NbPlL z)6t$PW1K>CODcwgho~V-OV0pIS5{3Z;w2U0r8~_WXJV?ak!Mz(gv>hvvU3p1V?S*2 zOrCp~Nl^C91it2_$FC7)oH_6e4sFKp#dBtYzfTCiUxZT(@v%PAL61Q zst5PiA(o|n-Nd-pj1jgI_&e*dac@xFPQSA3u72RS7slfq-@%KQ zt)FAD$sB|X<0OpawhI1ZDYvspq#Jwl= zlL6b)6AA~D7gA*e&Tk*z-%z~}VQah#)AmiX21{^Hm8smi%?f_XuGvC|?+XD+ zG@b^-ncOSNL&{d{2uW*BRGj4Pd+NI}A zL#4lHS9@l%a=wd{c-_1EY5S#KVz}xoOT1DK3qIRFRrUs9SS?v@*RB);9E+ z_PKwv)cO&x7f{75(Bp8jHaFu{M%UEnQs*95a@<$K>ldOOKg+1=l3 zzZCa}a}<~EyM-A#y%^t8$~Nvahzw*g+a1Pa+)kZMWeSd3`kd$M8_*TfmDn44-8sE~ z_w$#&x2^&owO-c>Hnq-y<_W#0cqP(q4ONI%tNDP_yv~EtVsJ1z>8n@Ruq*;@e9N4T8ot2Kw19Ol$RC0C( zGF3&a2?-EJ^4XnUWhI3*im3;YRvSZL|4HkRPVs?LrxrKX6T~G%y{cVGG;F?4;W(^1 zZ;K&@!1#kEhsd`g#_7M_y;9>gVO2RugtSH9fg|ZQCXQn+fk7befPo1d{d z*<)FN2B9b~1I}He2_2^&kpKZpG$*nr&VA~?`*ua4FvtQ&Dg&5ug=+P8R20z|jF+pA zgYskxq`jb#-yqvsi@Y@!Y)z=F7)36qN@O>P0Tf$AohK@YcJ zsHkqvZikR=-bhevtWP{7ql{_l^3F$#WW7zf`B+6L_)g-1Ik)a?_FoX7BUHe?nTMfl zI=nKwi52=c?=b2-OC>6(urv3%3;n7Vr4D};o8!d)$qH91@1y)uqVDyt!((34NA?** z){y+2QxbtK;3!N8A6Ldx59u9Smz>`WbY4uhf_>NX_=`a-&et&%|INem3)

)@>|xd=dr;G*~b zf#xHj(w?vxqhFE zDVK}znoP3r+}Zj)G7n0!s%PPF5~4pE%6m9c&SFhRsC-vAqR%>m2ts6xzpQ7V%KW9k zn*XMIIfsT4RH>3JDevslp28-M!gX8nmW(mU=flmZ33tugEf;_Pq!c+&n0GH5S7XCg&WmW(*pZ8*8RstVUkVxc1 z67hb5CQMerM*OB0=J$Y!dkUA)b2&xl@#VEC=bq08Kei6uqq;Ni%|S<&6R1hA1jdS% zBOjy!)};k58YgN8`}#MF!&GW5ais~4 zpsx&ZEQWG%E9IPE{cc$r6w z)NSpbY#8$*WiH!@+-7{Z{m?VClKP#C9|;wNTu&DhA*klcRb$5BcHw%K!4NH}%1>wO z4T1!gy@3Z8`f2%C8tyuH44di7Zt-oi#-ZbvQC9lwZG8MiXXonM{d=hwINFJ8iHJWy zV=uFB0v6be7z;L2Eh7tNJ~__IQR}*5kX})-E8t9{DWz1<2Ju|S0%04bbR?JLY=Av*%=a=1PEi7rhX;%1x9;j5)rBfz6($G(vm487fo3 z3g}Cv?fLkG0ELSH6KREMjhSG<%(hB{UOiF7ke{|su9O~zxbpM#E&s%rURu5ZKR5G0 zq`5%R-t_Z`@t87J+CCRZL9u7)hfq=p6mCl`m&t##$WStOC9szQ3Dy)!LMaVy-~fFV z)bYc69GY{jgeambfOw`HZ)j|*A{TM{V1WMg#%}H(k>nHls;l>s0;&(!tJOtB{~zVx B`=tN? diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-80.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/AppIcon.appiconset/Icon-80.png deleted file mode 100644 index deccf5c21acc50df718d59c0d36e48a2f1220b89..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3999 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 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back.imageset/Contents.json deleted file mode 100644 index f24c5fd..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "back_Icon-32.png" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back.imageset/back_Icon-32.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back.imageset/back_Icon-32.png deleted file mode 100644 index 7ffe69b3367cae31932a46f603d105db06fb66c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 710 zcmV;%0y+JOP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0$WK$K~z{ry_ef+ zQ$ZAl{}&MNL_8yEJ>VON=o2W4qEr+WQBgc0BI1h(1#O!qGikC!l{HnXJ&A?0viPK`v(Jhkw?b)>;rDnmB+)xPV#n8%96iuLB}dN6`%bq8YVO zEw%Bw(MCLZg#Q&LQpYLsf2ap!s#_F&3vZfjRP;?&2oma(WZpvE@0i=)v)Hb}FZhMc ztP&#Br)k;SnCUaG2P^P%`&lJKsLx=Q_PfWtV#mt}#`m&H2$MfYC!Nf^Rr5J#{sX0n z-K-MA+{0hZKYgr{otPZ;g*p%8c zf$~cPBWqYCOkB8+`Q$3_7Sz1AD37gUl`#G1!2axb#vi~r=u**l+_g*H1pfnqyzouv zV$`kdx4>IKd3+PAgsJH3n6qafISCrq{ZEKSx3EeWqpx=IL4Pu$eBc+hu}YXoT~4QC zw-QT;r88oeSYOPp3B0eAmUpsBm`I(^u8REcR1XfZN*JTgcIv`JQEDeq_kO}F>|vEK zMh&}8C|#B>Bh2q(l`w%i<$8mj#)MX)T3W$Wc|h+(s7{~}tae8OZOyubg=4NiOg5(# sYFGzKkUL0|Sfq~W58af9{51pMKg)m*#VkjqPyhe`07*qoM6N<$f{_GB6951J diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back_dark.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back_dark.imageset/Contents.json deleted file mode 100644 index f24c5fd..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back_dark.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "back_Icon-32.png" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back_dark.imageset/back_Icon-32.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Back_dark.imageset/back_Icon-32.png deleted file mode 100644 index 7ffe69b3367cae31932a46f603d105db06fb66c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 710 zcmV;%0y+JOP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0$WK$K~z{ry_ef+ zQ$ZAl{}&MNL_8yEJ>VON=o2W4qEr+WQBgc0BI1h(1#O!qGikC!l{HnXJ&A?0viPK`v(Jhkw?b)>;rDnmB+)xPV#n8%96iuLB}dN6`%bq8YVO zEw%Bw(MCLZg#Q&LQpYLsf2ap!s#_F&3vZfjRP;?&2oma(WZpvE@0i=)v)Hb}FZhMc ztP&#Br)k;SnCUaG2P^P%`&lJKsLx=Q_PfWtV#mt}#`m&H2$MfYC!Nf^Rr5J#{sX0n z-K-MA+{0hZKYgr{otPZ;g*p%8c zf$~cPBWqYCOkB8+`Q$3_7Sz1AD37gUl`#G1!2axb#vi~r=u**l+_g*H1pfnqyzouv zV$`kdx4>IKd3+PAgsJH3n6qafISCrq{ZEKSx3EeWqpx=IL4Pu$eBc+hu}YXoT~4QC zw-QT;r88oeSYOPp3B0eAmUpsBm`I(^u8REcR1XfZN*JTgcIv`JQEDeq_kO}F>|vEK zMh&}8C|#B>Bh2q(l`w%i<$8mj#)MX)T3W$Wc|h+(s7{~}tae8OZOyubg=4NiOg5(# sYFGzKkUL0|Sfq~W58af9{51pMKg)m*#VkjqPyhe`07*qoM6N<$f{_GB6951J diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Contents.json deleted file mode 100644 index da4a164..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Back/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip.imageset/ClipIcon.pdf b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip.imageset/ClipIcon.pdf deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip.imageset/Contents.json deleted file mode 100644 index e6d42a7..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "ClipIcon.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip_dark.imageset/Clip_dark.pdf b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip_dark.imageset/Clip_dark.pdf deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip_dark.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip_dark.imageset/Contents.json deleted file mode 100644 index f7203dd..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Clip_dark.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "Clip_dark.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Contents.json deleted file mode 100644 index da4a164..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Clip/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close.imageset/Contents.json b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close.imageset/Contents.json deleted file mode 100644 index a05197e..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "close_Icon-32.png" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close.imageset/close_Icon-32.png b/ios/libs/Webim/Example/WebimClientLibrary/Images.xcassets/Icons/Close/Close.imageset/close_Icon-32.png deleted file mode 100644 index a4f95b2e9115bfade461ed3891dd184699d7c384..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 549 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 - - - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - Webim - чат с компанией - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 3.24.7 - CFBundleSignature - ???? - CFBundleVersion - 3.24.7.1 - Fabric - - APIKey - 80055b71f053ff36cce8743fbac5eecae7df7f28 - Kits - - - KitInfo - - KitName - Crashlytics - - - - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - - UIRequiresFullScreen - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeRight - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - UIInterfaceOrientationPortraitUpsideDown - - UIViewControllerBasedStatusBarAppearance - - NSPhotoLibraryUsageDescription - This app requires access to the photo library. - - diff --git a/ios/libs/Webim/Example/WebimClientLibrary/MessageTableViewCell.swift b/ios/libs/Webim/Example/WebimClientLibrary/MessageTableViewCell.swift deleted file mode 100644 index 4d88cd8..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/MessageTableViewCell.swift +++ /dev/null @@ -1,315 +0,0 @@ -// -// MessageTableViewCell.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 06.10.17. -// Copyright © 2017 Webim. All rights reserved. -// -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import SnapKit -import UIKit -import WebimClientLibrary - -// MARK: - -final class MessageTableViewCell: UITableViewCell { - - // MARK: - Constants - private enum Size: CGFloat { - case avatar = 40.0 - } - - // MARK: - Properties - private static var imageCache = [URL: UIImage]() - private let dateFormatter: DateFormatter = { - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "dd MMM yyyy hh:mm:ss" - - return dateFormatter - }() - - // MARK: Subviews - lazy var avatarImageView = UIImageView() - lazy var bodyLabel: UILabel = { - let label = UILabel() - label.font = UIFont.preferredFont(forTextStyle: .body) - label.numberOfLines = 0 - - return label - }() - lazy var nameLabel: UILabel = { - let label = UILabel() - label.font = UIFont.preferredFont(forTextStyle: .subheadline) - - return label - }() - lazy var timeLabel: UILabel = { - let label = UILabel() - label.font = UIFont.preferredFont(forTextStyle: .footnote) - label.textColor = .lightGray - label.textAlignment = .right - - return label - }() - - - // MARK: - Initialization - - override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) { - super.init(style: style, - reuseIdentifier: reuseIdentifier) - - configureSubviews() - } - - required init?(coder aDecoder: NSCoder) { - // UITableViewCell requirement. - - super.init(coder: aDecoder) - } - - - // MARK: - Methods - - override func prepareForReuse() { - super.prepareForReuse() - - avatarImageView.image = nil - } - - func setContent(withMessage message: Message) { - switch message.getType() { - case .ACTION_REQUEST: - layoutActionRequest(message: message) - - break - case .CONTACTS_REQUEST: - layoutOperator(message: message) - - break - case .FILE_FROM_OPERATOR: - layoutFileFromOperator(message: message) - - break - case .FILE_FROM_VISITOR: - layoutFileFromVisitor(message: message) - - break - case .INFO: - layoutInfo(message: message) - - break - case .OPERATOR: - layoutOperator(message: message) - - break - case .OPERATOR_BUSY: - layoutOperatorBusy(message: message) - - break - case .VISITOR: - layoutVisitor(message: message) - - break - } - - backgroundColor = backgroundTableViewColor.color() - } - - // MARK: Private methods - - private func configureSubviews() { - self.addSubview(avatarImageView) - self.addSubview(nameLabel) - self.addSubview(bodyLabel) - self.addSubview(timeLabel) - - avatarImageView.snp.makeConstraints { [weak self] constraintsMaker in - guard let `self` = self else { - return - } - - constraintsMaker.height.equalTo(Size.avatar.rawValue) - constraintsMaker.width.equalTo(avatarImageView.snp.height) - constraintsMaker.top.equalTo(self).offset(10) - constraintsMaker.left.equalTo(self).offset(20) - } - - nameLabel.snp.makeConstraints { [weak self] constraintsMaker in - guard let `self` = self else { - return - } - - constraintsMaker.top.equalTo(self).offset(10) - constraintsMaker.left.equalTo(avatarImageView.snp.right).offset(10) - constraintsMaker.right.equalTo(self).offset(-20) - } - - bodyLabel.snp.makeConstraints { [weak self] constraintsMaker in - guard let `self` = self else { - return - } - - constraintsMaker.top.equalTo(nameLabel.snp.bottom).offset(1) - constraintsMaker.left.equalTo(avatarImageView.snp.right).offset(10) - constraintsMaker.right.equalTo(self).offset(-20) - } - - timeLabel.snp.makeConstraints { [weak self] constraintsMaker in - guard let `self` = self else { - return - } - - constraintsMaker.top.equalTo(bodyLabel.snp.bottom).offset(1) - constraintsMaker.left.equalTo(avatarImageView.snp.right).offset(10) - constraintsMaker.right.equalTo(self).offset(-20) - constraintsMaker.bottom.equalTo(self).offset(-10) - } - } - - private func layoutActionRequest(message: Message) { - // Action request messages are kind of customization. There's no such messages at demo account. - } - - private func layoutFileFromOperator(message: Message) { - if let fileName = message.getAttachment()?.getFileName() { - bodyLabel.text = fileName - } else { - bodyLabel.text = FileMessage.fileUnavailable.rawValue.localized - } - bodyLabel.textColor = textTintColor.color() - bodyLabel.isUserInteractionEnabled = true - selectionStyle = .none - - nameLabel.text = message.getSenderName() - - timeLabel.text = dateFormatter.string(from: message.getTime()) - - getOperatorAvatar(forImageView: avatarImageView, - message: message) - avatarImageView.accessibilityLabel = Avatar.accessibilityLabel.rawValue.localized - avatarImageView.accessibilityHint = Avatar.accessibilityHintOperator.rawValue.localized - } - - private func layoutFileFromVisitor(message: Message) { - if let fileName = message.getAttachment()?.getFileName() { - bodyLabel.text = fileName - } else { - bodyLabel.text = FileMessage.fileUnavailable.rawValue.localized - } - bodyLabel.textColor = textTintColor.color() - bodyLabel.isUserInteractionEnabled = true - selectionStyle = .none - - nameLabel.text = message.getSenderName() - - timeLabel.text = dateFormatter.string(from: message.getTime()) - - avatarImageView.image = #imageLiteral(resourceName: "HardcodedVisitorAvatar") - avatarImageView.isHidden = false - avatarImageView.isUserInteractionEnabled = false - avatarImageView.accessibilityLabel = Avatar.accessibilityLabel.rawValue.localized - } - - private func layoutInfo(message: Message) { - bodyLabel.text = message.getText().decodePercentEscapedLinksIfPresent() - bodyLabel.textColor = textSecondaryColor.color() - bodyLabel.isUserInteractionEnabled = false - selectionStyle = .none - - nameLabel.text = "" - - timeLabel.text = "" - - avatarImageView.isHidden = true - } - - private func layoutOperator(message: Message) { - bodyLabel.text = message.getText().decodePercentEscapedLinksIfPresent() - bodyLabel.textColor = textMainColor.color() - bodyLabel.isUserInteractionEnabled = false - selectionStyle = .none - - nameLabel.text = message.getSenderName() - nameLabel.textColor = textNameOperatorColor.color() - - timeLabel.text = dateFormatter.string(from: message.getTime()) - - getOperatorAvatar(forImageView: avatarImageView, - message: message) - avatarImageView.accessibilityLabel = Avatar.accessibilityLabel.rawValue.localized - avatarImageView.accessibilityHint = Avatar.accessibilityHintOperator.rawValue.localized - } - - private func layoutOperatorBusy(message: Message) { - bodyLabel.text = message.getText().decodePercentEscapedLinksIfPresent() - bodyLabel.textColor = textSecondaryColor.color() - bodyLabel.isUserInteractionEnabled = false - selectionStyle = .none - - nameLabel.text = "" - - timeLabel.text = "" - - avatarImageView.isHidden = true - } - - private func layoutVisitor(message: Message) { - bodyLabel.text = message.getText().decodePercentEscapedLinksIfPresent() - bodyLabel.textColor = textMainColor.color() - bodyLabel.isUserInteractionEnabled = false - selectionStyle = .none - - nameLabel.text = message.getSenderName() - nameLabel.textColor = textNameVisitorColor.color() - - timeLabel.text = dateFormatter.string(from: message.getTime()) - - avatarImageView.image = #imageLiteral(resourceName: "HardcodedVisitorAvatar") - avatarImageView.isHidden = false - avatarImageView.isUserInteractionEnabled = false - avatarImageView.accessibilityLabel = Avatar.accessibilityLabel.rawValue.localized - } - - private func getOperatorAvatar(forImageView imageView: UIImageView, - message: Message) { - // FIXME: Could load wrong image to cell due to cell reuse mechanism. - - imageView.image = #imageLiteral(resourceName: "DefaultAvatar") - imageView.isHidden = false - imageView.isUserInteractionEnabled = true - - guard let avatarURL = message.getSenderAvatarFullURL() else { - return - } - - if let image = MessageTableViewCell.imageCache[avatarURL] { - imageView.image = image - } else { - imageView.loadImageAsynchronouslyFrom(url: avatarURL, - rounded: true) { image in - MessageTableViewCell.imageCache[avatarURL] = image - } - } - } - -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Models/ColorScheme.swift b/ios/libs/Webim/Example/WebimClientLibrary/Models/ColorScheme.swift deleted file mode 100644 index ef54808..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Models/ColorScheme.swift +++ /dev/null @@ -1,134 +0,0 @@ -// -// ColorScheme.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 07.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import UIKit - -final class ColorScheme { - - // MARK: - Properties - static let shared = ColorScheme() - var schemeType: SchemeType - - // MARK: - Initialization - private init() { - if let settings = UserDefaults.standard.object(forKey: USER_DEFAULTS_NAME) as? [String : String] { - if let rawValue = settings[UserDefaultsKey.colorScheme.rawValue], - let option = SchemeType(rawValue: rawValue) { - self.schemeType = option - } else { - self.schemeType = .light - } - } else { - self.schemeType = .light - } - } - - // MARK: - Methods - - func navigationItemImage() -> UIImage { - switch schemeType { - case .light: - return #imageLiteral(resourceName: "LogoWebimNavigationBar") - case .dark: - return #imageLiteral(resourceName: "LogoWebimNavigationBar_dark") - } - } - - func backButtonImage() -> UIImage { - switch schemeType { - case .light: - return #imageLiteral(resourceName: "Back") - case .dark: - return #imageLiteral(resourceName: "Back_dark") - } - } - - func closeChatButtonImage() -> UIImage { - switch schemeType { - case .light: - return #imageLiteral(resourceName: "Close") - case .dark: - return #imageLiteral(resourceName: "Close_dark") - } - } - - func scrollToBottomButtonImage() -> UIImage { - switch schemeType { - case .light: - return #imageLiteral(resourceName: "ScrollToBottom") - case .dark: - return #imageLiteral(resourceName: "ScrollToBottom_dark") - } - } - - func keyboardAppearance() -> UIKeyboardAppearance { - switch schemeType { - case .light: - return .light - case .dark: - return .dark - } - } - - // MARK: - - enum SchemeType: String { - case light = "classic" - case dark = "dark" - } - -} - -// MARK: - -struct SchemeColor { - - // MARK: - Properties - private let classic: UIColor - private let dark: UIColor - - // MARK: - Initialization - init(classic: UIColor, - dark: UIColor) { - self.classic = classic - self.dark = dark - } - - // MARK: - Methods - - func color() -> UIColor { - return colorWith(scheme: ColorScheme.shared.schemeType) - } - - // MARK: Private methods - private func colorWith(scheme: ColorScheme.SchemeType) -> UIColor { - switch scheme { - case .light: - return classic - case .dark: - return dark - } - } - -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Models/Settings.swift b/ios/libs/Webim/Example/WebimClientLibrary/Models/Settings.swift deleted file mode 100644 index 4886aa0..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Models/Settings.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// Settings.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 28.11.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -// MARK: - Global constants -let USER_DEFAULTS_NAME = "settings" -enum UserDefaultsKey: String { - case accountName = "account_name" - case colorScheme = "color_scheme" - case location = "location" - case pageTitle = "page_title" -} - -// MARK: - -final class Settings { - - // MARK: - Constants - enum DefaultSettings: String { - case accountName = "demo" - case location = "mobile" - case pageTitle = "iOS demo app" - } - - // MARK: - Properties - static let shared = Settings() - var accountName: String - var location: String - var pageTitle: String - - // MARK: - Initialization - private init() { - if let settings = UserDefaults.standard.object(forKey: USER_DEFAULTS_NAME) as? [String : String] { - self.accountName = settings[UserDefaultsKey.accountName.rawValue] ?? DefaultSettings.accountName.rawValue - self.location = settings[UserDefaultsKey.location.rawValue] ?? DefaultSettings.location.rawValue - self.pageTitle = settings[UserDefaultsKey.pageTitle.rawValue] ?? DefaultSettings.pageTitle.rawValue - } else { - self.accountName = DefaultSettings.accountName.rawValue - self.location = DefaultSettings.location.rawValue - self.pageTitle = DefaultSettings.pageTitle.rawValue - } - } - - // MARK: - Methods - func save() { - let settings = [UserDefaultsKey.accountName.rawValue : accountName, - UserDefaultsKey.location.rawValue : location, - UserDefaultsKey.pageTitle.rawValue : pageTitle, - UserDefaultsKey.colorScheme.rawValue : ColorScheme.shared.schemeType.rawValue] - UserDefaults.standard.set(settings, - forKey: USER_DEFAULTS_NAME) - } - -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary/RatingViewController.swift b/ios/libs/Webim/Example/WebimClientLibrary/RatingViewController.swift deleted file mode 100644 index b6e0d1b..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/RatingViewController.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// RatingViewController.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 15.10.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Cosmos -import UIKit - -final class RatingViewController: UIViewController { - - // MARK: - Properties - // MARK: Outlets - @IBOutlet weak var backgroundView: UIView! - @IBOutlet weak var ratingView: CosmosView! - @IBOutlet weak var textLabel: UILabel! - - // MARK: - Methods - override func viewDidLoad() { - super.viewDidLoad() - - textLabel.textColor = textMainColor.color() - backgroundView.backgroundColor = backgroundSecondaryColor.color() - } - -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary/SettingsTableViewController.swift b/ios/libs/Webim/Example/WebimClientLibrary/SettingsTableViewController.swift deleted file mode 100644 index 5aeeec4..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/SettingsTableViewController.swift +++ /dev/null @@ -1,199 +0,0 @@ -// -// SettingsTableViewController.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 07.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import UIKit - -final class SettingsTableViewController: UITableViewController { - - // MARK: - Properties - - var delegate: SettingsViewController? - - // MARK: Outlets - - // Text fields - @IBOutlet weak var accountNameTextField: UITextField! - @IBOutlet weak var locationTextField: UITextField! - @IBOutlet weak var pageTitleTextField: UITextField! - - // Text fields error hints - @IBOutlet weak var accountNameHintLabel: UILabel! - @IBOutlet weak var locationHintLabel: UILabel! - - // Text - @IBOutlet var textFieldLabels: [UILabel]! - - // Color scheme - @IBOutlet weak var classicCheckboxImageView: UIImageView! // Row 0 - @IBOutlet weak var darkCheckboxImageView: UIImageView! // Row 2 - @IBOutlet var colorSchemeNames: [UILabel]! - - // Table cells - @IBOutlet weak var accountSettingsCell: UITableViewCell! - @IBOutlet var colorThemeCells: [UITableViewCell]! - @IBOutlet weak var delimiter: UIView! - - // MARK: - Methods - - override func viewDidLoad() { - super.viewDidLoad() - - accountNameTextField.text = Settings.shared.accountName - locationTextField.text = Settings.shared.location - pageTitleTextField.text = Settings.shared.pageTitle - - setupColorSchemeCheckboxes() - setupColorScheme() - - for hintLabel in [accountNameHintLabel, locationHintLabel] { - hintLabel!.alpha = 0.0 - hintLabel!.textColor = textTextFieldErrorColor.color() - } - for textField in [accountNameTextField, - locationTextField] { - textField!.addTarget(self, - action: #selector(textDidChange), - for: .editingChanged) - textField!.layer.cornerRadius = 5.0 - textField!.layer.borderColor = textTextFieldErrorColor.color().cgColor - textField!.delegate = self - } - pageTitleTextField.delegate = self - } - - // MARK: UITableViewDelegate protocol methods - - override func tableView(_ tableView: UITableView, - willDisplayHeaderView view: UIView, - forSection section: Int) { - view.tintColor = backgroundMainColor.color() - } - - override func tableView(_ tableView: UITableView, - didSelectRowAt indexPath: IndexPath) { - guard indexPath.section == 1 else { // Color theme section - return - } - - var selectedColorScheme: ColorScheme.SchemeType? - switch indexPath.row { - case 0: - selectedColorScheme = .light - - break - case 2: - selectedColorScheme = .dark - - break - default: - return - } - - if ColorScheme.shared.schemeType != selectedColorScheme { - ColorScheme.shared.schemeType = selectedColorScheme! - UIView.animate(withDuration: 0.2) { - self.setupColorSchemeCheckboxes() - self.setupColorScheme() - } - } - } - - // MARK: Private mwethods - - private func setupColorSchemeCheckboxes() { - switch ColorScheme.shared.schemeType { - case .light: - classicCheckboxImageView.alpha = 1.0 - darkCheckboxImageView.alpha = 0.0 - case .dark: - classicCheckboxImageView.alpha = 0.0 - darkCheckboxImageView.alpha = 1.0 - } - } - - private func setupColorScheme() { - delegate?.setupColorScheme() - - tableView.backgroundColor = backgroundMainColor.color() - accountSettingsCell.backgroundColor = backgroundMainColor.color() - for cell in colorThemeCells { - cell.backgroundColor = backgroundCellLightColor.color() - } - - for label in textFieldLabels { - label.textColor = textMainColor.color() - } - for label in colorSchemeNames { - label.textColor = textCellLightColor.color() - } - - for textField in [accountNameTextField, - locationTextField, - pageTitleTextField] { - textField!.backgroundColor = backgroundTextFieldColor.color() - textField!.textColor = textTextFieldColor.color() - textField!.tintColor = textTextFieldColor.color() - textField!.keyboardAppearance = ColorScheme.shared.keyboardAppearance() - } - - delimiter.backgroundColor = delimiterColor.color() - - let appDelegate = UIApplication.shared.delegate as! AppDelegate - appDelegate.setStatusBarColor() - } - - @objc - private func textDidChange(textField: UITextField) { - var hintLabel: UILabel? - if textField == accountNameTextField { - hintLabel = accountNameHintLabel - } else { - hintLabel = locationHintLabel - } - - UIView.animate(withDuration: 0.2) { - if (textField.text == nil) - || textField.text!.isEmpty { - textField.layer.borderWidth = 1.0 - hintLabel!.alpha = 1.0 - } else { - textField.layer.borderWidth = 0.0 - hintLabel!.alpha = 0.0 - } - } - } - -} - -extension SettingsTableViewController: UITextFieldDelegate { - - func textFieldShouldReturn(_ textField: UITextField) -> Bool { - textField.resignFirstResponder() - - return true - } - -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary/SettingsViewController.swift b/ios/libs/Webim/Example/WebimClientLibrary/SettingsViewController.swift deleted file mode 100644 index 129cd41..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/SettingsViewController.swift +++ /dev/null @@ -1,170 +0,0 @@ -// -// SettingsViewController.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 28.11.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import PopupDialog -import UIKit - -final class SettingsViewController: UIViewController { - - // MARK: - Properties - private var popupDialogHandler: PopupDialogHandler? - private var settingsTableViewController: SettingsTableViewController? - - // MARK: Outlets - @IBOutlet weak var saveButton: UIButton! - - - // MARK: - Methods - - override func viewDidLoad() { - super.viewDidLoad() - - popupDialogHandler = PopupDialogHandler(delegate: self) - - setupNavigationItem() - setupSaveButton() - - hideKeyboardOnTap() - } - - override func viewWillLayoutSubviews() { - super.viewWillLayoutSubviews() - - setupColorScheme() - } - - func setupColorScheme() { - view.backgroundColor = backgroundMainColor.color() - - navigationController?.navigationBar.barTintColor = backgroundSecondaryColor.color() - setupVisibleNavigationItemsElements() - - saveButton.backgroundColor = buttonColor.color() - saveButton.setTitleColor(textButtonColor.color(), - for: .normal) - } - - // MARK: Navigation - - override func prepare(for segue: UIStoryboardSegue, - sender: Any?) { - if let viewController = segue.destination as? SettingsTableViewController, - segue.identifier == "EmbedSettingsTable" { - settingsTableViewController = viewController - - viewController.delegate = self - } - } - - override func shouldPerformSegue(withIdentifier identifier: String, - sender: Any?) -> Bool { - if identifier != "EmbedSettingsTable", - !settingsValidated() { - return false - } - - return true - } - - // MARK: Private methods - - private func setupNavigationItem() { - setupVisibleNavigationItemsElements() - - // Need for title view to be centered. - let emptyBarButton = UIButton(type: .custom) - emptyBarButton.setImage(#imageLiteral(resourceName: "Empty"), - for: .normal) - emptyBarButton.isUserInteractionEnabled = false - navigationItem.rightBarButtonItem = UIBarButtonItem(customView: emptyBarButton) - } - - private func setupVisibleNavigationItemsElements() { - let backButton = UIButton(type: .custom) - backButton.setImage(ColorScheme.shared.backButtonImage(), - for: .normal) - backButton.imageView?.contentMode = .scaleAspectFit - backButton.accessibilityLabel = BackButton.accessibilityLabel.rawValue.localized - backButton.accessibilityHint = BackButton.accessibilityHint.rawValue.localized - backButton.addTarget(self, - action: #selector(onBackButtonClick(sender:)), - for: .touchUpInside) - let leftBarButtonItem = UIBarButtonItem(customView: backButton) - self.navigationItem.leftBarButtonItem = leftBarButtonItem - - let navigationItemImageView = UIImageView(image: ColorScheme.shared.navigationItemImage()) - navigationItemImageView.contentMode = .scaleAspectFit - navigationItem.titleView = navigationItemImageView - } - - @objc - private func onBackButtonClick(sender: UIButton) { - if settingsValidated() { - navigationController?.popViewController(animated: true) - } - } - - private func settingsValidated() -> Bool { - guard let accountName = settingsTableViewController?.accountNameTextField.text, - !accountName.isEmpty else { - popupDialogHandler?.showSettingsAlertDialog(withMessage: SettingsErrorDialog.wrongAccountName.rawValue.localized) - - return false - } - guard let location = settingsTableViewController?.locationTextField.text, - !location.isEmpty else { - popupDialogHandler?.showSettingsAlertDialog(withMessage: SettingsErrorDialog.wrongLocation.rawValue.localized) - - return false - } - - set(accountName: accountName, - location: location, - pageTitle: settingsTableViewController?.pageTitleTextField.text) - - return true - } - - private func set(accountName: String, - location: String, - pageTitle: String?) { - Settings.shared.accountName = accountName - Settings.shared.location = location - if let pageTitle = pageTitle, - !pageTitle.isEmpty { - Settings.shared.pageTitle = pageTitle - } - - Settings.shared.save() - } - - private func setupSaveButton() { - saveButton.layer.borderWidth = Button.borderWidth.rawValue - saveButton.layer.borderColor = buttonBorderColor.color().cgColor - saveButton.layer.cornerRadius = Button.cornerRadius.rawValue - } - -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary/StartViewController.swift b/ios/libs/Webim/Example/WebimClientLibrary/StartViewController.swift deleted file mode 100644 index e0b97aa..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/StartViewController.swift +++ /dev/null @@ -1,102 +0,0 @@ -// -// StartViewController.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 01.00.2017. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import UIKit - -final class StartViewController: UIViewController { - - // MARK: - Properties - // MARK: Outlets - @IBOutlet weak var startChatButton: UIButton! - @IBOutlet weak var settingsButton: UIButton! - @IBOutlet weak var welcomeTextView: UITextView! - - // MARK: - Methods - - override func viewDidLoad() { - super.viewDidLoad() - - setupStartChatButton() - setupSettingsButton() - - // Xcode does not localize UITextView text automatically. - welcomeTextView.text = NSLocalizedString(StartView.welcomeText.rawValue, - tableName: "Main", - bundle: .main, - value: "", - comment: "") - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - setupColorScheme() - setupNavigationItem() - } - - @IBAction func unwindFromSettings(_: UIStoryboardSegue) { - // No need to do anything. - } - - // MARK: Private methods - - private func setupStartChatButton() { - startChatButton.layer.cornerRadius = Button.cornerRadius.rawValue - startChatButton.layer.borderWidth = Button.borderWidth.rawValue - startChatButton.layer.borderColor = buttonBorderColor.color().cgColor - } - - private func setupSettingsButton() { - settingsButton.layer.cornerRadius = TransparentButton.cornerRadius.rawValue - settingsButton.layer.borderWidth = TransparentButton.borderWidth.rawValue - } - - private func setupColorScheme() { - view.backgroundColor = backgroundMainColor.color() - navigationController?.navigationBar.barTintColor = backgroundSecondaryColor.color() - - welcomeTextView.backgroundColor = backgroundMainColor.color() - welcomeTextView.textColor = textMainColor.color() - welcomeTextView.tintColor = textTintColor.color() - - startChatButton.backgroundColor = buttonColor.color() - startChatButton.setTitleColor(textButtonColor.color(), - for: .normal) - - settingsButton.setTitleColor(textButtonTransparentColor.color(), - for: .normal) - settingsButton.setTitleColor(textButtonTransparentHighlightedColor.color(), - for: .highlighted) - settingsButton.layer.borderColor = textButtonTransparentColor.color().cgColor - } - - private func setupNavigationItem() { - let navigationItemImageView = UIImageView(image: ColorScheme.shared.navigationItemImage()) - navigationItemImageView.contentMode = .scaleAspectFit - navigationItem.titleView = navigationItemImageView - } - -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/String.swift b/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/String.swift deleted file mode 100644 index 98e3890..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/String.swift +++ /dev/null @@ -1,93 +0,0 @@ -// -// String.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 24.01.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -extension String { - - // MARK: - Properties - var localized: String { - return NSLocalizedString(self, - comment: "") - } - -} - -// MARK: - -extension String { - - // MARK: - Methods - public func decodePercentEscapedLinksIfPresent() -> String { - var convertedString = String() - - let checkingTypes: NSTextCheckingResult.CheckingType = [.link] - if let linksDetector = try? NSDataDetector(types: checkingTypes.rawValue) { - let linkMatches = linksDetector.matches(in: self, - range: NSMakeRange(0, - self.count)) - if !linkMatches.isEmpty { - var position = 0 - - for linkMatch in linkMatches { - let linkMatchRange = linkMatch.range - if let url = linkMatch.url { - let beforeLinkStringSliceRangeStart = self.index(self.startIndex, - offsetBy: position) - let beforeLinkStringSliceRangeEnd = self.index(self.startIndex, - offsetBy: linkMatchRange.location) - let beforeLinkStringSlice = String(self[beforeLinkStringSliceRangeStart ..< beforeLinkStringSliceRangeEnd]) - convertedString += beforeLinkStringSlice - - position = linkMatchRange.location + linkMatchRange.length - - let urlString = url.absoluteString.removingPercentEncoding - if urlString != nil { - convertedString += urlString! - } else { - let linkStringSliceRangeStart = self.index(self.startIndex, - offsetBy: linkMatchRange.location) - let linkStringSliceRangeEnd = self.index(self.startIndex, - offsetBy: linkMatchRange.length) - convertedString += String(self[linkStringSliceRangeStart ..< linkStringSliceRangeEnd]) - } - } - } - - let closingStringSliceRangeStart = self.index(self.startIndex, - offsetBy: position) - let closingStringSliceRangeEnd = self.index(self.startIndex, - offsetBy: self.count) - let closingStringSlice = String(self[closingStringSliceRangeStart ..< closingStringSliceRangeEnd]) - convertedString += closingStringSlice - } else { - return self - } - } - - return convertedString - } - -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIImage.swift b/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIImage.swift deleted file mode 100644 index abe2ca3..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIImage.swift +++ /dev/null @@ -1,65 +0,0 @@ -// -// UIImage.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 14.10.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import UIKit - -extension UIImage { - - // MARK: - Methods - func roundImage() -> UIImage { - let minEdge = min(self.size.height, - self.size.width) - let size = CGSize(width: minEdge, - height: minEdge) - - UIGraphicsBeginImageContextWithOptions(size, - false, - 0.0) - let context = UIGraphicsGetCurrentContext()! - - self.draw(in: CGRect(origin: CGPoint.zero, - size: size), - blendMode: .copy, - alpha: 1.0) - - context.setBlendMode(.copy) - context.setFillColor(UIColor.clear.cgColor) - - let rectPath = UIBezierPath(rect: CGRect(origin: CGPoint.zero, - size: size)) - let circlePath = UIBezierPath(ovalIn: CGRect(origin: CGPoint.zero, - size: size)) - rectPath.append(circlePath) - rectPath.usesEvenOddFillRule = true - rectPath.fill() - - let result = UIGraphicsGetImageFromCurrentImageContext()! - UIGraphicsEndImageContext() - - return result - } - -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIImageView.swift b/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIImageView.swift deleted file mode 100644 index 2bc6905..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIImageView.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// UIImageView.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 13.10.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import UIKit - -extension UIImageView { - - // MARK: - Methods - public func loadImageAsynchronouslyFrom(url: URL, - rounded: Bool = false, - completion: ((_ image: UIImage) -> ())? = nil) { - let request = URLRequest(url: url) - - print("Requesting image: \(url.absoluteString)") - - URLSession.shared.dataTask(with: request, - completionHandler: { [weak self] (data, _, _) in - if let data = data { - DispatchQueue.main.async { - if let image = UIImage(data: data) { - var imageToSave = image - - if rounded { - imageToSave = imageToSave.roundImage() - } - - self?.image = imageToSave - - if let completion = completion { - completion(imageToSave) - } - } - } - } else { - return - } - }).resume() - } - -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UITableView.swift b/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UITableView.swift deleted file mode 100644 index 3e3655e..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UITableView.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// UITableView.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 03.01.18. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import UIKit - -extension UITableView { - - // MARK: - Methods - func emptyTableView(message: String) { - let messageLabel = UILabel(frame: CGRect(x: 0.0, - y: 0.0, - width: self.bounds.size.width, - height: self.bounds.size.height)) - messageLabel.attributedText = NSAttributedString(string: message) - messageLabel.textColor = textMainColor.color() - messageLabel.numberOfLines = 0 - messageLabel.textAlignment = .center - messageLabel.sizeToFit() - - self.backgroundView = messageLabel - self.separatorStyle = .none - } - -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIViewController.swift b/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIViewController.swift deleted file mode 100644 index 0096a83..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/Extensions/UIViewController.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// UIViewController.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 24.01.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import UIKit - -// MARK: - -extension UIViewController { - - // MARK: - Methods - - func hideKeyboardOnTap() { - let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, - action: #selector(dismissKeyboard)) - tap.cancelsTouchesInView = false - view.addGestureRecognizer(tap) - } - - // MARK: Private methods - @objc - private func dismissKeyboard() { - view.endEditing(true) - } - -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/MimeType.swift b/ios/libs/Webim/Example/WebimClientLibrary/Utilities/MimeType.swift deleted file mode 100644 index b7b0697..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/MimeType.swift +++ /dev/null @@ -1,159 +0,0 @@ -// -// MimeType.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 14.10.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -// MARK: - Global constants -fileprivate let DEFAULT_MIME_TYPE = "application/octet-stream" -fileprivate let mimeTypes = [ - "html" : "text/html", - "htm" : "text/html", - "shtml" : "text/html", - "css" : "text/css", - "xml" : "text/xml", - "gif" : "image/gif", - "jpeg" : "image/jpeg", - "jpg" : "image/jpeg", - "js" : "application/javascript", - "atom" : "application/atom+xml", - "rss" : "application/rss+xml", - "mml" : "text/mathml", - "txt" : "text/plain", - "jad" : "text/vnd.sun.j2me.app-descriptor", - "wml" : "text/vnd.wap.wml", - "htc" : "text/x-component", - "png" : "image/png", - "tif" : "image/tiff", - "tiff" : "image/tiff", - "wbmp" : "image/vnd.wap.wbmp", - "ico" : "image/x-icon", - "jng" : "image/x-jng", - "bmp" : "image/x-ms-bmp", - "svg" : "image/svg+xml", - "svgz" : "image/svg+xml", - "webp" : "image/webp", - "woff" : "application/font-woff", - "jar" : "application/java-archive", - "war" : "application/java-archive", - "ear" : "application/java-archive", - "json" : "application/json", - "hqx" : "application/mac-binhex40", - "doc" : "application/msword", - "pdf" : "application/pdf", - "ps" : "application/postscript", - "eps" : "application/postscript", - "ai" : "application/postscript", - "rtf" : "application/rtf", - "m3u8" : "application/vnd.apple.mpegurl", - "xls" : "application/vnd.ms-excel", - "eot" : "application/vnd.ms-fontobject", - "ppt" : "application/vnd.ms-powerpoint", - "wmlc" : "application/vnd.wap.wmlc", - "kml" : "application/vnd.google-earth.kml+xml", - "kmz" : "application/vnd.google-earth.kmz", - "7z" : "application/x-7z-compressed", - "cco" : "application/x-cocoa", - "jardiff" : "application/x-java-archive-diff", - "jnlp" : "application/x-java-jnlp-file", - "run" : "application/x-makeself", - "pl" : "application/x-perl", - "pm" : "application/x-perl", - "prc" : "application/x-pilot", - "pdb" : "application/x-pilot", - "rar" : "application/x-rar-compressed", - "rpm" : "application/x-redhat-package-manager", - "sea" : "application/x-sea", - "swf" : "application/x-shockwave-flash", - "sit" : "application/x-stuffit", - "tcl" : "application/x-tcl", - "tk" : "application/x-tcl", - "der" : "application/x-x509-ca-cert", - "pem" : "application/x-x509-ca-cert", - "crt" : "application/x-x509-ca-cert", - "xpi" : "application/x-xpinstall", - "xhtml" : "application/xhtml+xml", - "xspf" : "application/xspf+xml", - "zip" : "application/zip", - "bin" : "application/octet-stream", - "exe" : "application/octet-stream", - "dll" : "application/octet-stream", - "deb" : "application/octet-stream", - "dmg" : "application/octet-stream", - "iso" : "application/octet-stream", - "img" : "application/octet-stream", - "msi" : "application/octet-stream", - "msp" : "application/octet-stream", - "msm" : "application/octet-stream", - "docx" : "application/vnd.openxmlformats-officedocument.wordprocessingml.document", - "xlsx" : "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - "pptx" : "application/vnd.openxmlformats-officedocument.presentationml.presentation", - "mid" : "audio/midi", - "midi" : "audio/midi", - "kar" : "audio/midi", - "mp3" : "audio/mpeg", - "ogg" : "audio/ogg", - "m4a" : "audio/x-m4a", - "ra" : "audio/x-realaudio", - "3gpp" : "video/3gpp", - "3gp" : "video/3gpp", - "ts" : "video/mp2t", - "mp4" : "video/mp4", - "mpeg" : "video/mpeg", - "mpg" : "video/mpeg", - "mov" : "video/quicktime", - "webm" : "video/webm", - "flv" : "video/x-flv", - "m4v" : "video/x-m4v", - "mng" : "video/x-mng", - "asx" : "video/x-ms-asf", - "asf" : "video/x-ms-asf", - "wmv" : "video/x-ms-wmv", - "avi" : "video/x-msvideo" -] - -// MARK: - -struct MimeType { - - // MARK: - Properties - private let `extension`: String - var value: String { - return (mimeTypes[`extension`.lowercased()] ?? DEFAULT_MIME_TYPE) - } - - // MARK: - Initialization - public init(url: URL) { - `extension` = url.pathExtension - } - -} - -// MARK: - -func isImage(contentType: String) -> Bool { - return ((contentType == "image/gif") - || (contentType == "image/jpeg") - || (contentType == "image/png") - || (contentType == "image/tiff")) -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/PopupDialogHandler.swift b/ios/libs/Webim/Example/WebimClientLibrary/Utilities/PopupDialogHandler.swift deleted file mode 100644 index 055f417..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/PopupDialogHandler.swift +++ /dev/null @@ -1,230 +0,0 @@ -// -// PopupDialogHandler.swift -// WebimClientLibrary_Tests -// -// Created by Nikita Lazarev-Zubov on 13.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import PopupDialog -import UIKit -import WebimClientLibrary - -final class PopupDialogHandler { - - // MARK: - Constants - static let BUTTON_HEIGHT = 60 - - // MARK: - Properties - private let delegate: UIViewController - - // MARK - Initializer - init(delegate: UIViewController) { - self.delegate = delegate - } - - // MARK: - Methods - - func showSettingsAlertDialog(withMessage message: String) { - let popup = PopupDialog(title: SettingsErrorDialog.title.rawValue.localized, - message: message) - popup.view.backgroundColor = backgroundSecondaryColor.color() - (popup.viewController as! PopupDialogDefaultViewController).titleColor = textMainColor.color() - - let okButton = CancelButton(title: SettingsErrorDialog.buttonTitle.rawValue.localized, - action: nil) - okButton.accessibilityHint = SettingsErrorDialog.buttonAccessibilityHint.rawValue.localized - okButton.titleColor = textMainColor.color() - okButton.backgroundColor = backgroundSecondaryColor.color() - popup.addButton(okButton) - - delegate.present(popup, - animated: true, - completion: nil) - } - - func showCreatingSessionFailureDialog(withMessage message: String) { - let popup = PopupDialog(title: SessionCreationErrorDialog.title.rawValue.localized, - message: message.localized) - popup.view.backgroundColor = backgroundSecondaryColor.color() - (popup.viewController as! PopupDialogDefaultViewController).titleColor = textMainColor.color() - - let okButton = CancelButton(title: SessionCreationErrorDialog.buttonTitle.rawValue.localized, - action: nil) - okButton.accessibilityHint = SessionCreationErrorDialog.buttonAccessibilityHint.rawValue.localized - okButton.titleColor = textMainColor.color() - okButton.backgroundColor = backgroundSecondaryColor.color() - popup.addButton(okButton) - - delegate.present(popup, - animated: true, - completion: nil) - } - - func showDepartmentListDialog(withDepartmentList departmentList: [Department], - action: @escaping (String) -> ()) { - let popup = PopupDialog(title: DepartmentListDialog.title.rawValue.localized, - message: nil, - image: nil, - buttonAlignment: .vertical, - transitionStyle: .bounceDown, - completion: nil) - popup.view.backgroundColor = backgroundSecondaryColor.color() - (popup.viewController as! PopupDialogDefaultViewController).titleColor = textMainColor.color() - - for department in departmentList { - let button = DefaultButton(title: department.getName()) { - action(department.getKey()) - } - button.accessibilityHint = DepartmentListDialog.buttonAccessibilityHint.rawValue.localized - button.titleColor = textMainColor.color() - button.backgroundColor = backgroundSecondaryColor.color() - popup.addButton(button) - } - - let cancelButton = CancelButton(title: DepartmentListDialog.cancelButtonTitle.rawValue.localized, - height: PopupDialogHandler.BUTTON_HEIGHT, - dismissOnTap: true, - action: nil) - cancelButton.accessibilityHint = DepartmentListDialog.cancelButtonAccessibilityHint.rawValue.localized - cancelButton.backgroundColor = backgroundSecondaryColor.color() - popup.addButton(cancelButton) - - delegate.present(popup, - animated: true, - completion: nil) - } - - func showFileSendFailureDialog(withMessage message: String, - action: (() -> ())? = nil) { - let popupDialog = PopupDialog(title: SendFileErrorMessage.title.rawValue.localized, - message: message) - popupDialog.view.backgroundColor = backgroundSecondaryColor.color() - (popupDialog.viewController as! PopupDialogDefaultViewController).titleColor = textMainColor.color() - - let okButton = CancelButton(title: SendFileErrorMessage.buttonTitle.rawValue.localized) { - action?() - } - okButton.accessibilityHint = SendFileErrorMessage.buttonAccessibilityHint.rawValue.localized - okButton.backgroundColor = backgroundSecondaryColor.color() - okButton.titleColor = textMainColor.color() - popupDialog.addButton(okButton) - - delegate.present(popupDialog, - animated: true, - completion: nil) - } - - func showFileDialog(withMessage message: String?, - title: String, - image: UIImage?) { - let button = CancelButton(title: ShowFileDialog.buttonTitle.rawValue.localized, - action: nil) - button.accessibilityHint = ShowFileDialog.accessibilityHint.rawValue.localized - button.backgroundColor = backgroundSecondaryColor.color() - button.titleColor = textMainColor.color() - - let popup = PopupDialog(title: title, - message: message, - image: image, - buttonAlignment: .horizontal, - transitionStyle: .bounceUp, - gestureDismissal: true, - completion: nil) - popup.view.backgroundColor = backgroundSecondaryColor.color() - (popup.viewController as! PopupDialogDefaultViewController).titleColor = textMainColor.color() - popup.addButton(button) - - delegate.present(popup, - animated: true, - completion: nil) - } - - func showRatingDialog(forOperator operatorID: String, - action: @escaping (_ rating: Int) -> ()) { - let ratingViewController = RatingViewController(nibName: "RatingViewController", - bundle: nil) - let popup = PopupDialog(viewController: ratingViewController, - buttonAlignment: .horizontal, - transitionStyle: .bounceUp, - gestureDismissal: true) - - let cancelButton = CancelButton(title: RatingDialog.cancelButtonTitle.rawValue.localized, - height: PopupDialogHandler.BUTTON_HEIGHT, - dismissOnTap: true, - action: nil) - cancelButton.accessibilityHint = RatingDialog.cancelButtonAccessibilityHint.rawValue.localized - cancelButton.backgroundColor = backgroundSecondaryColor.color() - - let rateButton = DefaultButton(title: RatingDialog.actionButtonTitle.rawValue.localized, - height: PopupDialogHandler.BUTTON_HEIGHT, - dismissOnTap: true) { - action(Int(ratingViewController.ratingView.rating)) - } - rateButton.accessibilityHint = RatingDialog.actionButtonAccessibilityHint.rawValue.localized - rateButton.backgroundColor = backgroundSecondaryColor.color() - rateButton.titleColor = textMainColor.color() - - popup.addButtons([cancelButton, - rateButton]) - - delegate.present(popup, - animated: true, - completion: nil) - } - - func showRatingFailureDialog() { - let popupDialog = PopupDialog(title: RateOperatorErrorMessage.title.rawValue.localized, - message: RateOperatorErrorMessage.message.rawValue.localized) - popupDialog.view.backgroundColor = backgroundSecondaryColor.color() - (popupDialog.viewController as! PopupDialogDefaultViewController).titleColor = textMainColor.color() - - let okButton = CancelButton(title: RateOperatorErrorMessage.buttonTitle.rawValue.localized, - action: nil) - okButton.accessibilityHint = RateOperatorErrorMessage.buttonAccessibilityHint.rawValue.localized - okButton.titleColor = textMainColor.color() - okButton.backgroundColor = backgroundSecondaryColor.color() - popupDialog.addButton(okButton) - - delegate.present(popupDialog, - animated: true, - completion: nil) - } - - func showChatClosedDialog() { - let popupDialog = PopupDialog(title: nil, - message: ChatClosedDialog.message.rawValue.localized) - popupDialog.view.backgroundColor = backgroundSecondaryColor.color() - (popupDialog.viewController as! PopupDialogDefaultViewController).messageColor = textMainColor.color() - - let okButton = CancelButton(title: ChatClosedDialog.buttonTitle.rawValue.localized, - action: nil) - okButton.accessibilityHint = ChatClosedDialog.buttonAccessibilityHint.rawValue.localized - okButton.titleColor = textMainColor.color() - okButton.backgroundColor = backgroundSecondaryColor.color() - popupDialog.addButton(okButton) - - delegate.present(popupDialog, - animated: true, - completion: nil) - } - -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/WebimService.swift b/ios/libs/Webim/Example/WebimClientLibrary/Utilities/WebimService.swift deleted file mode 100644 index d8fb4ce..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/Utilities/WebimService.swift +++ /dev/null @@ -1,510 +0,0 @@ -// -// WebimService.swift -// WebimClientLibrary_Example -// -// Created by Nikita Lazarev-Zubov on 20.11.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -import WebimClientLibrary - -final class WebimService { - - // MARK: - Constants - private enum ChatSettings: Int { - case messagesPerRequest = 5 - } - private enum VisitorFields: String { - case id = "id" - case name = "display_name" - case crc = "crc" - } - private enum VisitorFieldsValue: String { - // Hardcoded. See more at https://webim.ru/help/identification/ - case id = "1234567890987654321" - case name = "Никита" - case crc = "ffadeb6aa3c788200824e311b9aa44cb" - } - - // MARK: - Properties - private let fatalErrorHandlerDelegate: FatalErrorHandlerDelegate - private let departmentListHandlerDelegate: DepartmentListHandlerDelegate - private var messageStream: MessageStream? - private var messageTracker: MessageTracker? - private var webimSession: WebimSession? - - // MARK: - Initialization - init(fatalErrorHandlerDelegate: FatalErrorHandlerDelegate, - departmentListHandlerDelegate: DepartmentListHandlerDelegate) { - self.fatalErrorHandlerDelegate = fatalErrorHandlerDelegate - self.departmentListHandlerDelegate = departmentListHandlerDelegate - } - - // MARK: - Methods - - func createSession() { - let deviceToken: String? = UserDefaults.standard.object(forKey: AppDelegate.UserDefaultsKey.deviceToken.rawValue) as? String - - var sessionBuilder = Webim.newSessionBuilder() - .set(accountName: Settings.shared.accountName) - .set(location: Settings.shared.location) - .set(pageTitle: Settings.shared.pageTitle) - .set(fatalErrorHandler: self) - .set(remoteNotificationSystem: ((deviceToken != nil) ? .APNS : .NONE)) - .set(deviceToken: deviceToken) - .set(isVisitorDataClearingEnabled: false) - .set(webimLogger: self, - verbosityLevel: .VERBOSE) - - if (Settings.shared.accountName == Settings.DefaultSettings.accountName.rawValue) { - sessionBuilder = sessionBuilder.set(visitorFieldsJSONString: "{\"\(VisitorFields.id.rawValue)\":\"\(VisitorFieldsValue.id.rawValue)\",\"\(VisitorFields.name.rawValue)\":\"\(VisitorFieldsValue.name.rawValue)\",\"\(VisitorFields.crc.rawValue)\":\"\(VisitorFieldsValue.crc.rawValue)\"}") // Hardcoded values that work with "demo" account only! - } - - do { - webimSession = try sessionBuilder.build() - } catch let error as SessionBuilder.SessionBuilderError { - // Assuming to check parameters values in Webim session builder methods. - switch error { - case .NIL_ACCOUNT_NAME: - print("Webim session object creating failed because of passing nil account name.") - - break - case .NIL_LOCATION: - print("Webim session object creating failed because of passing nil location name.") - - break - case .INVALID_REMOTE_NOTIFICATION_CONFIGURATION: - print("Webim session object creating failed because of invalid remote notifications configuration.") - - break - case .INVALID_AUTHENTICATION_PARAMETERS: - print("Webim session object creating failed because of invalid visitor authentication system configuration.") - - break - case .INVALIDE_HEX: - print("Webim can't parsed prechat fields") - } - } catch { - print("Webim session object creating failed with unknown error: \(error.localizedDescription)") - } - } - - func startSession() { - do { - try webimSession?.resume() - } catch let error as AccessError { - switch error { - case .INVALID_SESSION: - // Assuming to check Webim session object lifecycle or re-creating Webim session object. - print("Webim session starting/resuming failed because it was called when session object is invalid.") - - break - case .INVALID_THREAD: - // Assuming to check concurrent calls of WebimClientLibrary methods. - print("Webim session starting/resuming failed because it was called from a wrong thread.") - - break - } - } catch { - print("Webim session starting/resuming failed with unknown error: \(error.localizedDescription)") - } - - startChat() - } - - func stopSession() { - do { - try messageTracker?.destroy() - try webimSession?.destroy() - } catch let error as AccessError { - switch error { - case .INVALID_SESSION: - // Ignored because if session is already destroyed, we don't care (it's the same thing that we try to achieve). - - break - case .INVALID_THREAD: - // Assuming to check concurrent calls of WebimClientLibrary methods. - print("Webim session or message tracker destroing failed because it was called from a wrong thread.") - - break - } - } catch { - print("Webim session or message tracker destroing failed with unknown error: \(error.localizedDescription)") - } - } - - func setMessageStream() { - messageStream = webimSession?.getStream() - } - - func setVisitorTyping(draft: String?) { - do { - if messageStream == nil { - setMessageStream() - } - try messageStream?.setVisitorTyping(draftMessage: draft) - } catch let error as AccessError { - switch error { - case .INVALID_SESSION: - // Assuming to check Webim session object lifecycle. - print("Visitor status sending failed because it was called when session object is invalid.") - - break - case .INVALID_THREAD: - // Assuming to check concurrent calls of WebimClientLibrary methods. - print("Visitor status sending failed because it was called from a wrong thread.") - - break - } - } catch { - print("Visitor typing status sending failed with unknown error: \(error.localizedDescription)") - } - } - - func send(message: String, - completion: (() -> ())? = nil) { - do { - if messageStream == nil { - setMessageStream() - } - - if messageStream?.getVisitSessionState() == .DEPARTMENT_SELECTION, - let departments = messageStream?.getDepartmentList() { - departmentListHandlerDelegate.show(departmentList: departments) { [weak self] departmentKey in - self?.startChat(departmentKey: departmentKey, - message: message) - completion?() - } - } else { - _ = try messageStream?.send(message: message) // Returned message ID ignored. - completion?() - } - } catch let error as AccessError { - switch error { - case .INVALID_SESSION: - // Assuming to check Webim session object lifecycle or re-creating Webim session object. - print("Message sending failed because it was called when session object is invalid.") - - break - case .INVALID_THREAD: - // Assuming to check concurrent calls of WebimClientLibrary methods. - print("Message sending failed because it was called from a wrong thread.") - - break - } - } catch { - print("Message sending failed with unknown error: \(error.localizedDescription)") - } - } - - func send(file data: Data, - fileName: String, - mimeType: String, - completionHandler: SendFileCompletionHandler) { - if messageStream == nil { - setMessageStream() - } - - if messageStream?.getVisitSessionState() == .DEPARTMENT_SELECTION, - let departments = messageStream?.getDepartmentList() { - departmentListHandlerDelegate.show(departmentList: departments) { [weak self] departmentKey in - self?.startChat(departmentKey: departmentKey, - message: nil) - self?.sendFile(data: data, - fileName: fileName, - mimeType: mimeType, - completionHandler: completionHandler) - } - } else { - sendFile(data: data, - fileName: fileName, - mimeType: mimeType, - completionHandler: completionHandler) - } - } - - func isChatExist() -> Bool { - guard let chatState = messageStream?.getChatState() else { - return false - } - - return ((chatState == .CHATTING) - || (chatState == .CLOSED_BY_OPERATOR)) - } - - func closeChat() { - do { - if messageStream == nil { - setMessageStream() - } - - try messageStream?.closeChat() - } catch let error as AccessError { - switch error { - case .INVALID_SESSION: - // Assuming to check Webim session object lifecycle or re-creating Webim session object. - print("Webim session starting/resuming failed because it was called when session object is invalid.") - - break - case .INVALID_THREAD: - // Assuming to check concurrent calls of WebimClientLibrary methods. - print("Webim session starting/resuming failed because it was called from a wrong thread.") - - break - } - } catch { - print("Webim session starting/resuming failed with unknown error: \(error.localizedDescription)") - } - } - - func rateOperator(withID operatorID: String, - byRating rating: Int, - completionHandler: RateOperatorCompletionHandler?) { - do { - if messageStream == nil { - setMessageStream() - } - - try messageStream?.rateOperatorWith(id: operatorID, - byRating: rating, - completionHandler: completionHandler) - } catch let error as AccessError { - switch error { - case .INVALID_SESSION: - // Assuming to check Webim session object lifecycle or re-creating Webim session object. - print("Webim session starting/resuming failed because it was called when session object is invalid.") - - break - case .INVALID_THREAD: - // Assuming to check concurrent calls of WebimClientLibrary methods. - print("Webim session starting/resuming failed because it was called from a wrong thread.") - - break - } - } catch { - print("Webim session starting/resuming failed with unknown error: \(error.localizedDescription)") - } - } - - func setMessageTracker(withMessageListener messageListener: MessageListener) { - do { - if messageStream == nil { - setMessageStream() - } - - try messageTracker = messageStream?.newMessageTracker(messageListener: messageListener) - } catch let error as AccessError { - switch error { - case .INVALID_SESSION: - // Assuming to check Webim session object lifecycle or re-creating Webim session object. - print("Webim session starting/resuming failed because it was called when session object is invalid.") - - break - case .INVALID_THREAD: - // Assuming to check concurrent calls of WebimClientLibrary methods. - print("Webim session starting/resuming failed because it was called from a wrong thread.") - - break - } - } catch { - print("Webim session starting/resuming failed with unknown error: \(error.localizedDescription)") - } - } - - func getLastMessages(completion: @escaping (_ result: [Message]) -> ()) { - do { - try messageTracker?.getLastMessages(byLimit: ChatSettings.messagesPerRequest.rawValue, - completion: completion) - } catch let error as AccessError { - switch error { - case .INVALID_SESSION: - // Assuming to check Webim session object lifecycle or re-creating Webim session object. - print("Webim session starting/resuming failed because it was called when session object is invalid.") - - break - case .INVALID_THREAD: - // Assuming to check concurrent calls of WebimClientLibrary methods. - print("Webim session starting/resuming failed because it was called from a wrong thread.") - - break - } - } catch { - print("Webim session starting/resuming failed with unknown error: \(error.localizedDescription)") - } - } - - func getNextMessages(completion: @escaping (_ result: [Message]) -> ()) { - do { - try messageTracker?.getNextMessages(byLimit: ChatSettings.messagesPerRequest.rawValue, - completion: completion) - } catch let error as AccessError { - switch error { - case .INVALID_SESSION: - // Assuming to check Webim session object lifecycle or re-creating Webim session object. - print("Webim session starting/resuming failed because it was called when session object is invalid.") - - break - case .INVALID_THREAD: - // Assuming to check concurrent calls of WebimClientLibrary methods. - print("Webim session starting/resuming failed because it was called from a wrong thread.") - - break - } - } catch { - print("Webim session starting/resuming failed with unknown error: \(error.localizedDescription)") - } - } - - // MARK: Private methods - - private func startChat(departmentKey: String? = nil, - message: String? = nil) { - do { - if messageStream == nil { - setMessageStream() - } - - try messageStream?.startChat(departmentKey: departmentKey, - firstQuestion: message) - } catch let error as AccessError { - switch error { - case .INVALID_SESSION: - // Assuming to check Webim session object lifecycle or re-creating Webim session object. - print("Chat starting failed because it was called when session object is invalid.") - - break - case .INVALID_THREAD: - // Assuming to check concurrent calls of WebimClientLibrary methods. - print("Chat starting failed because it was called from a wrong thread.") - - break - - } - } catch { - print("Chat starting failed with unknown error: \(error.localizedDescription)") - } - } - - func setChatRead() { - do { - if messageStream == nil { - setMessageStream() - } - - try messageStream?.setChatRead() - } catch { - print("Read chat failed with unknown error: \(error.localizedDescription)") - } - } - - private func sendFile(data: Data, - fileName: String, - mimeType: String, - completionHandler: SendFileCompletionHandler) { - do { - _ = try messageStream?.send(file: data, - filename: fileName, - mimeType: mimeType, - completionHandler: completionHandler) // Returned message ID ignored. - } catch let error as AccessError { - switch error { - case .INVALID_SESSION: - // Assuming to check Webim session object lifecycle or re-creating Webim session object. - print("Message sending failed because it was called when session object is invalid.") - - break - case .INVALID_THREAD: - // Assuming to check concurrent calls of WebimClientLibrary methods. - print("Message sending failed because it was called from a wrong thread.") - - break - } - } catch { - print("Message status sending failed with unknown error: \(error.localizedDescription)") - } - } - -} - -// MARK: - WEBIM: FatalErrorHandler -extension WebimService: FatalErrorHandler { - - // MARK: - Methods - func on(error: WebimError) { - let errorType = error.getErrorType() - switch errorType { - case .ACCOUNT_BLOCKED: - // Assuming to contact with Webim support. - print("Account with used account name is blocked by Webim service.") - fatalErrorHandlerDelegate.showErrorDialog(withMessage: SessionCreationErrorDialog.accountBlocked.rawValue) - - break - case .PROVIDED_VISITOR_FIELDS_EXPIRED: - // Assuming to re-authorize it and re-create session object. - print("Provided visitor fields expired. See \"expires\" key of this fields.") - - break - case .UNKNOWN: - print("An unknown error occured: \(error.getErrorString()).") - - break - case .VISITOR_BANNED: - print("Visitor with provided visitor fields is banned by an operator.") - fatalErrorHandlerDelegate.showErrorDialog(withMessage: SessionCreationErrorDialog.visitorBanned.rawValue) - - break - case .WRONG_PROVIDED_VISITOR_HASH: - // Assuming to check visitor field generating. - print("Wrong CRC passed with visitor fields.") - - break - } - } - -} - -// MARK: - WebimLogger -extension WebimService: WebimLogger { - - // MARK: - Methods - func log(entry: String) { - print(entry) - } - -} - -// MARK: - -protocol FatalErrorHandlerDelegate: AnyObject { - - // MARK: - Methods - func showErrorDialog(withMessage message: String) - -} - -// MARK: - -protocol DepartmentListHandlerDelegate: AnyObject { - - // MARK: - Methods - func show(departmentList: [Department], - action: @escaping (String) -> ()) - -} diff --git a/ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/Localizable.strings b/ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/Localizable.strings deleted file mode 100644 index d79ce97..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/Localizable.strings +++ /dev/null @@ -1,109 +0,0 @@ -/* - Localizable.strings - WebimClientLibrary - - Created by Nikita Lazarev-Zubov on 11.12.17. - Copyright © 2017 Webim. All rights reserved. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - - -// MARK: - Remote notifications - -"P.OA" = "Обращению назначен оператор: %@."; -"P.OF" = "%@ прислал файл: %@."; -"P.OM" = "%@ написал сообщение: %@."; - - -// MARK: - StringConstants.swift - -// EMPTY_TABLE_VIEW_TEXT -"EmptyChat" = "Отправьте первое сообщение, чтобы начать чат."; - -// REFRESH_CONTROL_TEXT -"LoadingMessages" = "Сообщения загружаются..."; - -// Avatar -"SenderAvatarImage" = "Изображение аватара отправителя сообщения"; -"ShowsRatingDialog" = "Показывает окно оценки оператора."; - -// BackButton -"Back" = "Закрыть экран"; -"ClosesScreen" = "Закрывает экран и возвращает на предыдущий."; - -// ChatClosedDialog -"ChatClosed" = "Чат закончен."; -"OK" = "OK"; -"ClosesRateOperatorError" = "Закрывает окно."; - -// CloseChatButton -"CloseChat" = "Закрыть чат"; -"ClosesChat" = "Закрывает чат не закрывая данный экран."; - -// DepartmentListDialog -"ContactTopic" = "Тема обращения"; -"ChoosesTopic" = "Выбирает данную тему для обращения"; -"Cancel" = "Отмена"; -"ClosesDialog" = "Закрывает окно."; - -// FileMessage -"FileUnavailable" = "Файл недоступен."; - -// LeftButton -"ChooseFile" = "Выбрать файл для отправки"; -"ShowsImagePicker" = "Показывает окно выбора изображения для отправки."; - -// RateOperatorErrorMessage -"OperatorRatingFailed" = "Неудачная попытка оценить оператора"; -"OK" = "OK"; -"ClosesRateOperatorError" = "Закрывает окно."; -"RateOperatorErrorMessage" = "Произошла неизвестная ошибка."; - -// RatingDialog -"Rate" = "Оценить"; -"Cancel" = "Отмена"; -"RatesOperator" = "Оценивает оператора."; -"ClosesRatingDialog" = "Закрывает диалог."; - -// SendFileErrorMessage -"FileSendingFailed" = "Неудачная попытка отправки файла"; -"ClosesSendFileError" = "Закрывает окно."; -"FileTooLarge" = "Размер файла превышен."; -"FileTypeNotSupported" = "Данный тип файла не поддерживается."; -"FileNotFound" = "Отправляемый файл не был получен."; -"FileSendingUnknownError" = "Неизвестная ошибка при отправке файла"; - -// SessionCreationErrorDialog -"ClosesSessionError" = "Закрывает окно."; -"SessionCreationFailed" = "Неудачная попытка создания сессии"; -"AccountBlocked" = "Учетная запись, с помощью которой была произведена попытка начать сессию, заблокирован. Пожалуйста, обратитесь в службу поддержки \"Webim\" или используйте другую учетную запись."; -"VisitorBanned" = "Ваша учетная запись посетителя находится в черном списке."; - -// SettingsErrorDialog -"ClosesSettingsError" = "Закрывает окно."; -"InvalidSettings" = "Неверные данные учетной записи"; -"AccountNameEmpty" = "Название учетной записи не может быть пустым."; -"LocationEmpty" = "Значение размещения не может быть пустым."; - -// ShowFileDialog -"ImageFormatInvalid" = "Неверный формат изображения."; -"ImageLinkInvalid" = "Ссылка недействительна."; -"PreviewUnavailable" = "Просмотр недоступен."; -"ClosesFilePreview" = "Закрывает окно."; diff --git a/ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/Main.strings b/ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/Main.strings deleted file mode 100644 index 6bfda1d..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/Main.strings +++ /dev/null @@ -1,88 +0,0 @@ - -/* Class = "UILabel"; text = "Account name *"; ObjectID = "7Wr-eX-iv8"; */ -"7Wr-eX-iv8.text" = "Название аккаунта *"; - -/* Class = "UITableViewSection"; footerTitle = "If you are registered in Webim service you can use your own account name and location."; ObjectID = "FX1-M6-A8v"; */ -"FX1-M6-A8v.footerTitle" = "Если вы зарегистрированы в сервисе \"Webim\", вы можете использовать свою учетную запись."; - -/* Class = "UITableViewSection"; headerTitle = "ACCOUNT"; ObjectID = "FX1-M6-A8v"; */ -"FX1-M6-A8v.headerTitle" = "УЧЕТНАЯ ЗАПИСЬ"; - -/* Class = "UIButton"; accessibilityHint = "Saves current settings and shows start screen."; ObjectID = "QrB-ab-D1k"; */ -"QrB-ab-D1k.accessibilityHint" = "Сохраняет текущие настройки и возвращается к начальной странице."; - -/* Class = "UIButton"; accessibilityLabel = "Save"; ObjectID = "QrB-ab-D1k"; */ -"QrB-ab-D1k.accessibilityLabel" = "Сохранить"; - -/* Class = "UIButton"; normalTitle = "Save"; ObjectID = "QrB-ab-D1k"; */ -"QrB-ab-D1k.normalTitle" = "Сохранить"; - -/* Class = "UILabel"; accessibilityLabel = "Classic color theme"; ObjectID = "Xp5-8q-gOf"; */ -"Xp5-8q-gOf.accessibilityLabel" = "Стандартная цветовая схема"; - -/* Class = "UILabel"; text = "Classic"; ObjectID = "Xp5-8q-gOf"; */ -"Xp5-8q-gOf.text" = "Стандартная"; - -/* Class = "UITextField"; accessibilityLabel = "Page title field"; ObjectID = "YbA-Bc-Fio"; */ -"YbA-Bc-Fio.accessibilityLabel" = "Поле названия страницы чата"; - -/* Class = "UITextField"; text = "iOS Demo App"; ObjectID = "YbA-Bc-Fio"; */ -"YbA-Bc-Fio.text" = "iOS Demo App"; - -/* Class = "UITextField"; accessibilityLabel = "Location name field"; ObjectID = "ZbE-AG-UMG"; */ -"ZbE-AG-UMG.accessibilityLabel" = "Поле названия размещения (локации)"; - -/* Class = "UITextField"; text = "mobile"; ObjectID = "ZbE-AG-UMG"; */ -"ZbE-AG-UMG.text" = "mobile"; - -/* Class = "UITextView"; accessibilityLabel = "Greeting words"; ObjectID = "bPt-yP-yHN"; */ -"bPt-yP-yHN.accessibilityLabel" = "Приветственные слова"; - -// Xcode does not localize UITextView text automatically. -/* Class = "UITextView"; text = "Welcome to the WebimClientLibrary demo app!\n\nTo start a chat tap on the button below.\n\nOperator can answer to your chat at:\nhttps://demo.webim.ru/\nLogin: o@webim.ru\nPassword: password\n\nThis app source code can be found at:\nhttps://github.com/webim/webim-client-sdk-ios"; ObjectID = "bPt-yP-yHN"; */ -"Welcome to the WebimClientLibrary demo app!\n\nTo start a chat tap on the button below.\n\nOperator can answer to your chat at:\nhttps://demo.webim.ru/\nLogin: o@webim.ru\nPassword: password\n\nThis app source code can be found at:\nhttps://github.com/webim/webim-client-sdk-ios" = "Добро пожаловать в демо-приложение WebimClientLibrary!\n\nЧтобы начать чат, нажмите кнопку внизу.\n\nОператор может ответить на обращение здесь:\nhttps://demo.webim.ru/\nЛогин: o@webim.ru\nПароль: password\n\nИсходный код данного приложения может быть найден здесь:\nhttps://github.com/webim/webim-client-sdk-ios"; - -/* Class = "UIButton"; accessibilityHint = "Starts chat."; ObjectID = "edo-SU-HN8"; */ -"edo-SU-HN8.accessibilityHint" = "Начинает чат."; - -/* Class = "UIButton"; accessibilityLabel = "Start chat"; ObjectID = "edo-SU-HN8"; */ -"edo-SU-HN8.accessibilityLabel" = "Начать чат"; - -/* Class = "UIButton"; normalTitle = "Start chat"; ObjectID = "edo-SU-HN8"; */ -"edo-SU-HN8.normalTitle" = "Начать чат"; - -/* Class = "UITableViewSection"; headerTitle = "COLOR THEME"; ObjectID = "fJX-AG-mdU"; */ -"fJX-AG-mdU.headerTitle" = "ЦВЕТОВАЯ СХЕМА"; - -/* Class = "UILabel"; text = "Page title"; ObjectID = "kTz-jD-ziQ"; */ -"kTz-jD-ziQ.text" = "Название экрана чата"; - -/* Class = "UITextField"; accessibilityLabel = "Account name field"; ObjectID = "qLZ-bH-B74"; */ -"qLZ-bH-B74.accessibilityLabel" = "Поле названия учетной записи"; - -/* Class = "UITextField"; text = "demo"; ObjectID = "qLZ-bH-B74"; */ -"qLZ-bH-B74.text" = "demo"; - -/* Class = "UILabel"; text = "Location *"; ObjectID = "qQH-qh-OFD"; */ -"qQH-qh-OFD.text" = "Размещение *"; - -/* Class = "UIButton"; accessibilityHint = "Shows settings."; ObjectID = "rMR-x2-dzu"; */ -"rMR-x2-dzu.accessibilityHint" = "Показывает настройки."; - -/* Class = "UIButton"; accessibilityLabel = "Settings"; ObjectID = "rMR-x2-dzu"; */ -"rMR-x2-dzu.accessibilityLabel" = "Настройки"; - -/* Class = "UIButton"; normalTitle = "Settings"; ObjectID = "rMR-x2-dzu"; */ -"rMR-x2-dzu.normalTitle" = "Настройки"; - -/* Class = "UILabel"; accessibilityLabel = "Dark color theme"; ObjectID = "slT-Ti-eBV"; */ -"slT-Ti-eBV.accessibilityLabel" = "Темная цветовая СХЕМА"; - -/* Class = "UILabel"; text = "Dark"; ObjectID = "slT-Ti-eBV"; */ -"slT-Ti-eBV.text" = "Темная"; - -/* Class = "UILabel"; text = "* Account name can't be empty."; ObjectID = "5Lf-Fb-XN7"; */ -"5Lf-Fb-XN7.text" = "* Название учетной записи не может быть пустым."; - -/* Class = "UILabel"; text = "* Location can't be empty."; ObjectID = "6r5-5x-xIB"; */ -"6r5-5x-xIB.text" = "* Размещение (локация) не может быть пустым."; diff --git a/ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/RatingViewController.strings b/ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/RatingViewController.strings deleted file mode 100644 index 6f91939..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary/ru-RU.lproj/RatingViewController.strings +++ /dev/null @@ -1,9 +0,0 @@ - -/* Class = "UIView"; accessibilityHint = "Устанавливает оценку оператора числом от одного до пяти."; ObjectID = "TCC-HX-zVh"; */ -"TCC-HX-zVh.accessibilityHint" = "Устанавливает оценку оператора числом от одного до пяти."; - -/* Class = "UIView"; accessibilityLabel = "Оценка"; ObjectID = "TCC-HX-zVh"; */ -"TCC-HX-zVh.accessibilityLabel" = "Оценка"; - -/* Class = "UILabel"; text = "Оценить оператора"; ObjectID = "XLW-Lu-VBj"; */ -"XLW-Lu-VBj.text" = "Оценить оператора"; diff --git a/ios/libs/Webim/Example/WebimClientLibrary_Example.entitlements b/ios/libs/Webim/Example/WebimClientLibrary_Example.entitlements deleted file mode 100644 index 903def2..0000000 --- a/ios/libs/Webim/Example/WebimClientLibrary_Example.entitlements +++ /dev/null @@ -1,8 +0,0 @@ - - - - - aps-environment - development - - diff --git a/ios/libs/Webim/Info.plist b/ios/libs/Webim/Info.plist deleted file mode 100644 index cad21c5..0000000 --- a/ios/libs/Webim/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 3.24.7 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/ios/libs/Webim/LICENSE b/ios/libs/Webim/LICENSE deleted file mode 100644 index b116da0..0000000 --- a/ios/libs/Webim/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2017-2019 Webim - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/ios/libs/Webim/README.md b/ios/libs/Webim/README.md deleted file mode 100644 index 89f1549..0000000 --- a/ios/libs/Webim/README.md +++ /dev/null @@ -1,181 +0,0 @@ -

- -![Webim logo](Documentation/Images/Logo.png) - -
- -# WebimClientLibrary - -This library provides [_Webim SDK_ for _iOS_](https://webim.ru/integration/mobile-sdk/ios-sdk-howto/) – a way to integrate _Webim_ service into your _iOS_ app. - -## Installation - -> Minimum iOS version supported – 8.0. - -### CocoaPods - -Add following line for your target in your **Podfile**: -``` -pod 'WebimClientLibrary', :git => 'https://github.com/webim/webim-client-sdk-ios.git', :branch => 'master', :tag => '3.24.6' -``` -`use_frameworks!` must be specified. - -### Carthage - -Add following line to your **Cartfile**: -``` -github "webim/webim-client-sdk-ios" ~> 3.24.7 -``` - -### Additional notes - -#### Objective-C - -Trying to integrate _WebimClientLibrary_ into your _Objective-C_ code? Try out our [_WebimClientLibraryWrapper_](https://github.com/webim/webim-client-sdk-ios-wrapper). - -#### Previous version - -Previous _Objective-C_ version (version numbers 2.x.x) can be reached from **version2** branch. - -## Release notes -* SQLiteHistoryStorage methods bugs fixed. -* Uptime in HistoryPoller bag fixed. -* New parameters in User-Agent: Bundle ID and version. - -## Example - -![Start screen screenshot Classic theme](Documentation/Images/Screenshots/StartScreenClassic.png) ![Settings screen screenshot Classic theme](Documentation/Images/Screenshots/SettingsScreenClassic.png) ![Chat screen screenshot Classic theme](Documentation/Images/Screenshots/ChatScreenClassic.png) ![Image preview screenshot Classic theme](Documentation/Images/Screenshots/ImageScreenClassic.png) ![Rating window screenshot Classic theme](Documentation/Images/Screenshots/RatingScreenClassic.png) - -![Start screen screenshot Dark theme](Documentation/Images/Screenshots/StartScreenDark.png) ![Settings screen screenshot Dark theme](Documentation/Images/Screenshots/SettingsScreenDark.png) ![Chat screen screenshot Dark theme](Documentation/Images/Screenshots/ChatScreenDark.png) ![Image preview screenshot Dark theme](Documentation/Images/Screenshots/ImageScreenDark.png) ![Rating window screenshot Dark theme](Documentation/Images/Screenshots/RatingScreenDark.png) - -If you don't have _CocoaPods_ installed you should firstly run `sudo gem install cocoapods`. - -To run the example project, clone the repo and run `pod install` from the **Example** directory first. - -## Usage - -### Session - -SDK functionality usage starts with session object creating. - -`Webim` class method `newSessionBuilder()` returns session builder object (class `SessionBuilder`) (both of this classes and their methods are described inside **Webim.swift** file). Then setting session parameters methods are to be called on the created `SessionBuilder` object. After all necessary parameters are set, method `build()` is to be called. This method returns `WebimSession` object. - -Typical usage example: -``` -let webimSession = try Webim.newSessionBuilder().set(accountName: "ACCOUNT_NAME").set(location: "LOCATION_NAME").build() -``` - -All parameters that can be set while creating a session and all errors that can be thrown are also described in **Webim.swift** file. Account name and locations are the only required of them. - -After the session is created it must be started by `resume()` method (since a session object is initially paused). - -Session can be paused (`pause()` method) and resumed (`resume()` method) as well as destroyed (`destroy()` method) if necessary. All of this methods are described in **WebimSession.swift** file. - -### MessageStream - -All message stream methods are described in **MessageStream.swift** file. - -For this methods usage ability the `MessageStream` object is have to be getted through `getStream()` method by `WebimSession` class object. - -Methods examples: -`send(message:)` – send message, -`rateOperatorWith(id:byRating:)` – rate operator, -`closeChat()` – close chat. - -### MessageTracker - -`newMessageTracker(messageListener:)` method by `MessageStream` object creates `MessageTracker` object, which can be used to control a message stream inside an app. - -E.g. `getNextMessages(byLimit:completion:)` method requests a certain amount of messages from the history. - -Methods descriptions can be found inside **MessageTracker.swift** file. - -### MessageListener - -`MessageListener` protocol describes methods which can help to track changes in the message stream. An app must have a class which implements this protocol methods: `added(message:after:)`, `removed(message:)`, `removedAllMessages()`, `changed(message:to:)`. This methods are called automatically when new message is added, a message is deleted, all messages are deleted and a message is changed respectively. - -Full methods descriptions can be found inside **MessageListener.swift** file. - -### Message - -`MessageListener` protocol methods operate on `Message` objects which is described inside **Message.swift** file. - -All necessary information about specific message can be getted through `Message` objects methods: unique message number (`getID()` method), message text (`getText()` method), attached file info (`getAttachment()` method) etc. - -All related tools (methods for working with attachments, message types etc.) are also described in **Message.swift** file. - -### Additional features - -Methods for getting information about specific operator are described inside **Operator.swift** file. Operator object can be getted through `MessageStream` object `getCurrentOperator()` method. - -Methods for working with remote notifications by _Webim_ service are described inside **WebimRemoteNotification.swift** file. - -Specific remote notification object can be getted through `Webim` class `parse(remoteNotification:)` method. This class also has method `isWebim(remoteNotification:)` which can be used to easily discover whether the notification is send by _Webim_ service or not. - -**FatalErrorHandler.swift** contains `FatalErrorHandler` protocol description. Its methods can be implemented by an app for tracking errors which can arise in progress. All kinds of specific errors are described inside the same file. - -**MessageStream.swift** also contains additional protocols descriptions which can be implemented by an app classes for tracking different particular changes. E.g. `ChatStateListener` protocol methods are called when chat state is changed (all the specific chat states are described in the same file). - -## Remote notifications - -**For remote notifications to be enabled you should send your app certificates/private key to us. For more information please contact to our support!** - -For iOS to be able to handle remote notifications automatically your app must be aware of possible remote notification types and arguments. - -Possible `loc-key` values: -* `P.CR` means that operator sent contact information request. -* `P.OA` means that operator accepted chat. -* `P.OF` means that operator sent a flie. -* `P.OM` means that operator sent a text message. -* `P.WM` means that operator sent a widget message (for this functionality support one should contact _Webim_ support). - -`loc-args` values for this types: -* `P.CR`: empty. -* `P.OA`: operator's name. -* `P.OF`: operator's name, file name. -* `P.OM`: operator's name, message text. -* `P.WM`: empty. - -Remote notification handling with Strings.localizable file example: -``` -"P.OM" = "Message from %@ is received: %@." -``` - -### Conclusion - -Entities and methods described above are all that it necessary for working in an app with _Webim_ service and even more. - -Abilities described In this manual are not all of the existing ones, so after necessary minimum is implemented it is recommended to get acquainted with full list of protocols and methods listed in SDK public files. - -All public interfaces, classes and methods are described inside this files (in alphabetical order): -* **Department.swift**, -* **FatalErrorHandler.swift**, -* **Message.swift**, -* **MessageListener.swift**, -* **MessageStream.swift**, -* **MessageTracker.swit**, -* **Operator.swift**, -* **ProvidedAuthorizationTokenStateListener.swift** -* **Webim.swift**, -* **WebimError.swift**, -* **WebimLogger.swift**, -* **WebimRemoteNotification.swift**, -* **WebimSession.swift**. - -Every single class, protocol, method etc. description provided inside [documentation](Documentation/Index.md). - -## Additional information - -_WebimClientLibrary_ uses [_SQLite.swift_](https://github.com/stephencelis/SQLite.swift). (There's no need to add this depencies into Podfile.) - -In the sake of ease of several functionalities implementation Example app uses (in alphabetical order): -* [_Cosmos_](https://github.com/evgenyneu/Cosmos) – for visual implementation of operator rating mechanism. -* [_Crashlytics_](https://try.crashlytics.com) – for detecting crashes and investigating their causes. -* [_PopupDialog_](https://github.com/Orderella/PopupDialog) – for implemetation of pop-up dialogs. -* [_SnapKit_](https://github.com/SnapKit/SnapKit) – for AutoLayout mechanism implementation inside the code. -* [_SlackTextViewController_](https://github.com/slackhq/SlackTextViewController) – for chat stream displaying inside Table View. - - -## License - -_WebimClientLibrary_ is available under the MIT license. See the LICENSE file for more info. diff --git a/ios/libs/Webim/WebimClientLibrary.podspec b/ios/libs/Webim/WebimClientLibrary.podspec deleted file mode 100644 index 0fa9652..0000000 --- a/ios/libs/Webim/WebimClientLibrary.podspec +++ /dev/null @@ -1,19 +0,0 @@ -Pod::Spec.new do |s| - - s.name = 'WebimClientLibrary' - s.version = '3.24.7' - - s.author = { 'Webim.ru Ltd.' => 'n.lazarev-zubov@webim.ru' } - s.homepage = 'https://webim.ru/integration/mobile-sdk/ios-sdk-howto/' - s.license = { :type => 'MIT', :file => 'LICENSE' } - s.summary = 'Webim.ru client SDK for iOS.' - - s.ios.deployment_target = '8.0' - s.swift_version = '4.2' - s.source = { :git => 'https://github.com/webim/webim-client-sdk-ios.git', :tag => s.version.to_s } - - s.dependency 'SQLite.swift', '0.11.5' - s.frameworks = 'Foundation' - s.source_files = 'WebimClientLibrary/**/*' - -end diff --git a/ios/libs/Webim/WebimClientLibrary.xcodeproj/project.pbxproj b/ios/libs/Webim/WebimClientLibrary.xcodeproj/project.pbxproj deleted file mode 100644 index fb13e71..0000000 --- a/ios/libs/Webim/WebimClientLibrary.xcodeproj/project.pbxproj +++ /dev/null @@ -1,778 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 48; - objects = { - -/* Begin PBXBuildFile section */ - 8FD2428B200CDB18007EB9CB /* WebimClientLibrary.h in Headers */ = {isa = PBXBuildFile; fileRef = 8FD2427D200CDB18007EB9CB /* WebimClientLibrary.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8FD244A8200CE25C007EB9CB /* WebimLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2445C200CE258007EB9CB /* WebimLogger.swift */; }; - 8FD244A9200CE25C007EB9CB /* MessageListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2445D200CE258007EB9CB /* MessageListener.swift */; }; - 8FD244AA200CE25C007EB9CB /* WebimRemoteNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2445E200CE259007EB9CB /* WebimRemoteNotification.swift */; }; - 8FD244AB200CE25C007EB9CB /* WebimSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2445F200CE259007EB9CB /* WebimSession.swift */; }; - 8FD244AC200CE25C007EB9CB /* Operator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24460200CE259007EB9CB /* Operator.swift */; }; - 8FD244AD200CE25C007EB9CB /* Department.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24461200CE259007EB9CB /* Department.swift */; }; - 8FD244AE200CE25C007EB9CB /* ProvidedAuthorizationTokenStateListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24462200CE259007EB9CB /* ProvidedAuthorizationTokenStateListener.swift */; }; - 8FD244AF200CE25C007EB9CB /* MessageTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24463200CE25A007EB9CB /* MessageTracker.swift */; }; - 8FD244B0200CE25C007EB9CB /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24464200CE25A007EB9CB /* Message.swift */; }; - 8FD244B1200CE25C007EB9CB /* HistoryMetaInformationStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24466200CE25A007EB9CB /* HistoryMetaInformationStorage.swift */; }; - 8FD244B2200CE25C007EB9CB /* MemoryHistoryStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24467200CE25A007EB9CB /* MemoryHistoryStorage.swift */; }; - 8FD244B3200CE25C007EB9CB /* InternalErrorListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24468200CE25A007EB9CB /* InternalErrorListener.swift */; }; - 8FD244B4200CE25C007EB9CB /* MemoryHistoryMetaInformationStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24469200CE25A007EB9CB /* MemoryHistoryMetaInformationStorage.swift */; }; - 8FD244B5200CE25C007EB9CB /* ClientSideID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2446A200CE25A007EB9CB /* ClientSideID.swift */; }; - 8FD244B6200CE25C007EB9CB /* WebimActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2446B200CE25A007EB9CB /* WebimActions.swift */; }; - 8FD244B7200CE25C007EB9CB /* MessageComposingHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2446C200CE25A007EB9CB /* MessageComposingHandler.swift */; }; - 8FD244B8200CE25C007EB9CB /* WebimInternalError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2446D200CE25A007EB9CB /* WebimInternalError.swift */; }; - 8FD244B9200CE25C007EB9CB /* LocationSettingsHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2446E200CE25A007EB9CB /* LocationSettingsHolder.swift */; }; - 8FD244BB200CE25C007EB9CB /* WebimRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24470200CE25A007EB9CB /* WebimRequest.swift */; }; - 8FD244BC200CE25C007EB9CB /* WebimClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24471200CE25A007EB9CB /* WebimClient.swift */; }; - 8FD244BD200CE25C007EB9CB /* RemoteHistoryProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24472200CE25A007EB9CB /* RemoteHistoryProvider.swift */; }; - 8FD244BE200CE25C007EB9CB /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24475200CE25A007EB9CB /* Dictionary.swift */; }; - 8FD244BF200CE25C007EB9CB /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24476200CE25A007EB9CB /* String.swift */; }; - 8FD244C0200CE25C007EB9CB /* MessageFactories.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24477200CE25A007EB9CB /* MessageFactories.swift */; }; - 8FD244C1200CE25C007EB9CB /* InternalUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24478200CE25A007EB9CB /* InternalUtils.swift */; }; - 8FD244C2200CE25C007EB9CB /* CompletionHandlerWrappers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24479200CE25A007EB9CB /* CompletionHandlerWrappers.swift */; }; - 8FD244C3200CE25C007EB9CB /* AbstractRequestLoop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2447A200CE25A007EB9CB /* AbstractRequestLoop.swift */; }; - 8FD244C4200CE25C007EB9CB /* DeltaCallback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2447B200CE25A007EB9CB /* DeltaCallback.swift */; }; - 8FD244C5200CE25C007EB9CB /* ActionRequestLoop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2447C200CE25A007EB9CB /* ActionRequestLoop.swift */; }; - 8FD244C6200CE25C007EB9CB /* SessionDestroyer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2447D200CE25A007EB9CB /* SessionDestroyer.swift */; }; - 8FD244C7200CE25C007EB9CB /* ProvidedVisitorFields.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2447E200CE25A007EB9CB /* ProvidedVisitorFields.swift */; }; - 8FD244C8200CE25C007EB9CB /* ExecIfNotDestroyedHandlerExecutor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2447F200CE25A007EB9CB /* ExecIfNotDestroyedHandlerExecutor.swift */; }; - 8FD244C9200CE25C007EB9CB /* AuthorizationData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24480200CE25A007EB9CB /* AuthorizationData.swift */; }; - 8FD244CA200CE25C007EB9CB /* DeltaRequestLoop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24481200CE25A007EB9CB /* DeltaRequestLoop.swift */; }; - 8FD244CB200CE25C007EB9CB /* OperatorItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24483200CE25A007EB9CB /* OperatorItem.swift */; }; - 8FD244CC200CE25C007EB9CB /* DepartmentItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24484200CE25A007EB9CB /* DepartmentItem.swift */; }; - 8FD244CD200CE25C007EB9CB /* RatingItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24485200CE25A007EB9CB /* RatingItem.swift */; }; - 8FD244CE200CE25C007EB9CB /* VisitSessionStateItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24486200CE25A007EB9CB /* VisitSessionStateItem.swift */; }; - 8FD244CF200CE25C007EB9CB /* HistoryBeforeResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24488200CE25A007EB9CB /* HistoryBeforeResponse.swift */; }; - 8FD244D0200CE25C007EB9CB /* HistorySinceResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24489200CE25A007EB9CB /* HistorySinceResponse.swift */; }; - 8FD244D1200CE25C007EB9CB /* DeltaResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2448A200CE25A007EB9CB /* DeltaResponse.swift */; }; - 8FD244D2200CE25C007EB9CB /* FileParametersItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2448B200CE25A007EB9CB /* FileParametersItem.swift */; }; - 8FD244D3200CE25C007EB9CB /* OnlineStatusItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2448C200CE25A007EB9CB /* OnlineStatusItem.swift */; }; - 8FD244D4200CE25C007EB9CB /* DeltaItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2448E200CE25A007EB9CB /* DeltaItem.swift */; }; - 8FD244D5200CE25C007EB9CB /* FullUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2448F200CE25A007EB9CB /* FullUpdate.swift */; }; - 8FD244D6200CE25C007EB9CB /* ChatItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24490200CE25A007EB9CB /* ChatItem.swift */; }; - 8FD244D7200CE25C007EB9CB /* VisitorItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24491200CE25A007EB9CB /* VisitorItem.swift */; }; - 8FD244D8200CE25C007EB9CB /* MessageItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24492200CE25A007EB9CB /* MessageItem.swift */; }; - 8FD244D9200CE25C007EB9CB /* MessageToSend.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24493200CE25A007EB9CB /* MessageToSend.swift */; }; - 8FD244DA200CE25C007EB9CB /* SessionParametersListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24494200CE25A007EB9CB /* SessionParametersListener.swift */; }; - 8FD244DB200CE25C007EB9CB /* AccessChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24495200CE25A007EB9CB /* AccessChecker.swift */; }; - 8FD244DC200CE25C007EB9CB /* SQLiteHistoryStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24496200CE25A007EB9CB /* SQLiteHistoryStorage.swift */; }; - 8FD244DD200CE25C007EB9CB /* HistoryID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24497200CE25A007EB9CB /* HistoryID.swift */; }; - 8FD244DE200CE25C007EB9CB /* HistoryStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24498200CE25A007EB9CB /* HistoryStorage.swift */; }; - 8FD244DF200CE25C007EB9CB /* MessageHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD24499200CE25A007EB9CB /* MessageHolder.swift */; }; - 8FD244E0200CE25C007EB9CB /* DepartmentImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2449B200CE25B007EB9CB /* DepartmentImpl.swift */; }; - 8FD244E1200CE25C007EB9CB /* OperatorImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2449C200CE25B007EB9CB /* OperatorImpl.swift */; }; - 8FD244E2200CE25C007EB9CB /* MessageStreamImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2449D200CE25B007EB9CB /* MessageStreamImpl.swift */; }; - 8FD244E3200CE25C007EB9CB /* WebimRemoteNotificationImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2449E200CE25B007EB9CB /* WebimRemoteNotificationImpl.swift */; }; - 8FD244E4200CE25C007EB9CB /* MessageImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD2449F200CE25B007EB9CB /* MessageImpl.swift */; }; - 8FD244E5200CE25C007EB9CB /* WebimErrorImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD244A0200CE25B007EB9CB /* WebimErrorImpl.swift */; }; - 8FD244E6200CE25C007EB9CB /* MessageTrackerImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD244A1200CE25B007EB9CB /* MessageTrackerImpl.swift */; }; - 8FD244E7200CE25C007EB9CB /* WebimSessionImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD244A2200CE25B007EB9CB /* WebimSessionImpl.swift */; }; - 8FD244E8200CE25C007EB9CB /* LocationSettingsImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD244A3200CE25B007EB9CB /* LocationSettingsImpl.swift */; }; - 8FD244E9200CE25C007EB9CB /* FatalErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD244A4200CE25B007EB9CB /* FatalErrorHandler.swift */; }; - 8FD244EA200CE25C007EB9CB /* WebimError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD244A5200CE25B007EB9CB /* WebimError.swift */; }; - 8FD244EB200CE25C007EB9CB /* MessageStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD244A6200CE25B007EB9CB /* MessageStream.swift */; }; - 8FD244EC200CE25C007EB9CB /* Webim.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FD244A7200CE25B007EB9CB /* Webim.swift */; }; - CE2E681120123DB7004E99EA /* Array.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2E681020123DB6004E99EA /* Array.swift */; }; - CE2E681320123DC9004E99EA /* Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2E681220123DC9004E99EA /* Collection.swift */; }; - CE2E681520123DD0004E99EA /* Int.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2E681420123DD0004E99EA /* Int.swift */; }; - CE2E681720123DD4004E99EA /* UInt32.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2E681620123DD4004E99EA /* UInt32.swift */; }; - CE529807222EA38C00033278 /* HistoryRevisionItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE529806222EA38C00033278 /* HistoryRevisionItem.swift */; }; - CE6A6978220C730F00B11E29 /* FAQItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE6A6977220C730F00B11E29 /* FAQItem.swift */; }; - CE6A697A220C731600B11E29 /* FAQ.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE6A6979220C731600B11E29 /* FAQ.swift */; }; - CE6A697C220C799300B11E29 /* FAQActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE6A697B220C799300B11E29 /* FAQActions.swift */; }; - CE6A697E220C7F3000B11E29 /* FAQClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE6A697D220C7F3000B11E29 /* FAQClient.swift */; }; - CE6A6980220C83F900B11E29 /* FAQRequestLoop.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE6A697F220C83F900B11E29 /* FAQRequestLoop.swift */; }; - CE6A6982220C968D00B11E29 /* FAQImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE6A6981220C968D00B11E29 /* FAQImpl.swift */; }; - CE6A6984220C9BBB00B11E29 /* FAQDestroyer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE6A6983220C9BBB00B11E29 /* FAQDestroyer.swift */; }; - CE6A6986220C9DE200B11E29 /* FAQAccessChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE6A6985220C9DE200B11E29 /* FAQAccessChecker.swift */; }; - CE6A6988220CA70A00B11E29 /* FAQItemItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE6A6987220CA70A00B11E29 /* FAQItemItem.swift */; }; - CE76D61F22108835006A5BF0 /* ExecIfNotDestroyedFAQHandlerExecutor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE76D61E22108834006A5BF0 /* ExecIfNotDestroyedFAQHandlerExecutor.swift */; }; - CE76D6212210A6DC006A5BF0 /* FAQStructure.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE76D6202210A6DC006A5BF0 /* FAQStructure.swift */; }; - CE76D6232210A6F3006A5BF0 /* FAQCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE76D6222210A6F3006A5BF0 /* FAQCategory.swift */; }; - CE86FA95203AF37F00CB9C2D /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE86FA94203AF37F00CB9C2D /* UIColor.swift */; }; - CE86FAAB203B2A2600CB9C2D /* OperatorFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE86FAAA203B2A2600CB9C2D /* OperatorFactory.swift */; }; - CE86FAAD203B2A4500CB9C2D /* DepartmentFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE86FAAC203B2A4500CB9C2D /* DepartmentFactory.swift */; }; - CEBF03962211D5EE001658D8 /* FAQStructureItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEBF03952211D5EE001658D8 /* FAQStructureItem.swift */; }; - CEBF03982211D837001658D8 /* FAQCategoryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEBF03972211D837001658D8 /* FAQCategoryItem.swift */; }; - CEBF039A2211F070001658D8 /* FAQCategoryInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEBF03992211F070001658D8 /* FAQCategoryInfo.swift */; }; - CED72593200E11D900CD1623 /* WebimInternalLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = CED72592200E11D900CD1623 /* WebimInternalLogger.swift */; }; - CEF33876221C74C700A7EA27 /* FAQCategoryInfoItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEF33875221C74C700A7EA27 /* FAQCategoryInfoItem.swift */; }; - D6A45F8B22A13A2400B5BB27 /* SQLite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6A45F8A22A13A2400B5BB27 /* SQLite.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 8FD2427A200CDB18007EB9CB /* WebimClientLibrary.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = WebimClientLibrary.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 8FD2427D200CDB18007EB9CB /* WebimClientLibrary.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebimClientLibrary.h; sourceTree = ""; }; - 8FD2445C200CE258007EB9CB /* WebimLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebimLogger.swift; sourceTree = ""; }; - 8FD2445D200CE258007EB9CB /* MessageListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageListener.swift; sourceTree = ""; }; - 8FD2445E200CE259007EB9CB /* WebimRemoteNotification.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebimRemoteNotification.swift; sourceTree = ""; }; - 8FD2445F200CE259007EB9CB /* WebimSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebimSession.swift; sourceTree = ""; }; - 8FD24460200CE259007EB9CB /* Operator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operator.swift; sourceTree = ""; }; - 8FD24461200CE259007EB9CB /* Department.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Department.swift; sourceTree = ""; }; - 8FD24462200CE259007EB9CB /* ProvidedAuthorizationTokenStateListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProvidedAuthorizationTokenStateListener.swift; sourceTree = ""; }; - 8FD24463200CE25A007EB9CB /* MessageTracker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageTracker.swift; sourceTree = ""; }; - 8FD24464200CE25A007EB9CB /* Message.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = ""; }; - 8FD24466200CE25A007EB9CB /* HistoryMetaInformationStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoryMetaInformationStorage.swift; sourceTree = ""; }; - 8FD24467200CE25A007EB9CB /* MemoryHistoryStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MemoryHistoryStorage.swift; sourceTree = ""; }; - 8FD24468200CE25A007EB9CB /* InternalErrorListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InternalErrorListener.swift; sourceTree = ""; }; - 8FD24469200CE25A007EB9CB /* MemoryHistoryMetaInformationStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MemoryHistoryMetaInformationStorage.swift; sourceTree = ""; }; - 8FD2446A200CE25A007EB9CB /* ClientSideID.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClientSideID.swift; sourceTree = ""; }; - 8FD2446B200CE25A007EB9CB /* WebimActions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebimActions.swift; sourceTree = ""; }; - 8FD2446C200CE25A007EB9CB /* MessageComposingHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageComposingHandler.swift; sourceTree = ""; }; - 8FD2446D200CE25A007EB9CB /* WebimInternalError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebimInternalError.swift; sourceTree = ""; }; - 8FD2446E200CE25A007EB9CB /* LocationSettingsHolder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationSettingsHolder.swift; sourceTree = ""; }; - 8FD24470200CE25A007EB9CB /* WebimRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebimRequest.swift; sourceTree = ""; }; - 8FD24471200CE25A007EB9CB /* WebimClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebimClient.swift; sourceTree = ""; }; - 8FD24472200CE25A007EB9CB /* RemoteHistoryProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteHistoryProvider.swift; sourceTree = ""; }; - 8FD24475200CE25A007EB9CB /* Dictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dictionary.swift; sourceTree = ""; }; - 8FD24476200CE25A007EB9CB /* String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; }; - 8FD24477200CE25A007EB9CB /* MessageFactories.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageFactories.swift; sourceTree = ""; }; - 8FD24478200CE25A007EB9CB /* InternalUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InternalUtils.swift; sourceTree = ""; }; - 8FD24479200CE25A007EB9CB /* CompletionHandlerWrappers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CompletionHandlerWrappers.swift; sourceTree = ""; }; - 8FD2447A200CE25A007EB9CB /* AbstractRequestLoop.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AbstractRequestLoop.swift; sourceTree = ""; }; - 8FD2447B200CE25A007EB9CB /* DeltaCallback.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeltaCallback.swift; sourceTree = ""; }; - 8FD2447C200CE25A007EB9CB /* ActionRequestLoop.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionRequestLoop.swift; sourceTree = ""; }; - 8FD2447D200CE25A007EB9CB /* SessionDestroyer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionDestroyer.swift; sourceTree = ""; }; - 8FD2447E200CE25A007EB9CB /* ProvidedVisitorFields.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProvidedVisitorFields.swift; sourceTree = ""; }; - 8FD2447F200CE25A007EB9CB /* ExecIfNotDestroyedHandlerExecutor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExecIfNotDestroyedHandlerExecutor.swift; sourceTree = ""; }; - 8FD24480200CE25A007EB9CB /* AuthorizationData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthorizationData.swift; sourceTree = ""; }; - 8FD24481200CE25A007EB9CB /* DeltaRequestLoop.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeltaRequestLoop.swift; sourceTree = ""; }; - 8FD24483200CE25A007EB9CB /* OperatorItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperatorItem.swift; sourceTree = ""; }; - 8FD24484200CE25A007EB9CB /* DepartmentItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DepartmentItem.swift; sourceTree = ""; }; - 8FD24485200CE25A007EB9CB /* RatingItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RatingItem.swift; sourceTree = ""; }; - 8FD24486200CE25A007EB9CB /* VisitSessionStateItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VisitSessionStateItem.swift; sourceTree = ""; }; - 8FD24488200CE25A007EB9CB /* HistoryBeforeResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoryBeforeResponse.swift; sourceTree = ""; }; - 8FD24489200CE25A007EB9CB /* HistorySinceResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistorySinceResponse.swift; sourceTree = ""; }; - 8FD2448A200CE25A007EB9CB /* DeltaResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeltaResponse.swift; sourceTree = ""; }; - 8FD2448B200CE25A007EB9CB /* FileParametersItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileParametersItem.swift; sourceTree = ""; }; - 8FD2448C200CE25A007EB9CB /* OnlineStatusItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnlineStatusItem.swift; sourceTree = ""; }; - 8FD2448E200CE25A007EB9CB /* DeltaItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeltaItem.swift; sourceTree = ""; }; - 8FD2448F200CE25A007EB9CB /* FullUpdate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FullUpdate.swift; sourceTree = ""; }; - 8FD24490200CE25A007EB9CB /* ChatItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatItem.swift; sourceTree = ""; }; - 8FD24491200CE25A007EB9CB /* VisitorItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VisitorItem.swift; sourceTree = ""; }; - 8FD24492200CE25A007EB9CB /* MessageItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageItem.swift; sourceTree = ""; }; - 8FD24493200CE25A007EB9CB /* MessageToSend.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageToSend.swift; sourceTree = ""; }; - 8FD24494200CE25A007EB9CB /* SessionParametersListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionParametersListener.swift; sourceTree = ""; }; - 8FD24495200CE25A007EB9CB /* AccessChecker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccessChecker.swift; sourceTree = ""; }; - 8FD24496200CE25A007EB9CB /* SQLiteHistoryStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteHistoryStorage.swift; sourceTree = ""; }; - 8FD24497200CE25A007EB9CB /* HistoryID.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoryID.swift; sourceTree = ""; }; - 8FD24498200CE25A007EB9CB /* HistoryStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoryStorage.swift; sourceTree = ""; }; - 8FD24499200CE25A007EB9CB /* MessageHolder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageHolder.swift; sourceTree = ""; }; - 8FD2449B200CE25B007EB9CB /* DepartmentImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DepartmentImpl.swift; sourceTree = ""; }; - 8FD2449C200CE25B007EB9CB /* OperatorImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperatorImpl.swift; sourceTree = ""; }; - 8FD2449D200CE25B007EB9CB /* MessageStreamImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageStreamImpl.swift; sourceTree = ""; }; - 8FD2449E200CE25B007EB9CB /* WebimRemoteNotificationImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebimRemoteNotificationImpl.swift; sourceTree = ""; }; - 8FD2449F200CE25B007EB9CB /* MessageImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageImpl.swift; sourceTree = ""; }; - 8FD244A0200CE25B007EB9CB /* WebimErrorImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebimErrorImpl.swift; sourceTree = ""; }; - 8FD244A1200CE25B007EB9CB /* MessageTrackerImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageTrackerImpl.swift; sourceTree = ""; }; - 8FD244A2200CE25B007EB9CB /* WebimSessionImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebimSessionImpl.swift; sourceTree = ""; }; - 8FD244A3200CE25B007EB9CB /* LocationSettingsImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationSettingsImpl.swift; sourceTree = ""; }; - 8FD244A4200CE25B007EB9CB /* FatalErrorHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FatalErrorHandler.swift; sourceTree = ""; }; - 8FD244A5200CE25B007EB9CB /* WebimError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebimError.swift; sourceTree = ""; }; - 8FD244A6200CE25B007EB9CB /* MessageStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageStream.swift; sourceTree = ""; }; - 8FD244A7200CE25B007EB9CB /* Webim.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Webim.swift; sourceTree = ""; }; - 8FD244ED200CE3E4007EB9CB /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; - CE2E681020123DB6004E99EA /* Array.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Array.swift; sourceTree = ""; }; - CE2E681220123DC9004E99EA /* Collection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Collection.swift; sourceTree = ""; }; - CE2E681420123DD0004E99EA /* Int.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Int.swift; sourceTree = ""; }; - CE2E681620123DD4004E99EA /* UInt32.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UInt32.swift; sourceTree = ""; }; - CE529806222EA38C00033278 /* HistoryRevisionItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryRevisionItem.swift; sourceTree = ""; }; - CE6A6977220C730F00B11E29 /* FAQItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FAQItem.swift; sourceTree = ""; }; - CE6A6979220C731600B11E29 /* FAQ.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FAQ.swift; sourceTree = ""; }; - CE6A697B220C799300B11E29 /* FAQActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAQActions.swift; sourceTree = ""; }; - CE6A697D220C7F3000B11E29 /* FAQClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAQClient.swift; sourceTree = ""; }; - CE6A697F220C83F900B11E29 /* FAQRequestLoop.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAQRequestLoop.swift; sourceTree = ""; }; - CE6A6981220C968D00B11E29 /* FAQImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAQImpl.swift; sourceTree = ""; }; - CE6A6983220C9BBB00B11E29 /* FAQDestroyer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAQDestroyer.swift; sourceTree = ""; }; - CE6A6985220C9DE200B11E29 /* FAQAccessChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAQAccessChecker.swift; sourceTree = ""; }; - CE6A6987220CA70A00B11E29 /* FAQItemItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAQItemItem.swift; sourceTree = ""; }; - CE76D61E22108834006A5BF0 /* ExecIfNotDestroyedFAQHandlerExecutor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExecIfNotDestroyedFAQHandlerExecutor.swift; sourceTree = ""; }; - CE76D6202210A6DC006A5BF0 /* FAQStructure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAQStructure.swift; sourceTree = ""; }; - CE76D6222210A6F3006A5BF0 /* FAQCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAQCategory.swift; sourceTree = ""; }; - CE86FA94203AF37F00CB9C2D /* UIColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = ""; }; - CE86FAAA203B2A2600CB9C2D /* OperatorFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperatorFactory.swift; sourceTree = ""; }; - CE86FAAC203B2A4500CB9C2D /* DepartmentFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DepartmentFactory.swift; sourceTree = ""; }; - CEBF03952211D5EE001658D8 /* FAQStructureItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAQStructureItem.swift; sourceTree = ""; }; - CEBF03972211D837001658D8 /* FAQCategoryItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAQCategoryItem.swift; sourceTree = ""; }; - CEBF03992211F070001658D8 /* FAQCategoryInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAQCategoryInfo.swift; sourceTree = ""; }; - CED72592200E11D900CD1623 /* WebimInternalLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebimInternalLogger.swift; path = Backend/WebimInternalLogger.swift; sourceTree = ""; }; - CEF33875221C74C700A7EA27 /* FAQCategoryInfoItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAQCategoryInfoItem.swift; sourceTree = ""; }; - D6A45F8A22A13A2400B5BB27 /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SQLite.framework; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 8FD24276200CDB18007EB9CB /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - D6A45F8B22A13A2400B5BB27 /* SQLite.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 8FD24270200CDB18007EB9CB = { - isa = PBXGroup; - children = ( - 8FD2427C200CDB18007EB9CB /* WebimClientLibrary */, - 8FD2427B200CDB18007EB9CB /* Products */, - 8FD24457200CE029007EB9CB /* Frameworks */, - ); - sourceTree = ""; - }; - 8FD2427B200CDB18007EB9CB /* Products */ = { - isa = PBXGroup; - children = ( - 8FD2427A200CDB18007EB9CB /* WebimClientLibrary.framework */, - ); - name = Products; - sourceTree = ""; - }; - 8FD2427C200CDB18007EB9CB /* WebimClientLibrary */ = { - isa = PBXGroup; - children = ( - 8FD2427D200CDB18007EB9CB /* WebimClientLibrary.h */, - 8FD24465200CE25A007EB9CB /* Backend */, - 8FD2449A200CE25B007EB9CB /* Implementation */, - 8FD24461200CE259007EB9CB /* Department.swift */, - 8FD244A4200CE25B007EB9CB /* FatalErrorHandler.swift */, - CE6A6979220C731600B11E29 /* FAQ.swift */, - CE6A6977220C730F00B11E29 /* FAQItem.swift */, - 8FD24464200CE25A007EB9CB /* Message.swift */, - 8FD2445D200CE258007EB9CB /* MessageListener.swift */, - 8FD244A6200CE25B007EB9CB /* MessageStream.swift */, - CED72592200E11D900CD1623 /* WebimInternalLogger.swift */, - 8FD24463200CE25A007EB9CB /* MessageTracker.swift */, - 8FD24460200CE259007EB9CB /* Operator.swift */, - 8FD24462200CE259007EB9CB /* ProvidedAuthorizationTokenStateListener.swift */, - 8FD244A7200CE25B007EB9CB /* Webim.swift */, - 8FD244A5200CE25B007EB9CB /* WebimError.swift */, - 8FD2445C200CE258007EB9CB /* WebimLogger.swift */, - 8FD2445E200CE259007EB9CB /* WebimRemoteNotification.swift */, - 8FD2445F200CE259007EB9CB /* WebimSession.swift */, - 8FD244ED200CE3E4007EB9CB /* Info.plist */, - CE76D6202210A6DC006A5BF0 /* FAQStructure.swift */, - CE76D6222210A6F3006A5BF0 /* FAQCategory.swift */, - CEBF03992211F070001658D8 /* FAQCategoryInfo.swift */, - ); - path = WebimClientLibrary; - sourceTree = ""; - }; - 8FD24457200CE029007EB9CB /* Frameworks */ = { - isa = PBXGroup; - children = ( - D6A45F8A22A13A2400B5BB27 /* SQLite.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 8FD24465200CE25A007EB9CB /* Backend */ = { - isa = PBXGroup; - children = ( - 8FD24482200CE25A007EB9CB /* Items */, - 8FD24473200CE25A007EB9CB /* Utilities */, - 8FD24466200CE25A007EB9CB /* HistoryMetaInformationStorage.swift */, - 8FD24467200CE25A007EB9CB /* MemoryHistoryStorage.swift */, - 8FD24468200CE25A007EB9CB /* InternalErrorListener.swift */, - 8FD24469200CE25A007EB9CB /* MemoryHistoryMetaInformationStorage.swift */, - 8FD2446A200CE25A007EB9CB /* ClientSideID.swift */, - 8FD2446B200CE25A007EB9CB /* WebimActions.swift */, - 8FD2446C200CE25A007EB9CB /* MessageComposingHandler.swift */, - 8FD2446D200CE25A007EB9CB /* WebimInternalError.swift */, - 8FD2446E200CE25A007EB9CB /* LocationSettingsHolder.swift */, - 8FD24470200CE25A007EB9CB /* WebimRequest.swift */, - 8FD24471200CE25A007EB9CB /* WebimClient.swift */, - 8FD24472200CE25A007EB9CB /* RemoteHistoryProvider.swift */, - 8FD2447A200CE25A007EB9CB /* AbstractRequestLoop.swift */, - 8FD2447B200CE25A007EB9CB /* DeltaCallback.swift */, - 8FD2447C200CE25A007EB9CB /* ActionRequestLoop.swift */, - 8FD2447D200CE25A007EB9CB /* SessionDestroyer.swift */, - 8FD2447E200CE25A007EB9CB /* ProvidedVisitorFields.swift */, - 8FD2447F200CE25A007EB9CB /* ExecIfNotDestroyedHandlerExecutor.swift */, - 8FD24480200CE25A007EB9CB /* AuthorizationData.swift */, - 8FD24481200CE25A007EB9CB /* DeltaRequestLoop.swift */, - 8FD24493200CE25A007EB9CB /* MessageToSend.swift */, - 8FD24494200CE25A007EB9CB /* SessionParametersListener.swift */, - 8FD24495200CE25A007EB9CB /* AccessChecker.swift */, - 8FD24496200CE25A007EB9CB /* SQLiteHistoryStorage.swift */, - 8FD24497200CE25A007EB9CB /* HistoryID.swift */, - 8FD24498200CE25A007EB9CB /* HistoryStorage.swift */, - 8FD24499200CE25A007EB9CB /* MessageHolder.swift */, - CE6A697B220C799300B11E29 /* FAQActions.swift */, - CE6A697D220C7F3000B11E29 /* FAQClient.swift */, - CE6A697F220C83F900B11E29 /* FAQRequestLoop.swift */, - CE6A6983220C9BBB00B11E29 /* FAQDestroyer.swift */, - CE6A6985220C9DE200B11E29 /* FAQAccessChecker.swift */, - CE76D61E22108834006A5BF0 /* ExecIfNotDestroyedFAQHandlerExecutor.swift */, - ); - path = Backend; - sourceTree = ""; - }; - 8FD24473200CE25A007EB9CB /* Utilities */ = { - isa = PBXGroup; - children = ( - 8FD24474200CE25A007EB9CB /* Extensions */, - 8FD24479200CE25A007EB9CB /* CompletionHandlerWrappers.swift */, - CE86FAAC203B2A4500CB9C2D /* DepartmentFactory.swift */, - 8FD24478200CE25A007EB9CB /* InternalUtils.swift */, - 8FD24477200CE25A007EB9CB /* MessageFactories.swift */, - CE86FAAA203B2A2600CB9C2D /* OperatorFactory.swift */, - ); - path = Utilities; - sourceTree = ""; - }; - 8FD24474200CE25A007EB9CB /* Extensions */ = { - isa = PBXGroup; - children = ( - CE2E681020123DB6004E99EA /* Array.swift */, - CE2E681220123DC9004E99EA /* Collection.swift */, - 8FD24475200CE25A007EB9CB /* Dictionary.swift */, - CE2E681420123DD0004E99EA /* Int.swift */, - 8FD24476200CE25A007EB9CB /* String.swift */, - CE86FA94203AF37F00CB9C2D /* UIColor.swift */, - CE2E681620123DD4004E99EA /* UInt32.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - 8FD24482200CE25A007EB9CB /* Items */ = { - isa = PBXGroup; - children = ( - 8FD24483200CE25A007EB9CB /* OperatorItem.swift */, - 8FD24484200CE25A007EB9CB /* DepartmentItem.swift */, - 8FD24485200CE25A007EB9CB /* RatingItem.swift */, - 8FD24486200CE25A007EB9CB /* VisitSessionStateItem.swift */, - 8FD24487200CE25A007EB9CB /* Responses */, - 8FD2448B200CE25A007EB9CB /* FileParametersItem.swift */, - 8FD2448C200CE25A007EB9CB /* OnlineStatusItem.swift */, - 8FD2448D200CE25A007EB9CB /* Deltas */, - 8FD24490200CE25A007EB9CB /* ChatItem.swift */, - 8FD24491200CE25A007EB9CB /* VisitorItem.swift */, - 8FD24492200CE25A007EB9CB /* MessageItem.swift */, - CE6A6987220CA70A00B11E29 /* FAQItemItem.swift */, - CEBF03952211D5EE001658D8 /* FAQStructureItem.swift */, - CEBF03972211D837001658D8 /* FAQCategoryItem.swift */, - CEF33875221C74C700A7EA27 /* FAQCategoryInfoItem.swift */, - CE529806222EA38C00033278 /* HistoryRevisionItem.swift */, - ); - path = Items; - sourceTree = ""; - }; - 8FD24487200CE25A007EB9CB /* Responses */ = { - isa = PBXGroup; - children = ( - 8FD24488200CE25A007EB9CB /* HistoryBeforeResponse.swift */, - 8FD24489200CE25A007EB9CB /* HistorySinceResponse.swift */, - 8FD2448A200CE25A007EB9CB /* DeltaResponse.swift */, - ); - path = Responses; - sourceTree = ""; - }; - 8FD2448D200CE25A007EB9CB /* Deltas */ = { - isa = PBXGroup; - children = ( - 8FD2448E200CE25A007EB9CB /* DeltaItem.swift */, - 8FD2448F200CE25A007EB9CB /* FullUpdate.swift */, - ); - path = Deltas; - sourceTree = ""; - }; - 8FD2449A200CE25B007EB9CB /* Implementation */ = { - isa = PBXGroup; - children = ( - 8FD2449B200CE25B007EB9CB /* DepartmentImpl.swift */, - 8FD244A3200CE25B007EB9CB /* LocationSettingsImpl.swift */, - 8FD2449F200CE25B007EB9CB /* MessageImpl.swift */, - 8FD2449D200CE25B007EB9CB /* MessageStreamImpl.swift */, - 8FD244A1200CE25B007EB9CB /* MessageTrackerImpl.swift */, - 8FD2449C200CE25B007EB9CB /* OperatorImpl.swift */, - 8FD244A0200CE25B007EB9CB /* WebimErrorImpl.swift */, - 8FD2449E200CE25B007EB9CB /* WebimRemoteNotificationImpl.swift */, - 8FD244A2200CE25B007EB9CB /* WebimSessionImpl.swift */, - CE6A6981220C968D00B11E29 /* FAQImpl.swift */, - ); - path = Implementation; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 8FD24277200CDB18007EB9CB /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 8FD2428B200CDB18007EB9CB /* WebimClientLibrary.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 8FD24279200CDB18007EB9CB /* WebimClientLibrary */ = { - isa = PBXNativeTarget; - buildConfigurationList = 8FD2428E200CDB18007EB9CB /* Build configuration list for PBXNativeTarget "WebimClientLibrary" */; - buildPhases = ( - 8FD24275200CDB18007EB9CB /* Sources */, - 8FD24276200CDB18007EB9CB /* Frameworks */, - 8FD24277200CDB18007EB9CB /* Headers */, - 8FD24278200CDB18007EB9CB /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = WebimClientLibrary; - productName = WebimClientLibrary; - productReference = 8FD2427A200CDB18007EB9CB /* WebimClientLibrary.framework */; - productType = "com.apple.product-type.framework"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 8FD24271200CDB18007EB9CB /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 0920; - ORGANIZATIONNAME = "Sergey Maslov"; - TargetAttributes = { - 8FD24279200CDB18007EB9CB = { - CreatedOnToolsVersion = 9.2; - LastSwiftMigration = 0920; - ProvisioningStyle = Manual; - }; - }; - }; - buildConfigurationList = 8FD24274200CDB18007EB9CB /* Build configuration list for PBXProject "WebimClientLibrary" */; - compatibilityVersion = "Xcode 8.0"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 8FD24270200CDB18007EB9CB; - productRefGroup = 8FD2427B200CDB18007EB9CB /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 8FD24279200CDB18007EB9CB /* WebimClientLibrary */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 8FD24278200CDB18007EB9CB /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 8FD24275200CDB18007EB9CB /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - CE86FAAB203B2A2600CB9C2D /* OperatorFactory.swift in Sources */, - CE6A6988220CA70A00B11E29 /* FAQItemItem.swift in Sources */, - 8FD244B5200CE25C007EB9CB /* ClientSideID.swift in Sources */, - 8FD244B6200CE25C007EB9CB /* WebimActions.swift in Sources */, - CE86FAAD203B2A4500CB9C2D /* DepartmentFactory.swift in Sources */, - 8FD244D2200CE25C007EB9CB /* FileParametersItem.swift in Sources */, - 8FD244BC200CE25C007EB9CB /* WebimClient.swift in Sources */, - CE529807222EA38C00033278 /* HistoryRevisionItem.swift in Sources */, - 8FD244BD200CE25C007EB9CB /* RemoteHistoryProvider.swift in Sources */, - 8FD244AF200CE25C007EB9CB /* MessageTracker.swift in Sources */, - CEF33876221C74C700A7EA27 /* FAQCategoryInfoItem.swift in Sources */, - 8FD244E9200CE25C007EB9CB /* FatalErrorHandler.swift in Sources */, - 8FD244C6200CE25C007EB9CB /* SessionDestroyer.swift in Sources */, - 8FD244E2200CE25C007EB9CB /* MessageStreamImpl.swift in Sources */, - 8FD244AE200CE25C007EB9CB /* ProvidedAuthorizationTokenStateListener.swift in Sources */, - 8FD244CD200CE25C007EB9CB /* RatingItem.swift in Sources */, - 8FD244C1200CE25C007EB9CB /* InternalUtils.swift in Sources */, - 8FD244C3200CE25C007EB9CB /* AbstractRequestLoop.swift in Sources */, - CE6A697C220C799300B11E29 /* FAQActions.swift in Sources */, - CE6A6978220C730F00B11E29 /* FAQItem.swift in Sources */, - 8FD244C0200CE25C007EB9CB /* MessageFactories.swift in Sources */, - CE2E681720123DD4004E99EA /* UInt32.swift in Sources */, - 8FD244C4200CE25C007EB9CB /* DeltaCallback.swift in Sources */, - 8FD244DB200CE25C007EB9CB /* AccessChecker.swift in Sources */, - 8FD244E6200CE25C007EB9CB /* MessageTrackerImpl.swift in Sources */, - 8FD244DC200CE25C007EB9CB /* SQLiteHistoryStorage.swift in Sources */, - CE86FA95203AF37F00CB9C2D /* UIColor.swift in Sources */, - 8FD244D4200CE25C007EB9CB /* DeltaItem.swift in Sources */, - CE76D6232210A6F3006A5BF0 /* FAQCategory.swift in Sources */, - 8FD244D3200CE25C007EB9CB /* OnlineStatusItem.swift in Sources */, - 8FD244BF200CE25C007EB9CB /* String.swift in Sources */, - 8FD244CB200CE25C007EB9CB /* OperatorItem.swift in Sources */, - CE6A6986220C9DE200B11E29 /* FAQAccessChecker.swift in Sources */, - 8FD244A8200CE25C007EB9CB /* WebimLogger.swift in Sources */, - 8FD244B0200CE25C007EB9CB /* Message.swift in Sources */, - 8FD244D6200CE25C007EB9CB /* ChatItem.swift in Sources */, - 8FD244E3200CE25C007EB9CB /* WebimRemoteNotificationImpl.swift in Sources */, - 8FD244CA200CE25C007EB9CB /* DeltaRequestLoop.swift in Sources */, - CE6A6984220C9BBB00B11E29 /* FAQDestroyer.swift in Sources */, - CE6A697E220C7F3000B11E29 /* FAQClient.swift in Sources */, - 8FD244EB200CE25C007EB9CB /* MessageStream.swift in Sources */, - 8FD244AB200CE25C007EB9CB /* WebimSession.swift in Sources */, - 8FD244E7200CE25C007EB9CB /* WebimSessionImpl.swift in Sources */, - 8FD244B2200CE25C007EB9CB /* MemoryHistoryStorage.swift in Sources */, - 8FD244DF200CE25C007EB9CB /* MessageHolder.swift in Sources */, - 8FD244AC200CE25C007EB9CB /* Operator.swift in Sources */, - 8FD244E1200CE25C007EB9CB /* OperatorImpl.swift in Sources */, - CEBF03962211D5EE001658D8 /* FAQStructureItem.swift in Sources */, - 8FD244B8200CE25C007EB9CB /* WebimInternalError.swift in Sources */, - 8FD244DA200CE25C007EB9CB /* SessionParametersListener.swift in Sources */, - 8FD244D0200CE25C007EB9CB /* HistorySinceResponse.swift in Sources */, - 8FD244C5200CE25C007EB9CB /* ActionRequestLoop.swift in Sources */, - 8FD244C9200CE25C007EB9CB /* AuthorizationData.swift in Sources */, - CE6A6982220C968D00B11E29 /* FAQImpl.swift in Sources */, - CE6A6980220C83F900B11E29 /* FAQRequestLoop.swift in Sources */, - 8FD244BE200CE25C007EB9CB /* Dictionary.swift in Sources */, - 8FD244C8200CE25C007EB9CB /* ExecIfNotDestroyedHandlerExecutor.swift in Sources */, - CEBF03982211D837001658D8 /* FAQCategoryItem.swift in Sources */, - CEBF039A2211F070001658D8 /* FAQCategoryInfo.swift in Sources */, - CE2E681120123DB7004E99EA /* Array.swift in Sources */, - 8FD244D8200CE25C007EB9CB /* MessageItem.swift in Sources */, - 8FD244AA200CE25C007EB9CB /* WebimRemoteNotification.swift in Sources */, - 8FD244B9200CE25C007EB9CB /* LocationSettingsHolder.swift in Sources */, - 8FD244B7200CE25C007EB9CB /* MessageComposingHandler.swift in Sources */, - 8FD244A9200CE25C007EB9CB /* MessageListener.swift in Sources */, - 8FD244E0200CE25C007EB9CB /* DepartmentImpl.swift in Sources */, - 8FD244EC200CE25C007EB9CB /* Webim.swift in Sources */, - 8FD244BB200CE25C007EB9CB /* WebimRequest.swift in Sources */, - 8FD244DE200CE25C007EB9CB /* HistoryStorage.swift in Sources */, - 8FD244E4200CE25C007EB9CB /* MessageImpl.swift in Sources */, - CED72593200E11D900CD1623 /* WebimInternalLogger.swift in Sources */, - 8FD244CC200CE25C007EB9CB /* DepartmentItem.swift in Sources */, - CE76D61F22108835006A5BF0 /* ExecIfNotDestroyedFAQHandlerExecutor.swift in Sources */, - 8FD244D5200CE25C007EB9CB /* FullUpdate.swift in Sources */, - 8FD244B4200CE25C007EB9CB /* MemoryHistoryMetaInformationStorage.swift in Sources */, - 8FD244CE200CE25C007EB9CB /* VisitSessionStateItem.swift in Sources */, - 8FD244C7200CE25C007EB9CB /* ProvidedVisitorFields.swift in Sources */, - 8FD244CF200CE25C007EB9CB /* HistoryBeforeResponse.swift in Sources */, - 8FD244DD200CE25C007EB9CB /* HistoryID.swift in Sources */, - 8FD244C2200CE25C007EB9CB /* CompletionHandlerWrappers.swift in Sources */, - CE76D6212210A6DC006A5BF0 /* FAQStructure.swift in Sources */, - 8FD244B1200CE25C007EB9CB /* HistoryMetaInformationStorage.swift in Sources */, - 8FD244D7200CE25C007EB9CB /* VisitorItem.swift in Sources */, - CE2E681320123DC9004E99EA /* Collection.swift in Sources */, - 8FD244EA200CE25C007EB9CB /* WebimError.swift in Sources */, - 8FD244E8200CE25C007EB9CB /* LocationSettingsImpl.swift in Sources */, - 8FD244AD200CE25C007EB9CB /* Department.swift in Sources */, - 8FD244E5200CE25C007EB9CB /* WebimErrorImpl.swift in Sources */, - 8FD244B3200CE25C007EB9CB /* InternalErrorListener.swift in Sources */, - CE6A697A220C731600B11E29 /* FAQ.swift in Sources */, - 8FD244D9200CE25C007EB9CB /* MessageToSend.swift in Sources */, - 8FD244D1200CE25C007EB9CB /* DeltaResponse.swift in Sources */, - CE2E681520123DD0004E99EA /* Int.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 8FD2428C200CDB18007EB9CB /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 8FD2428D200CDB18007EB9CB /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 8FD2428F200CDB18007EB9CB /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); - INFOPLIST_FILE = Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = ru.webim.WebimClientLibrary; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.2; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 8FD24290200CDB18007EB9CB /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); - INFOPLIST_FILE = Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = ru.webim.WebimClientLibrary; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SKIP_INSTALL = YES; - SWIFT_VERSION = 4.2; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 8FD24274200CDB18007EB9CB /* Build configuration list for PBXProject "WebimClientLibrary" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 8FD2428C200CDB18007EB9CB /* Debug */, - 8FD2428D200CDB18007EB9CB /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 8FD2428E200CDB18007EB9CB /* Build configuration list for PBXNativeTarget "WebimClientLibrary" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 8FD2428F200CDB18007EB9CB /* Debug */, - 8FD24290200CDB18007EB9CB /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 8FD24271200CDB18007EB9CB /* Project object */; -} diff --git a/ios/libs/Webim/WebimClientLibrary.xcodeproj/xcshareddata/xcschemes/WebimClientLibrary.xcscheme b/ios/libs/Webim/WebimClientLibrary.xcodeproj/xcshareddata/xcschemes/WebimClientLibrary.xcscheme deleted file mode 100644 index d8d23a3..0000000 --- a/ios/libs/Webim/WebimClientLibrary.xcodeproj/xcshareddata/xcschemes/WebimClientLibrary.xcscheme +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/AbstractRequestLoop.swift b/ios/libs/Webim/WebimClientLibrary/Backend/AbstractRequestLoop.swift deleted file mode 100644 index 740ee99..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/AbstractRequestLoop.swift +++ /dev/null @@ -1,278 +0,0 @@ -// -// AbstractRequestLoop.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 15.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that handles HTTP-request sending by SDK. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -class AbstractRequestLoop { - - // MARK: - Constants - enum HTTPMethods: String { - case get = "GET" - case post = "POST" - } - enum ResponseFields: String { - case data = "data" - case error = "error" - } - enum DataFields: String { - case error = "error" - } - enum UnknownError: Error { - case interrupted - case serverError - } - - // MARK: - Properties - private let pauseCondition = NSCondition() - private let pauseLock = NSRecursiveLock() - var paused = true - var running = true - private var currentDataTask: URLSessionDataTask? - - // MARK: - Methods - - func start() { - preconditionFailure("This method must be overridden!") - } - - func pause() { - pauseLock.lock() - paused = true - pauseLock.unlock() - } - - func resume() { - pauseLock.lock() - paused = false - pauseCondition.broadcast() - pauseLock.unlock() - } - - func stop() { - running = false - resume() - - if let currentDataTask = currentDataTask { - currentDataTask.cancel() - } - } - - func isRunning() -> Bool { - return running - } - - func perform(request: URLRequest) throws -> Data { - var requestWithUesrAngent = request - requestWithUesrAngent.setValue("iOS: Webim-Client (\(UIDevice.current.model); \(UIDevice.current.systemVersion)); Bundle ID and version: \(Bundle.main.bundleIdentifier ?? "none") \(Bundle.main.infoDictionary?["CFBundleVersion"] ?? "none")", forHTTPHeaderField: "User-Agent") - - var errorCounter = 0 - var lastHTTPCode = -1 - - while isRunning() { - let startTime = Date() - var httpCode = 0 - - let semaphore = DispatchSemaphore(value: 0) - var receivedData: Data? = nil - - log(request: requestWithUesrAngent) - - let dataTask = URLSession.shared.dataTask(with: requestWithUesrAngent) { [weak self] data, response, error in - guard let `self` = `self` else { - return - } - - if let response = response { - httpCode = (response as! HTTPURLResponse).statusCode - } - - if error != nil { - semaphore.signal() - - // Error log. - var webimLoggerEntry = "Webim response:\n" - + "URL – " + requestWithUesrAngent.url!.absoluteString - if let httpBody = requestWithUesrAngent.httpBody { - if let dataString = String(data: httpBody, - encoding: .utf8) { - webimLoggerEntry += ("\nParameters – " + dataString) - } - } - webimLoggerEntry += "\nHTTP code – " + String(httpCode) - webimLoggerEntry += "\nError – " + error!.localizedDescription - WebimInternalLogger.shared.log(entry: webimLoggerEntry) - - if let error = error as NSError?, !(error.domain == NSURLErrorDomain && error.code == NSURLErrorNotConnectedToInternet) { - return - } - } - - if let data = data { - receivedData = data - - var webimLoggerEntry = "Webim response:\n" - + "URL – " + requestWithUesrAngent.url!.absoluteString - if let httpBody = requestWithUesrAngent.httpBody { - if let dataString = String(data: httpBody, - encoding: .utf8) { - webimLoggerEntry += ("\nParameters – " + dataString) - } - } - webimLoggerEntry += "\nHTTP code – " + String(httpCode) - webimLoggerEntry += self.encode(responseData: data) - WebimInternalLogger.shared.log(entry: webimLoggerEntry, verbosityLevel: .DEBUG) - } - - semaphore.signal() - } - currentDataTask = dataTask - dataTask.resume() - - _ = semaphore.wait(timeout: .distantFuture) - currentDataTask = nil - blockUntilPaused() - - if !isRunning() { - break - } - - if httpCode == 0 { - usleep(useconds_t(10_000_000.0)) - continue - } - - if let receivedData = receivedData, - httpCode == 200 { - return receivedData - } - - if httpCode == 413 { // Request Entity Too Large - throw SendFileError.FILE_SIZE_EXCEEDED - } - if httpCode == 415 { // Unsupported Media Type - throw SendFileError.FILE_TYPE_NOT_ALLOWED - } - - if httpCode == lastHTTPCode { - var parametersString: String? - if let httpBody = requestWithUesrAngent.httpBody { - parametersString = String(data: httpBody, - encoding: .utf8) - } - WebimInternalLogger.shared.log(entry: "Request \(requestWithUesrAngent.url!.absoluteString)" - + "\(parametersString ?? "") " - + "failed with HTTP code: \(httpCode).", - verbosityLevel: .WARNING) - } - - errorCounter += 1 - - lastHTTPCode = httpCode - - // If request wasn't successful and error isn't fatal, wait some time and try again. - if (errorCounter >= 5) { - // If there was more that five tries stop trying. - throw UnknownError.serverError - } - let sleepTime = Double(errorCounter) as TimeInterval - let timeElapsed = Date().timeIntervalSince(startTime) - if Double(timeElapsed) < Double(sleepTime) { - let remainingTime = Double(sleepTime) - Double(timeElapsed) - usleep(useconds_t(remainingTime * 1_000_000.0)) - } - } - - throw UnknownError.interrupted - } - - func handleRequestLoop(error: UnknownError) { - switch error { - case .interrupted: - WebimInternalLogger.shared.log(entry: "Request interrupted (it's OK if WebimSession object was destroyed).", - verbosityLevel: .DEBUG) - - break - case .serverError: - WebimInternalLogger.shared.log(entry: "Request failed with server error.") - - break - } - } - - // MARK: Private methods - - private func blockUntilPaused() { - pauseCondition.lock() - while paused { - pauseCondition.wait() - } - pauseCondition.unlock() - } - - private func log(request: URLRequest) { - var webimLoggerEntry = "Webim request:\n" - webimLoggerEntry += ("HTTP method - " + request.httpMethod! + "\n") - webimLoggerEntry += ("URL – " + request.url!.absoluteString) - if let httpBody = request.httpBody { - if let dataString = String(data: httpBody, - encoding: .utf8) { - webimLoggerEntry += ("\nParameters – " + dataString) - } - } - - WebimInternalLogger.shared.log(entry: webimLoggerEntry, - verbosityLevel: .INFO) - } - - private func encode(responseData: Data) -> String { - do { - let jsonResponse = try JSONSerialization.jsonObject(with: responseData, - options: .mutableContainers) - let prettyPrintedJSONResponse = try JSONSerialization.data(withJSONObject: jsonResponse, - options: .prettyPrinted) - - if let dataResponseString = String(data: prettyPrintedJSONResponse, - encoding: .utf8) { - return "\nJSON:\n" + dataResponseString - } - } catch { - if let dataResponseString = String(data: responseData, - encoding: .utf8) { - return "\nData:\n" + dataResponseString - } - } - - return "" - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/AccessChecker.swift b/ios/libs/Webim/WebimClientLibrary/Backend/AccessChecker.swift deleted file mode 100644 index 7e9cd42..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/AccessChecker.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// AccessChecker.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 11.09.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that checks if session methods are called in appropriate conditions. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -class AccessChecker { - - // MARK: - Properties - let thread: Thread - let sessionDestroyer: SessionDestroyer - - // MARK: - Initialization - init(thread: Thread, - sessionDestroyer: SessionDestroyer) { - self.thread = thread - self.sessionDestroyer = sessionDestroyer - } - - // MARK: - Methods - func checkAccess() throws { - guard thread == Thread.current else { - throw AccessError.INVALID_THREAD - } - - guard !sessionDestroyer.isDestroyed() else { - throw AccessError.INVALID_SESSION - } - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/ActionRequestLoop.swift b/ios/libs/Webim/WebimClientLibrary/Backend/ActionRequestLoop.swift deleted file mode 100644 index 87c33c5..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/ActionRequestLoop.swift +++ /dev/null @@ -1,407 +0,0 @@ -// -// ActionRequestLoop.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 14.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that handles HTTP-requests sended by WebimClientLibrary with visitor requested actions (e.g. sending messages, operator rating, chat closing etc.). - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -class ActionRequestLoop: AbstractRequestLoop { - - // MARK: - Properties - private let completionHandlerExecutor: ExecIfNotDestroyedHandlerExecutor - private let internalErrorListener: InternalErrorListener - var operationQueue: OperationQueue? - private var authorizationData: AuthorizationData? - - - // MARK: - Initialization - init(completionHandlerExecutor: ExecIfNotDestroyedHandlerExecutor, - internalErrorListener: InternalErrorListener) { - self.completionHandlerExecutor = completionHandlerExecutor - self.internalErrorListener = internalErrorListener - } - - // MARK: - Methods - - override func start() { - guard operationQueue == nil else { - return - } - - operationQueue = OperationQueue() - operationQueue?.maxConcurrentOperationCount = 1 - operationQueue?.qualityOfService = .userInitiated - } - - override func stop() { - super.stop() - - operationQueue?.cancelAllOperations() - operationQueue = nil - } - - func set(authorizationData: AuthorizationData?) { - self.authorizationData = authorizationData - } - - func enqueue(request: WebimRequest) { - operationQueue?.addOperation { [weak self] in - guard let `self` = self else { - return - } - - if self.authorizationData == nil { - do { - try self.authorizationData = self.awaitForNewAuthorizationData(withLastAuthorizationData: nil) - } catch { - return - } - } - let usedAuthorizationData = self.authorizationData! - - if !self.isRunning() { - return - } - - var parameterDictionary = request.getPrimaryData() - parameterDictionary[WebimActions.Parameter.pageID.rawValue] = usedAuthorizationData.getPageID() - parameterDictionary[WebimActions.Parameter.authorizationToken.rawValue] = usedAuthorizationData.getAuthorizationToken() - let parametersString = parameterDictionary.stringFromHTTPParameters() - - var url: URL? - var urlRequest: URLRequest? - let httpMethod = request.getHTTPMethod() - if httpMethod == .get { - url = URL(string: (request.getBaseURLString() + "?" + parametersString)) - urlRequest = URLRequest(url: url!) - } else { // POST - if let fileName = request.getFileName(), - let mimeType = request.getMimeType(), - let fileData = request.getFileData(), - let boundaryString = request.getBoundaryString() { - // Assuming that ready HTTP body is passed only for multipart requests. - url = URL(string: (request.getBaseURLString())) - urlRequest = URLRequest(url: url!) - urlRequest!.httpBody = self.createHTTPBody(filename: fileName, - mimeType: mimeType, - fileData: fileData, - boundaryString: boundaryString, - primaryData: parameterDictionary) - } else { - // For URL encoded requests. - url = URL(string: request.getBaseURLString()) - urlRequest = URLRequest(url: url!) - urlRequest!.httpBody = parametersString.data(using: .utf8) - } - - // Assuming that content type field is always exists when it is POST request, and does not when request is of GET type. - urlRequest!.setValue(request.getContentType(), - forHTTPHeaderField: "Content-Type") - } - - urlRequest!.httpMethod = httpMethod.rawValue - - do { - let data = try self.perform(request: urlRequest!) - if let dataJSON = try? JSONSerialization.jsonObject(with: data) as? [String: Any] { - if let error = dataJSON?[AbstractRequestLoop.ResponseFields.error.rawValue] as? String { - switch error { - case WebimInternalError.reinitializationRequired.rawValue: - do { - try self.authorizationData = self.awaitForNewAuthorizationData(withLastAuthorizationData: nil) - } catch { - return - } - self.enqueue(request: request) - - break - case WebimInternalError.fileSizeExceeded.rawValue, - WebimInternalError.fileTypeNotAllowed.rawValue, - WebimInternalError.uploadedFileNotFound.rawValue, - WebimInternalError.notAllowedMimeType.rawValue, - WebimInternalError.notMatchingMagicNumbers.rawValue: - self.handleSendFile(error: error, - ofRequest: request) - - break - case WebimInternalError.wrongArgumentValue.rawValue: - self.handleWrongArgumentValueError(ofRequest: request) - - break - case WebimInternalError.noChat.rawValue, - WebimInternalError.operatorNotInChat.rawValue: - self.handleRateOperator(error: error, - ofRequest: request) - - break - case WebimInternalError.messageNotFound.rawValue, - WebimInternalError.notAllowed.rawValue, - WebimInternalError.messageNotOwned.rawValue: - self.handleDeleteMessage(error: error, - ofRequest: request) - break - default: - self.running = false - - self.completionHandlerExecutor.execute(task: DispatchWorkItem { - self.internalErrorListener.on(error: error) - }) - - break - } - - return - } - - // Some internal errors can be received inside "error" field inside "data" field. - if let dataDictionary = dataJSON?[AbstractRequestLoop.ResponseFields.data.rawValue] as? [String: Any], - let errorString = dataDictionary[AbstractRequestLoop.DataFields.error.rawValue] as? String { - self.handleDataMessage(error: errorString, - ofRequest: request) - } - - if let completionHandler = request.getCompletionHandler() { - self.completionHandlerExecutor.execute(task: DispatchWorkItem { - do { - try completionHandler(data) - } catch { - WebimInternalLogger.shared.log(entry: "Error executing callback on receiver data: \(String(data: data, encoding: .utf8) ?? "unreadable data").", - verbosityLevel: .WARNING) - } - - }) - } - - self.handleClientCompletionHandlerOf(request: request) - } else { - WebimInternalLogger.shared.log(entry: "Error de-serializing server response: \(String(data: data, encoding: .utf8) ?? "unreadable data")", - verbosityLevel: .WARNING) - } - } catch let sendFileError as SendFileError { - // SendFileErrors are generated from HTTP code. - if let sendFileCompletionHandler = request.getSendFileCompletionHandler() { - sendFileCompletionHandler.onFailure(messageID: request.getMessageID()!, - error: sendFileError) - } - } catch let unknownError as UnknownError { - self.handleRequestLoop(error: unknownError) - } catch { - WebimInternalLogger.shared.log(entry: "Request failed with unknown error: \(request.getBaseURLString()).", - verbosityLevel: .WARNING) - } - } - } - - // MARK: Private methods - - private func createHTTPBody(filename: String, - mimeType: String, - fileData: Data, - boundaryString: String, - primaryData: [String: Any]) -> Data { - - let boundaryStart = "--\(boundaryString)\r\n" - let contentDispositionString = "Content-Disposition: form-data; name=\"webim_upload_file\"; filename=\"\(filename)\"\r\n" - let contentTypeString = "Content-Type: \(mimeType)\r\n\r\n" - let boundaryEnd = "--\(boundaryString)--\r\n" - - var requestBodyData = Data() - for (key, value) in primaryData { - requestBodyData.append("--\(boundaryString)\r\n".data(using: .utf8)!) - requestBodyData.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n".data(using: .utf8)!) - requestBodyData.append("\(value)\r\n".data(using: .utf8)!) - } - requestBodyData.append(boundaryStart.data(using: .utf8)!) - requestBodyData.append(contentDispositionString.data(using: .utf8)!) - requestBodyData.append(contentTypeString.data(using: .utf8)!) - requestBodyData.append(fileData) - requestBodyData.append("\r\n".data(using: .utf8)!) - requestBodyData.append(boundaryEnd.data(using: .utf8)!) - - return requestBodyData - } - - private func awaitForNewAuthorizationData(withLastAuthorizationData lastAuthorizationData: AuthorizationData?) throws -> AuthorizationData { - while isRunning() - && (lastAuthorizationData == authorizationData) { - usleep(100_000) // 0.1 s. - } - - if authorizationData == nil { - // Interrupted request. - throw AbstractRequestLoop.UnknownError.interrupted - } - - return authorizationData! - } - - private func handleDataMessage(error errorString: String, - ofRequest webimRequest: WebimRequest) { - if let dataMessageCompletionHandler = webimRequest.getDataMessageCompletionHandler() { - completionHandlerExecutor.execute(task: DispatchWorkItem { - dataMessageCompletionHandler.onFailure(messageID: webimRequest.getMessageID()!, - error: ActionRequestLoop.convertToPublic(dataMessageErrorString: errorString)) - }) - } - } - - private func handleRateOperator(error errorString: String, - ofRequest webimRequest: WebimRequest) { - if let rateOperatorCompletionhandler = webimRequest.getRateOperatorCompletionHandler() { - completionHandlerExecutor.execute(task: DispatchWorkItem { - let rateOperatorError: RateOperatorError - if errorString == WebimInternalError.noChat.rawValue { - rateOperatorError = .NO_CHAT - } else { - rateOperatorError = .WRONG_OPERATOR_ID - } - - rateOperatorCompletionhandler.onFailure(error: rateOperatorError) - }) - } - } - - private func handleEditMessage(error errorString: String, - ofRequest webimRequest: WebimRequest) { - if let editMessageCompletionHandler = webimRequest.getEditMessageCompletionHandler() { - completionHandlerExecutor.execute(task: DispatchWorkItem { - let editMessageError: EditMessageError - switch errorString { - case WebimInternalError.messageEmpty.rawValue: - editMessageError = .MESSAGE_EMPTY - break - case WebimInternalError.maxMessageLengthExceeded.rawValue: - editMessageError = .MAX_LENGTH_EXCEEDED - break - case WebimInternalError.notAllowed.rawValue: - editMessageError = .NOT_ALLOWED - break - case WebimInternalError.messageNotOwned.rawValue: - editMessageError = .MESSAGE_NOT_OWNED - break - case WebimInternalError.wrongMessageKind.rawValue: - editMessageError = .WRONG_MESSAGE_KIND - break - default: - editMessageError = .UNKNOWN - } - - editMessageCompletionHandler.onFailure(messageID: webimRequest.getMessageID()!, - error: editMessageError) - }) - } - } - - private func handleDeleteMessage(error errorString: String, - ofRequest webimRequest: WebimRequest) { - if let deleteMessageCompletionHandler = webimRequest.getDeleteMessageCompletionHandler() { - completionHandlerExecutor.execute(task: DispatchWorkItem { - let deleteMessageError: DeleteMessageError - switch errorString { - case WebimInternalError.messageNotFound.rawValue: - deleteMessageError = .MESSAGE_NOT_FOUND - break - case WebimInternalError.notAllowed.rawValue: - deleteMessageError = .NOT_ALLOWED - break - case WebimInternalError.messageNotOwned.rawValue: - deleteMessageError = .MESSAGE_NOT_OWNED - break - default: - deleteMessageError = .UNKNOWN - } - - deleteMessageCompletionHandler.onFailure(messageID: webimRequest.getMessageID()!, - error: deleteMessageError) - }) - } - } - - private func handleSendFile(error errorString: String, - ofRequest webimRequest: WebimRequest) { - if let sendFileCompletionHandler = webimRequest.getSendFileCompletionHandler() { - completionHandlerExecutor.execute(task: DispatchWorkItem { - let sendFileError: SendFileError - switch errorString { - case WebimInternalError.fileSizeExceeded.rawValue: - sendFileError = .FILE_SIZE_EXCEEDED - break - case WebimInternalError.fileTypeNotAllowed.rawValue: - sendFileError = .FILE_TYPE_NOT_ALLOWED - break - case WebimInternalError.uploadedFileNotFound.rawValue: - sendFileError = .UPLOADED_FILE_NOT_FOUND - break - default: - sendFileError = .UNKNOWN - } - - sendFileCompletionHandler.onFailure(messageID: webimRequest.getMessageID()!, - error: sendFileError) - }) - } - } - - private func handleWrongArgumentValueError(ofRequest webimRequest: WebimRequest) { - WebimInternalLogger.shared.log(entry: "Request \(webimRequest.getBaseURLString()) with parameters \(webimRequest.getPrimaryData().stringFromHTTPParameters()) failed with error \(WebimInternalError.wrongArgumentValue.rawValue)", - verbosityLevel: .WARNING) - } - - private func handleClientCompletionHandlerOf(request: WebimRequest) { - completionHandlerExecutor.execute(task: DispatchWorkItem { - request.getDataMessageCompletionHandler()?.onSuccess(messageID: request.getMessageID()!) - request.getSendFileCompletionHandler()?.onSuccess(messageID: request.getMessageID()!) - request.getRateOperatorCompletionHandler()?.onSuccess() - request.getDeleteMessageCompletionHandler()?.onSuccess(messageID: request.getMessageID()!) - request.getEditMessageCompletionHandler()?.onSuccess(messageID: request.getMessageID()!) - }) - } - - private static func convertToPublic(dataMessageErrorString: String) -> DataMessageError { - switch dataMessageErrorString { - case WebimInternalError.quotedMessageCannotBeReplied.rawValue: - return .QUOTED_MESSAGE_CANNOT_BE_REPLIED - case WebimInternalError.quotedMessageCorruptedID.rawValue: - return .QUOTED_MESSAGE_WRONG_ID - case WebimInternalError.quotedMessageFromAnotherVisitor.rawValue: - return .QUOTED_MESSAGE_FROM_ANOTHER_VISITOR - case WebimInternalError.quotedMessageMultipleID.rawValue: - return .QUOTED_MESSAGE_MULTIPLE_IDS - case WebimInternalError.quotedMessageNotFound.rawValue: - return .QUOTED_MESSAGE_WRONG_ID - case WebimInternalError.quotedMessageRequiredArgumentsMissing.rawValue: - return .QUOTED_MESSAGE_REQUIRED_ARGUMENTS_MISSING - default: - return .UNKNOWN - } - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/AuthorizationData.swift b/ios/libs/Webim/WebimClientLibrary/Backend/AuthorizationData.swift deleted file mode 100644 index 2edb709..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/AuthorizationData.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// AuthorizationData.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 11.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Struct that encapsulates session authorization data. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -struct AuthorizationData { - - // MARK: - Properties - private var pageID: String - private var authorizationToken: String - - - // MARK: - Initialization - init?(pageID: String?, - authorizationToken: String?) { - guard let pageID = pageID, - let authorizationToken = authorizationToken else { - return nil - } - - self.pageID = pageID - self.authorizationToken = authorizationToken - } - - - // MARK: - Methods - - func getPageID() -> String { - return pageID - } - - func getAuthorizationToken() -> String? { - return authorizationToken - } - -} - -// MARK: - Equatable -extension AuthorizationData: Equatable { - - static func == (lhs: AuthorizationData, - rhs: AuthorizationData) -> Bool { - return (lhs.pageID == rhs.pageID) - && (lhs.authorizationToken == rhs.authorizationToken) - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/ClientSideID.swift b/ios/libs/Webim/WebimClientLibrary/Backend/ClientSideID.swift deleted file mode 100644 index 98ce576..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/ClientSideID.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// StringID.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 09.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class which is responsible for generating random IDs (e.g. for sending messages). - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -struct ClientSideID { - - // MARK: - Constants - enum StringSize: Int { - case clientSideID = 32 - } - enum StringSymbols: NSString { - case uid = "abcdef0123456789" - } - - // MARK: - Methods - - static func generateClientSideID() -> String { - return generateRandomString(ofCharactersNumber: StringSize.clientSideID.rawValue) - } - - static func generateRandomString(ofCharactersNumber numberOfCharacters: Int) -> String { - let letters: NSString = StringSymbols.uid.rawValue - let length = UInt32(letters.length) - - var randomString = "" - - for _ in 0 ..< numberOfCharacters { - let random = arc4random_uniform(length) - var nextChar = letters.character(at: Int(random)) - randomString = randomString + (NSString(characters: &nextChar, - length: 1) as String) - } - - return randomString - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/DeltaCallback.swift b/ios/libs/Webim/WebimClientLibrary/Backend/DeltaCallback.swift deleted file mode 100644 index c873d80..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/DeltaCallback.swift +++ /dev/null @@ -1,395 +0,0 @@ -// -// DeltaCallback.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 12.10.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that handles server response when SDK requests chat updates. - - seealso: - `DeltaResponse` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class DeltaCallback { - - // MARK: - Properties - private let currentChatMessageMapper: MessageMapper - private var currentChat: ChatItem? - private let readBeforeTimestampString = "read_before_timestamp" - private weak var messageHolder: MessageHolder? - private weak var messageStream: MessageStreamImpl? - private weak var historyPoller: HistoryPoller? - - // MARK: - Initialization - init(currentChatMessageMapper: MessageMapper) { - self.currentChatMessageMapper = currentChatMessageMapper - } - - // MARK: - Methods - - func set(messageStream: MessageStreamImpl, - messageHolder: MessageHolder, - historyPoller: HistoryPoller) { - self.messageStream = messageStream - self.messageHolder = messageHolder - self.historyPoller = historyPoller - } - - func process(deltaList: [DeltaItem]) { - for delta in deltaList { - guard let deltaType = delta.getDeltaType() else { - continue - } - - switch deltaType { - case .chat: - handleChatUpdateBy(delta: delta) - - break - case .chatMessage: - handleChatMessageUpdateBy(delta: delta) - - break - case .chatOperator: - handleChatOperatorUpdateBy(delta: delta) - - break - case .chatOperatorTyping: - handleChatOperatorTypingUpdateBy(delta: delta) - - break - case .chatReadByVisitor: - handleChatReadByVisitorUpdateBy(delta: delta) - - break - case .chatState: - handleChatStateUpdateBy(delta: delta) - - break - case .chatUnreadByOperatorTimestamp: - handleUnreadByOperatorTimestampUpdateBy(delta: delta) - - break - case .departmentList: - handleDepartmentListUpdateBy(delta: delta) - - break - case .historyRevision: - handleHistoryRevisionUpdateBy(delta: delta) - - break - case .operatorRate: - handleOperatorRateUpdateBy(delta: delta) - - break - case .unreadByVisitor: - handleUnreadByVisitorUpdateBy(delta: delta) - - break - case .visitSessionState: - handleVisitSessionStateUpdateBy(delta: delta) - - break - case .chatMessageRead: - handleMessageRead(delta: delta) - break - default: - // Not supported delta type. - - break - } - } - } - - func process(fullUpdate: FullUpdate) { - if let visitSessionState = fullUpdate.getState() { - messageStream?.set(visitSessionState: (VisitSessionStateItem(rawValue: visitSessionState) ?? .unknown)) - } - - if let departments = fullUpdate.getDepartments() { - messageStream?.onReceiving(departmentItemList: departments) - } - - currentChat = fullUpdate.getChat() - - messageStream?.changingChatStateOf(chat: currentChat) - messageStream?.saveLocationSettingsOn(fullUpdate: fullUpdate) - - if let revision = fullUpdate.getHistoryRevision() { - historyPoller?.set(hasHistoryRevision: true) - historyPoller?.requestHistory(since: revision) - } - - if let onlineStatusString = fullUpdate.getOnlineStatus() { - if let onlineStatus = OnlineStatusItem(rawValue: onlineStatusString) { - messageStream?.onOnlineStatusChanged(to: onlineStatus) - } - } - - if currentChat != nil { - for messageItem in (currentChat?.getMessages())! { - if let message = currentChatMessageMapper.map(message: messageItem) { - if (message.getType() == MessageType.FILE_FROM_VISITOR || message.getType() != MessageType.VISITOR) && message.isReadByOperator() { - let time = message.getTimeInMicrosecond() - if time > Int64(UserDefaults.standard.integer(forKey: readBeforeTimestampString)) { - UserDefaults.standard.set(time, forKey: readBeforeTimestampString) - historyPoller?.updateReadBeforeTimestamp(timestamp: time) - } - } - } - } - } else { - UserDefaults.standard.set(-1, forKey: readBeforeTimestampString) - } - } - - // MARK: Private methods - - private func handleChatUpdateBy(delta: DeltaItem) { - guard delta.getEvent() == .update, - let deltaData = delta.getData() as? [String : Any?] else { - return - } - - currentChat = ChatItem(jsonDictionary: deltaData) - messageStream?.changingChatStateOf(chat: currentChat) - } - - private func handleChatMessageUpdateBy(delta: DeltaItem) { - let deltaEvent = delta.getEvent() - let deltaID = delta.getID() - - if deltaEvent == .delete { - if currentChat != nil { - var currentChatMessages = currentChat!.getMessages() - for (currentChatMessageIndex, currentChatMessage) in currentChatMessages.enumerated() { - if currentChatMessage.getID() == deltaID { // Deleted message ID is passed as delta ID. - currentChatMessages.remove(at: currentChatMessageIndex) - currentChat!.set(messages: currentChatMessages) - - break - } - } - } - - messageHolder?.deletedMessageWith(id: deltaID) - } else { - guard let deltaData = delta.getData() as? [String : Any] else { - return - } - - let messageItem = MessageItem(jsonDictionary: deltaData) - let message = currentChatMessageMapper.map(message: messageItem) - if deltaEvent == .add { - var isNewMessage = false - if currentChat != nil && !currentChat!.getMessages().contains(messageItem) { - currentChat?.add(message: messageItem) - isNewMessage = true - } - - if isNewMessage && message != nil { - messageHolder?.receive(newMessage: message!) - } - - } else if deltaEvent == .update { - if currentChat != nil { - var currentChatMessages = currentChat!.getMessages() - for (currentChatMessageIndex, currentChatMessage) in currentChatMessages.enumerated() { - if currentChatMessage.getID() == messageItem.getID() { - currentChatMessages[currentChatMessageIndex] = messageItem - - break - } - } - } - - if message != nil { - messageHolder?.changed(message: message!) - } - } - } - } - - - private func handleMessageRead(delta: DeltaItem) { - let deltaEvent = delta.getEvent() - let deltaId = delta.getID() - - if let isRead = delta.getData() as? Bool, deltaEvent == .update { - if currentChat != nil { - var currentChatMessages = currentChat!.getMessages() - for (currentChatMessageIndex, currentChatMessage) in currentChatMessages.enumerated() { - if currentChatMessage.getID() == deltaId { - currentChatMessage.setRead(read: isRead) - guard let message = currentChatMessageMapper.map(message: currentChatMessage) else { - return - } - currentChatMessages[currentChatMessageIndex] = currentChatMessage - messageHolder?.changed(message: message) - let time = message.getTimeInMicrosecond() - if time > UserDefaults.standard.integer(forKey: "readBeforeTimestampString") { - UserDefaults.standard.set(time, forKey: "readBeforeTimestampString") - historyPoller?.updateReadBeforeTimestamp(timestamp: time) - } - break - } - } - } - } - } - - private func handleChatOperatorUpdateBy(delta: DeltaItem) { - guard delta.getEvent() == .update, - let deltaData = delta.getData() as? [String : Any] else { - return - } - - if let operatorItem = OperatorItem(jsonDictionary: deltaData) { - currentChat?.set(operator: operatorItem) - - messageStream?.changingChatStateOf(chat: currentChat) - } - } - - private func handleChatOperatorTypingUpdateBy(delta: DeltaItem) { - guard delta.getEvent() == .update, - let operatorTyping = delta.getData() as? Bool else { - return - } - - currentChat?.set(operatorTyping: operatorTyping) - messageStream?.changingChatStateOf(chat: currentChat) - } - - private func handleChatReadByVisitorUpdateBy(delta: DeltaItem) { - guard let readByVisitor = delta.getData() as? Bool, - delta.getEvent() == .update else { - return - } - - currentChat?.set(readByVisitor: readByVisitor) - - if readByVisitor { - currentChat?.set(unreadByVisitorTimestamp: nil) - currentChat?.set(unreadByVisitorMessageCount: 0) - messageStream?.set(unreadByVisitorTimestamp: nil) - messageStream?.set(unreadByVisitorMessageCount: 0) - } - } - - private func handleChatStateUpdateBy(delta: DeltaItem) { - guard delta.getEvent() == .update, - let chatState = delta.getData() as? String else { - return - } - - currentChat?.set(state: ChatItem.ChatItemState(withType: chatState)) - - messageStream?.changingChatStateOf(chat: currentChat) - } - - private func handleUnreadByOperatorTimestampUpdateBy(delta: DeltaItem) { - guard delta.getEvent() == .update else { - return - } - - var unreadByOperatorTimestamp: Double? - if delta.getData() != nil { - unreadByOperatorTimestamp = delta.getData() as? Double - } - currentChat?.set(unreadByOperatorTimestamp: unreadByOperatorTimestamp) - messageStream?.set(unreadByOperatorTimestamp: (unreadByOperatorTimestamp != nil ? Date(timeIntervalSince1970: unreadByOperatorTimestamp!) : nil)) - } - - private func handleDepartmentListUpdateBy(delta: DeltaItem) { - guard let deltaData = delta.getData() as? [Any] else { - return - } - - var departmentItems = [DepartmentItem]() - for departmentData in deltaData { - if let departmentDictionary = departmentData as? [String: Any] { - if let deparmentItem = DepartmentItem(jsonDictionary: departmentDictionary) { - departmentItems.append(deparmentItem) - } - } - } - - messageStream?.onReceiving(departmentItemList: departmentItems) - } - - private func handleHistoryRevisionUpdateBy(delta: DeltaItem) { - guard let deltaData = delta.getData() as? [String: Any] else { - return - } - - let revisionItem = HistoryRevisionItem(jsonDictionary: deltaData) - historyPoller?.requestHistory(since: revisionItem.getRevision()) - } - - private func handleOperatorRateUpdateBy(delta: DeltaItem) { - guard let deltaData = delta.getData() as? [String: Any] else { - return - } - - if let rating = RatingItem(jsonDictionary: deltaData) { - if delta.getEvent() == .update { - currentChat?.set(rating: rating, - toOperatorWithId: rating.getOperatorID()) - } - } - } - - private func handleUnreadByVisitorUpdateBy(delta: DeltaItem) { - guard delta.getEvent() == .update, - let unreadByVisitorUpdate = delta.getData() as? [String: Any], - let unreadByVisitorMessageConut = unreadByVisitorUpdate[DeltaItem.UnreadByVisitorField.messageCount.rawValue] as? Int, - let unreadByVisitorTimestamp = unreadByVisitorUpdate[DeltaItem.UnreadByVisitorField.timestamp.rawValue] as? Double else { - return - } - currentChat?.set(unreadByVisitorMessageCount: unreadByVisitorMessageConut) - messageStream?.set(unreadByVisitorTimestamp: Date(timeIntervalSince1970: unreadByVisitorTimestamp)) - messageStream?.set(unreadByVisitorMessageCount: unreadByVisitorMessageConut) - } - - private func handleVisitSessionStateUpdateBy(delta: DeltaItem) { - guard let sessionState = delta.getData() as? String else { - return - } - - if sessionState == VisitSessionStateItem.offlineMessage.rawValue { - messageStream?.set(onlineStatus: .offline) - messageStream?.getWebimActions().closeChat() - } - - if delta.getEvent() == .update { - messageStream?.set(visitSessionState: (VisitSessionStateItem(rawValue: sessionState) ?? .unknown)) - } - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/DeltaRequestLoop.swift b/ios/libs/Webim/WebimClientLibrary/Backend/DeltaRequestLoop.swift deleted file mode 100644 index 2f8b84d..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/DeltaRequestLoop.swift +++ /dev/null @@ -1,388 +0,0 @@ -// -// DeltaRequestLoop.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 16.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that handles HTTP-requests sending by SDK with internal requested actions (initialization and chat updates). - - seealso: - `DeltaCallback` - `DeltaResponse` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -class DeltaRequestLoop: AbstractRequestLoop { - - // MARK: - Properties - private static var providedAuthenticationTokenErrorCount = 0 - private let appVersion: String? - private let baseURL: String - private let completionHandlerExecutor: ExecIfNotDestroyedHandlerExecutor - private let deltaCallback: DeltaCallback - private let deviceID: String - private let internalErrorListener: InternalErrorListener - private let sessionParametersListener: SessionParametersListener? - private let title: String - var authorizationData: AuthorizationData? - var queue: DispatchQueue? - var since: Int64 = 0 - private var deviceToken: String? - private var location: String - private var providedAuthenticationToken: String? - private weak var providedAuthenticationTokenStateListener: ProvidedAuthorizationTokenStateListener? - private var sessionID: String? - private var visitorFieldsJSONString: String? - private var visitorJSONString: String? - private var prechat: String? - - // MARK: - Initialization - init(deltaCallback: DeltaCallback, - completionHandlerExecutor: ExecIfNotDestroyedHandlerExecutor, - sessionParametersListener: SessionParametersListener?, - internalErrorListener: InternalErrorListener, - baseURL: String, - title: String, - location: String, - appVersion: String?, - visitorFieldsJSONString: String?, - providedAuthenticationTokenStateListener: ProvidedAuthorizationTokenStateListener?, - providedAuthenticationToken: String?, - deviceID: String, - deviceToken: String?, - visitorJSONString: String?, - sessionID: String?, - prechat:String?, - authorizationData: AuthorizationData?) { - self.deltaCallback = deltaCallback - self.completionHandlerExecutor = completionHandlerExecutor - self.sessionParametersListener = sessionParametersListener - self.internalErrorListener = internalErrorListener - self.baseURL = baseURL - self.title = title - self.location = location - self.appVersion = appVersion - self.visitorFieldsJSONString = visitorFieldsJSONString - self.deviceID = deviceID - self.deviceToken = deviceToken - self.visitorJSONString = visitorJSONString - self.sessionID = sessionID - self.authorizationData = authorizationData - self.providedAuthenticationTokenStateListener = providedAuthenticationTokenStateListener - self.providedAuthenticationToken = providedAuthenticationToken - self.prechat = prechat - } - - // MARK: - Methods - - override func start() { - guard queue == nil else { - return - } - - queue = DispatchQueue(label: "ru.webim.DeltaDispatchQueue") - queue!.async { - self.run() - } - } - - override func stop() { - super.stop() - - queue = nil - } - - func set(deviceToken: String) { - self.deviceToken = deviceToken - } - - func change(location: String) throws { - self.location = location - - authorizationData = nil - since = 0 - - requestInitialization() - } - - func getAuthorizationData() -> AuthorizationData? { - return authorizationData - } - - func run() { - while isRunning() { - if authorizationData != nil && since != 0 { - requestDelta() - } else { - requestInitialization() - } - } - } - - func requestInitialization() { - let url = URL(string: getDeltaServerURLString() + "?" + getInitializationParameterString()) - var request = URLRequest(url: url!) - request.httpMethod = AbstractRequestLoop.HTTPMethods.get.rawValue - - do { - let data = try perform(request: request) - if let dataJSON = try? JSONSerialization.jsonObject(with: data) as! [String: Any] { - if let error = dataJSON[AbstractRequestLoop.ResponseFields.error.rawValue] as? String { - handleInitialization(error: error) - } else { - DeltaRequestLoop.providedAuthenticationTokenErrorCount = 0 - - let deltaResponse = DeltaResponse(jsonDictionary: dataJSON) - - if let deltaList = deltaResponse.getDeltaList() { - if deltaList.count > 0 { - handleIncorrectServerAnswer() - - return - } - } - - guard let fullUpdate = deltaResponse.getFullUpdate() else { - handleIncorrectServerAnswer() - - return - } - - if let since = deltaResponse.getRevision() { - self.since = since - } - - process(fullUpdate: fullUpdate) - } - } else { - WebimInternalLogger.shared.log(entry: "Error de-serializing server response: \(String(data: data, encoding: .utf8) ?? "unreadable data").", - verbosityLevel: .WARNING) - } - } catch let unknownError as UnknownError { - handleRequestLoop(error: unknownError) - } catch { - WebimInternalLogger.shared.log(entry: "Request failed with unknown error: \(error.localizedDescription)", - verbosityLevel: .WARNING) - } - } - - func requestDelta() { - let url = URL(string: getDeltaServerURLString() + "?" + getDeltaParameterString()) - var request = URLRequest(url: url!) - request.httpMethod = AbstractRequestLoop.HTTPMethods.get.rawValue - - do { - let data = try perform(request: request) - if let dataJSON = try? JSONSerialization.jsonObject(with: data) as! [String: Any] { - if let error = dataJSON[AbstractRequestLoop.ResponseFields.error.rawValue] as? String { - handleDeltaRequest(error: error) - } else { - let deltaResponse = DeltaResponse(jsonDictionary: dataJSON) - - guard let revision = deltaResponse.getRevision() else { - // Delta timeout. - return - } - since = revision - - if let fullUpdate = deltaResponse.getFullUpdate() { - completionHandlerExecutor.execute(task: DispatchWorkItem { - self.process(fullUpdate: fullUpdate) - }) - } else if let deltaList = deltaResponse.getDeltaList() { - if deltaList.count > 0 { - completionHandlerExecutor.execute(task: DispatchWorkItem { - self.deltaCallback.process(deltaList: deltaList) - }) - } - } - } - } else { - WebimInternalLogger.shared.log(entry: "Error de-serializing server response: \(String(data: data, encoding: .utf8) ?? "unreadable data").", - verbosityLevel: .WARNING) - } - } catch let unknownError as UnknownError { - handleRequestLoop(error: unknownError) - } catch { - WebimInternalLogger.shared.log(entry: "Request failed with unknown error: \(error.localizedDescription).", - verbosityLevel: .WARNING) - } - } - - // MARK: Private methods - - private func getDeltaServerURLString() -> String { - return (baseURL + WebimActions.ServerPathSuffix.getDelta.rawValue) - } - - private func getInitializationParameterString() -> String { - var parameterDictionary = [WebimActions.Parameter.deviceID.rawValue: deviceID, - WebimActions.Parameter.event.rawValue: WebimActions.Event.initialization.rawValue, - WebimActions.Parameter.location.rawValue: location, - WebimActions.Parameter.platform.rawValue: WebimActions.Platform.ios.rawValue, - WebimActions.Parameter.respondImmediately.rawValue: String(1), // true - WebimActions.Parameter.since.rawValue: String(0), - WebimActions.Parameter.title.rawValue: title] as [String: Any] - if let appVersion = appVersion { - parameterDictionary[WebimActions.Parameter.applicationVersion.rawValue] = appVersion - } - if let deviceToken = deviceToken { - parameterDictionary[WebimActions.Parameter.deviceToken.rawValue] = deviceToken - } - if let sessionID = sessionID { - parameterDictionary[WebimActions.Parameter.visitSessionID.rawValue] = sessionID - } - if let visitorJSONString = visitorJSONString { - parameterDictionary[WebimActions.Parameter.visitor.rawValue] = visitorJSONString - } - if let visitorFieldsJSONString = visitorFieldsJSONString { - parameterDictionary[WebimActions.Parameter.visitorExt.rawValue] = visitorFieldsJSONString - } - if let providedAuthenticationToken = providedAuthenticationToken { - parameterDictionary[WebimActions.Parameter.providedAuthenticationToken.rawValue] = providedAuthenticationToken - } - if let prechat = prechat { - parameterDictionary[WebimActions.Parameter.prechat.rawValue] = prechat - } - - return parameterDictionary.stringFromHTTPParameters() - } - - private func getDeltaParameterString() -> String { - let currentTimestamp = Int64(CFAbsoluteTimeGetCurrent() * 1000) - var parameterDictionary = [WebimActions.Parameter.since.rawValue: String(since), - WebimActions.Parameter.timestamp.rawValue: String(currentTimestamp)] as [String: Any] - if let authorizationData = authorizationData { - parameterDictionary[WebimActions.Parameter.pageID.rawValue] = authorizationData.getPageID() - parameterDictionary[WebimActions.Parameter.authorizationToken.rawValue] = authorizationData.getAuthorizationToken() - } - - return parameterDictionary.stringFromHTTPParameters() - } - - private func sleepBetweenInitializationAttempts() { - authorizationData = nil - since = 0 - - usleep(1_000_000) // 1s - } - - private func handleIncorrectServerAnswer() { - WebimInternalLogger.shared.log(entry: "Incorrect server answer while requesting initialization.", - verbosityLevel: .DEBUG) - - usleep(1_000_000) // 1s - } - - private func handleInitialization(error: String) { - switch error { - case WebimInternalError.reinitializationRequired.rawValue: - handleReinitializationRequiredError() - - break - case WebimInternalError.providedAuthenticationTokenNotFound.rawValue: - handleProvidedAuthenticationTokenNotFoundError() - - break - default: - running = false - - completionHandlerExecutor.execute(task: DispatchWorkItem { - self.internalErrorListener.on(error: error) - }) - - break - } - } - - private func handleDeltaRequest(error: String) { - if error == WebimInternalError.reinitializationRequired.rawValue { - handleReinitializationRequiredError() - } else { - completionHandlerExecutor.execute(task: DispatchWorkItem { - self.internalErrorListener.on(error: error) - }) - } - } - - private func handleReinitializationRequiredError() { - authorizationData = nil - since = 0 - } - - private func handleProvidedAuthenticationTokenNotFoundError() { - DeltaRequestLoop.providedAuthenticationTokenErrorCount += 1 - - if DeltaRequestLoop.providedAuthenticationTokenErrorCount < 5 { - sleepBetweenInitializationAttempts() - } else { - providedAuthenticationTokenStateListener?.update(providedAuthorizationToken: providedAuthenticationToken!) - - DeltaRequestLoop.providedAuthenticationTokenErrorCount = 0 - - sleepBetweenInitializationAttempts() - } - } - - private func process(fullUpdate: FullUpdate) { - let visitorJSONString = fullUpdate.getVisitorJSONString() - let sessionID = fullUpdate.getSessionID() - let authorizationData = AuthorizationData(pageID: fullUpdate.getPageID(), - authorizationToken: fullUpdate.getAuthorizationToken()) - - let isNecessaryToUpdateVisitorFieldJSONString = (self.visitorFieldsJSONString == nil) - || (self.visitorFieldsJSONString != visitorFieldsJSONString) - let isNecessaryToUpdateSessionID = (self.sessionID == nil) - || (self.sessionID != sessionID) - let isNecessaryToUpdateAuthorizationData = (self.authorizationData == nil) - || ((self.authorizationData?.getPageID() != fullUpdate.getPageID()) - || (self.authorizationData?.getAuthorizationToken() != fullUpdate.getAuthorizationToken())) - - if (isNecessaryToUpdateVisitorFieldJSONString - || isNecessaryToUpdateSessionID) - || isNecessaryToUpdateAuthorizationData { - self.visitorJSONString = visitorJSONString - self.sessionID = sessionID - self.authorizationData = authorizationData - - DispatchQueue.global(qos: .background).async { [weak self] in - guard let `self` = self else { - return - } - - self.sessionParametersListener?.onSessionParametersChanged(visitorFieldsJSONString: self.visitorJSONString!, - sessionID: self.sessionID!, - authorizationData: self.authorizationData!) - } - } - - completionHandlerExecutor.execute(task: DispatchWorkItem { - self.deltaCallback.process(fullUpdate: fullUpdate) - }) - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/ExecIfNotDestroyedFAQHandlerExecutor.swift b/ios/libs/Webim/WebimClientLibrary/Backend/ExecIfNotDestroyedFAQHandlerExecutor.swift deleted file mode 100644 index 8eb4480..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/ExecIfNotDestroyedFAQHandlerExecutor.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// ExecIfNotDestroyedFAQHandlerExecutor.swift -// WebimClientLibrary -// -// Created by Nikita Kaberov on 07.02.19. -// Copyright © 2019 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that encapsulates asynchronous callbacks calling. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -final class ExecIfNotDestroyedFAQHandlerExecutor { - - // MARK: - Properties - private let faqDestroyer: FAQDestroyer - private let queue: DispatchQueue - - // MARK: - Initialization - init(faqDestroyer: FAQDestroyer, - queue: DispatchQueue) { - self.faqDestroyer = faqDestroyer - self.queue = queue - } - - // MARK: - Methods - func execute(task: DispatchWorkItem) { - if !faqDestroyer.isDestroyed() { - queue.async { - if !self.faqDestroyer.isDestroyed() { - task.perform() - } - } - } - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/ExecIfNotDestroyedHandlerExecutor.swift b/ios/libs/Webim/WebimClientLibrary/Backend/ExecIfNotDestroyedHandlerExecutor.swift deleted file mode 100644 index b716fe7..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/ExecIfNotDestroyedHandlerExecutor.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// ExecIfNotDestroyedHandlerExecutor.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 11.09.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that encapsulates asynchronous callbacks calling. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class ExecIfNotDestroyedHandlerExecutor { - - // MARK: - Properties - private let sessionDestroyer: SessionDestroyer - private let queue: DispatchQueue - - // MARK: - Initialization - init(sessionDestroyer: SessionDestroyer, - queue: DispatchQueue) { - self.sessionDestroyer = sessionDestroyer - self.queue = queue - } - - // MARK: - Methods - func execute(task: DispatchWorkItem) { - if !sessionDestroyer.isDestroyed() { - queue.async { - if !self.sessionDestroyer.isDestroyed() { - task.perform() - } - } - } - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/FAQAccessChecker.swift b/ios/libs/Webim/WebimClientLibrary/Backend/FAQAccessChecker.swift deleted file mode 100644 index 93ab9ac..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/FAQAccessChecker.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// AccessChecker.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 11.09.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that checks if FAQ methods are called in appropriate conditions. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -class FAQAccessChecker { - - // MARK: - Properties - let thread: Thread - let faqDestroyer: FAQDestroyer - - // MARK: - Initialization - init(thread: Thread, - faqDestroyer: FAQDestroyer) { - self.thread = thread - self.faqDestroyer = faqDestroyer - } - - // MARK: - Methods - func checkAccess() throws { - guard thread == Thread.current else { - throw FAQAccessError.INVALID_THREAD - } - - guard !faqDestroyer.isDestroyed() else { - throw FAQAccessError.INVALID_FAQ - } - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/FAQActions.swift b/ios/libs/Webim/WebimClientLibrary/Backend/FAQActions.swift deleted file mode 100644 index 103ec96..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/FAQActions.swift +++ /dev/null @@ -1,96 +0,0 @@ -// -// FAQActions.swift -// WebimClientLibrary -// -// Created by Nikita Kaberov on 07.02.19. -// Copyright © 2019 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -class FAQActions { - - // MARK: - Constants - enum Parameter: String { - case itemId = "itemid" - case categoryId = "categoryid" - } - enum ServerPathSuffix: String { - case item = "/services/faq/v1/item" - case category = "/services/faq/v1/category" - case structure = "/services/faq/v1/structure" - } - - // MARK: - Properties - private let baseURL: String - private let faqRequestLoop: FAQRequestLoop - - // MARK: - Initialization - init(baseURL: String, - faqRequestLoop: FAQRequestLoop) { - self.baseURL = baseURL - self.faqRequestLoop = faqRequestLoop - } - - // MARK: - Methods - - func getItem(itemId: String, - completion: @escaping (_ faqItem: Data?) throws -> ()) { - let dataToPost = [Parameter.itemId.rawValue: itemId] as [String: Any] - - let urlString = baseURL + ServerPathSuffix.item.rawValue - - faqRequestLoop.enqueue(request: WebimRequest(httpMethod: .get, - primaryData: dataToPost, - baseURLString: urlString, - faqItemRequestCompletionHandler: completion)) - } - - func getCategory(categoryId: Int, - completion: @escaping (_ faqCategory: Data?) throws -> ()) { - let dataToPost = [Parameter.categoryId.rawValue: String(categoryId)] as [String: Any] - - let urlString = baseURL + ServerPathSuffix.category.rawValue - - faqRequestLoop.enqueue(request: WebimRequest(httpMethod: .get, - primaryData: dataToPost, - baseURLString: urlString, - faqCategoryRequestCompletionHandler: completion)) - } - - func getStructure(categoryId: Int, - completion: @escaping (_ faqStructure: Data?) throws -> ()) { - let dataToPost = [Parameter.categoryId.rawValue: String(categoryId)] as [String: Any] - - let urlString = baseURL + ServerPathSuffix.structure.rawValue - - faqRequestLoop.enqueue(request: WebimRequest(httpMethod: .get, - primaryData: dataToPost, - baseURLString: urlString, - faqStructureRequestCompletionHandler: completion)) - } -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/FAQClient.swift b/ios/libs/Webim/WebimClientLibrary/Backend/FAQClient.swift deleted file mode 100644 index b795356..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/FAQClient.swift +++ /dev/null @@ -1,106 +0,0 @@ -// -// FAQClient.swift -// WebimClientLibrary -// -// Created by Nikita Kaberov on 07.02.19. -// Copyright © 2019 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -final class FAQClientBuilder { - - // MARK: - Properties - private var baseURL: String? - private var completionHandlerExecutor: ExecIfNotDestroyedFAQHandlerExecutor? - - // MARK: - Builder methods - - func set(baseURL: String) -> FAQClientBuilder { - self.baseURL = baseURL - - return self - } - - func set(completionHandlerExecutor: ExecIfNotDestroyedFAQHandlerExecutor?) -> FAQClientBuilder { - self.completionHandlerExecutor = completionHandlerExecutor - - return self - } - - func build() -> FAQClient { - let faqRequestLoop = FAQRequestLoop(completionHandlerExecutor: completionHandlerExecutor!) - - return FAQClient(withFAQRequestLoop: faqRequestLoop, - faqActions: FAQActions(baseURL: baseURL!, faqRequestLoop: faqRequestLoop)) - } - -} - -// MARK: - -/** - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -final class FAQClient { - - // MARK: - Properties - private let faqRequestLoop: FAQRequestLoop - private let faqActions: FAQActions - - // MARK: - Initialization - init(withFAQRequestLoop faqRequestLoop: FAQRequestLoop, - faqActions: FAQActions) { - self.faqRequestLoop = faqRequestLoop - self.faqActions = faqActions - } - - // MARK: - Methods - - func start() { - faqRequestLoop.start() - } - - func pause() { - faqRequestLoop.pause() - } - - func resume() { - faqRequestLoop.resume() - } - - func stop() { - faqRequestLoop.stop() - } - - func getActions() -> FAQActions { - return faqActions - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/FAQDestroyer.swift b/ios/libs/Webim/WebimClientLibrary/Backend/FAQDestroyer.swift deleted file mode 100644 index a2f6651..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/FAQDestroyer.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// FAQDestroyer.swift -// WebimClientLibrary -// -// Created by Nikita Kaberov on 07.02.19. -// Copyright © 2019 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -final class FAQDestroyer { - - // MARK: - Properties - private lazy var actions = [() -> ()]() - private var destroyed = false - - // MARK: - Methods - - func add(action: @escaping () -> ()) { - actions.append(action) - } - - func destroy() { - if !destroyed { - destroyed = true - - for action in actions { - action() - } - actions.removeAll(keepingCapacity: false) - } - } - - func isDestroyed() -> Bool { - return destroyed - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/FAQRequestLoop.swift b/ios/libs/Webim/WebimClientLibrary/Backend/FAQRequestLoop.swift deleted file mode 100644 index ab04ab5..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/FAQRequestLoop.swift +++ /dev/null @@ -1,148 +0,0 @@ -// -// FAQRequestLoop.swift -// WebimClientLibrary -// -// Created by Nikita Kaberov on 07.02.17. -// Copyright © 2019 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that handles HTTP-requests sended by WebimClientLibrary with visitor FAQ actions. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -class FAQRequestLoop: AbstractRequestLoop { - - // MARK: - Properties - private let completionHandlerExecutor: ExecIfNotDestroyedFAQHandlerExecutor - var operationQueue: OperationQueue? - - - // MARK: - Initialization - init(completionHandlerExecutor: ExecIfNotDestroyedFAQHandlerExecutor) { - self.completionHandlerExecutor = completionHandlerExecutor - } - - // MARK: - Methods - - override func start() { - guard operationQueue == nil else { - return - } - - operationQueue = OperationQueue() - operationQueue?.maxConcurrentOperationCount = 1 - operationQueue?.qualityOfService = .userInitiated - } - - override func stop() { - super.stop() - - operationQueue?.cancelAllOperations() - operationQueue = nil - } - - func enqueue(request: WebimRequest) { - operationQueue?.addOperation { [weak self] in - guard let `self` = self else { - return - } - - if !self.isRunning() { - return - } - - let parameterDictionary = request.getPrimaryData() - let parametersString = parameterDictionary.stringFromHTTPParameters() - - var url: URL? - var urlRequest: URLRequest? - let httpMethod = request.getHTTPMethod() - url = URL(string: (request.getBaseURLString() + "?" + parametersString)) - urlRequest = URLRequest(url: url!) - - urlRequest!.httpMethod = httpMethod.rawValue - - do { - let data = try self.perform(request: urlRequest!) - if let dataJSON = try? JSONSerialization.jsonObject(with: data) as? [String: Any] { - if let error = dataJSON?[AbstractRequestLoop.ResponseFields.error.rawValue] as? String { - self.running = false - - return - } - - if let completionHandler = request.getFAQItemRequestCompletionHandler() { - self.completionHandlerExecutor.execute(task: DispatchWorkItem { - do { - try completionHandler(data) - } catch { - } - - }) - } - - if let completionHandler = request.getFAQCategoryRequestCompletionHandler() { - self.completionHandlerExecutor.execute(task: DispatchWorkItem { - do { - try completionHandler(data) - } catch { - } - - }) - } - - if let completionHandler = request.getFAQStructureRequestCompletionHandler() { - self.completionHandlerExecutor.execute(task: DispatchWorkItem { - do { - try completionHandler(data) - } catch { - } - - }) - } - - self.handleClientCompletionHandlerOf(request: request) - } - } catch let unknownError as UnknownError { - self.handleRequestLoop(error: unknownError) - } catch { - } - } - } - - // MARK: Private methode - - private func handleClientCompletionHandlerOf(request: WebimRequest) { - completionHandlerExecutor.execute(task: DispatchWorkItem { - request.getDataMessageCompletionHandler()?.onSuccess(messageID: request.getMessageID()!) - request.getSendFileCompletionHandler()?.onSuccess(messageID: request.getMessageID()!) - request.getRateOperatorCompletionHandler()?.onSuccess() - request.getDeleteMessageCompletionHandler()?.onSuccess(messageID: request.getMessageID()!) - request.getEditMessageCompletionHandler()?.onSuccess(messageID: request.getMessageID()!) - }) - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/HistoryID.swift b/ios/libs/Webim/WebimClientLibrary/Backend/HistoryID.swift deleted file mode 100644 index 4e6d901..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/HistoryID.swift +++ /dev/null @@ -1,71 +0,0 @@ -// -// HistoryID.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 15.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that encapsulates message ID in history context. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class HistoryID { - - // MARK: - Properties - private let dbID: String - private let timeInMicrosecond: Int64 - - // MARK: - Initialization - init(dbID: String, - timeInMicrosecond: Int64) { - self.dbID = dbID - self.timeInMicrosecond = timeInMicrosecond - } - - // MARK: - Methods - - func getDBid() -> String { - return dbID - } - - func getTimeInMicrosecond() -> Int64 { - return timeInMicrosecond - } - -} - -// MARK: - Equatable -extension HistoryID: Equatable { - - // MARK: - Methods - static func == (lhs: HistoryID, - rhs: HistoryID) -> Bool { - return ((lhs.dbID == rhs.dbID) - && (lhs.timeInMicrosecond == rhs.timeInMicrosecond)) - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/HistoryMetaInformationStorage.swift b/ios/libs/Webim/WebimClientLibrary/Backend/HistoryMetaInformationStorage.swift deleted file mode 100644 index 182dd32..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/HistoryMetaInformationStorage.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// HistoryMetaInformationStorage.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 11.09.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -protocol HistoryMetaInformationStorage { - - func isHistoryEnded() -> Bool - - func set(historyEnded: Bool) - - func set(revision: String?) - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/HistoryStorage.swift b/ios/libs/Webim/WebimClientLibrary/Backend/HistoryStorage.swift deleted file mode 100644 index c661811..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/HistoryStorage.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// HistoryStorage.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 11.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -protocol HistoryStorage { - - /** - When this values is changed history will be re-requested. - */ - func getMajorVersion() -> Int - - func set(reachedHistoryEnd: Bool) - - func getFullHistory(completion: @escaping ([Message]) -> ()) - - func getLatestHistory(byLimit limitOfMessages: Int, - completion: @escaping ([Message]) -> ()) - - func getHistoryBefore(id: HistoryID, - limitOfMessages: Int, - completion: @escaping ([Message]) -> ()) - - func receiveHistoryBefore(messages: [MessageImpl], - hasMoreMessages: Bool) - - func receiveHistoryUpdate(withMessages messages: [MessageImpl], - idsToDelete: Set, - completion: @escaping (_ endOfBatch: Bool, _ messageDeleted: Bool, _ deletedMesageID: String?, _ messageChanged: Bool, _ changedMessage: MessageImpl?, _ messageAdded: Bool, _ addedMessage: MessageImpl?, _ idBeforeAddedMessage: HistoryID?) -> ()) - - func updateReadBeforeTimestamp(timestamp: Int64) -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/InternalErrorListener.swift b/ios/libs/Webim/WebimClientLibrary/Backend/InternalErrorListener.swift deleted file mode 100644 index 9cdae79..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/InternalErrorListener.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// InternalErrorListener.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 11.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -protocol InternalErrorListener { - - func on(error: String) - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/ChatItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/ChatItem.swift deleted file mode 100644 index 520b83c..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Items/ChatItem.swift +++ /dev/null @@ -1,318 +0,0 @@ -// -// ChatItem.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 09.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that encapsulates chat data. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class ChatItem { - - // MARK: - Constants - - // Raw values equal to field names received in responses from server. - private enum JSONField: String { - case category = "category" - case clientSideID = "clientSideId" - case creationTimestamp = "creationTs" - case id = "id" - case messages = "messages" - case modificationTimestamp = "modificationTs" - case offline = "offline" - case `operator` = "operator" - case operatorIDToRate = "operatorIdToRate" - case operatorTyping = "operatorTyping" - case readByVisitor = "readByVisitor" - case state = "state" - case subcategory = "subcategory" - case subject = "subject" - case unreadByOperatorTimestamp = "unreadByOperatorSinceTs" - case unreadByVisitorMessageCount = "unreadByVisitorMsgCnt" - case unreadByVisitorTimestamp = "unreadByVisitorSinceTs" - case visitorTyping = "visitorTyping" - } - - // MARK: - Properties - private var category: String? - private var clientSideID: String? - private var creationTimestamp: Double - private var id: String - private lazy var messages = [MessageItem]() - private var modificationTimestamp: Double? - private var offline: Bool? - private var `operator`: OperatorItem? - private lazy var operatorIDToRate = [String: RatingItem]() - private var operatorTyping: Bool? - private var readByVisitor: Bool? - private var state: String? - private var subcategory: String? - private var subject: String? - private var unreadByOperatorTimestamp: Double? - private var unreadByVisitorMessageCount: Int - private var unreadByVisitorTimestamp: Double? - private var visitorTyping: Bool? - - // MARK: - Initialization - - init(jsonDictionary: [String: Any?]) { - if let creationTimestampValue = jsonDictionary[JSONField.creationTimestamp.rawValue] as? Double { - creationTimestamp = creationTimestampValue - } else { - creationTimestamp = ChatItem.createCreationTimestamp() - } - - if let idValue = jsonDictionary[JSONField.id.rawValue] as? String { - id = idValue - } else { - id = String(Int(-creationTimestamp)) - } - - if let unreadByVisitorMessageCount = jsonDictionary[JSONField.unreadByVisitorMessageCount.rawValue] as? Int { - self.unreadByVisitorMessageCount = unreadByVisitorMessageCount - } else { - self.unreadByVisitorMessageCount = 0 - } - - if let messagesValue = jsonDictionary[JSONField.messages.rawValue] as? [Any] { - for message in messagesValue { - if let messageValue = message as? [String: Any?] { - let messageItem = MessageItem(jsonDictionary: messageValue) - messages.append(messageItem) - } - } - } - - if let operatorValue = jsonDictionary[JSONField.`operator`.rawValue] as? [String: Any?] { - `operator` = OperatorItem(jsonDictionary: operatorValue) - } - - if let operatorIDToRateValue = jsonDictionary[JSONField.operatorIDToRate.rawValue] as? [String: Any?] { - for (operatorIDValue, ratingValue) in operatorIDToRateValue { - if let ratingItemValue = ratingValue as? [String: Any?] { - let rating = RatingItem(jsonDictionary: ratingItemValue) - operatorIDToRate[operatorIDValue] = rating - } - } - } - - if let category = jsonDictionary[JSONField.category.rawValue] as? String { - self.category = category - } - - if let clientSideID = jsonDictionary[JSONField.clientSideID.rawValue] as? String { - self.clientSideID = clientSideID - } - - if let modificationTimestamp = jsonDictionary[JSONField.modificationTimestamp.rawValue] as? Double { - self.modificationTimestamp = modificationTimestamp - } - - if let offline = jsonDictionary[JSONField.offline.rawValue] as? Bool { - self.offline = offline - } - - if let operatorTyping = jsonDictionary[JSONField.operatorTyping.rawValue] as? Bool { - self.operatorTyping = operatorTyping - } - - if let readByVisitor = jsonDictionary[JSONField.readByVisitor.rawValue] as? Bool { - self.readByVisitor = readByVisitor - } - - if let state = jsonDictionary[JSONField.state.rawValue] as? String { - self.state = state - } - - if let subcategory = jsonDictionary[JSONField.subcategory.rawValue] as? String { - self.subcategory = subcategory - } - - if let subject = jsonDictionary[JSONField.subject.rawValue] as? String { - self.subject = subject - } - - if let unreadByOperatorTimestamp = jsonDictionary[JSONField.unreadByOperatorTimestamp.rawValue] as? Double { - self.unreadByOperatorTimestamp = unreadByOperatorTimestamp - } - - if let unreadByVisitorTimestamp = jsonDictionary[JSONField.unreadByVisitorTimestamp.rawValue] as? Double { - self.unreadByVisitorTimestamp = unreadByVisitorTimestamp - } - - if let visitorTyping = jsonDictionary[JSONField.visitorTyping.rawValue] as? Bool { - self.visitorTyping = visitorTyping - } - } - - // For testing purpoeses. - init(id: String? = nil) { - creationTimestamp = ChatItem.createCreationTimestamp() - - if id == nil { - self.id = String(Int(-creationTimestamp)) - } else { - self.id = id! - } - - unreadByVisitorMessageCount = 0 - } - - // MARK: - Methods - - func getMessages() -> [MessageItem] { - return messages - } - - func set(messages: [MessageItem]) { - self.messages = messages - } - - func add(message: MessageItem, - atPosition position: Int? = nil) { - if position == nil { - messages.append(message) - } else { - messages.insert(message, - at: position!) - } - } - - func isOperatorTyping() -> Bool { - return (operatorTyping == true) - } - - func set(operatorTyping: Bool?) { - self.operatorTyping = operatorTyping - } - - func getState() -> ChatItemState? { - return ChatItemState(withType: state!) - } - - func set(state: ChatItemState) { - self.state = state.rawValue - } - - func getOperator() -> OperatorItem? { - return `operator` - } - - func set(operator: OperatorItem) { - self.`operator` = `operator` - } - - func getReadByVisitor() -> Bool? { - return readByVisitor - } - - func set(readByVisitor: Bool?) { - self.readByVisitor = readByVisitor - } - - func getOperatorIDToRate() -> [String: RatingItem]? { - return operatorIDToRate - } - - func set(rating: RatingItem, - toOperatorWithId operatorID: String) { - operatorIDToRate[operatorID] = rating - } - - func getUnreadByVisitorMessageCount() -> Int { - return unreadByVisitorMessageCount - } - - func set(unreadByVisitorMessageCount: Int) { - self.unreadByVisitorMessageCount = unreadByVisitorMessageCount - } - - func getUnreadByVisitorTimestamp() -> Double? { - return unreadByVisitorTimestamp - } - - func getUnreadByOperatorTimestamp() -> Double? { - return unreadByOperatorTimestamp - } - - func set(unreadByOperatorTimestamp: Double?) { - self.unreadByOperatorTimestamp = unreadByOperatorTimestamp - } - - func set(unreadByVisitorTimestamp: Double?) { - self.unreadByVisitorTimestamp = unreadByVisitorTimestamp - } - - - // MARK: Private methods - private static func createCreationTimestamp() -> Double { - return Double(InternalUtils.getCurrentTimeInMicrosecond()) - } - - // MARK: - - enum ChatItemState: String { - case chatting = "chatting" - case chattingWithRobot = "chatting_with_robot" - case closed = "closed" - case closedByOperator = "closed_by_operator" - case closedByVisitor = "closed_by_visitor" - case invitation = "invitation" - case queue = "queue" - case unknown = "unknown" - - // MARK: - Initialization - init(withType typeValue: String) { - self = ChatItemState(rawValue: typeValue) ?? .unknown - } - - - // MARK: - Methods - func isClosed() -> Bool { - return (((self == .closed) - || (self == .closedByVisitor)) - || (self == .closedByOperator)) - || (self == .unknown) - } - - } - -} - -// MARK: - Equatable -extension ChatItem: Equatable { - - // MARK: - Methods - // Used inside MessageHolderImpl.receiving(newChat:previousChat:newMessages:) only. - static func == (lhs: ChatItem, - rhs: ChatItem) -> Bool { - return (lhs.id == rhs.id) - && (lhs.clientSideID == rhs.clientSideID) - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/Deltas/DeltaItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/Deltas/DeltaItem.swift deleted file mode 100644 index 1e36854..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Items/Deltas/DeltaItem.swift +++ /dev/null @@ -1,117 +0,0 @@ -// -// DeltaItem.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 15.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that encapsulates chat update data, received from a server. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class DeltaItem { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - enum DeltaType: String { - case chat = "CHAT" - case chatMessage = "CHAT_MESSAGE" - case chatOperator = "CHAT_OPERATOR" - case chatOperatorTyping = "CHAT_OPERATOR_TYPING" - case chatReadByVisitor = "CHAT_READ_BY_VISITOR" - case chatState = "CHAT_STATE" - case chatUnreadByOperatorTimestamp = "CHAT_UNREAD_BY_OPERATOR_SINCE_TS" - case departmentList = "DEPARTMENT_LIST" - case historyRevision = "HISTORY_REVISION" - case offlineChatMessage = "OFFLINE_CHAT_MESSAGE" - case operatorRate = "OPERATOR_RATE" - case unreadByVisitor = "UNREAD_BY_VISITOR" - case visitSession = "VISIT_SESSION" - case visitSessionState = "VISIT_SESSION_STATE" - case chatMessageRead = "MESSAGE_READ" - } - enum Event: String { - case add = "add" - case delete = "del" - case update = "upd" - } - enum UnreadByVisitorField: String { - case timestamp = "sinceTs" - case messageCount = "msgCnt" - } - private enum JSONField: String { - case data = "data" - case event = "event" - case objectType = "objectType" - case id = "id" - } - - // MARK: - Properties - private var data: Any? - private var event: Event - private var deltaType: DeltaType? - private var id: String - - // MARK: - Initialization - init?(jsonDictionary: [String: Any?]) { - guard let eventString = jsonDictionary[JSONField.event.rawValue] as? String, - let event = Event(rawValue: eventString) else { - return nil - } - self.event = event - - guard let id = jsonDictionary[JSONField.id.rawValue] as? String else { - return nil - } - self.id = id - - self.data = jsonDictionary[JSONField.data.rawValue] ?? nil - - if let objectTypeString = jsonDictionary[JSONField.objectType.rawValue] as? String { - deltaType = DeltaType(rawValue: objectTypeString) - } - } - - // MARK: - Methods - - func getDeltaType() -> DeltaType? { - return deltaType - } - - func getID() -> String { - return id - } - - func getEvent() -> Event { - return event - } - - func getData() -> Any? { - return data - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/Deltas/FullUpdate.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/Deltas/FullUpdate.swift deleted file mode 100644 index e4663c7..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Items/Deltas/FullUpdate.swift +++ /dev/null @@ -1,162 +0,0 @@ -// -// FullUpdate.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 15.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that encapsulates full data update, received from a server. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -struct FullUpdate { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - private enum JSONField: String { - case authorizationToken = "authToken" - case chat = "chat" - case departments = "departments" - case hintsEnabled = "hintsEnabled" - case historyRevision = "historyRevision" - case onlineStatus = "onlineStatus" - case pageID = "pageId" - case sessionID = "visitSessionId" - case state = "state" - case visitor = "visitor" - } - - // MARK: - Properties - private var authorizationToken: String? - private var chat: ChatItem? - private var departments: [DepartmentItem]? - private var hintsEnabled: Bool - private var historyRevision: Int? - private var onlineStatus: String? - private var pageID: String? - private var sessionID: String? - private var state: String? - private var visitorJSONString: String? - - // MARK: - Initialization - init(jsonDictionary: [String: Any?]) { - if let authorizationToken = jsonDictionary[JSONField.authorizationToken.rawValue] as? String { - self.authorizationToken = authorizationToken - } - - if let chatValue = jsonDictionary[JSONField.chat.rawValue] as? [String: Any?] { - chat = ChatItem(jsonDictionary: chatValue) - } - - if let pageID = jsonDictionary[JSONField.pageID.rawValue] as? String { - self.pageID = pageID - } - - if let onlineStatus = jsonDictionary[JSONField.onlineStatus.rawValue] as? String { - self.onlineStatus = onlineStatus - } - - if let sessionID = jsonDictionary[JSONField.sessionID.rawValue] as? String { - self.sessionID = sessionID - } - - if let state = jsonDictionary[JSONField.state.rawValue] as? String { - self.state = state - } - - if let visitorJSON = jsonDictionary[JSONField.visitor.rawValue] { - if let visitorJSONData = try? JSONSerialization.data(withJSONObject: visitorJSON!) { - visitorJSONString = String(data: visitorJSONData, - encoding: .utf8) - } - } - - if let departmantsData = jsonDictionary[JSONField.departments.rawValue] as? [Any] { - var departmentItems = [DepartmentItem]() - for departmentData in departmantsData { - if let departmentDictionary = departmentData as? [String: Any] { - if let deparmentItem = DepartmentItem(jsonDictionary: departmentDictionary) { - departmentItems.append(deparmentItem) - } - } - } - self.departments = departmentItems - } - - hintsEnabled = (jsonDictionary[JSONField.hintsEnabled.rawValue] as? Bool) ?? false - - if let historyRevision = jsonDictionary[JSONField.historyRevision.rawValue] as? Int { - self.historyRevision = historyRevision - } - } - - // MARK: - Methods - - func getAuthorizationToken() -> String? { - return authorizationToken - } - - func getDepartments() -> [DepartmentItem]? { - return departments - } - - func getChat() -> ChatItem? { - return chat - } - - func getHintsEnabled() -> Bool { - return hintsEnabled - } - - func getHistoryRevision() -> String? { - guard historyRevision != nil else { - return nil - } - return String(historyRevision!) - } - - func getOnlineStatus() -> String? { - return onlineStatus - } - - func getPageID() -> String? { - return pageID - } - - func getSessionID() -> String? { - return sessionID - } - - func getState() -> String? { - return state - } - - func getVisitorJSONString() -> String? { - return visitorJSONString - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/DepartmentItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/DepartmentItem.swift deleted file mode 100644 index 5758cfd..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Items/DepartmentItem.swift +++ /dev/null @@ -1,115 +0,0 @@ -// -// DepartmentItem.swift -// Cosmos -// -// Created by Nikita Lazarev-Zubov on 11.12.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Encapsulates internal representation of single department. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class DepartmentItem { - - // MARK: - Constants - - // Raw values equal to field names received in responses from server. - private enum JSONField: String { - case key = "key" - case localizedNames = "localeToName" - case name = "name" - case onlineStatus = "online" - case order = "order" - case logo = "logo" - } - - enum InternalDepartmentOnlineStatus: String { - case busyOffline = "busy_offline" - case busyOnline = "busy_online" - case offline = "offline" - case online = "online" - case unknown - } - - // MARK: - Properties - private let key: String - private let name: String - private let onlineStatus: InternalDepartmentOnlineStatus - private let order: Int - private var localizedNames: [String: String]? - private var logo: String? - - // MARK: - Initialization - init?(jsonDictionary: [String: Any?]) { - guard let key = jsonDictionary[JSONField.key.rawValue] as? String, - let name = jsonDictionary[JSONField.name.rawValue] as? String, - let onlineStatusString = jsonDictionary[JSONField.onlineStatus.rawValue] as? String, - let order = jsonDictionary[JSONField.order.rawValue] as? Int else { - return nil - } - - self.key = key - self.name = name - self.onlineStatus = InternalDepartmentOnlineStatus(rawValue: onlineStatusString) ?? .unknown - self.order = order - - if let logoURLString = jsonDictionary[JSONField.logo.rawValue] as? String { - self.logo = logoURLString - } - - if let localizedNames = jsonDictionary[JSONField.localizedNames.rawValue] as? [String: String] { - self.localizedNames = localizedNames - } - } - - // MARK: - Methods - - func getKey() -> String { - return key - } - - func getName() -> String { - return name - } - - func getOnlineStatus() -> InternalDepartmentOnlineStatus { - return onlineStatus - } - - func getOrder() -> Int { - return order - } - - func getLocalizedNames() -> [String: String]? { - return localizedNames - } - - func getLogoURLString() -> String? { - return logo - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQCategoryInfoItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQCategoryInfoItem.swift deleted file mode 100644 index df84463..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQCategoryInfoItem.swift +++ /dev/null @@ -1,85 +0,0 @@ -// -// FAQCategoryInfoItem.swift -// WebimClientLibrary -// -// Created by Nikita Kaberov on 07.02.19. -// Copyright © 2019 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -final class FAQCategoryInfoItem { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - private enum JSONField: String { - case id = "id" - case title = "title" - } - - // MARK: - Properties - private var id: Int? - private var title: String? - - // MARK: - Initialization - init(jsonDictionary: [String: Any?]) { - if let id = jsonDictionary[JSONField.id.rawValue] as? Int { - self.id = id - } - - if let title = jsonDictionary[JSONField.title.rawValue] as? String { - self.title = title - } - } - -} - -extension FAQCategoryInfoItem: FAQCategoryInfo { - func getID() -> Int { - return id! - } - - func getTitle() -> String { - return title! - } - -} - -// MARK: - Equatable -extension FAQCategoryInfoItem: Equatable { - - // MARK: - Methods - static func == (lhs: FAQCategoryInfoItem, - rhs: FAQCategoryInfoItem) -> Bool { - if lhs.id == rhs.id { - return true - } - - return false - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQCategoryItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQCategoryItem.swift deleted file mode 100644 index c5c97ff..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQCategoryItem.swift +++ /dev/null @@ -1,152 +0,0 @@ -// -// FAQCategoryItem.swift -// WebimClientLibrary -// -// Created by Nikita Kaberov on 07.02.19. -// Copyright © 2019 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -final class FAQCategoryItem { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - private enum JSONField: String { - case id = "categoryid" - case title = "title" - case childs = "childs" - } - - // MARK: - Properties - private var id: Int? - private var title: String? - private var children = [Child]() - - // MARK: - Initialization - init(jsonDictionary: [String: Any?]) { - if let id = jsonDictionary[JSONField.id.rawValue] as? Int { - self.id = id - } - - if let title = jsonDictionary[JSONField.title.rawValue] as? String { - self.title = title - } - - if let childs = jsonDictionary[JSONField.childs.rawValue] as? [Any] { - for child in childs { - if let childValue = child as? [String: Any?] { - let childItem = Child(jsonDictionary: childValue) - children.append(childItem) - } - } - } - } - -} - -extension FAQCategoryItem: FAQCategory { - func getID() -> Int { - return id! - } - - func getTitle() -> String { - return title! - } - - func getItems() -> [FAQItem] { - var items = [FAQItem]() - for child in children { - if child.type == .ITEM { - items.append(child.data as! FAQItemItem) - } - } - return items - } - - func getSubcategories() -> [FAQCategoryInfo] { - var subCategories = [FAQCategoryInfo]() - for child in children { - if child.type == .CATEGORY { - subCategories.append(child.data as! FAQCategoryInfoItem) - } - } - return subCategories - } - - -} - -// MARK: - Equatable -extension FAQCategoryItem: Equatable { - - // MARK: - Methods - static func == (lhs: FAQCategoryItem, - rhs: FAQCategoryItem) -> Bool { - if lhs.id == rhs.id { - return true - } - - return false - } - -} - -final class Child { - // MARK: - Constants - // Raw values equal to field names received in responses from server. - private enum JSONField: String { - case type = "type" - case data = "data" - } - - // MARK: - Properties - public var type: RootType? - public var data: Any? - - // MARK: - Initialization - init(jsonDictionary: [String: Any?]) { - if let type = jsonDictionary[JSONField.type.rawValue] as? String { - switch type { - case "item": - self.type = .ITEM - if let data = jsonDictionary[JSONField.data.rawValue] as? [String: Any?] { - self.data = FAQItemItem(jsonDictionary: data) - } - break - case "category": - self.type = .CATEGORY - if let data = jsonDictionary[JSONField.data.rawValue] as? [String: Any?] { - self.data = FAQCategoryInfoItem(jsonDictionary: data) - } - break - default: - self.type = .UNKNOWN - } - } - } -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQItemItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQItemItem.swift deleted file mode 100644 index 1bd7440..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQItemItem.swift +++ /dev/null @@ -1,137 +0,0 @@ -// -// FAQItemItem.swift -// WebimClientLibrary -// -// Created by Nikita Kaberov on 07.02.19. -// Copyright © 2019 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -final class FAQItemItem { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - private enum JSONField: String { - case id = "id" - case categories = "categories" - case title = "title" - case tags = "tags" - case content = "content" - case likes = "likes" - case dislikes = "dislikes" - } - - // MARK: - Properties - private var id: String? - private var categories: [Int]? - private var title: String? - private var tags: [String]? - private var content: String? - private var likes: Int? - private var dislikes: Int? - - // MARK: - Initialization - init(jsonDictionary: [String: Any?]) { - if let id = jsonDictionary[JSONField.id.rawValue] as? String { - self.id = id - } - - if let categories = jsonDictionary[JSONField.categories.rawValue] as? [Int] { - self.categories = categories - } - - if let title = jsonDictionary[JSONField.title.rawValue] as? String { - self.title = title - } - - if let tags = jsonDictionary[JSONField.tags.rawValue] as? [String] { - self.tags = tags - } - - if let content = jsonDictionary[JSONField.content.rawValue] as? String { - self.content = content - } - - if let likes = jsonDictionary[JSONField.likes.rawValue] as? Int { - self.likes = likes - } - - if let dislikes = jsonDictionary[JSONField.dislikes.rawValue] as? Int { - self.dislikes = dislikes - } - } - -} - -extension FAQItemItem: FAQItem { - - func getID() -> String { - return id! - } - - func getCategories() -> [Int] { - return categories! - } - - func getTitle() -> String { - return title! - } - - func getTags() -> [String] { - return tags! - } - - func getContent() -> String { - return content! - } - - func getLikeCount() -> Int { - return likes! - } - - func getDislikeCount() -> Int { - return dislikes! - } - - -} - -// MARK: - Equatable -extension FAQItemItem: Equatable { - - // MARK: - Methods - static func == (lhs: FAQItemItem, - rhs: FAQItemItem) -> Bool { - if lhs.id == rhs.id { - return true - } - - return false - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQStructureItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQStructureItem.swift deleted file mode 100644 index a8b4810..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Items/FAQStructureItem.swift +++ /dev/null @@ -1,133 +0,0 @@ -// -// FAQStructureItem.swift -// WebimClientLibrary -// -// Created by Nikita Kaberov on 07.02.19. -// Copyright © 2019 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -final class FAQStructureItem { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - private enum JSONField: String { - case id = "id" - case type = "type" - case childs = "childs" - case title = "title" - } - - // MARK: - Properties - private var id: String? - private var title: String? - private var type: RootType? - private var children = [FAQStructureItem]() - - // MARK: - Initialization - init(jsonDictionary: [String: Any?]) { - if let id = jsonDictionary[JSONField.id.rawValue] as? String { - self.id = id - } - - if let title = jsonDictionary[JSONField.title.rawValue] as? String { - self.title = title - } - - if let type = jsonDictionary[JSONField.type.rawValue] as? String { - self.type = toRootType(type: type) - } - - if type == .ITEM { - if let id = jsonDictionary[JSONField.id.rawValue] as? String { - self.id = id - } - } else { - if let id = jsonDictionary[JSONField.id.rawValue] as? Int { - self.id = String(id) - } - } - - if let childs = jsonDictionary[JSONField.childs.rawValue] as? [Any] { - for child in childs { - if let childValue = child as? [String: Any?] { - let childItem = FAQStructureItem(jsonDictionary: childValue) - children.append(childItem) - } - } - } - } - - private func toRootType(type: String) -> RootType? { - switch type { - case "item": - return .ITEM - case "category": - return .CATEGORY - default: - return nil - } - } - -} - -extension FAQStructureItem: FAQStructure { - func getID() -> String { - return id! - } - - func getType() -> RootType { - return type! - } - - func getChildren() -> [FAQStructure] { - return children - } - - func getTitle() -> String { - return title! - } - - - -} - -// MARK: - Equatable -extension FAQStructureItem: Equatable { - - // MARK: - Methods - static func == (lhs: FAQStructureItem, - rhs: FAQStructureItem) -> Bool { - if lhs.id == rhs.id { - return true - } - - return false - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/FileParametersItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/FileParametersItem.swift deleted file mode 100644 index 04d2d9d..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Items/FileParametersItem.swift +++ /dev/null @@ -1,162 +0,0 @@ -// -// FileParametersItem.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 15.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class FileParametersItem { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - private enum JSONField: String { - case contentType = "content_type" - case fileName = "filename" - case guid = "guid" - case imageParameters = "image" - case size = "size" - } - - // MARK: - Properties - private var contentType: String? - private var filename: String? - private var guid: String? - private var imageParameters: ImageParameters? - private var size: Int64? - - // MARK: - Initialization - init(jsonDictionary: [String: Any?]) { - if let imageParametersDictionary = jsonDictionary[JSONField.imageParameters.rawValue] as? [String: Any?] { - imageParameters = ImageParameters(jsonDictionary: imageParametersDictionary) - } - - if let contentType = jsonDictionary[JSONField.contentType.rawValue] as? String { - self.contentType = contentType - } - - if let filename = jsonDictionary[JSONField.fileName.rawValue] as? String { - self.filename = filename - } - - if let guid = jsonDictionary[JSONField.guid.rawValue] as? String { - self.guid = guid - } - - if let size = jsonDictionary[JSONField.size.rawValue] as? Int64 { - self.size = size - } - } - - // MARK: - Methods - - func getSize() -> Int64? { - return size - } - - func getGUID() -> String? { - return guid - } - - func getContentType() -> String? { - return contentType - } - - func getFilename() -> String? { - return filename - } - - func getImageParameters() -> ImageParameters? { - return imageParameters - } - -} - -// MARK: - -final class ImageParameters { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - private enum JSONField: String { - case size = "size" - } - - // MARK: - Properties - private var size: ImageSize? - - // MARK: - Initialization - init(jsonDictionary: [String: Any?]) { - if let sizeDictionary = jsonDictionary[JSONField.size.rawValue] as? [String: Any?] { - self.size = ImageSize(jsonDictionary: sizeDictionary) - } - } - - // MARK: - Methods - func getSize() -> ImageSize? { - return size - } - -} - -// MARK: - -struct ImageSize { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - private enum JSONField: String { - case height = "height" - case width = "width" - } - - // MARK: - Properties - private var width: Int? - private var height: Int? - - // MARK: - Initialization - init(jsonDictionary: [String: Any?]) { - if let height = jsonDictionary[JSONField.height.rawValue] as? Int { - self.height = height - } - - if let width = jsonDictionary[JSONField.width.rawValue] as? Int { - self.width = width - } - } - - // MARK: - Methods - - func getWidth() -> Int? { - return width - } - - func getHeight() -> Int? { - return height - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/HistoryRevisionItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/HistoryRevisionItem.swift deleted file mode 100644 index c4c9897..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Items/HistoryRevisionItem.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// HistoryRevisionItem.swift -// WebimClientLibrary -// -// Created by Nikita Kaberov on 05.03.19. -// Copyright © 2019 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -final class HistoryRevisionItem { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - private enum JSONField: String { - case revision = "revision" - } - - // MARK: - Properties - private var revision: Int64 - - // MARK: - Initialization - init(jsonDictionary: [String: Any?]) { - if let revision = jsonDictionary[JSONField.revision.rawValue] as? Int64 { - self.revision = revision - } else { - self.revision = 0 - } - } - - // MARK: - Methods - func getRevision() -> String { - return String(revision) - } -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/MessageItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/MessageItem.swift deleted file mode 100644 index 758f410..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Items/MessageItem.swift +++ /dev/null @@ -1,262 +0,0 @@ -// -// MessageItem.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 14.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that encapsulates message data, received from a server. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class MessageItem { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - private enum JSONField: String { - case authorID = "authorId" - case avatarURLString = "avatar" - case canBeEdited = "canBeEdited" - case chatID = "chatId" - case clientSideID = "clientSideId" - case data = "data" - case deleted = "deleted" - case id = "id" - case kind = "kind" - case read = "read" - case senderName = "name" - case text = "text" - case timestampInMicrosecond = "ts_m" - case timestampInSecond = "ts" - } - - // MARK: - Properties - private var authorID: String? - private var avatarURLString: String? - private var canBeEdited: Bool? - private var chatID: String? - private var clientSideID: String? - private var data: [String: Any?]? - private var deleted: Bool? - private var id: String? - private var kind: MessageKind? - private var senderName: String? - private var text: String? - private var timestampInMicrosecond: Int64 = -1 - private var timestampInSecond: Double? - private var read: Bool? - - // MARK: - Initialization - init(jsonDictionary: [String: Any?]) { - if let messageKind = jsonDictionary[JSONField.kind.rawValue] as? String { - kind = MessageKind(rawValue: messageKind) - } - - if let authorID = jsonDictionary[JSONField.authorID.rawValue] as? Int { - self.authorID = String(authorID) - } - - if let avatarURLString = jsonDictionary[JSONField.avatarURLString.rawValue] as? String { - self.avatarURLString = avatarURLString - } - - if let canBeEdited = jsonDictionary[JSONField.canBeEdited.rawValue] as? Bool { - self.canBeEdited = canBeEdited - } - - if let chatID = jsonDictionary[JSONField.chatID.rawValue] as? String { - self.chatID = chatID - } - - if let clientSideID = jsonDictionary[JSONField.clientSideID.rawValue] as? String { - self.clientSideID = clientSideID - } - - if let data = jsonDictionary[JSONField.data.rawValue] as? [String: Any?] { - self.data = data - } - - if let deleted = jsonDictionary[JSONField.deleted.rawValue] as? Bool { - self.deleted = deleted - } - - if let id = jsonDictionary[JSONField.id.rawValue] as? String { - self.id = id - } - - if let read = jsonDictionary[JSONField.read.rawValue] as? Bool { - self.read = read - } - - if let senderName = jsonDictionary[JSONField.senderName.rawValue] as? String { - self.senderName = senderName - } - - if let text = jsonDictionary[JSONField.text.rawValue] as? String { - self.text = text - } - - if let timestampInMicrosecond = jsonDictionary[JSONField.timestampInMicrosecond.rawValue] as? Int64 { - self.timestampInMicrosecond = timestampInMicrosecond - } - - if let timestampInSecond = jsonDictionary[JSONField.timestampInSecond.rawValue] as? Double { - self.timestampInSecond = timestampInSecond - } - } - - // MARK: - Methods - - func getClientSideID() -> String? { - if clientSideID == nil { - clientSideID = id - } - - return clientSideID - } - - func getID() -> String? { - return id - } - - func getText() -> String? { - return text - } - - func getSenderID() -> String? { - return authorID - } - - func getSenderAvatarURLString() -> String? { - return avatarURLString - } - - func getData() -> [String: Any?]? { - return data - } - - func isDeleted() -> Bool { - return (deleted == true) - } - - func getKind() -> MessageKind? { - return kind - } - - func getSenderName() -> String? { - return senderName - } - - func getTimeInMicrosecond() -> Int64? { - return ((timestampInMicrosecond != -1) ? timestampInMicrosecond : Int64(timestampInSecond! * 1_000_000)) - } - - func getRead() -> Bool? { - return read - } - - func setRead(read:Bool) { - self.read = read - } - - func getCanBeEdited() -> Bool { - return canBeEdited ?? false - } - - // MARK: - - enum MessageKind: String { - // Raw values equal to field names received in responses from server. - case actionRequest = "action_request" - case contactInformationRequest = "cont_req" - case contactInformation = "contacts" - case fileFromOperator = "file_operator" - case fileFromVisitor = "file_visitor" - case forOperator = "for_operator" - case info = "info" - case operatorMessage = "operator" - case operatorBusy = "operator_busy" - case visitorMessage = "visitor" - - // MARK: - Initialization - init(messageType: MessageType) { - switch messageType { - case .ACTION_REQUEST: - self = .actionRequest - - break - case .CONTACTS_REQUEST: - self = .contactInformationRequest - - break - case .FILE_FROM_OPERATOR: - self = .fileFromOperator - - break - case .FILE_FROM_VISITOR: - self = .fileFromVisitor - - break - case .INFO: - self = .info - - break - case .OPERATOR: - self = .operatorMessage - - break - case .OPERATOR_BUSY: - self = .operatorBusy - - break - case .VISITOR: - self = .visitorMessage - - break - } - } - - } - -} - -// MARK: - Equatable -extension MessageItem: Equatable { - - // MARK: - Methods - static func == (lhs: MessageItem, - rhs: MessageItem) -> Bool { - if (((lhs.id == rhs.id) - && (lhs.clientSideID == rhs.clientSideID)) - && (lhs.timestampInSecond == rhs.timestampInSecond)) - && (lhs.text == rhs.text) { - return true - } - - return false - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/OnlineStatusItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/OnlineStatusItem.swift deleted file mode 100644 index 85c23a7..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Items/OnlineStatusItem.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// OnlineStatusItem.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 15.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Raw values equal to field names received in responses from server (except `unknown` case which is custom). - * `BUSY_OFFLINE` - user can't send messages at all; - * `BUSY_ONLINE` - user send offline messages, but server can return an error; - * `OFFLINE` - user can send offline messages; - * `ONLINE` - user can send online and offline messages; - * `UNKNOWN` - session has not received data from server. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -enum OnlineStatusItem: String { - case busyOffline = "busy_offline" - case busyOnline = "busy_online" - case offline = "offline" - case online = "online" - case unknown = "unknown" -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/OperatorItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/OperatorItem.swift deleted file mode 100644 index 8701d21..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Items/OperatorItem.swift +++ /dev/null @@ -1,85 +0,0 @@ -// -// OperatorItem.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 14.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that encapsulates chat operator data, received from server. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -struct OperatorItem { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - private enum JSONField: String { - case avatarURLString = "avatar" - case departmentKeys = "departmentKeys" - case id = "id" - case fullName = "fullname" - } - - // MARK: - Properties - private var avatarURLString: String? - private var id: String - private var fullName: String - - // MARK: - Initialization - init?(jsonDictionary: [String: Any?]) { - if let id = jsonDictionary[JSONField.id.rawValue] as? Int { - self.id = String(id) - } else { - return nil - } - - if let fullName = jsonDictionary[JSONField.fullName.rawValue] as? String { - self.fullName = fullName - } else { - return nil - } - - if let avatarURLString = jsonDictionary[JSONField.avatarURLString.rawValue] as? String { - self.avatarURLString = avatarURLString - } - } - - // MARK: - Methods - - func getID() -> String { - return id - } - - func getFullName() -> String { - return fullName - } - - func getAvatarURLString() -> String? { - return avatarURLString - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/RatingItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/RatingItem.swift deleted file mode 100644 index 7056618..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Items/RatingItem.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// RatingItem.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 14.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that encapsulates operator rating data. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -struct RatingItem { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - private enum JSONField: String { - case operatorID = "operatorId" - case rating = "rating" - } - - // MARK: - Properties - private var operatorID: String - private var rating: Int - - // MARK: - Initialization - init?(jsonDictionary: [String : Any?]) { - guard let operatorID = jsonDictionary[JSONField.operatorID.rawValue] as? Int, - let rating = jsonDictionary[JSONField.rating.rawValue] as? Int else { - return nil - } - - self.operatorID = String(operatorID) - self.rating = rating - } - - // MARK: - Methods - - func getOperatorID() -> String { - return operatorID - } - - func getRating() -> Int { - return rating - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/DeltaResponse.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/DeltaResponse.swift deleted file mode 100644 index ecccee9..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/DeltaResponse.swift +++ /dev/null @@ -1,86 +0,0 @@ -// -// DeltaResponse.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 15.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that encapsulates chat update respnonce, requested from a server. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class DeltaResponse { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - private enum JSONField: String { - case deltaList = "deltaList" - case fullUpdate = "fullUpdate" - case revision = "revision" - } - - // MARK: - Properties - private lazy var deltaList = [DeltaItem]() - private var fullUpdate: FullUpdate? - private var revision: Int64? - - // MARK: - Initialization - init(jsonDictionary: [String: Any?]) { - if let revision = jsonDictionary[JSONField.revision.rawValue] as? Int64 { - self.revision = revision - } - - if let fullUpdateValue = jsonDictionary[JSONField.fullUpdate.rawValue] as? [String: Any?] { - fullUpdate = FullUpdate(jsonDictionary: fullUpdateValue) - } - - if let deltaItemArray = jsonDictionary[JSONField.deltaList.rawValue] as? [Any] { - for arrayItem in deltaItemArray { - if let arrayItem = arrayItem as? [String: Any?] { - if let deltaItem = DeltaItem(jsonDictionary: arrayItem) { - deltaList.append(deltaItem) - } - } - } - } - } - - // MARK: - Methods - - func getRevision() -> Int64? { - return revision - } - - func getFullUpdate() -> FullUpdate? { - return fullUpdate - } - - func getDeltaList() -> [DeltaItem]? { - return deltaList - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/HistoryBeforeResponse.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/HistoryBeforeResponse.swift deleted file mode 100644 index 41e051d..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/HistoryBeforeResponse.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// HistoryBeforeResponse.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 14.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -struct HistoryBeforeResponse { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - enum JSONField: String { - case data = "data" - } - - // MARK: - Properties - private var historyResponseData: HistoryResponseData? - private var result: String? - - // MARK: - Initialization - init(jsonDictionary: [String: Any?]) { - if let dataDictionary = jsonDictionary[JSONField.data.rawValue] as? [String: Any?] { - historyResponseData = HistoryResponseData(jsonDictionary: dataDictionary) - } - } - - // MARK: - Methods - func getData() -> HistoryResponseData? { - return historyResponseData - } - - // MARK: - - struct HistoryResponseData { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - enum JSONField: String { - case hasMore = "hasMore" - case messages = "messages" - } - - // MARK: - Properties - private var hasMore: Bool - private var messages: [MessageItem]? - - // MARK: - Initialization - init(jsonDictionary: [String: Any?]) { - messages = [MessageItem]() - if let messagesArray = jsonDictionary[JSONField.messages.rawValue] as? [Any?] { - for item in messagesArray { - if let messageDictionary = item as? [String: Any?] { - let messageItem = MessageItem(jsonDictionary: messageDictionary) - messages?.append(messageItem) - } - } - } - - hasMore = ((jsonDictionary[JSONField.hasMore.rawValue] as? Bool) ?? false) - } - - // MARK: - Methods - - func isHasMore() -> Bool { - return hasMore - } - - func getMessages() -> [MessageItem]? { - return messages - } - - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/HistorySinceResponse.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/HistorySinceResponse.swift deleted file mode 100644 index b33b47e..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Items/Responses/HistorySinceResponse.swift +++ /dev/null @@ -1,107 +0,0 @@ -// -// HistorySinceResponse.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 15.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -struct HistorySinceResponse { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - enum JSONField: String { - case data = "data" - } - - // MARK: - Properties - private var historyResponseData: HistoryResponseData? - - // MARK: - Initialization - init(jsonDictionary: [String: Any?]) { - if let dataDictionary = jsonDictionary[JSONField.data.rawValue] as? [String: Any?] { - historyResponseData = HistoryResponseData(jsonDictionary: dataDictionary) - } - } - - // MARK: - Methods - func getData() -> HistoryResponseData? { - return historyResponseData - } - - // MARK: - - struct HistoryResponseData { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - enum JSONField: String { - case hasMore = "hasMore" - case messages = "messages" - case revision = "revision" - } - - // MARK: - Properties - private var hasMore: Bool? - private var messages: [MessageItem]? - private var revision: String? - - // MARK: - Initialization - init(jsonDictionary: [String: Any?]) { - var messages = [MessageItem]() - if let messagesArray = jsonDictionary[JSONField.messages.rawValue] as? [Any?] { - for item in messagesArray { - if let messageDictionary = item as? [String: Any?] { - let messageItem = MessageItem(jsonDictionary: messageDictionary) - messages.append(messageItem) - } - } - } - self.messages = messages - - hasMore = ((jsonDictionary[JSONField.hasMore.rawValue] as? Bool) ?? false) - revision = jsonDictionary[JSONField.revision.rawValue] as! String? - } - - // MARK: - Methods - - func getMessages() -> [MessageItem]? { - return messages - } - - func isHasMore() -> Bool? { - return hasMore - } - - func getRevision() -> String? { - return revision - } - - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/VisitSessionStateItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/VisitSessionStateItem.swift deleted file mode 100644 index b2d15b7..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Items/VisitSessionStateItem.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// VisitSessionStateItem.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 15.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -enum VisitSessionStateItem: String { - // Raw values equal to field names received in responses from server. - case callbackHunter = "callback-hunter" - case chat = "chat" - case chatShowing = "chat-showing" - case departmentSelection = "department-selection" - case end = "end" - case firstQuestion = "first-question" - case idle = "idle" - case idleAfterChat = "idle-after-chat" - case offlineMessage = "offline-message" - case showing = "showing" - case showingAuto = "showing-auto" - case showingByURLParameter = "showing-by-url-param" - case unknown -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Items/VisitorItem.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Items/VisitorItem.swift deleted file mode 100644 index 52833df..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Items/VisitorItem.swift +++ /dev/null @@ -1,181 +0,0 @@ -// -// VisitorItem.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 15.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import UIKit - -// This class is not used anywhere yet. Implemented for the future tasks. -/** - Internal representation of visitor information. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -struct VisitorItem { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - private enum JSONField: String { - case icon = "icon" - case id = "id" - case fields = "fields" - } - - // MARK: - Properties - private var icon: IconItem? - private var id: String - private var visitorFields: VisitorFieldsItem - - // MARK: - Initialization - init?(jsonDictionary: [String: Any?]) { - guard let id = jsonDictionary[JSONField.id.rawValue] as? String, - let visitorFieldsValue = jsonDictionary[JSONField.fields.rawValue] as? [String: Any?], - let visitorFields = VisitorFieldsItem(jsonDictionary: visitorFieldsValue) else { - return nil - } - - self.id = id - self.visitorFields = visitorFields - - if let iconValue = jsonDictionary[JSONField.icon.rawValue] as? [String : Any?] { - icon = IconItem(jsonDictionary: iconValue) - } - } - - // MARK: - Methods - - func getIcon() -> IconItem? { - return icon - } - - func getID() -> String { - return id - } - - func getVisitorFields() -> VisitorFieldsItem { - return visitorFields - } - -} - -/** - Representation of generated by server visitor avatar image of standard ones. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -struct IconItem { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - private enum JSONField: String { - case color = "color" - case shape = "shape" - } - - // MARK: - Properties - private var color: UIColor - private var shape: String - - // MARK: - Initialization - init?(jsonDictionary: [String: Any?]) { - guard let colorString = jsonDictionary[JSONField.color.rawValue] as? String, - let color = UIColor(hexString: colorString), - let shape = jsonDictionary[JSONField.shape.rawValue] as? String else { - return nil - } - - self.color = color - self.shape = shape - } - - // MARK: - Methods - - func getColor() -> UIColor { - return color - } - - func getShape() -> String { - return shape - } - -} - -// MARK: - -/** - Internal representation of visitor fields. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -struct VisitorFieldsItem { - - // MARK: - Constants - // Raw values equal to field names received in responses from server. - private enum JSONField: String { - case email = "email" - case name = "name" - case phone = "phone" - } - - // MARK: - Properties - private var email: String? - private var name: String - private var phone: String? - - // MARK: - Initialization - init?(jsonDictionary: [String : Any?]) { - guard let name = jsonDictionary[JSONField.name.rawValue] as? String else { - return nil - } - self.name = name - - if let email = jsonDictionary[JSONField.email.rawValue] as? String { - self.email = email - } - - if let phone = jsonDictionary[JSONField.phone.rawValue] as? String { - self.phone = phone - } - } - - // MARK: - Methods - - func getName() -> String { - return name - } - - func getEmail() -> String? { - return email - } - - func getPhone() -> String? { - return phone - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/LocationSettingsHolder.swift b/ios/libs/Webim/WebimClientLibrary/Backend/LocationSettingsHolder.swift deleted file mode 100644 index 042511d..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/LocationSettingsHolder.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// LocationSettingsHolder.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 09.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class LocationSettingsHolder { - - // MARK: - Properties - private let locationSettings: LocationSettingsImpl - private let userDefaultsKey: String - - // MARK: - Initialization - init(userDefaultsKey: String) { - self.userDefaultsKey = userDefaultsKey - locationSettings = LocationSettingsImpl.getFrom(userDefaults: userDefaultsKey) - } - - // MARK: - Methods - - func getLocationSettings() -> LocationSettingsImpl { - return locationSettings - } - - func receiving(locationSettings: LocationSettingsImpl) -> Bool { - if locationSettings != self.locationSettings { - locationSettings.saveTo(userDefaults: userDefaultsKey) - - return true - } - - return false - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/MemoryHistoryMetaInformationStorage.swift b/ios/libs/Webim/WebimClientLibrary/Backend/MemoryHistoryMetaInformationStorage.swift deleted file mode 100644 index 819f386..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/MemoryHistoryMetaInformationStorage.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// MemoryHistoryMetaInformationStorage.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 11.09.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class MemoryHistoryMetaInformationStorage: HistoryMetaInformationStorage { - - // MARK: - Properties - private var historyEnded = false - - // MARK: - Methods - // MARK: HistoryMetaInformationStorage protocol methods - - func isHistoryEnded() -> Bool { - return historyEnded - } - - func set(historyEnded: Bool) { - self.historyEnded = historyEnded - } - - func set(revision: String?) { - // No need to do anything in this implementation. - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/MemoryHistoryStorage.swift b/ios/libs/Webim/WebimClientLibrary/Backend/MemoryHistoryStorage.swift deleted file mode 100644 index ba63482..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/MemoryHistoryStorage.swift +++ /dev/null @@ -1,226 +0,0 @@ -// -// MemoryHistoryStorage.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 11.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that is responsible for history storage when it is set to memory mode. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class MemoryHistoryStorage: HistoryStorage { - - // MARK: - Properties - private let majorVersion = Int(InternalUtils.getCurrentTimeInMicrosecond() % Int64(Int.max)) - private lazy var historyMessages = [MessageImpl]() - private var reachedHistoryEnd = false - private var readBeforeTimestamp: Int64 - - // MARK: - Initialization - - init() { - // Empty initializer introduced because of init(with:) existence. - self.readBeforeTimestamp = -1 - } - - init(readBeforeTimestamp: Int64) { - self.readBeforeTimestamp = readBeforeTimestamp - } - - // For testing purposes only. - init(messagesToAdd: [MessageImpl]) { - self.readBeforeTimestamp = -1 - for message in messagesToAdd { - historyMessages.append(message) - } - } - - // MARK: - Methods - // MARK: HistoryStorage protocol methods - - func getMajorVersion() -> Int { - return majorVersion - } - - func set(reachedHistoryEnd: Bool) { - // No need in this implementation. - } - - func getFullHistory(completion: @escaping ([Message]) -> ()) { - completion(historyMessages as [Message]) - } - - func getLatestHistory(byLimit limitOfMessages: Int, - completion: @escaping ([Message]) -> ()) { - respondTo(messages: historyMessages, - limitOfMessages: limitOfMessages, - completion: completion) - } - - func getHistoryBefore(id: HistoryID, - limitOfMessages: Int, - completion: @escaping ([Message]) -> ()) { - let sortedMessages = historyMessages.sorted { $0.getHistoryID()!.getTimeInMicrosecond() < $1.getHistoryID()!.getTimeInMicrosecond() } - - if sortedMessages[0].getHistoryID()!.getTimeInMicrosecond() > id.getTimeInMicrosecond() { - completion([MessageImpl]()) - - return - } - - for (index, message) in sortedMessages.enumerated() { - if message.getHistoryID() == id { - respondTo(messages: sortedMessages, - limitOfMessages: limitOfMessages, - offset: index, - completion: completion) - - break - } - } - } - - func receiveHistoryBefore(messages: [MessageImpl], - hasMoreMessages: Bool) { - if !hasMoreMessages { - reachedHistoryEnd = true - } - - historyMessages = messages + historyMessages - } - - func receiveHistoryUpdate(withMessages messages: [MessageImpl], - idsToDelete: Set, - completion: @escaping (_ endOfBatch: Bool, _ messageDeleted: Bool, _ deletedMesageID: String?, _ messageChanged: Bool, _ changedMessage: MessageImpl?, _ messageAdded: Bool, _ addedMessage: MessageImpl?, _ idBeforeAddedMessage: HistoryID?) -> ()) { - deleteFromHistory(idsToDelete: idsToDelete, - completion: completion) - mergeHistoryChanges(messages: messages, - completion: completion) - - completion(true, false, nil, false, nil, false, nil, nil) - } - - func updateReadBeforeTimestamp(timestamp: Int64) { - self.readBeforeTimestamp = timestamp - } - - // MARK: Private methods - - private func respondTo(messages: [MessageImpl], - limitOfMessages: Int, - completion: ([Message]) -> ()) { - completion((messages.count == 0) ? messages : ((messages.count <= limitOfMessages) ? messages : Array(messages[(messages.count - limitOfMessages) ..< messages.count]))) - } - - private func respondTo(messages: [MessageImpl], - limitOfMessages: Int, - offset: Int, - completion: ([Message]) -> ()) { - let supposedQuantity = offset - limitOfMessages - completion(Array(messages[((supposedQuantity > 0) ? supposedQuantity : 0) ..< offset])) - } - - private func deleteFromHistory(idsToDelete: Set, - completion: (_ endOfBatch: Bool, _ messageDeleted: Bool, _ deletedMesageID: String?, _ messageChanged: Bool, _ changedMessage: MessageImpl?, _ messageAdded: Bool, _ addedMessage: MessageImpl?, _ idBeforeAddedMessage: HistoryID?) -> ()) { - for idToDelete in idsToDelete { - for (index, message) in historyMessages.enumerated() { - if message.getHistoryID()?.getDBid() == idToDelete { - historyMessages.remove(at: index) - completion(false, true, message.getHistoryID()?.getDBid(), false, nil, false, nil, nil) - - break - } - } - } - } - - private func mergeHistoryChanges(messages: [MessageImpl], - completion: (_ endOfBatch: Bool, _ messageDeleted: Bool, _ deletedMesageID: String?, _ messageChanged: Bool, _ changedMessage: MessageImpl?, _ messageAdded: Bool, _ addedMessage: MessageImpl?, _ idBeforeAddedMessage: HistoryID?) -> ()) { - /* - Algorithm merges messages with history messages. - Messages before first history message are ignored. - Messages with the same time in Microseconds with corresponding history messages are replacing them. - Messages after last history message are added in the end. - The rest of the messages are merged in the middle of history messages. - */ - - var receivedMessages = messages - var result = [MessageImpl]() - - outerLoop: for historyMessage in historyMessages { - while receivedMessages.count > 0 { - for message in receivedMessages { - if (message.getTimeInMicrosecond() <= readBeforeTimestamp || readBeforeTimestamp == -1) { - message.setRead(isRead: true) - } - if message.getTimeInMicrosecond() < historyMessage.getTimeInMicrosecond() { - if !result.isEmpty { - result.append(message) - completion(false, false, nil, false, nil, true, message, historyMessage.getHistoryID()) - - receivedMessages.remove(at: 0) - - continue - } else { - receivedMessages.remove(at: 0) - - break - } - } - - if message.getTimeInMicrosecond() > historyMessage.getTimeInMicrosecond() { - result.append(historyMessage) - - continue outerLoop - } - - if message.getTimeInMicrosecond() == historyMessage.getTimeInMicrosecond() { - result.append(message) - completion(false, false, nil, true, message, false, nil, nil) - - receivedMessages.remove(at: 0) - - continue outerLoop - } - } - } - - result.append(historyMessage) - } - - if receivedMessages.count > 0 { - for message in receivedMessages { - result.append(message) - completion(false, false, nil, false, nil, true, message, nil) - } - } - - historyMessages = result - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/MessageComposingHandler.swift b/ios/libs/Webim/WebimClientLibrary/Backend/MessageComposingHandler.swift deleted file mode 100644 index 6866787..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/MessageComposingHandler.swift +++ /dev/null @@ -1,115 +0,0 @@ -// -// MessageComposingHandlerImpl.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 14.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that is responsible for sending drafts of visitor typed messages to an operator side chat. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class MessageComposingHandler { - - // MARK: - Constants - private enum Deadline: Int { - case draftSendingInterval = 1 // Second - case resetStatusDelay = 5 // Second - } - - // MARK: - Properties - private let queue: DispatchQueue - private let webimActions: WebimActions - private var latestDraft: String? - private var resetTimer: Timer? - private var updateDraftScheduled = false - - // MARK: - Initialization - init(webimActions: WebimActions, - queue: DispatchQueue) { - self.webimActions = webimActions - self.queue = queue - } - - // MARK: - Methods - - func setComposing(draft: String?) { - latestDraft = draft - - if !updateDraftScheduled { - send(draft: draft) - updateDraftScheduled = true - - queue.asyncAfter(deadline: (DispatchTime.now() + .seconds(Deadline.draftSendingInterval.rawValue)), - execute: { [weak self] in - guard let `self` = self else { - return - } - - self.updateDraftScheduled = false - - if self.latestDraft != draft { - self.send(draft: self.latestDraft) - } - }) - } - - resetTimer?.invalidate() - - if draft != nil { - let resetTime = Date().addingTimeInterval(Double(Deadline.resetStatusDelay.rawValue)) - resetTimer = Timer(fireAt: resetTime, - interval: 0.0, - target: self, - selector: #selector(resetTypingStatus), - userInfo: nil, - repeats: false) - RunLoop.main.add(resetTimer!, - forMode: RunLoop.Mode.common) - } - } - - // MARK: Private methods - - @objc - private func resetTypingStatus() { - queue.async { - self.webimActions.set(visitorTyping: false, - draft: nil, - deleteDraft: false) - } - } - - private func send(draft: String?) { - let visitorTyping = ((draft == nil) ? false : (draft!.isEmpty ? false : true)) - let deleteDraft = ((draft == nil) ? true : (draft!.isEmpty ? true : false)) - webimActions.set(visitorTyping: visitorTyping, - draft: draft, - deleteDraft: deleteDraft) - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/MessageHolder.swift b/ios/libs/Webim/WebimClientLibrary/Backend/MessageHolder.swift deleted file mode 100644 index fca4754..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/MessageHolder.swift +++ /dev/null @@ -1,564 +0,0 @@ -// -// MessageHolder.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 20.10.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class MessageHolder { - - // MARK: - Properties - private let accessChecker: AccessChecker - private let historyStorage: HistoryStorage - private let remoteHistoryProvider: RemoteHistoryProvider - private lazy var currentChatMessages = [MessageImpl]() - private var lastChatMessageIndex = 0 - private lazy var messagesToSend = [MessageToSend]() - private var messageTracker: MessageTrackerImpl? - private var reachedEndOfLocalHistory = false - private var reachedEndOfRemoteHistory: Bool - - // MARK: - Initialization - init(accessChecker: AccessChecker, - remoteHistoryProvider: RemoteHistoryProvider, - historyStorage: HistoryStorage, - reachedEndOfRemoteHistory: Bool) { - self.accessChecker = accessChecker - self.remoteHistoryProvider = remoteHistoryProvider - self.historyStorage = historyStorage - self.reachedEndOfRemoteHistory = reachedEndOfRemoteHistory - } - - // MARK: - Methods - - func checkAccess() throws { - try accessChecker.checkAccess() - } - - func getCurrentChatMessages() -> [MessageImpl] { - return currentChatMessages - } - - func set(currentChatMessages: [MessageImpl]) { - self.currentChatMessages = currentChatMessages - } - - func getMessagesToSend() -> [MessageToSend] { - return messagesToSend - } - - func removeFromMessagesToSendAt(index: Int) { - messagesToSend.remove(at: index) - } - - func set(messagesToSend: [MessageToSend]) { - self.messagesToSend = messagesToSend - } - - func getLatestMessages(byLimit limitOfMessages: Int, - completion: @escaping ([Message]) -> ()) { - if !currentChatMessages.isEmpty { - respondTo(messages: currentChatMessages, - limitOfMessages: limitOfMessages, - completion: completion) - } else { - historyStorage.getLatestHistory(byLimit: limitOfMessages, - completion: completion) - } - } - - func getMessagesBy(limit: Int, - before message: MessageImpl, - completion: @escaping ([Message]) -> ()) { - if message.getSource().isCurrentChatMessage() { - if currentChatMessages.isEmpty { - WebimInternalLogger.shared.log(entry: "Current chat is empty. Requesting history rejected.", - verbosityLevel: .VERBOSE) - - completion([Message]()) - - return - } - - let firstMessage = currentChatMessages.first! - if message == firstMessage { - if !firstMessage.hasHistoryComponent() { - historyStorage.getLatestHistory(byLimit: limit, - completion: completion) - } else { - getMessagesFromHistoryBefore(id: firstMessage.getHistoryID()!, - limit: limit, - completion: completion) - } - } else { - getMessagesFromCurrentChatBefore(message: message, - limit: limit, - completion: completion) - } - } else { - getMessagesFromHistoryBefore(id: message.getHistoryID()!, - limit: limit, - completion: completion) - } - } - - func set(messageTracker: MessageTrackerImpl?) { - self.messageTracker = messageTracker - } - - func getHistoryStorage() -> HistoryStorage { - return historyStorage - } - - func set(reachedEndOfLocalHistory: Bool) { - self.reachedEndOfLocalHistory = reachedEndOfLocalHistory - } - - func newMessageTracker(withMessageListener messageListener: MessageListener) throws -> MessageTrackerImpl { - try messageTracker?.destroy() - - set(messageTracker: MessageTrackerImpl(messageListener: messageListener, - messageHolder: self)) - - return messageTracker! - } - - func receiveHistoryUpdateWith(messages: [MessageImpl], - deleted: Set, - completion: @escaping () -> ()) { - historyStorage.receiveHistoryUpdate(withMessages: messages, - idsToDelete: deleted) { [weak self] (endOfBatch: Bool, messageDeleted: Bool, deletedMessageID: String?, messageChanged: Bool, changedMessage: MessageImpl?, messageAdded: Bool, addedMessage: MessageImpl?, idBeforeAddedMessage: HistoryID?) -> () in - if endOfBatch { - self?.messageTracker?.endedHistoryBatch() - - completion() - } - - if messageDeleted { - // Assuming that when messageDeleted == true deletedMessageID cannot be nil. - self?.messageTracker?.deletedHistoryMessage(withID: deletedMessageID!) - } - - if messageChanged { - // Assuming that when messageChanged == true changedMessage cannot be nil. - self?.messageTracker?.changedHistory(message: changedMessage!) - } - - if messageAdded { - // Assuming that when messageAdded == true addedMessage cannot be nil. - if (self?.tryMergeWithLastChat(message: addedMessage!) != true) { - self?.messageTracker?.addedHistory(message: addedMessage!, - before: idBeforeAddedMessage) - } - } - } - } - - func receiving(newChat: ChatItem?, - previousChat: ChatItem?, - newMessages: [MessageImpl]) { - if currentChatMessages.isEmpty { - receive(newMessages: newMessages) - } else { - if newChat == nil { - historifyCurrentChat() - } else if (previousChat == nil) || - (newChat != previousChat) { - historifyCurrentChat() - - receive(newMessages: newMessages) - } else { - mergeCurrentChatWith(newMessages: newMessages) - } - } - } - - func receive(newMessage: MessageImpl) { - if messageTracker != nil { - messageTracker!.addedNew(message: newMessage, - of: self) - } else { - currentChatMessages.append(newMessage) - } - } - - func changed(message: MessageImpl) { - for messageIndex in lastChatMessageIndex ..< currentChatMessages.count { - let previousVersion = currentChatMessages[messageIndex] - if previousVersion.getCurrentChatID() == message.getCurrentChatID() { - currentChatMessages[messageIndex] = message - - messageTracker?.changedCurrentChatMessage(from: previousVersion, - to: message, - at: messageIndex, - of: self) - - return - } - } - } - - func deletedMessageWith(id: String) { - for messageIndex in lastChatMessageIndex ..< currentChatMessages.count { - let message = currentChatMessages[messageIndex] - if message.getCurrentChatID() == id { - currentChatMessages.remove(at: messageIndex) - - messageTracker?.deletedCurrentChat(message: message, - at: messageIndex, - messageHolder: self) - - return - } - } - } - - func sending(message: MessageToSend) { - messagesToSend.append(message) - - messageTracker?.messageListener?.added(message: message, - after: nil) - } - - func sendingCancelledWith(messageID: String) { - for messageIndex in 0 ..< messagesToSend.count { - if messagesToSend[messageIndex].getID() == messageID { - let message = messagesToSend[messageIndex] - - messagesToSend.remove(at: messageIndex) - - messageTracker?.messageListener?.removed(message: message) - - return - } - } - } - - func changing(messageID: String, message: String?) -> String? { - if messageTracker == nil { - return nil - } - var messageImpl: MessageImpl? = nil - - for curr in currentChatMessages { - if curr.getID() == messageID { - messageImpl = curr - break - } - } - - if messageImpl == nil { - return nil - } - - let newMessage = MessageImpl(serverURLString: (messageImpl?.getServerUrlString())!, - id: messageID, - operatorID: messageImpl?.getOperatorID(), - senderAvatarURLString: messageImpl?.getSenderAvatarURLString(), - senderName: (messageImpl?.getSenderName())!, - sendStatus: .SENDING, - type: (messageImpl?.getType())!, - data: messageImpl?.getData(), - text: (message == nil ? messageImpl?.getText() : message)!, - timeInMicrosecond: (messageImpl?.getTimeInMicrosecond())!, - attachment: messageImpl?.getAttachment(), - historyMessage: (messageImpl?.getSource().isHistoryMessage())!, - internalID: messageImpl?.getCurrentChatID(), - rawText: messageImpl?.getRawText(), - read: (messageImpl?.isReadByOperator())!, - messageCanBeEdited: (messageImpl?.canBeEdited())!) - messageTracker?.messageListener?.changed(message: messageImpl!, to: newMessage) - return messageImpl?.getText() - } - - func changingCancelledWith(messageID: String, message: String) { - if messageTracker == nil { - return - } - var messageImpl: MessageImpl? = nil - - for curr in currentChatMessages { - if curr.getID() == messageID { - messageImpl = curr - break - } - } - - if messageImpl == nil { - return - } - - let newMessage = MessageImpl(serverURLString: (messageImpl?.getServerUrlString())!, - id: messageID, - operatorID: messageImpl?.getOperatorID(), - senderAvatarURLString: messageImpl?.getSenderAvatarURLString(), - senderName: (messageImpl?.getSenderName())!, - sendStatus: .SENT, - type: (messageImpl?.getType())!, - data: messageImpl?.getData(), - text: message, - timeInMicrosecond: (messageImpl?.getTimeInMicrosecond())!, - attachment: messageImpl?.getAttachment(), - historyMessage: (messageImpl?.getSource().isHistoryMessage())!, - internalID: messageImpl?.getCurrentChatID(), - rawText: messageImpl?.getRawText(), - read: (messageImpl?.isReadByOperator())!, - messageCanBeEdited: (messageImpl?.canBeEdited())!) - messageTracker?.messageListener?.changed(message: messageImpl!, to: newMessage) - } - - // MARK: For testing purposes. - - func getLastChatMessageIndex() -> Int { - return lastChatMessageIndex - } - - func getRemoteHistoryProvider() -> RemoteHistoryProvider { - return remoteHistoryProvider - } - - func set(endOfHistoryReached: Bool) { - reachedEndOfRemoteHistory = endOfHistoryReached - historyStorage.set(reachedHistoryEnd: endOfHistoryReached) - } - - // MARK: Private methods - - private func receive(newMessages: [MessageImpl]) { - if messageTracker != nil { - messageTracker!.addedNew(messages: newMessages, - of: self) - } else { - for message in newMessages { - currentChatMessages.append(message) - } - } - } - - private func respondTo(messages: [MessageImpl], - limitOfMessages: Int, - completion: ([Message]) -> ()) { - completion(messages.isEmpty - ? [MessageImpl]() - : (messages.count <= limitOfMessages) ? messages : Array(messages[(messages.count - limitOfMessages) ..< messages.count])) - } - - private func respondTo(messages: [MessageImpl], - limitOfMessages: Int, - offset: Int, - completion: ([Message]) -> ()) { - let messageList = Array(messages[max(0, (offset - limitOfMessages)) ..< offset]) - completion(messageList) - } - - private func historifyCurrentChat() { - var newCurrentChatMessages = [MessageImpl]() - - for currentChatMessage in currentChatMessages { - if currentChatMessage.hasHistoryComponent() { - currentChatMessage.invertHistoryStatus() - - if let id = currentChatMessage.getHistoryID()?.getDBid() { - if let historyMessage = messageTracker?.idToHistoryMessageMap[id] { - historyMessage.setMessageCanBeEdited(messageCanBeEdited: false) - if currentChatMessage != historyMessage { - messageTracker?.messageListener?.changed(message: currentChatMessage, - to: historyMessage) - } else { - messageTracker?.idToHistoryMessageMap[id] = currentChatMessage - } - } - } - } else { - newCurrentChatMessages.append(currentChatMessage) - if currentChatMessage.canBeEdited() { - currentChatMessage.setMessageCanBeEdited(messageCanBeEdited: false) - messageTracker?.messageListener?.changed(message: currentChatMessage, to: currentChatMessage) - } - } - } - - self.set(currentChatMessages: newCurrentChatMessages) - - lastChatMessageIndex = currentChatMessages.count - } - - private func requestHistory(beforeID id: HistoryID, - limit: Int, - completion: @escaping ([Message]) -> ()) { - remoteHistoryProvider.requestHistory(beforeTimestamp: id.getTimeInMicrosecond(), - completion: { [weak self] (messages: [MessageImpl], hasMoreMessages: Bool) in - if messages.isEmpty { - self?.reachedEndOfRemoteHistory = true - } else { - self?.historyStorage.receiveHistoryBefore(messages: messages, - hasMoreMessages: hasMoreMessages) - } - - self?.respondTo(messages: messages, - limitOfMessages: limit, - completion: completion) - }) - } - - private func getMessagesFromHistoryBefore(id: HistoryID, - limit: Int, - completion: @escaping ([Message]) -> ()) { - if reachedEndOfLocalHistory != true { - historyStorage.getHistoryBefore(id: id, - limitOfMessages: limit, - completion: { [weak self] messages in - if !messages.isEmpty { - completion(messages) - } else { - self?.reachedEndOfLocalHistory = true - self?.getMessagesFromHistoryBefore(id: id, - limit: limit, - completion: completion) - } - }) - } else if reachedEndOfRemoteHistory == true { - completion([MessageImpl]()) - } else { - requestHistory(beforeID: id, - limit: limit, - completion: completion) - } - } - - private func getMessagesFromCurrentChatBefore(message: MessageImpl, - limit: Int, - completion: ([Message]) -> ()) { - do { - try message.getSource().assertIsCurrentChat() - } catch { - WebimInternalLogger.shared.log(entry: "Message before which messages are requested is not a part of current chat: \(message.toString()).", - verbosityLevel: .DEBUG) - - return - } - - let messageIndex = currentChatMessages.index(of: message)! - - guard messageIndex >= 1 else { - WebimInternalLogger.shared.log(entry: "Message \(message.toString()) before which messages of current chat are requested can't have index less than 1. Current index: \(messageIndex).", - verbosityLevel: .DEBUG) - - return - } - - respondTo(messages: currentChatMessages, - limitOfMessages: limit, - offset: messageIndex, - completion: completion) - } - - private func mergeCurrentChatWith(newMessages: [MessageImpl]) { - var previousMessageIndex = lastChatMessageIndex - var areOldMessagesEnded = false - - for messageIndex in 0 ..< newMessages.count { - let newMessage = newMessages[messageIndex] - - if !areOldMessagesEnded { - var isMerged = false - - while previousMessageIndex < currentChatMessages.count { - let previousMessage = currentChatMessages[previousMessageIndex] - if previousMessage.getID() == newMessage.getID() { - if previousMessage != newMessage { - currentChatMessages[previousMessageIndex] = newMessage - - messageTracker?.changedCurrentChatMessage(from: previousMessage, - to: newMessage, - at: previousMessageIndex, - of: self) - } - - isMerged = true - - previousMessageIndex = previousMessageIndex + 1 - - break - } else { - currentChatMessages.remove(at: previousMessageIndex) - - messageTracker?.deletedCurrentChat(message: previousMessage, - at: previousMessageIndex, - messageHolder: self) - } - } // End of "while previousMessageIndex < currentChatMessages.count". - - if !isMerged && - (previousMessageIndex >= currentChatMessages.count) { - areOldMessagesEnded = true - } - } // End of "if !areOldMessagesEnded". - - if areOldMessagesEnded { - receive(newMessage: newMessage) - } - } - } - - private func tryMergeWithLastChat(message: MessageImpl) -> Bool { - for (currentChatMessageIndex, currentChatMessage) in currentChatMessages.enumerated() { - guard currentChatMessage.getID() == message.getID() else { - continue - } - - if currentChatMessageIndex < lastChatMessageIndex { - let replacementMessage = currentChatMessage.transferToHistory(message: message) - messageTracker?.idToHistoryMessageMap[message.getHistoryID()!.getDBid()] = replacementMessage - - if replacementMessage != currentChatMessage { - messageTracker?.messageListener?.changed(message: currentChatMessage, - to: replacementMessage) - } - - currentChatMessages.remove(at: currentChatMessageIndex) - lastChatMessageIndex -= 1 - } else { - currentChatMessage.setSecondaryHistory(historyEquivalentMessage: message) - - messageTracker?.idToHistoryMessageMap[message.getHistoryID()!.getDBid()] = message - } - - return true - } - - return false - } - - func updateReadBeforeTimestamp(timestamp: Int64) { - historyStorage.updateReadBeforeTimestamp(timestamp: timestamp) - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/MessageToSend.swift b/ios/libs/Webim/WebimClientLibrary/Backend/MessageToSend.swift deleted file mode 100644 index e69061d..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/MessageToSend.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// MessageToSend.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 17.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Message subtype which is used when message is sending by visitor at the moment. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class MessageToSend: MessageImpl { - - // MARK: - Initialization - init(serverURLString: String, - id: String, - senderName: String, - type: MessageType, - text: String, - timeInMicrosecond: Int64) { - super.init(serverURLString: serverURLString, - id: id, - operatorID: nil, - senderAvatarURLString: nil, - senderName: senderName, - sendStatus: .SENDING, - type: type, - data: nil, - text: text, - timeInMicrosecond: timeInMicrosecond, - attachment: nil, - historyMessage: false, - internalID: nil, - rawText: nil, - read: false, - messageCanBeEdited: false) - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/ProvidedVisitorFields.swift b/ios/libs/Webim/WebimClientLibrary/Backend/ProvidedVisitorFields.swift deleted file mode 100644 index 504d9a2..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/ProvidedVisitorFields.swift +++ /dev/null @@ -1,106 +0,0 @@ -// -// ProvidedVisitorFields.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 08.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that encapsulates unique visitor data. - - Author: - Nikita Lazarev-Zubov - - Copyright: - 2017 Webim - */ -final class ProvidedVisitorFields { - - // MARK: - Properties - private let id: String - private let jsonString: String - - // MARK: - Initialization - - convenience init?(withJSONString jsonString: String) { - if let jsonData = jsonString.data(using: .utf8) { - self.init(jsonString: jsonString, - JSONObject: jsonData) - } else { - return nil - } - } - - convenience init?(withJSONObject jsonData: Data) { - let jsonString = String(data: jsonData, - encoding: .utf8) - - self.init(jsonString: jsonString!, - JSONObject: jsonData) - - } - - private init?(jsonString: String, - JSONObject: Data) { - do { - if let jsonData = try JSONSerialization.jsonObject(with: JSONObject) as? [String: Any] { - if let fields = jsonData["fields"] as? [String: String] { - if let id = fields["id"] { - self.id = id - } else { - throw VisitorFieldsError.invalidVisitorFields("Visitor fields JSON object must contain ID field") - } - } else if let id = jsonData["id"] as? String { - self.id = id - } else { - throw VisitorFieldsError.invalidVisitorFields("Visitor fields JSON object must contain ID field") - } - } else { - throw VisitorFieldsError.serializingFail("Error serializing visitor JSON data.") - } - - self.jsonString = jsonString - } catch { - WebimInternalLogger.shared.log(entry: "Error serializing provided visitor fields: \(String(data: JSONObject, encoding: .utf8) ?? "unreadable data").", - verbosityLevel: .DEBUG) - - return nil - } - } - - // MARK: - Methods - - func getID() -> String { - return id - } - - func getJSONString() -> String { - return jsonString - } - - // MARK: - - enum VisitorFieldsError: Error { - case serializingFail(String) - case invalidVisitorFields(String) - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/RemoteHistoryProvider.swift b/ios/libs/Webim/WebimClientLibrary/Backend/RemoteHistoryProvider.swift deleted file mode 100644 index f5e3d9c..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/RemoteHistoryProvider.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// RemoteHistoryProvider.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 11.09.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -class RemoteHistoryProvider { - - // MARK: - Properties - private var webimActions: WebimActions - private var historyMessageMapper: MessageMapper - private var historyMetaInformationStorage: HistoryMetaInformationStorage - - // MARK: - Initialization - init(webimActions: WebimActions, - historyMessageMapper: MessageMapper, - historyMetaInformationStorage: HistoryMetaInformationStorage) { - self.webimActions = webimActions - self.historyMessageMapper = historyMessageMapper - self.historyMetaInformationStorage = historyMetaInformationStorage - } - - // MARK: - Methods - func requestHistory(beforeTimestamp: Int64, - completion: @escaping ([MessageImpl], Bool) -> ()) { - webimActions.requestHistory(beforeMessageTimestamp: beforeTimestamp) { [weak self] data in - guard data != nil, - let `self` = self else { - completion([MessageImpl](), false) - - return - } - - let json = try? JSONSerialization.jsonObject(with: data!, - options: []) - if let historyBeforeResponseDictionary = json as? [String: Any?] { - let historyBeforeResponse = HistoryBeforeResponse(jsonDictionary: historyBeforeResponseDictionary) - - if let messages = historyBeforeResponse.getData()?.getMessages() { - completion(self.historyMessageMapper.mapAll(messages: messages), (historyBeforeResponse.getData()?.isHasMore() == true)) - - if historyBeforeResponse.getData()?.isHasMore() != true { - self.historyMetaInformationStorage.set(historyEnded: true) - } - } else { - completion([MessageImpl](), false) - self.historyMetaInformationStorage.set(historyEnded: true) - } - } - } - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/SQLiteHistoryStorage.swift b/ios/libs/Webim/WebimClientLibrary/Backend/SQLiteHistoryStorage.swift deleted file mode 100644 index 83c715d..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/SQLiteHistoryStorage.swift +++ /dev/null @@ -1,677 +0,0 @@ -// -// SQLiteHistoryStorage.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 11.08.17. -// Copyright В© 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -import SQLite - -/** - Class that is responsible for history storage inside SQLite DB. Uses SQLite.swift library. - - seealso: - https://github.com/stephencelis/SQLite.swift - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class SQLiteHistoryStorage: HistoryStorage { - - // MARK: - Constants - - // MARK: SQLite tables and columns names - private enum TableName: String { - case history = "history" - } - private enum ColumnName: String { - // In DB columns order. - case id = "id" - case clientSideID = "client_side_id" - case timestamp = "timestamp" - case senderID = "sender_id" - case senderName = "sender_name" - case avatarURLString = "avatar_url_string" - case type = "type" - case text = "text" - case data = "data" - } - - // MARK: SQLite.swift abstractions - - private static let history = Table(TableName.history.rawValue) - - // In DB columns order. - private static let id = Expression(ColumnName.id.rawValue) - private static let clientSideID = Expression(ColumnName.clientSideID.rawValue) - private static let timestamp = Expression(ColumnName.timestamp.rawValue) - private static let senderID = Expression(ColumnName.senderID.rawValue) - private static let senderName = Expression(ColumnName.senderName.rawValue) - private static let avatarURLString = Expression(ColumnName.avatarURLString.rawValue) - private static let type = Expression(ColumnName.type.rawValue) - private static let text = Expression(ColumnName.text.rawValue) - private static let data = Expression(ColumnName.data.rawValue) - - - // MARK: - Properties - private static let queryQueue = DispatchQueue(label: "SQLiteHistoryStorageQueryQueue", qos: .background) - private let completionHandlerQueue: DispatchQueue - private let serverURLString: String - private let webimClient: WebimClient - private var db: Connection? - private var firstKnownTimestamp: Int64 = -1 - private var readBeforeTimestamp: Int64 - private var prepared = false - private var reachedHistoryEnd: Bool - - - // MARK: - Initialization - init(dbName: String, - serverURL serverURLString: String, - webimClient: WebimClient, - reachedHistoryEnd: Bool, - queue: DispatchQueue, - readBeforeTimestamp: Int64) { - self.serverURLString = serverURLString - self.webimClient = webimClient - self.reachedHistoryEnd = reachedHistoryEnd - self.completionHandlerQueue = queue - self.readBeforeTimestamp = readBeforeTimestamp - - createTableWith(name: dbName) - } - - // MARK: - Methods - - // MARK: HistoryStorage protocol methods - - func getMajorVersion() -> Int { - // No need in this implementation. - return 1 - } - - func getVersionDB() -> Int { - return 1 - } - - func set(reachedHistoryEnd: Bool) { - self.reachedHistoryEnd = reachedHistoryEnd - } - - func updateDB() { - dropTables() - createTables() - } - - func getFullHistory(completion: @escaping ([Message]) -> ()) { - SQLiteHistoryStorage.queryQueue.async { [weak self] in - guard let `self` = self else { - return - } - - /* - SELECT * FROM history - ORDER BY timestamp_in_microsecond ASC - */ - let query = SQLiteHistoryStorage - .history - .order(SQLiteHistoryStorage.timestamp.asc) - - var messages = [MessageImpl]() - - do { - for row in try self.db!.prepare(query) { - let message = self.createMessageBy(row: row) - messages.append(message) - - self.db?.trace { - WebimInternalLogger.shared.log(entry: "\($0)", - verbosityLevel: .DEBUG) - } - } - - self.completionHandlerQueue.async { - completion(messages as [Message]) - } - } catch { - WebimInternalLogger.shared.log(entry: error.localizedDescription, - verbosityLevel: .WARNING) - } - } - } - - func getLatestHistory(byLimit limitOfMessages: Int, - completion: @escaping ([Message]) -> ()) { - SQLiteHistoryStorage.queryQueue.async { [weak self] in - guard let `self` = self else { - return - } - - /* - SELECT * FROM history - ORDER BY timestamp_in_microsecond DESC - LIMIT limitOfMessages - */ - let query = SQLiteHistoryStorage - .history - .order(SQLiteHistoryStorage.timestamp.desc) - .limit(limitOfMessages) - - var messages = [MessageImpl]() - - do { - for row in try self.db!.prepare(query) { - let message = self.createMessageBy(row: row) - messages.append(message) - } - - self.db?.trace { - WebimInternalLogger.shared.log(entry: "\($0)", - verbosityLevel: .DEBUG) - } - - messages = messages.reversed() - self.completionHandlerQueue.async { - completion(messages as [Message]) - } - } catch { - WebimInternalLogger.shared.log(entry: error.localizedDescription, - verbosityLevel: .WARNING) - } - } - } - - func getHistoryBefore(id: HistoryID, - limitOfMessages: Int, - completion: @escaping ([Message]) -> ()) { - SQLiteHistoryStorage.queryQueue.async { [weak self] in - guard let `self` = self else { - return - } - - let beforeTimeInMicrosecond = id.getTimeInMicrosecond() - - /* - SELECT * FROM history - WHERE timestamp_in_microsecond < beforeTimeInMicrosecond - ORDER BY timestamp_in_microsecond DESC - LIMIT limitOfMessages - */ - let query = SQLiteHistoryStorage - .history - .filter(SQLiteHistoryStorage.timestamp < beforeTimeInMicrosecond) - .order(SQLiteHistoryStorage.timestamp.desc) - .limit(limitOfMessages) - - var messages = [MessageImpl]() - - do { - for row in try self.db!.prepare(query) { - let message = self.createMessageBy(row: row) - messages.append(message) - - self.db?.trace { - WebimInternalLogger.shared.log(entry: "\($0)", - verbosityLevel: .DEBUG) - } - } - - messages = messages.reversed() - self.completionHandlerQueue.async { - completion(messages as [Message]) - } - } catch { - WebimInternalLogger.shared.log(entry: error.localizedDescription, - verbosityLevel: .WARNING) - } - } - } - - func receiveHistoryBefore(messages: [MessageImpl], - hasMoreMessages: Bool) { - SQLiteHistoryStorage.queryQueue.async { [weak self] in - guard let `self` = self else { - return - } - - var newFirstKnownTimeInMicrosecond = Int64.max - - for message in messages { - newFirstKnownTimeInMicrosecond = min(newFirstKnownTimeInMicrosecond, - message.getHistoryID()!.getTimeInMicrosecond()) - do { - /* - INSERT OR FAIL - INTO history - (id, timestamp_in_microsecond, sender_id, sender_name, avatar_url_string, type, text, data) - VALUES - (message.getID(), message.getHistoryID()!.getTimeInMicrosecond(), message.getOperatorID(), message.getSenderName(), message.getSenderAvatarURLString(), MessageItem.MessageKind(messageType: message.getType()).rawValue, message.getRawText() ?? message.getText(), SQLiteHistoryStorage.convertToBlob(dictionary: message.getData())) - */ - let statement = try self.db!.prepare("INSERT OR FAIL INTO history (" - + "\(SQLiteHistoryStorage.ColumnName.id.rawValue), " - + "\(SQLiteHistoryStorage.ColumnName.timestamp.rawValue), " - + "\(SQLiteHistoryStorage.ColumnName.senderID.rawValue), " - + "\(SQLiteHistoryStorage.ColumnName.senderName.rawValue), " - + "\(SQLiteHistoryStorage.ColumnName.avatarURLString.rawValue), " - + "\(SQLiteHistoryStorage.ColumnName.type.rawValue), " - + "\(SQLiteHistoryStorage.ColumnName.text.rawValue), " - + "\(SQLiteHistoryStorage.ColumnName.data.rawValue)) VALUES (?, ?, ?, ?, ?, ?, ?, ?)") - try statement.run(message.getID(), - message.getHistoryID()!.getTimeInMicrosecond(), - message.getOperatorID(), - message.getSenderName(), - message.getSenderAvatarURLString(), - MessageItem.MessageKind(messageType: message.getType()).rawValue, - message.getRawText() ?? message.getText(), - SQLiteHistoryStorage.convertToBlob(dictionary: message.getData())) - // Raw SQLite statement constructed because there's no way to implement INSERT OR FAIL query with SQLite.swift methods. Appropriate INSERT query can look like this: - /*try self.db!.run(SQLiteHistoryStorage - .history - .insert(SQLiteHistoryStorage.id <- message.getID(), - SQLiteHistoryStorage.timestampInMicrosecond <- message.getTimeInMicrosecond(), - SQLiteHistoryStorage.senderID <- message.getOperatorID(), - SQLiteHistoryStorage.senderName <- message.getSenderName(), - SQLiteHistoryStorage.avatarURLString <- message.getSenderAvatarURLString(), - SQLiteHistoryStorage.type <- MessageItem.MessageKind(messageType: message.getType()).rawValue, - SQLiteHistoryStorage.text <- message.getText(), - SQLiteHistoryStorage.data <- SQLiteHistoryStorage.convertToBlob(dictionary: message.getData())))*/ - - self.db?.trace { - WebimInternalLogger.shared.log(entry: "\($0)", - verbosityLevel: .DEBUG) - } - } catch { - WebimInternalLogger.shared.log(entry: error.localizedDescription, - verbosityLevel: .WARNING) - } - } - - if newFirstKnownTimeInMicrosecond != Int64.max { - self.firstKnownTimestamp = newFirstKnownTimeInMicrosecond - } - } - } - - func receiveHistoryUpdate(withMessages messages: [MessageImpl], - idsToDelete: Set, - completion: @escaping (_ endOfBatch: Bool, _ messageDeleted: Bool, _ deletedMesageID: String?, _ messageChanged: Bool, _ changedMessage: MessageImpl?, _ messageAdded: Bool, _ addedMessage: MessageImpl?, _ idBeforeAddedMessage: HistoryID?) -> ()) { - SQLiteHistoryStorage.queryQueue.sync { [weak self] in - guard let `self` = self else { - return - } - - self.prepare() - - var newFirstKnownTimestamp = Int64.max - - for message in messages { - guard message.getHistoryID() != nil else { - continue - } - - if ((self.firstKnownTimestamp != -1) - && (message.getHistoryID()!.getTimeInMicrosecond() < self.firstKnownTimestamp)) - && !self.reachedHistoryEnd { - continue - } - - newFirstKnownTimestamp = min(newFirstKnownTimestamp, - message.getHistoryID()!.getTimeInMicrosecond()) - - do { - try self.insert(message: message) - - /* - SELECT * - FROM history - WHERE timestamp > message.getTimeInMicrosecond() - ORDER BY timestamp ASC - LIMIT 1 - */ - let postQuery = SQLiteHistoryStorage - .history - .filter(SQLiteHistoryStorage.timestamp > message.getTimeInMicrosecond()) - .order(SQLiteHistoryStorage.timestamp.asc) - .limit(1) - do { - if let row = try self.db!.pluck(postQuery) { - self.db?.trace { - WebimInternalLogger.shared.log(entry: "\($0)", - verbosityLevel: .DEBUG) - } - - let nextMessage = self.createMessageBy(row: row) - completionHandlerQueue.async { - completion(false, - false, - nil, - false, - nil, - true, - message, - nextMessage.getHistoryID()!) - } - } else { - completionHandlerQueue.async { - completion(false, - false, - nil, - false, - nil, - true, - message, - nil) - } - } - } catch let error { - WebimInternalLogger.shared.log(entry: error.localizedDescription, - verbosityLevel: .WARNING) - } - } catch let Result.error(_, code, _) where code == SQLITE_CONSTRAINT { - do { - try update(message: message) - - completionHandlerQueue.async { - completion(false, false, nil, true, message, false, nil, nil) - } - } catch { - WebimInternalLogger.shared.log(entry: "Update received message: \(message.toString()) failed: \(error.localizedDescription)", - verbosityLevel: .ERROR) - } - } catch { - WebimInternalLogger.shared.log(entry: "Insert / update received message: \(message.toString()) failed: \(error.localizedDescription)", - verbosityLevel: .ERROR) - } - } // End of `for message in messages` - - if (firstKnownTimestamp == -1) - && (newFirstKnownTimestamp != Int64.max) { - firstKnownTimestamp = newFirstKnownTimestamp - } - - self.completionHandlerQueue.async { - completion(true, false, nil, false, nil, false, nil, nil) - } - } - } - - func updateReadBeforeTimestamp(timestamp: Int64) { - self.readBeforeTimestamp = timestamp - } - - // MARK: Private methods - - private static func convertToBlob(dictionary: [String: Any?]?) -> Blob? { - if let dictionary = dictionary { - let data = NSKeyedArchiver.archivedData(withRootObject: dictionary) - - return data.datatypeValue - } - - return nil - } - - private func dropTables() { - try! self.db?.run(SQLiteHistoryStorage.history.drop(ifExists: true)) - } - - private func createTableWith(name: String) { - SQLiteHistoryStorage.queryQueue.sync { [weak self] in - guard let `self` = self else { - return - } - - let fileManager = FileManager.default - let documentsPath = try! fileManager.url(for: .documentDirectory, - in: .userDomainMask, - appropriateFor: nil, - create: false) - let dbPath = "\(documentsPath)/\(name)" - self.db = try! Connection(dbPath) - self.db?.userVersion = 1 - self.db?.busyTimeout = 1.0 - self.db?.busyHandler() { tries in - if tries >= 3 { - return false - } - - return true - } - - createTables() - } - } - - private func createTables() { - /* - CREATE TABLE history - id TEXT PRIMARY KEY NOT NULL, - client_side_id TEXT, - timestamp_in_microsecond INTEGER NOT NULL, - sender_id TEXT, - sender_name TEXT NOT NULL, - avatar_url_string TEXT, - type TEXT NOT NULL, - text TEXT NOT NULL, - data TEXT - */ - try! self.db?.run(SQLiteHistoryStorage.history.create(ifNotExists: true) { t in - t.column(SQLiteHistoryStorage.id, - primaryKey: true) - t.column(SQLiteHistoryStorage.clientSideID) - t.column(SQLiteHistoryStorage.timestamp) - t.column(SQLiteHistoryStorage.senderID) - t.column(SQLiteHistoryStorage.senderName) - t.column(SQLiteHistoryStorage.avatarURLString) - t.column(SQLiteHistoryStorage.type) - t.column(SQLiteHistoryStorage.text) - t.column(SQLiteHistoryStorage.data) - }) - self.db?.trace { - WebimInternalLogger.shared.log(entry: "\($0)", - verbosityLevel: .DEBUG) - } - } - - private func createIndex() { - do { - /* - CREATE UNIQUE INDEX index_history_on_timestamp_in_microsecond - ON history (time_since_in_microsecond) - */ - _ = try db?.run(SQLiteHistoryStorage - .history - .createIndex(SQLiteHistoryStorage.timestamp, - unique: true)) - } catch { - WebimInternalLogger.shared.log(entry: error.localizedDescription, - verbosityLevel: .VERBOSE) - } - - db?.trace { - WebimInternalLogger.shared.log(entry: "\($0)", - verbosityLevel: .DEBUG) - } - - createIndex() - } - - private func prepare() { - if !prepared { - prepared = true - - /* - SELECT timestamp_in_microsecond - FROM history - ORDER BY timestamp_in_microsecond ASC - LIMIT 1 - */ - let query = SQLiteHistoryStorage - .history - .select(SQLiteHistoryStorage.timestamp) - .order(SQLiteHistoryStorage.timestamp.asc) - .limit(1) - - do { - if let row = try self.db!.pluck(query) { - db?.trace { - WebimInternalLogger.shared.log(entry: "\($0)", - verbosityLevel: .DEBUG) - } - - firstKnownTimestamp = row[SQLiteHistoryStorage.timestamp] - } - } catch { - WebimInternalLogger.shared.log(entry: error.localizedDescription, - verbosityLevel: .WARNING) - } - } - } - - private func createMessageBy(row: Row) -> MessageImpl { - let id = row[SQLiteHistoryStorage.id] - let clientSideID = row[SQLiteHistoryStorage.clientSideID] - - var rawText: String? = nil - var text = row[SQLiteHistoryStorage.text] - let type = MessageMapper.convert(messageKind: MessageItem.MessageKind(rawValue: row[SQLiteHistoryStorage.type])!) - if (type == .FILE_FROM_OPERATOR) - || (type == .FILE_FROM_VISITOR) { - rawText = text - text = "" - } - - var data: [String: Any?]? - if let dataValue = row[SQLiteHistoryStorage.data] { - data = NSKeyedUnarchiver.unarchiveObject(with: Data.fromDatatypeValue(dataValue)) as? [String: Any?] - } - - - var attachment: MessageAttachment? = nil - if let rawText = rawText { - attachment = MessageAttachmentImpl.getAttachment(byServerURL: serverURLString, - webimClient: webimClient, - text: rawText) - } - - return MessageImpl(serverURLString: serverURLString, - id: (clientSideID ?? id), - operatorID: row[SQLiteHistoryStorage.senderID], - senderAvatarURLString: row[SQLiteHistoryStorage.avatarURLString], - senderName: row[SQLiteHistoryStorage.senderName], - type: type!, - data: data, - text: text, - timeInMicrosecond: row[SQLiteHistoryStorage.timestamp], - attachment: attachment, - historyMessage: true, - internalID: id, - rawText: rawText, - read: row[SQLiteHistoryStorage.timestamp] <= readBeforeTimestamp || readBeforeTimestamp == -1, - messageCanBeEdited: false) - } - - private func insert(message: MessageImpl) throws { - /* - INSERT INTO history (id, - client_side_id, - timestamp, - sender_id, - sender_name, - avatar_url_string, - type, - text, - data - ) VALUES ( - historyID.getDBid(), - message.getID(), - timeInMicorsecond, - message.getOperatorID(), - message.getSenderName(), - message.getSenderAvatarURLString(), - MessageItem.MessageKind(messageType: message.getType()).rawValue, - (message.getRawText() ?? message.getText()), - SQLiteHistoryStorage.convertToBlob(dictionary: message.getData()))) - */ - try db?.run(SQLiteHistoryStorage - .history - .insert(SQLiteHistoryStorage.id <- message.getHistoryID()!.getDBid(), - SQLiteHistoryStorage.clientSideID <- message.getID(), - SQLiteHistoryStorage.timestamp <- message.getHistoryID()!.getTimeInMicrosecond(), - SQLiteHistoryStorage.senderID <- message.getOperatorID(), - SQLiteHistoryStorage.senderName <- message.getSenderName(), - SQLiteHistoryStorage.avatarURLString <- message.getSenderAvatarURLString(), - SQLiteHistoryStorage.type <- MessageItem.MessageKind(messageType: message.getType()).rawValue, - SQLiteHistoryStorage.text <- (message.getRawText() ?? message.getText()), - SQLiteHistoryStorage.data <- SQLiteHistoryStorage.convertToBlob(dictionary: message.getData()))) - - db?.trace { - WebimInternalLogger.shared.log(entry: "\($0)", - verbosityLevel: .DEBUG) - } - } - - private func update(message: MessageImpl) throws { - /* - UPDATE history - SET ( - client_side_id = message.getID(), - timestamp = message.getHistoryID()!.getTimeInMicrosecond(), - sender_id = message.getOperatorID(), - sender_name = message.getSenderName(), - avatar_url_string = message.getSenderAvatarURLString(), - type = MessageItem.MessageKind(messageType: message.getType()).rawValue, - text = (message.getRawText() ?? message.getText()), - data = SQLiteHistoryStorage.convertToBlob(dictionary: message.getData())) - WHERE id = message.getHistoryID()!.getDBid() - */ - try db!.run(SQLiteHistoryStorage - .history - .where(SQLiteHistoryStorage.id == message.getHistoryID()!.getDBid()) - .update(SQLiteHistoryStorage.clientSideID <- message.getID(), - SQLiteHistoryStorage.timestamp <- message.getHistoryID()!.getTimeInMicrosecond(), - SQLiteHistoryStorage.senderID <- message.getOperatorID(), - SQLiteHistoryStorage.senderName <- message.getSenderName(), - SQLiteHistoryStorage.avatarURLString <- message.getSenderAvatarURLString(), - SQLiteHistoryStorage.type <- MessageItem.MessageKind(messageType: message.getType()).rawValue, - SQLiteHistoryStorage.text <- (message.getRawText() ?? message.getText()), - SQLiteHistoryStorage.data <- SQLiteHistoryStorage.convertToBlob(dictionary: message.getData()))) - - db?.trace { - WebimInternalLogger.shared.log(entry: "\($0)", - verbosityLevel: .DEBUG) - } - } - -} - -// MARK: - -extension Connection { - - // MARK: - Properties - public var userVersion: Int32 { - get { return Int32(try! scalar("PRAGMA user_version") as! Int64) } - set { try! run("PRAGMA user_version = \(newValue)") } - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/SessionDestroyer.swift b/ios/libs/Webim/WebimClientLibrary/Backend/SessionDestroyer.swift deleted file mode 100644 index a1a93a1..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/SessionDestroyer.swift +++ /dev/null @@ -1,71 +0,0 @@ -// -// SessionDestroyer.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 11.09.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class SessionDestroyer { - - // MARK: - Properties - private lazy var actions = [() -> ()]() - private var destroyed = false - private var userDefaultsKey: String - - init(userDefaultsKey: String) { - self.userDefaultsKey = userDefaultsKey - } - - // MARK: - Methods - - func add(action: @escaping () -> ()) { - actions.append(action) - } - - func getUserDefaulstKey() -> String { - return userDefaultsKey - } - - func destroy() { - if !destroyed { - destroyed = true - - for action in actions { - action() - } - actions.removeAll(keepingCapacity: false) - } - } - - func isDestroyed() -> Bool { - return destroyed - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/SessionParametersListener.swift b/ios/libs/Webim/WebimClientLibrary/Backend/SessionParametersListener.swift deleted file mode 100644 index 0168bae..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/SessionParametersListener.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// SessionParametersListener.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 11.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that is responsible for history storage when it is set to memory mode. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -protocol SessionParametersListener { - - func onSessionParametersChanged(visitorFieldsJSONString: String, - sessionID: String, - authorizationData: AuthorizationData) - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/CompletionHandlerWrappers.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/CompletionHandlerWrappers.swift deleted file mode 100644 index 7cb795b..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/CompletionHandlerWrappers.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// CompletionHandlerWrappers.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 20.10.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class used for handling storing cached completion handler in `MessageTrackerImpl` class. - - seealso: - `MessageTrackerImpl.cachedCompletionHandler` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class MessageHolderCompletionHandlerWrapper { - - // MARK: - Properties - private var messageHolderCompletionHandler: ([Message]) -> () - - // MARK: - Initialization - init(completionHandler: @escaping ([Message]) -> ()) { - messageHolderCompletionHandler = completionHandler - } - - // MARK: - Methods - func getCompletionHandler() -> ([Message]) -> () { - return messageHolderCompletionHandler - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/DepartmentFactory.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/DepartmentFactory.swift deleted file mode 100644 index d1ef309..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/DepartmentFactory.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// DepartmentFactory.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 19.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Mapper class that is responsible for converting internal department model objects to public ones. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ -final class DepartmentFactory { - - // MARK: - Properties - let serverURLString: String - - // MARK - Initialization - init(serverURLString: String) { - self.serverURLString = serverURLString - } - - // MARK: - Methods - - func convert(departmentItem: DepartmentItem) -> DepartmentImpl { - var fullLogoURL: URL? = nil - if let logoURLString = departmentItem.getLogoURLString() { - fullLogoURL = URL(string: serverURLString + logoURLString) - } - - return DepartmentImpl(key: departmentItem.getKey(), - name: departmentItem.getName(), - departmentOnlineStatus: publicState(ofDepartmentOnlineStatus: departmentItem.getOnlineStatus()), - order: departmentItem.getOrder(), - localizedNames: departmentItem.getLocalizedNames(), - logo: fullLogoURL) - } - - // MARK: Private methods - private func publicState(ofDepartmentOnlineStatus departmentOnlineStatus: DepartmentItem.InternalDepartmentOnlineStatus) -> DepartmentOnlineStatus { - switch departmentOnlineStatus { - case .busyOffline: - return .BUSY_OFFLINE - case .busyOnline: - return .BUSY_ONLINE - case .offline: - return .OFFLINE - case .online: - return .ONLINE - case .unknown: - return .UNKNOWN - } - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Array.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Array.swift deleted file mode 100644 index afc2694..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Array.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// Array.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 17.01.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -extension Array where Element == UInt8 { - - // MARK: - Methods - /** - Part or HMAC SHA256 generation system. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - public func toHexString() -> String { - return `lazy`.reduce("") { - var s = String($1, - radix: 16) - if s.count == 1 { - s = "0" + s - } - - return $0 + s - } - } -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Collection.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Collection.swift deleted file mode 100644 index 57de148..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Collection.swift +++ /dev/null @@ -1,112 +0,0 @@ -// -// Collection.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 17.01.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -extension Collection { - - /** - Part or HMAC SHA256 generation system. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - func batched(by size: IndexDistance) -> BatchedCollection { - return BatchedCollection(base: self, - size: size) - } - -} - -// MARK: - -/** - Part or HMAC SHA256 generation system. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ -struct BatchedCollection: Collection { - - typealias Index = BatchedCollectionIndex - - // MARK: - Properties - let base: Base - let size: Base.IndexDistance - - // MARK: - Methods - private func nextBreak(after idx: Base.Index) -> Base.Index { - return (base.index(idx, - offsetBy: size, - limitedBy: base.endIndex) ?? base.endIndex) - } - - var startIndex: Index { - return Index(range: base.startIndex ..< nextBreak(after: base.startIndex)) - } - - var endIndex: Index { - return Index(range: base.endIndex ..< base.endIndex) - } - - func index(after idx: Index) -> Index { - return Index(range: idx.range.upperBound ..< nextBreak(after: idx.range.upperBound)) - } - - subscript(idx: Index) -> Base.SubSequence { - return base[idx.range] - } -} - -// MARK: - Comparable -extension BatchedCollectionIndex: Comparable { - - // MARK: - Methods - - static func ==(lhs: BatchedCollectionIndex, - rhs: BatchedCollectionIndex) -> Bool { - return (lhs.range.lowerBound == rhs.range.lowerBound) - } - - static func <(lhs: BatchedCollectionIndex, - rhs: BatchedCollectionIndex) -> Bool { - return (lhs.range.lowerBound < rhs.range.lowerBound) - } - -} - -// MARK: - -/** - Part or HMAC SHA256 generation system. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ -struct BatchedCollectionIndex { - let range: Range -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Dictionary.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Dictionary.swift deleted file mode 100644 index d312cc6..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Dictionary.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// Dictionary.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 11.10.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -extension Dictionary { - - // MARK: - Methods - /** - Build string representation of HTTP parameter dictionary of keys and objects. - This percent escapes in compliance with RFC 3986. - - important: - Supports only non-optional String keys and values. - - seealso: - http://www.ietf.org/rfc/rfc3986.txt - - returns: - String representation in the form of key1=value1&key2=value2 where the keys and values are percent escaped. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func stringFromHTTPParameters() -> String { - let parameterArray = map { (key, value) -> String in - let percentEscapedKey = (key as! String).addingPercentEncodingForURLQueryValue()! - let percentEscapedValue = (value as! String).addingPercentEncodingForURLQueryValue()! - return "\(percentEscapedKey)=\(percentEscapedValue)" - } - - return parameterArray.joined(separator: "&") - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Int.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Int.swift deleted file mode 100644 index 112dee3..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/Int.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// Int.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 17.01.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -extension Int { - - // MARK: - Methods - /** - Part or HMAC SHA256 generation system. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - @_transparent - func bytes(totalBytes: Int) -> Array { - let valuePointer = UnsafeMutablePointer.allocate(capacity: 1) - valuePointer.pointee = self - - let bytesPointer = UnsafeMutablePointer(OpaquePointer(valuePointer)) - var bytes = Array(repeating: 0, - count: totalBytes) - let memoryLayoutSize = MemoryLayout.size - let constraint = ((memoryLayoutSize < totalBytes) ? memoryLayoutSize : totalBytes) - for j in 0 ..< constraint { - bytes[(totalBytes - 1 - j)] = (bytesPointer + j).pointee - } - - valuePointer.deinitialize() - valuePointer.deallocate(capacity: 1) - - return bytes - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/String.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/String.swift deleted file mode 100644 index b8b01c8..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/String.swift +++ /dev/null @@ -1,407 +0,0 @@ -// -// String.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 11.10.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -extension String { - - // MARK: - Methods - - /** - Percent escapes values to be added to a URL query as specified in RFC 3986. - This percent-escapes all characters besides the alphanumeric character set and "-", ".", "_", and "~". - - seealso: - http://ietf.org/rfc/rfc3986.txt - - returns: - Percent-escaped string. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func addingPercentEncodingForURLQueryValue() -> String? { - let generalDelimitersToEncode = ":#[]@" // Does not include "?" or "/" due to RFC 3986 - Section 3.4. - let subDelimitersToEncode = "!$&'()*+,;=" - - var allowed = CharacterSet.urlQueryAllowed - allowed.remove(charactersIn: (generalDelimitersToEncode + subDelimitersToEncode)) - - return addingPercentEncoding(withAllowedCharacters: allowed) - } - - /** - Generates HMAC SHA256 code taken on passed key value for self. - - parameter key: - Key to generate hash code. - - returns: - Hash code of string taken with passed key. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func hmacSHA256(withKey key: String) -> String? { - let stringBytes: [UInt8] = Array(self.utf8) - let keyBytes: [UInt8] = Array(key.utf8) - let hmac = try! HMACsha256(key: keyBytes).authenticate(stringBytes).toHexString() - - return hmac - } - -} - -// MARK: - -/** - Part or HMAC SHA256 generation system. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ -public final class HMACsha256 { - - // MARK: - Constants - private enum Error: Swift.Error { - case authenticateError - } - private static let blockSize = 64 - - - // MARK: - Properties - var key: Array - - - // MARK: - Initialization - public init(key: Array) { - self.key = key - - if key.count > HMACsha256.blockSize { - if let hash = calculateHash(key) { - self.key = hash - } - } - - if key.count < HMACsha256.blockSize { - self.key = add(to: key) - } - } - - - // MARK: - Methods - - func authenticate(_ bytes: Array) throws -> Array { - var opad = Array(repeating: 0x5c, - count: HMACsha256.blockSize) - for idx in key.indices { - opad[idx] = key[idx] ^ opad[idx] - } - var ipad = Array(repeating: 0x36, - count: HMACsha256.blockSize) - for idx in key.indices { - ipad[idx] = key[idx] ^ ipad[idx] - } - - guard let ipadAndMessageHash = calculateHash(ipad + bytes), - let result = calculateHash(opad + ipadAndMessageHash) else { - throw Error.authenticateError - } - - return result - } - - // MARK: Private methods - - private func calculateHash(_ bytes: Array) -> Array? { - return SHA256().calculate(for: bytes) - } - - private func add(to bytes: Array) -> Array { - let paddingCount = HMACsha256.blockSize - (bytes.count % HMACsha256.blockSize) - if paddingCount > 0 { - return (bytes + Array(repeating: 0, - count: paddingCount)) - } - - return bytes - } - -} - -// MARK: - -/** - Part or HMAC SHA256 generation system. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ -public final class SHA256 { - - // MARK: - Constants - private static let blockSize = 64 - private static let digestLength = 32 - private static let h: Array = [0x6a09e667, - 0xbb67ae85, - 0x3c6ef372, - 0xa54ff53a, - 0x510e527f, - 0x9b05688c, - 0x1f83d9ab, - 0x5be0cd19] - private static let k: Array = [0x428a2f98, - 0x71374491, - 0xb5c0fbcf, - 0xe9b5dba5, - 0x3956c25b, - 0x59f111f1, - 0x923f82a4, - 0xab1c5ed5, - 0xd807aa98, - 0x12835b01, - 0x243185be, - 0x550c7dc3, - 0x72be5d74, - 0x80deb1fe, - 0x9bdc06a7, - 0xc19bf174, - 0xe49b69c1, - 0xefbe4786, - 0x0fc19dc6, - 0x240ca1cc, - 0x2de92c6f, - 0x4a7484aa, - 0x5cb0a9dc, - 0x76f988da, - 0x983e5152, - 0xa831c66d, - 0xb00327c8, - 0xbf597fc7, - 0xc6e00bf3, - 0xd5a79147, - 0x06ca6351, - 0x14292967, - 0x27b70a85, - 0x2e1b2138, - 0x4d2c6dfc, - 0x53380d13, - 0x650a7354, - 0x766a0abb, - 0x81c2c92e, - 0x92722c85, - 0xa2bfe8a1, - 0xa81a664b, - 0xc24b8b70, - 0xc76c51a3, - 0xd192e819, - 0xd6990624, - 0xf40e3585, - 0x106aa070, - 0x19a4c116, - 0x1e376c08, - 0x2748774c, - 0x34b0bcb5, - 0x391c0cb3, - 0x4ed8aa4a, - 0x5b9cca4f, - 0x682e6ff3, - 0x748f82ee, - 0x78a5636f, - 0x84c87814, - 0x8cc70208, - 0x90befffa, - 0xa4506ceb, - 0xbef9a3f7, - 0xc67178f2] - - // MARK: - Properties - private var accumulatedHash32 = SHA256.h.map { UInt32($0) } - private var processedBytesTotalCount: Int = 0 - - // MARK: - Methods - - func calculate(for bytes: Array) -> Array { - do { - return try update(withBytes: bytes[bytes.startIndex ..< bytes.endIndex]) - } catch { - return [] - } - } - - // MARK: Private methods - - private func update(withBytes bytes: ArraySlice) throws -> Array { - var accumulated = Array() - accumulated += bytes - - let lengthInBits = (processedBytesTotalCount + accumulated.count) * 8 - let lengthBytes = lengthInBits.bytes(totalBytes: (SHA256.blockSize / 8)) // A 64-bit/128-bit representation of b. blockSize fit by accident. - - // Step 1. Append padding. - SHA256.bitPadding(to: &accumulated, - blockSize: SHA256.blockSize, - allowance: (SHA256.blockSize / 8)) - - // Step 2. Append Length a 64-bit representation of lengthInBits. - accumulated += lengthBytes - - var processedBytes = 0 - for chunk in accumulated.batched(by: SHA256.blockSize) { - process32(block: chunk, - currentHash: &accumulatedHash32) - processedBytes += chunk.count - } - accumulated.removeFirst(processedBytes) - processedBytesTotalCount += processedBytes - - // Current hash output. - var result = Array(repeating: 0, - count: SHA256.digestLength) - var pos = 0 - for idx in 0 ..< accumulatedHash32.count where idx < Int.max { - let h = accumulatedHash32[idx].bigEndian - result[pos] = UInt8(h & 0xff) - result[pos + 1] = UInt8((h >> 8) & 0xff) - result[pos + 2] = UInt8((h >> 16) & 0xff) - result[pos + 3] = UInt8((h >> 24) & 0xff) - pos += 4 - } - - return result - } - - // Mutating currentHash in place is way faster than returning new result. - private func process32(block chunk: ArraySlice, - currentHash hh: inout Array) { - // Break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15, big-endian. - // Extend the sixteen 32-bit words into sixty-four 32-bit words: - let M = UnsafeMutablePointer.allocate(capacity: SHA256.k.count) - M.initialize(to: 0, count: - SHA256.k.count) - defer { - M.deinitialize(count: SHA256.k.count) - M.deallocate(capacity: SHA256.k.count) - } - - for x in 0 ..< SHA256.k.count { - switch x { - case 0 ... 15: - let start = chunk.startIndex.advanced(by: (x * 4)) - M[x] = UInt32(bytes: chunk, - fromIndex: start) - - break - default: - let s0 = SHA256.rotateRight(M[x - 15], - by: 7) ^ SHA256.rotateRight(M[x - 15], - by: 18) ^ (M[x - 15] >> 3) - let s1 = SHA256.rotateRight(M[x - 2], - by: 17) ^ SHA256.rotateRight(M[x - 2], - by: 19) ^ (M[x - 2] >> 10) - M[x] = M[x - 16] &+ s0 &+ M[x - 7] &+ s1 - - break - } - } - - var A = hh[0] - var B = hh[1] - var C = hh[2] - var D = hh[3] - var E = hh[4] - var F = hh[5] - var G = hh[6] - var H = hh[7] - - // Main loop - for j in 0.., - blockSize: Int, - allowance: Int) { - let msgLength = data.count - // Step 1. Append Padding Bits. - // Append one bit (UInt8 with one bit) to message. - data.append(0x80) - - // Step 2. Append "0" bit until message length in bits ≡ 448 (mod 512). - let max = blockSize - allowance // 448, 986. - if msgLength % blockSize < max { // 448. - data += Array(repeating: 0, - count: (max - 1 - (msgLength % blockSize))) - } else { - data += Array(repeating: 0, - count: (blockSize + max - 1 - (msgLength % blockSize))) - } - } - - private static func rotateRight(_ value: UInt32, - by: UInt32) -> UInt32 { - return ((value >> by) | (value << (32 - by))) - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/UIColor.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/UIColor.swift deleted file mode 100644 index 68a30be..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/UIColor.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// UIColor.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 19.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import UIKit - -extension UIColor { - - /** - Initializes and returns a color object using hex string. - - parameter hexString: - Hex string representing color with or whithout "#" prefix. - - returns: - The color object or `nil` if passed string can't represent a color. The color information represented by this object is in an RGB colorspace. On applications linked for iOS 10 or later, the color is specified in an extended range sRGB color space. On earlier versions of iOS, the color is specified in a device RGB colorspace. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - convenience init?(hexString: String) { - var colorString: String = hexString.trimmingCharacters(in: .whitespacesAndNewlines).uppercased() - - if (colorString.hasPrefix("#")) { - colorString.remove(at: colorString.startIndex) - } - - if colorString.count != 6 { - return nil - } - - var rgbValue: UInt32 = 0 - Scanner(string: colorString).scanHexInt32(&rgbValue) - - self.init(red: (CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0), - green:(CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0), - blue: (CGFloat(rgbValue & 0x0000FF) / 255.0), - alpha: 1.0) - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/UInt32.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/UInt32.swift deleted file mode 100644 index 26b641d..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/Extensions/UInt32.swift +++ /dev/null @@ -1,58 +0,0 @@ -// -// UInt32.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 17.01.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -extension UInt32 { - - // MARK: - Initialization - /** - Part or HMAC SHA256 generation system. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - @_specialize(exported: true, where T == ArraySlice) - init(bytes: T, - fromIndex index: T.Index) where T.Element == UInt8, T.Index == Int { - if bytes.isEmpty { - self = 0 - - return - } - - let count = bytes.count - - let val0 = ((count > 0) ? (UInt32(bytes[index.advanced(by: 0)]) << 24) : 0) - let val1 = ((count > 1) ? (UInt32(bytes[index.advanced(by: 1)]) << 16) : 0) - let val2 = ((count > 2) ? (UInt32(bytes[index.advanced(by: 2)]) << 8) : 0) - let val3 = ((count > 3) ? UInt32(bytes[index.advanced(by: 3)]) : 0) - - self = val0 | val1 | val2 | val3 - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/InternalUtils.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/InternalUtils.swift deleted file mode 100644 index ab111b1..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/InternalUtils.swift +++ /dev/null @@ -1,103 +0,0 @@ -// -// InternalUtils.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 08.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Various SDK utilities. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class InternalUtils { - - // MARK: - Methods - - static func createServerURLStringBy(accountName: String) -> String { - var serverURLstring = accountName - - if serverURLstring.range(of: "://") != nil { - if serverURLstring.last! == "/" { - serverURLstring.removeLast() - } - - return serverURLstring - } - - return "https://\(serverURLstring).webim.ru" - } - - static func getCurrentTimeInMicrosecond() -> Int64 { - return Int64(Date().timeIntervalSince1970 * 1_000_000) - } - - static func parse(remoteNotification: [AnyHashable : Any], visitorId: String?) -> WebimRemoteNotification? { - if let apsFields = remoteNotification[WebimRemoteNotificationImpl.APNSField.aps.rawValue] as? [String: Any] { - if let alertFields = apsFields[WebimRemoteNotificationImpl.APSField.alert.rawValue] as? [String: Any] { - if visitorId != nil { - return WebimRemoteNotificationImpl(jsonDictionary: alertFields) as WebimRemoteNotification? - } else { - let notification = WebimRemoteNotificationImpl(jsonDictionary: alertFields) as WebimRemoteNotification? - let params = notification?.getParameters() - var indexOfId: Int - switch notification?.getType() { - case .OPERATOR_ACCEPTED?: - indexOfId = 1 - break - case .OPERATOR_FILE?, - .OPERATOR_MESSAGE?: - indexOfId = 2 - break - default: - indexOfId = 0 - } - - if params?.count ?? 0 <= indexOfId { - return notification - } - return params?[indexOfId] == visitorId ? notification : nil - } - } else { - return nil - } - } else { - WebimInternalLogger.shared.log(entry: "Unknown remote notification format: \(remoteNotification).", - verbosityLevel: .DEBUG) - - return nil - } - } - - static func isWebim(remoteNotification: [AnyHashable: Any]) -> Bool { - if let webimField = remoteNotification[WebimRemoteNotificationImpl.APNSField.webim.rawValue] as? Bool { - return webimField - } - - return false - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/MessageFactories.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/MessageFactories.swift deleted file mode 100644 index 344db10..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/MessageFactories.swift +++ /dev/null @@ -1,222 +0,0 @@ -// -// MessageFactories.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 10.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -// MARK: - -/** - Abstract class that supposed to be parent of mapper classes that are responsible for converting internal message model objects to public one. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -class MessageMapper { - - // MARK: - Constants - private enum MapError: Error { - case invalidMessageType(String) - } - - // MARK: - Properties - private let serverURLString: String - private weak var webimClient: WebimClient? - - // MARK: - Initialization - init(withServerURLString serverURLString: String) { - self.serverURLString = serverURLString - } - - // MARK: - Methods - - static func convert(messageKind: MessageItem.MessageKind) -> MessageType? { - switch messageKind { - case .actionRequest: - return .ACTION_REQUEST - case .contactInformationRequest: - return .CONTACTS_REQUEST - case .fileFromOperator: - return .FILE_FROM_OPERATOR - case .fileFromVisitor: - return .FILE_FROM_VISITOR - case .info: - return .INFO - case .operatorMessage: - return .OPERATOR - case .operatorBusy: - return .OPERATOR_BUSY - case .visitorMessage: - return .VISITOR - default: - WebimInternalLogger.shared.log(entry: "Invalid message type received: \(messageKind.rawValue)", - verbosityLevel: .WARNING) - - return nil - } - } - - func convert(messageItem: MessageItem, - historyMessage: Bool) -> MessageImpl? { - let kind = messageItem.getKind() - if (kind == nil) - || (kind == .contactInformation) - || (kind == .forOperator) { - return nil - } - let type = MessageMapper.convert(messageKind: kind!) - if type == nil { - return nil - } - - var attachment: MessageAttachment? = nil - var text: String? = nil - var rawText: String? = nil - - let messageItemText = messageItem.getText() - if (kind == .fileFromVisitor) - || (kind == .fileFromOperator) { - attachment = MessageAttachmentImpl.getAttachment(byServerURL: serverURLString, - webimClient: webimClient!, - text: messageItemText!) - if attachment == nil { - return nil - } - - text = attachment?.getFileName() - rawText = messageItemText! - } else { - text = messageItemText ?? "" - } - - return MessageImpl(serverURLString: serverURLString, - id: messageItem.getClientSideID()!, - operatorID: messageItem.getSenderID(), - senderAvatarURLString: messageItem.getSenderAvatarURLString(), - senderName: messageItem.getSenderName()!, - type: type!, - data: messageItem.getData(), - text: text!, - timeInMicrosecond: messageItem.getTimeInMicrosecond()!, - attachment: attachment, - historyMessage: historyMessage, - internalID: messageItem.getID(), - rawText: rawText, - read: messageItem.getRead() ?? true, - messageCanBeEdited: messageItem.getCanBeEdited()) - } - - func set(webimClient: WebimClient) { - self.webimClient = webimClient - } - - func mapAll(messages: [MessageItem]) -> [MessageImpl] { - return messages.map { map(message: $0) }.compactMap { $0 } - } - - func map(message: MessageItem) -> MessageImpl? { - preconditionFailure("This method must be overridden!") - } - -} - -// MARK: - -/** - Concrete mapper class that is responsible for converting internal message model objects to public message model objects of current chat. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class CurrentChatMessageMapper: MessageMapper { - - // MARK: - Methods - override func map(message: MessageItem) -> MessageImpl? { - return convert(messageItem: message, - historyMessage: false) - } - -} - -// MARK: - -/** - Concrete mapper class that is responsible for converting internal message model objects to public message model objects of previous chats. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class HistoryMessageMapper: MessageMapper { - - // MARK: - Methods - override func map(message: MessageItem) -> MessageImpl? { - return convert(messageItem: message, - historyMessage: true) - } - -} - -// MARK: - -/** - Class that responsible for creating child class objects for public message model objects of messages that are to be sent by visitor. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class SendingFactory { - - // MARK: - Properties - var serverURLString: String - - - // MARK: - Initialization - init(withServerURLString serverURLString: String) { - self.serverURLString = serverURLString - } - - - // MARK: - Methods - - func createTextMessageToSendWith(id: String, - text: String) -> MessageToSend { - return MessageToSend(serverURLString: serverURLString, - id: id, - senderName: "", - type: .VISITOR, - text: text, - timeInMicrosecond: InternalUtils.getCurrentTimeInMicrosecond()) - } - - func createFileMessageToSendWith(id: String) -> MessageToSend { - return MessageToSend(serverURLString: serverURLString, - id: id, - senderName: "", - type: .FILE_FROM_VISITOR, - text: "", - timeInMicrosecond: InternalUtils.getCurrentTimeInMicrosecond()) - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/OperatorFactory.swift b/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/OperatorFactory.swift deleted file mode 100644 index ac1db66..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/Utilities/OperatorFactory.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// OperatorFactory.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 19.02.18. -// Copyright © 2018 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Mapper class that is responsible for converting internal operator model objects to public ones. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class OperatorFactory { - - // MARK: - Properties - var serverURLString: String - - // MARK: - Initialization - init(withServerURLString serverURLString: String) { - self.serverURLString = serverURLString - } - - // MARK: - Methods - func createOperatorFrom(operatorItem: OperatorItem?) -> OperatorImpl? { - return ((operatorItem == nil) ? nil : OperatorImpl(id: operatorItem!.getID(), - name: operatorItem!.getFullName(), - avatarURLString: ((operatorItem!.getAvatarURLString() == nil) ? nil : (serverURLString + operatorItem!.getAvatarURLString()!)))) - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/WebimActions.swift b/ios/libs/Webim/WebimClientLibrary/Backend/WebimActions.swift deleted file mode 100644 index a9895e8..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/WebimActions.swift +++ /dev/null @@ -1,348 +0,0 @@ -// -// WebimActions.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 11.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that is responsible for history storage when it is set to memory mode. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -class WebimActions { - - // MARK: - Constants - enum ContentType: String { - case multipartBody = "multipart/form-data; boundary=" // + boundary string - case urlEncoded = "application/x-www-form-urlencoded" - } - enum Event: String { - case initialization = "init" - } - enum Parameter: String { - case actionn = "action" - case applicationVersion = "app-version" - case authorizationToken = "auth-token" - case beforeTimestamp = "before-ts" - case chatMode = "chat-mode" - case clientSideID = "client-side-id" - case data = "data" - case deleteDraft = "del-message-draft" - case departmentKey = "department-key" - case deviceID = "device-id" - case deviceToken = "push-token" - case draft = "message-draft" - case event = "event" - case firstQuestion = "first-question" - case forceOnline = "force-online" - case hintQuestion = "hint_question" - case location = "location" - case message = "message" - case operatorID = "operator_id" - case pageID = "page-id" - case platform = "platform" - case providedAuthenticationToken = "provided_auth_token" - case rating = "rate" - case respondImmediately = "respond-immediately" - case visitSessionID = "visit-session-id" - case since = "since" - case timestamp = "ts" - case title = "title" - case visitor = "visitor" - case visitorExt = "visitor-ext" - case visitorTyping = "typing" - case prechat = "prechat-key-independent-fields" - case customFields = "custom_fields" - } - enum Platform: String { - case ios = "ios" - } - enum ServerPathSuffix: String { - case doAction = "/l/v/m/action" - case getDelta = "/l/v/m/delta" - case downloadFile = "/l/v/m/download" - case getHistory = "/l/v/m/history" - case uploadFile = "/l/v/m/upload" - } - enum MultipartBody: String { - case name = "webim_upload_file" - } - private enum ChatMode: String { - case online = "online" - } - private enum Action: String { - case closeChat = "chat.close" - case rateOperator = "chat.operator_rate_select" - case respondSentryCall = "chat.action_request.call_sentry_action_request" - case sendMessage = "chat.message" - case deleteMessage = "chat.delete_message" - case setDeviceToken = "set_push_token" - case setPrechat = "chat.set_prechat_fields" - case setVisitorTyping = "chat.visitor_typing" - case startChat = "chat.start" - case chatRead = "chat.read_by_visitor" - case widgetUpdate = "widget.update" - } - - // MARK: - Properties - private let baseURL: String - private let actionRequestLoop: ActionRequestLoop - - // MARK: - Initialization - init(baseURL: String, - actionRequestLoop: ActionRequestLoop) { - self.baseURL = baseURL - self.actionRequestLoop = actionRequestLoop - } - - // MARK: - Methods - - func send(message: String, - clientSideID: String, - dataJSONString: String?, - isHintQuestion: Bool?, - dataMessageCompletionHandler: DataMessageCompletionHandler? = nil, - editMessageCompletionHandler: EditMessageCompletionHandler? = nil) { - var dataToPost = [Parameter.actionn.rawValue: Action.sendMessage.rawValue, - Parameter.clientSideID.rawValue: clientSideID, - Parameter.message.rawValue: message] as [String: Any] - if let isHintQuestion = isHintQuestion { - dataToPost[Parameter.hintQuestion.rawValue] = isHintQuestion ? "1" : "0" // True / false. - } - if let dataJSONString = dataJSONString { - dataToPost[Parameter.data.rawValue] = dataJSONString - } - - let urlString = baseURL + ServerPathSuffix.doAction.rawValue - - actionRequestLoop.enqueue(request: WebimRequest(httpMethod: .post, - primaryData: dataToPost, - messageID: clientSideID, - contentType: ContentType.urlEncoded.rawValue, - baseURLString: urlString, - dataMessageCompletionHandler: dataMessageCompletionHandler, - editMessageCompletionHandler: editMessageCompletionHandler)) - } - - func send(file: Data, - filename: String, - mimeType: String, - clientSideID: String, - completionHandler: SendFileCompletionHandler?) { - let dataToPost = [Parameter.chatMode.rawValue: ChatMode.online.rawValue, - Parameter.clientSideID.rawValue: clientSideID] as [String: Any] - - let urlString = baseURL + ServerPathSuffix.uploadFile.rawValue - - let boundaryString = NSUUID().uuidString - - actionRequestLoop.enqueue(request: WebimRequest(httpMethod: .post, - primaryData: dataToPost, - messageID: clientSideID, - filename: filename, - mimeType: mimeType, - fileData: file, - boundaryString: boundaryString, - contentType: (ContentType.multipartBody.rawValue + boundaryString), - baseURLString: urlString, - sendFileCompletionHandler: completionHandler)) - } - - func delete(clientSideID: String, - completionHandler: DeleteMessageCompletionHandler?) { - let dataToPost = [Parameter.actionn.rawValue: Action.deleteMessage.rawValue, - Parameter.clientSideID.rawValue: clientSideID] as [String: Any] - - let urlString = baseURL + ServerPathSuffix.doAction.rawValue - - actionRequestLoop.enqueue(request: WebimRequest(httpMethod: .post, - primaryData: dataToPost, - messageID: clientSideID, - contentType: ContentType.urlEncoded.rawValue, - baseURLString: urlString, - deleteMessageCompletionHandler: completionHandler)) - } - - func startChat(withClientSideID clientSideID: String, - firstQuestion: String? = nil, - departmentKey: String? = nil, - customFields: String? = nil) { - var dataToPost = [Parameter.actionn.rawValue: Action.startChat.rawValue, - Parameter.forceOnline.rawValue: "1", // true - Parameter.clientSideID.rawValue: clientSideID] as [String: Any] - if let firstQuestion = firstQuestion { - dataToPost[Parameter.firstQuestion.rawValue] = firstQuestion - } - if let departmentKey = departmentKey { - dataToPost[Parameter.departmentKey.rawValue] = departmentKey - } - if let custom_fields = customFields { - dataToPost[Parameter.customFields.rawValue] = custom_fields - } - - let urlString = baseURL + ServerPathSuffix.doAction.rawValue - - actionRequestLoop.enqueue(request: WebimRequest(httpMethod: .post, - primaryData: dataToPost, - contentType: ContentType.urlEncoded.rawValue, - baseURLString: urlString)) - } - - func closeChat() { - let dataToPost = [Parameter.actionn.rawValue: Action.closeChat.rawValue] as [String: Any] - - let urlString = baseURL + ServerPathSuffix.doAction.rawValue - - actionRequestLoop.enqueue(request: WebimRequest(httpMethod: .post, - primaryData: dataToPost, - contentType: ContentType.urlEncoded.rawValue, - baseURLString: urlString)) - } - - func set(visitorTyping: Bool, - draft: String?, - deleteDraft: Bool) { - var dataToPost = [Parameter.actionn.rawValue: Action.setVisitorTyping.rawValue, - Parameter.deleteDraft.rawValue: deleteDraft ? "1" : "0", // true / false - Parameter.visitorTyping.rawValue: visitorTyping ? "1" : "0"] as [String: Any] // true / false - if let draft = draft { - dataToPost[Parameter.draft.rawValue] = draft - } - - let urlString = baseURL + ServerPathSuffix.doAction.rawValue - - actionRequestLoop.enqueue(request: WebimRequest(httpMethod: .post, - primaryData: dataToPost, - contentType: ContentType.urlEncoded.rawValue, - baseURLString: urlString)) - } - - func set(prechatFields: String) { - let dataToPost = [Parameter.actionn.rawValue: Action.setPrechat.rawValue, - Parameter.prechat.rawValue: prechatFields] as [String: Any] - - let urlString = baseURL + ServerPathSuffix.doAction.rawValue - - actionRequestLoop.enqueue(request: WebimRequest(httpMethod: .post, - primaryData: dataToPost, - contentType: ContentType.urlEncoded.rawValue, - baseURLString: urlString)) - } - - func requestHistory(since: String?, - completion: @escaping (_ data: Data?) throws -> ()) { - var dataToPost = [String: Any]() - if let since = since { - dataToPost[Parameter.since.rawValue] = since - } - - let urlString = baseURL + ServerPathSuffix.getHistory.rawValue - - actionRequestLoop.enqueue(request: WebimRequest(httpMethod: .get, - primaryData: dataToPost, - baseURLString: urlString, - historyRequestCompletionHandler: completion)) - } - - func requestHistory(beforeMessageTimestamp: Int64, - completion: @escaping (_ data: Data?) throws -> ()) { - let dataToPost = [Parameter.beforeTimestamp.rawValue: String(beforeMessageTimestamp)] as [String: Any] - - let urlString = baseURL + ServerPathSuffix.getHistory.rawValue - - actionRequestLoop.enqueue(request: WebimRequest(httpMethod: .get, - primaryData: dataToPost, - baseURLString: urlString, - historyRequestCompletionHandler: completion)) - } - - func rateOperatorWith(id: String?, - rating: Int, - completionHandler: RateOperatorCompletionHandler?) { - var dataToPost = [Parameter.actionn.rawValue: Action.rateOperator.rawValue, - Parameter.rating.rawValue: String(rating)] as [String: Any] - if let id = id { - dataToPost[Parameter.operatorID.rawValue] = id - } - - let urlString = baseURL + ServerPathSuffix.doAction.rawValue - - actionRequestLoop.enqueue(request: WebimRequest(httpMethod: .post, - primaryData: dataToPost, - contentType: ContentType.urlEncoded.rawValue, - baseURLString: urlString, - rateOperatorCompletionHandler: completionHandler)) - } - - func respondSentryCall(id: String) { - let dataToPost = [Parameter.actionn.rawValue: Action.respondSentryCall.rawValue, - Parameter.clientSideID.rawValue: id] as [String: Any] - - let urlString = baseURL + ServerPathSuffix.doAction.rawValue - - actionRequestLoop.enqueue(request: WebimRequest(httpMethod: .post, - primaryData: dataToPost, - contentType: ContentType.urlEncoded.rawValue, - baseURLString: urlString)) - } - - func update(deviceToken: String) { - let dataToPost = [Parameter.actionn.rawValue: Action.setDeviceToken.rawValue, - Parameter.deviceToken.rawValue: deviceToken] as [String: Any] - - let urlString = baseURL + ServerPathSuffix.doAction.rawValue - - actionRequestLoop.enqueue(request: WebimRequest(httpMethod: .post, - primaryData: dataToPost, - contentType: ContentType.urlEncoded.rawValue, - baseURLString: urlString)) - } - - func setChatRead() { - let dataToPost = [Parameter.actionn.rawValue: Action.chatRead.rawValue] as [String: Any] - - let urlString = baseURL + ServerPathSuffix.doAction.rawValue - - actionRequestLoop.enqueue(request: WebimRequest(httpMethod: .post, - primaryData: dataToPost, - contentType: ContentType.urlEncoded.rawValue, - baseURLString: urlString)) - } - - func updateWidgetStatusWith(data: String) { - let dataToPost = [Parameter.actionn.rawValue: Action.widgetUpdate.rawValue, - Parameter.data.rawValue: data] as [String: Any] - - let urlString = baseURL + ServerPathSuffix.doAction.rawValue - - actionRequestLoop.enqueue(request: WebimRequest(httpMethod: .post, - primaryData: dataToPost, - contentType: ContentType.urlEncoded.rawValue, - baseURLString: urlString)) - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/WebimClient.swift b/ios/libs/Webim/WebimClientLibrary/Backend/WebimClient.swift deleted file mode 100644 index 7a7db1e..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/WebimClient.swift +++ /dev/null @@ -1,283 +0,0 @@ -// -// WebimClient.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 10.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class WebimClientBuilder { - - // MARK: - Properties - private var appVersion: String? - private var prechat: String? - private var authorizationData: AuthorizationData? - private var baseURL: String? - private var completionHandlerExecutor: ExecIfNotDestroyedHandlerExecutor? - private var deltaCallback: DeltaCallback? - private var deviceID: String? - private var deviceToken: String? - private var internalErrorListener: InternalErrorListener? - private var location: String? - private var providedAuthenticationToken: String? - private weak var providedAuthenticationTokenStateListener: ProvidedAuthorizationTokenStateListener? - private var sessionID: String? - private var sessionParametersListener: SessionParametersListener? - private var title: String? - private var visitorFieldsJSONString: String? - private var visitorJSONString: String? - - // MARK: - Builder methods - - func set(appVersion: String?) -> WebimClientBuilder { - self.appVersion = appVersion - - return self - } - - func set(baseURL: String) -> WebimClientBuilder { - self.baseURL = baseURL - - return self - } - - func set(location: String) -> WebimClientBuilder { - self.location = location - - return self - } - - func set(deltaCallback: DeltaCallback) -> WebimClientBuilder { - self.deltaCallback = deltaCallback - - return self - } - - func set(sessionParametersListener: SessionParametersListener) -> WebimClientBuilder { - self.sessionParametersListener = sessionParametersListener - - return self - } - - func set(internalErrorListener: InternalErrorListener) -> WebimClientBuilder { - self.internalErrorListener = internalErrorListener - - return self - } - - func set(visitorJSONString: String?) -> WebimClientBuilder { - self.visitorJSONString = visitorJSONString - - return self - } - - func set(visitorFieldsJSONString: String?) -> WebimClientBuilder { - self.visitorFieldsJSONString = visitorFieldsJSONString - - return self - } - - func set(providedAuthenticationTokenStateListener: ProvidedAuthorizationTokenStateListener?, - providedAuthenticationToken: String? = nil) -> WebimClientBuilder { - self.providedAuthenticationTokenStateListener = providedAuthenticationTokenStateListener - self.providedAuthenticationToken = providedAuthenticationToken - - return self - } - - func set(sessionID: String?) -> WebimClientBuilder { - self.sessionID = sessionID - - return self - } - - func set(authorizationData: AuthorizationData?) -> WebimClientBuilder { - self.authorizationData = authorizationData - - return self - } - - func set(completionHandlerExecutor: ExecIfNotDestroyedHandlerExecutor?) -> WebimClientBuilder { - self.completionHandlerExecutor = completionHandlerExecutor - - return self - } - - func set(title: String) -> WebimClientBuilder { - self.title = title - - return self - } - - func set(deviceToken: String?) -> WebimClientBuilder { - self.deviceToken = deviceToken - - return self - } - - func set(deviceID: String) -> WebimClientBuilder { - self.deviceID = deviceID - - return self - } - - func set(prechat:String?) -> WebimClientBuilder { - self.prechat = prechat - return self - } - - func build() -> WebimClient { - let actionRequestLoop = ActionRequestLoop(completionHandlerExecutor: completionHandlerExecutor!, - internalErrorListener: internalErrorListener!) - - actionRequestLoop.set(authorizationData: authorizationData) - - let deltaRequestLoop = DeltaRequestLoop(deltaCallback: deltaCallback!, - completionHandlerExecutor: completionHandlerExecutor!, - sessionParametersListener: SessionParametersListenerWrapper(withSessionParametersListenerToWrap: sessionParametersListener, - actionRequestLoop: actionRequestLoop), - internalErrorListener: internalErrorListener!, - baseURL: baseURL!, - title: title!, - location: location!, - appVersion: appVersion, - visitorFieldsJSONString: visitorFieldsJSONString, - providedAuthenticationTokenStateListener: providedAuthenticationTokenStateListener, - providedAuthenticationToken: providedAuthenticationToken, - deviceID: deviceID!, - deviceToken: deviceToken, - visitorJSONString: visitorJSONString, - sessionID: sessionID, - prechat: prechat, - authorizationData: authorizationData - ) - - return WebimClient(withActionRequestLoop: actionRequestLoop, - deltaRequestLoop: deltaRequestLoop, - webimActions: WebimActions(baseURL: baseURL!, - actionRequestLoop: actionRequestLoop)) - } - -} - -// MARK: - -// Need to update deviceToken in DeltaRequestLoop on update in WebimActions. -/** - Class that is responsible for history storage when it is set to memory mode. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class WebimClient { - - // MARK: - Properties - private let actionRequestLoop: ActionRequestLoop - private let deltaRequestLoop: DeltaRequestLoop - private let webimActions: WebimActions - - // MARK: - Initialization - init(withActionRequestLoop actionRequestLoop: ActionRequestLoop, - deltaRequestLoop: DeltaRequestLoop, - webimActions: WebimActions) { - self.actionRequestLoop = actionRequestLoop - self.deltaRequestLoop = deltaRequestLoop - self.webimActions = webimActions - } - - // MARK: - Methods - - func start() { - deltaRequestLoop.start() - actionRequestLoop.start() - } - - func pause() { - deltaRequestLoop.pause() - actionRequestLoop.pause() - } - - func resume() { - deltaRequestLoop.resume() - actionRequestLoop.resume() - } - - func stop() { - deltaRequestLoop.stop() - actionRequestLoop.stop() - } - - func set(deviceToken: String) { - deltaRequestLoop.set(deviceToken: deviceToken) - webimActions.update(deviceToken: deviceToken) - } - - func getDeltaRequestLoop() -> DeltaRequestLoop { - return deltaRequestLoop - } - - func getActions() -> WebimActions { - return webimActions - } - -} - -// MARK: - -// Need to update AuthorizationData in ActionRequestLoop on update in DeltaRequestLoop. -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final private class SessionParametersListenerWrapper: SessionParametersListener { - - // MARK: - Properties - private let wrappedSessionParametersListener: SessionParametersListener? - private let actionRequestLoop: ActionRequestLoop - - // MARK: - Initializers - init(withSessionParametersListenerToWrap wrappingSessionParametersListener: SessionParametersListener?, - actionRequestLoop: ActionRequestLoop) { - wrappedSessionParametersListener = wrappingSessionParametersListener - self.actionRequestLoop = actionRequestLoop - } - - // MARK: - SessionParametersListener protocol methods - func onSessionParametersChanged(visitorFieldsJSONString visitorJSONString: String, - sessionID: String, - authorizationData: AuthorizationData) { - actionRequestLoop.set(authorizationData: authorizationData) - - wrappedSessionParametersListener?.onSessionParametersChanged(visitorFieldsJSONString: visitorJSONString, - sessionID: sessionID, - authorizationData: authorizationData) - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/WebimInternalError.swift b/ios/libs/Webim/WebimClientLibrary/Backend/WebimInternalError.swift deleted file mode 100644 index e62ed34..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/WebimInternalError.swift +++ /dev/null @@ -1,84 +0,0 @@ -// -// WebimInternalError.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 17.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Errors that can be received from a server after a HTTP-request. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -enum WebimInternalError: String, Error { - case accountBlocked = "account-blocked" - case chatRequired = "chat-required" - case contentTypeNotRecognized = "content_type_not_recognized"; - case domainNotFromWhitelist = "domain-not-from-whitelist"; - case fileSizeExceeded = "max_file_size_exceeded" - case fileTypeNotAllowed = "not_allowed_file_type" - case notAllowedMimeType = "not_allowed_mime_type"; - case noPreviousChats = "no_previous_chats"; - case notMatchingMagicNumbers = "not_matching_magic_numbers"; - case providedVisitorFieldsExpired = "provided-visitor-expired" - case reinitializationRequired = "reinit-required" - case settingDisabled = "setting_disabled"; - case serverNotReady = "server-not-ready" - case sessionNotFound = "session_not_found"; - case uploadedFileNotFound = "uploaded-file-not-found"; - case visitorBanned = "visitor_banned" - case wrongArgumentValue = "wrong-argument-value" - case wrongProvidedVisitorFieldsHashValue = "wrong-provided-visitor-hash-value" - - // Data errors - // Quoting message errors - case quotedMessageCannotBeReplied = "quoting-message-that-cannot-be-replied" - case quotedMessageFromAnotherVisitor = "quoting-message-from-another-visitor" - case quotedMessageCorruptedID = "corrupted-quoted-message-id" - case quotedMessageMultipleID = "multiple-quoted-messages-found" - case quotedMessageNotFound = "quoted-message-not-found" - case quotedMessageRequiredArgumentsMissing = "required-quote-args-missing" - - // Provided authonication token errors - case providedAuthenticationTokenNotFound = "provided-auth-token-not-found" - - // Send, edit and delete message errors. - // send or edit: - case messageEmpty = "message_empty"; - case maxMessageLengthExceeded = "max-message-length-exceeded"; - // delete: - case messageNotFound = "message_not_found"; - // edit or delete - case notAllowed = "not_allowed"; - case messageNotOwned = "message_not_owned"; - // edit - case wrongMessageKind = "wrong_message_kind"; - - - // Rate operator errors - case noChat = "no-chat" - case operatorNotInChat = "operator-not-in-chat" -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/WebimInternalLogger.swift b/ios/libs/Webim/WebimClientLibrary/Backend/WebimInternalLogger.swift deleted file mode 100644 index 52b1848..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/WebimInternalLogger.swift +++ /dev/null @@ -1,134 +0,0 @@ -// -// WebimInternalLogger.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 15.01.18. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that wraps `WebimLogger` into singleton pattern and encapsulates its verbose level. - First, one should call `setup(webimLogger:verbosityLevel:)` method with particular parameters, then it will be possible to use `WebimInternalLogger.shared`. - - seealso: - `WebimLogger`. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ -final class WebimInternalLogger { - - // MARK: - Properties - static let shared = WebimInternalLogger() - private static let setup = WebimInternalLoggerParametersHelper() - - // MARK: - Initialization - private init() { - // Needed for singleton pattern. - } - - // MARK: - Methods - - class func setup(webimLogger: WebimLogger?, - verbosityLevel: SessionBuilder.WebimLoggerVerbosityLevel?) { - WebimInternalLogger.setup.webimLogger = webimLogger - WebimInternalLogger.setup.verbosityLevel = verbosityLevel - } - - func log(entry: String, - verbosityLevel: SessionBuilder.WebimLoggerVerbosityLevel = .ERROR) { - let logEntry = "WEBIM LOG. " + Date().debugDescription + " " + entry - switch verbosityLevel { - case .VERBOSE: - if isVerbose() { - WebimInternalLogger.setup.webimLogger?.log(entry: logEntry) - } - - break - case .DEBUG: - if isDebug() { - WebimInternalLogger.setup.webimLogger?.log(entry: logEntry) - } - - break - case .INFO: - if isInfo() { - WebimInternalLogger.setup.webimLogger?.log(entry: logEntry) - } - - break - case .WARNING: - if isWarning() { - WebimInternalLogger.setup.webimLogger?.log(entry: logEntry) - } - - break - case .ERROR: - WebimInternalLogger.setup.webimLogger?.log(entry: logEntry) - - break - } - } - - // MARK: Private methods - - private func isVerbose() -> Bool { - return (WebimInternalLogger.setup.verbosityLevel == .VERBOSE) - } - - private func isDebug() -> Bool { - return ((WebimInternalLogger.setup.verbosityLevel == .DEBUG) - || (WebimInternalLogger.setup.verbosityLevel == .VERBOSE)) - } - - private func isInfo() -> Bool { - return ((WebimInternalLogger.setup.verbosityLevel == .VERBOSE) - || (WebimInternalLogger.setup.verbosityLevel == .DEBUG) - || (WebimInternalLogger.setup.verbosityLevel == .INFO)) - } - - private func isWarning() -> Bool { - return ((WebimInternalLogger.setup.verbosityLevel == .VERBOSE) - || (WebimInternalLogger.setup.verbosityLevel == .DEBUG) - || (WebimInternalLogger.setup.verbosityLevel == .INFO) - || (WebimInternalLogger.setup.verbosityLevel == .WARNING)) - } - -} - -/** - Helper class for `WebimInternalLogger` singleton instance setup. - - seealso: - `WebimInternalLogger`. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ -final class WebimInternalLoggerParametersHelper { - - // MARK: - Properties - var verbosityLevel: SessionBuilder.WebimLoggerVerbosityLevel? - var webimLogger: WebimLogger? - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Backend/WebimRequest.swift b/ios/libs/Webim/WebimClientLibrary/Backend/WebimRequest.swift deleted file mode 100644 index 5c3e799..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Backend/WebimRequest.swift +++ /dev/null @@ -1,172 +0,0 @@ -// -// WebimRequest.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 11.09.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that encapsulates paramters or HTTP-requests sending by WebimClientLibrary. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class WebimRequest { - - // MARK: - Properties - private let baseURLString: String - private let httpMethod: AbstractRequestLoop.HTTPMethods - private let primaryData: [String: Any] - private var contentType: String? - private weak var dataMessageCompletionHandler: DataMessageCompletionHandler? - private var historyRequestCompletionHandler: ((_ data: Data?) throws -> ())? - private var faqItemRequestCompletionHandler: ((_ item: Data?) throws -> ())? - private var faqCategoryRequestCompletionHandler: ((_ item: Data?) throws -> ())? - private var faqStructureRequestCompletionHandler: ((_ item: Data?) throws -> ())? - private var httpBody: Data? - private var messageID: String? - private var filename: String? - private var mimeType: String? - private var fileData: Data? - private var boundaryString: String? - private weak var rateOperatorCompletionHandler: RateOperatorCompletionHandler? - private var sendFileCompletionHandler: SendFileCompletionHandler? - private var deleteMessageCompletionHandler: DeleteMessageCompletionHandler? - private var editMessageCompletionHandler: EditMessageCompletionHandler? - - // MARK: - Initialization - init(httpMethod: AbstractRequestLoop.HTTPMethods, - primaryData: [String: Any], - messageID: String? = nil, - filename: String? = nil, - mimeType: String? = nil, - fileData: Data? = nil, - boundaryString: String? = nil, - contentType: String? = nil, - baseURLString: String, - historyRequestCompletionHandler: ((_ data: Data?) throws -> ())? = nil, - faqItemRequestCompletionHandler: ((_ item: Data?) throws -> ())? = nil, - faqCategoryRequestCompletionHandler: ((_ item: Data?) throws -> ())? = nil, - faqStructureRequestCompletionHandler: ((_ item: Data?) throws -> ())? = nil, - dataMessageCompletionHandler: DataMessageCompletionHandler? = nil, - rateOperatorCompletionHandler: RateOperatorCompletionHandler? = nil, - sendFileCompletionHandler: SendFileCompletionHandler? = nil, - deleteMessageCompletionHandler: DeleteMessageCompletionHandler? = nil, - editMessageCompletionHandler: EditMessageCompletionHandler? = nil) { - self.httpMethod = httpMethod - self.primaryData = primaryData - self.messageID = messageID - self.filename = filename - self.mimeType = mimeType - self.fileData = fileData - self.boundaryString = boundaryString - self.contentType = contentType - self.baseURLString = baseURLString - self.historyRequestCompletionHandler = historyRequestCompletionHandler - self.dataMessageCompletionHandler = dataMessageCompletionHandler - self.rateOperatorCompletionHandler = rateOperatorCompletionHandler - self.sendFileCompletionHandler = sendFileCompletionHandler - self.deleteMessageCompletionHandler = deleteMessageCompletionHandler - self.editMessageCompletionHandler = editMessageCompletionHandler - self.faqItemRequestCompletionHandler = faqItemRequestCompletionHandler - self.faqCategoryRequestCompletionHandler = faqCategoryRequestCompletionHandler - self.faqStructureRequestCompletionHandler = faqStructureRequestCompletionHandler - } - - - // MARK: - Methods - - func getHTTPMethod() -> AbstractRequestLoop.HTTPMethods { - return httpMethod - } - - func getBaseURLString() -> String { - return baseURLString - } - - func getContentType() -> String? { - return contentType - } - - func getCompletionHandler() -> ((_ data: Data?) throws -> ())? { - return historyRequestCompletionHandler - } - - func getFAQItemRequestCompletionHandler() -> ((_ data: Data?) throws -> ())? { - return faqItemRequestCompletionHandler - } - - func getFAQCategoryRequestCompletionHandler() -> ((_ data: Data?) throws -> ())? { - return faqCategoryRequestCompletionHandler - } - - func getFAQStructureRequestCompletionHandler() -> ((_ data: Data?) throws -> ())? { - return faqStructureRequestCompletionHandler - } - - func getFileName() -> String? { - return filename - } - - func getMimeType() -> String? { - return mimeType - } - - func getFileData() -> Data? { - return fileData - } - - func getBoundaryString() -> String? { - return boundaryString - } - - func getMessageID() -> String? { - return messageID - } - - func getPrimaryData() -> [String: Any] { - return primaryData - } - - func getDataMessageCompletionHandler() -> DataMessageCompletionHandler? { - return dataMessageCompletionHandler - } - - func getRateOperatorCompletionHandler() -> RateOperatorCompletionHandler? { - return rateOperatorCompletionHandler - } - - func getSendFileCompletionHandler() -> SendFileCompletionHandler? { - return sendFileCompletionHandler - } - - func getDeleteMessageCompletionHandler() -> DeleteMessageCompletionHandler? { - return deleteMessageCompletionHandler - } - - func getEditMessageCompletionHandler() -> EditMessageCompletionHandler? { - return editMessageCompletionHandler - } -} diff --git a/ios/libs/Webim/WebimClientLibrary/Department.swift b/ios/libs/Webim/WebimClientLibrary/Department.swift deleted file mode 100644 index 5ba3720..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Department.swift +++ /dev/null @@ -1,162 +0,0 @@ -// -// Department.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 12.12.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Single department entity. Provides methods to get department information. - Department objects can be received through `DepartmentListChangeListener` protocol methods and `getDepartmentList()` method of `MessageStream` protocol. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol Department { - - /** - Department key is used to start chat with some department. - - seealso: - `startChat(departmentKey:)` method of `MessageStream` protocol. - - returns: - Department key value that uniquely identifies this department. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getKey() -> String - - /** - - returns: - Department public name. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getName() -> String - - /** - - seealso: - `DepartmentOnlineStatus`. - - returns: - Department online status. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getDepartmentOnlineStatus() -> DepartmentOnlineStatus - - /** - - returns: - Order number. Higher numbers match higher priority. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getOrder() -> Int - - /** - - returns: - Dictionary of department localized names (if exists). Key is custom locale descriptor, value is matching name. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getLocalizedNames() -> [String: String]? - - /** - - returns: - Department logo URL (if exists). - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getLogoURL() -> URL? - -} - -/** - Possible department online statuses. - - seealso: - `getDepartmentOnlineStatus()` of `Department` protocol. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public enum DepartmentOnlineStatus { - - /** - Offline state with chats' count limit exceeded. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case BUSY_OFFLINE - - /** - Online state with chats' count limit exceeded. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case BUSY_ONLINE - - /** - Visitor is able to send offline messages. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case OFFLINE - - /** - Visitor is able to send both online and offline messages. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case ONLINE - - /** - Any status that is not supported by this version of the library. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case UNKNOWN - -} diff --git a/ios/libs/Webim/WebimClientLibrary/FAQ.swift b/ios/libs/Webim/WebimClientLibrary/FAQ.swift deleted file mode 100644 index 2c1a87e..0000000 --- a/ios/libs/Webim/WebimClientLibrary/FAQ.swift +++ /dev/null @@ -1,169 +0,0 @@ -// -// FAQ.swift -// WebimClientLibrary -// -// Created by Nikita Kaberov on 07.02.19. -// Copyright © 2019 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - - -import Foundation - -/** - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -public protocol FAQ { - - /** - Resumes FAQ networking. - - important: - FAQ is created as paused. To start using it firstly you should call this method. - - throws: - `FAQAccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `FAQAccessError.INVALID_FAQ` if FAQ was destroyed. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func resume() throws - - /** - Pauses FAQ networking. - - throws: - `FAQAccessError.INVALID_THREAD` if the method was called not from the thread the FAQ was created in. - `FAQAccessError.INVALID_FAQ` if FAQ was destroyed. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func pause() throws - - /** - Destroys FAQ. After that any FAQ methods are not available. - - throws: - `FAQAccessError.INVALID_THREAD` if the method was called not from the thread the FAQ was created in. - `FAQAccessError.INVALID_FAQ` if FAQ was destroyed. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func destroy() throws - - /** - Requests category. If nil is passed inside completion, there no category with this id. - - seealso: - `destroy()` method. - `FAQCategory` protocol. - - parameter id: - Category ID. - - parameter completion: - Completion to be called on category if method call succeeded. - - parameter result: - Resulting category if method call succeeded. - - throws: - `FAQAccessError.INVALID_THREAD` if the method was called not from the thread the FAQ was created in. - `FAQAccessError.INVALID_FAQ` if the method was called after FAQ object was destroyed. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getCategory(id: Int, completion: @escaping (_ result: FAQCategory?) -> ()) throws - - /** - Requests item. If nil is passed inside completion, there no item with this id. - - seealso: - `destroy()` method. - `FAQItem` protocol. - - parameter id: - Item ID. - - parameter completion: - Completion to be called on item if method call succeeded. - - parameter result: - Resulting item if method call succeeded. - - throws: - `FAQAccessError.INVALID_THREAD` if the method was called not from the thread the FAQ was created in. - `FAQAccessError.INVALID_FAQ` if the method was called after FAQ object was destroyed. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getItem(id: String, completion: @escaping (_ result: FAQItem?) -> ()) throws - - /** - Requests structure. If nil is passed inside completion, there no structure with this id. - - seealso: - `destroy()` method. - `FAQStructure` protocol. - - parameter id: - Structure ID. - - parameter completion: - Completion to be called on structure if method call succeeded. - - parameter result: - Resulting structure if method call succeeded. - - throws: - `FAQAccessError.INVALID_THREAD` if the method was called not from the thread the FAQ was created in. - `FAQAccessError.INVALID_FAQ` if the method was called after FAQ object was destroyed. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getStructure(id: Int, completion: @escaping (_ result: FAQStructure?) -> ()) throws -} - -// MARK: - -/** - Error types that can be throwed by FAQ methods. - - seealso: - `FAQ` methods. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -public enum FAQAccessError: Error { - - /** - Error that is thrown if the method was called not from the thread the FAQ was created in. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - case INVALID_THREAD - - /** - Error that is thrown if FAQ was destroyed. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - case INVALID_FAQ -} diff --git a/ios/libs/Webim/WebimClientLibrary/FAQCategory.swift b/ios/libs/Webim/WebimClientLibrary/FAQCategory.swift deleted file mode 100644 index 13275cb..0000000 --- a/ios/libs/Webim/WebimClientLibrary/FAQCategory.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// FAQCategory.swift -// WebimClientLibrary -// -// Created by Nikita Kaberov on 07.02.19. -// Copyright © 2019 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - - -import Foundation - -/** - FAQ category contains pages with some information and subcategories. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -public protocol FAQCategory { - - /** - Every category can be uniquefied by its ID. - - returns: - Unique ID of the category. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getID() -> Int - - /** - - returns: - Title of the category. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getTitle() -> String - - /** - Every category contains items. - - returns: - List of category items. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getItems() -> [FAQItem] - - /** - Every category can be contains subcategories. - - returns: - List of categories that contains the item. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getSubcategories() -> [FAQCategoryInfo] -} diff --git a/ios/libs/Webim/WebimClientLibrary/FAQCategoryInfo.swift b/ios/libs/Webim/WebimClientLibrary/FAQCategoryInfo.swift deleted file mode 100644 index 8f79a79..0000000 --- a/ios/libs/Webim/WebimClientLibrary/FAQCategoryInfo.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// FAQCategoryInfo.swift -// WebimClientLibrary -// -// Created by Nikita Kaberov on 07.02.19. -// Copyright © 2019 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - - -import Foundation - -/** - FAQCategory without children. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -public protocol FAQCategoryInfo { - - /** - Every category can be uniquefied by its ID. - - returns: - Unique ID of the category. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getID() -> Int - - /** - - returns: - Title of the category. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getTitle() -> String -} diff --git a/ios/libs/Webim/WebimClientLibrary/FAQItem.swift b/ios/libs/Webim/WebimClientLibrary/FAQItem.swift deleted file mode 100644 index 530796d..0000000 --- a/ios/libs/Webim/WebimClientLibrary/FAQItem.swift +++ /dev/null @@ -1,111 +0,0 @@ -// -// FAQItem.swift -// WebimClientLibrary -// -// Created by Nikita Kaberov on 07.02.19. -// Copyright © 2019 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - - -import Foundation - -/** - FAQ page with some information. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -public protocol FAQItem { - - /** - Every item can be uniquefied by its ID. - - returns: - Unique ID of the item. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getID() -> String - - /** - Every item can be contained in different categories. - - returns: - List of categories that contains the item. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getCategories() -> [Int] - - /** - - returns: - Title of the item. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getTitle() -> String - - /** - - returns: - List of item tags. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getTags() -> [String] - - /** - - returns: - Item content. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getContent() -> String - - /** - - returns: - Like count of the item. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getLikeCount() -> Int - - - /** - - returns: - Dislike count of the item. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getDislikeCount() -> Int -} diff --git a/ios/libs/Webim/WebimClientLibrary/FAQStructure.swift b/ios/libs/Webim/WebimClientLibrary/FAQStructure.swift deleted file mode 100644 index 8edf9e3..0000000 --- a/ios/libs/Webim/WebimClientLibrary/FAQStructure.swift +++ /dev/null @@ -1,118 +0,0 @@ -// -// FAQStructure.swift -// WebimClientLibrary -// -// Created by Nikita Kaberov on 07.02.19. -// Copyright © 2019 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - - -import Foundation - -/** - Category subtree. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -public protocol FAQStructure { - /** - Every structure has root. - - returns: - Unique ID of the tree root. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getID() -> String - - /** - - returns: - Root type. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getType() -> RootType - - /** - - returns: - Root's children. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getChildren() -> [FAQStructure] - - /** - - returns: - Root title. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func getTitle() -> String -} - -// MARK: - -/** - Supported structure root types. - - seealso: - `FAQStructure.getType()` - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -public enum RootType { - /** - Root is category. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - case CATEGORY - - /** - Root is item. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - case ITEM - - /** - Unknown root type. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - case UNKNOWN - -} diff --git a/ios/libs/Webim/WebimClientLibrary/FatalErrorHandler.swift b/ios/libs/Webim/WebimClientLibrary/FatalErrorHandler.swift deleted file mode 100644 index 2866d40..0000000 --- a/ios/libs/Webim/WebimClientLibrary/FatalErrorHandler.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// FatalErrorHandler.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 08.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - - -import Foundation - - -/** - Protocol that provides methods to handle errors are sent by Webim service. - - seealso: - `set(fatalErrorHandler:)` method of `SessionBuilder` class. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol FatalErrorHandler: class { - - /** - This method is to be called when Webim service error is received. - - important: - Method called NOT FROM THE MAIN THREAD! - - parameter error: - Error type. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func on(error: WebimError) - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/DepartmentImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/DepartmentImpl.swift deleted file mode 100644 index f04f437..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Implementation/DepartmentImpl.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// DepartmentImpl.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 12.12.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -final class DepartmentImpl: Department { - - // MARK: - Properties - private let departmentOnlineStatus: DepartmentOnlineStatus - private let key: String - private let name: String - private let order: Int - private var localizedNames: [String: String]? - private var logoURL: URL? - - // MARK: - Initialization - init(key: String, - name: String, - departmentOnlineStatus: DepartmentOnlineStatus, - order: Int, - localizedNames: [String: String]? = nil, - logo: URL? = nil) { - self.key = key - self.name = name - self.departmentOnlineStatus = departmentOnlineStatus - self.order = order - self.localizedNames = localizedNames - self.logoURL = logo - } - - // MARK: - Methods - // MARK: Department protocol methods - - func getKey() -> String { - return key - } - - func getName() -> String { - return name - } - - func getDepartmentOnlineStatus() -> DepartmentOnlineStatus { - return departmentOnlineStatus - } - - func getOrder() -> Int { - return order - } - - func getLocalizedNames() -> [String: String]? { - return localizedNames - } - - func getLogoURL() -> URL? { - return logoURL - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/FAQImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/FAQImpl.swift deleted file mode 100644 index ca88519..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Implementation/FAQImpl.swift +++ /dev/null @@ -1,175 +0,0 @@ -// -// FAQImpl.swift -// WebimClientLibrary -// -// Created by Nikita Kaberov on 07.02.19. -// Copyright © 2019 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -// MARK: - -/** - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ -final class FAQImpl { - - // MARK: - Properties - private var accessChecker: FAQAccessChecker - private var clientStarted = false - private var faqDestroyer: FAQDestroyer - private var faqClient: FAQClient - - // MARK: - Initialization - private init(accessChecker: FAQAccessChecker, - faqDestroyer: FAQDestroyer, - faqClient: FAQClient) { - self.accessChecker = accessChecker - self.faqDestroyer = faqDestroyer - self.faqClient = faqClient - } - - // MARK: - Methods - - static func newInstanceWith(accountName: String) -> FAQImpl { - - let faqDestroyer = FAQDestroyer() - - let serverURLString = InternalUtils.createServerURLStringBy(accountName: accountName) - - let queue = DispatchQueue.global(qos: .userInteractive) - - let faqClient = FAQClientBuilder() - .set(baseURL: serverURLString) - .set(completionHandlerExecutor: ExecIfNotDestroyedFAQHandlerExecutor(faqDestroyer: faqDestroyer, - queue: queue)) - .build() as FAQClient - - let accessChecker = FAQAccessChecker(thread: Thread.current, - faqDestroyer: faqDestroyer) - - faqDestroyer.add() { - faqClient.stop() - } - - return FAQImpl(accessChecker: accessChecker, - faqDestroyer: faqDestroyer, - faqClient: faqClient) - } -} - -// MARK: - FAQ -extension FAQImpl: FAQ { - func getCategory(id: Int, completion: @escaping (FAQCategory?) -> ()) throws { - try accessChecker.checkAccess() - - faqClient.getActions().getCategory(categoryId: id) { data in - if data != nil { - let json = try? JSONSerialization.jsonObject(with: data!, - options: []) - if let faqCategoryDictionary = json as? [String: Any?] { - let faqCategory = FAQCategoryItem(jsonDictionary: faqCategoryDictionary) - - completion(faqCategory) - } - } else { - completion(nil) - } - } - } - - func getStructure(id: Int, completion: @escaping (FAQStructure?) -> ()) throws { - try accessChecker.checkAccess() - faqClient.getActions().getStructure(categoryId: id) { data in - if data != nil { - let json = try? JSONSerialization.jsonObject(with: data!, - options: []) - if let faqStructureDictionary = json as? [String: Any?] { - let faqStructure = FAQStructureItem(jsonDictionary: faqStructureDictionary) - - completion(faqStructure) - } - } else { - completion(nil) - } - } - - } - - func getItem(id: String, completion: @escaping (FAQItem?) -> ()) throws { - try accessChecker.checkAccess() - - faqClient.getActions().getItem(itemId: id) { data in - if data != nil { - let json = try? JSONSerialization.jsonObject(with: data!, - options: []) - if let faqItemDictionary = json as? [String: Any?] { - let faqItem = FAQItemItem(jsonDictionary: faqItemDictionary) - - completion(faqItem) - } - } else { - completion(nil) - } - } - } - - - func resume() throws { - try checkAccess() - - if !clientStarted { - faqClient.start() - clientStarted = true - } - - faqClient.resume() - } - - func pause() throws { - if faqDestroyer.isDestroyed() { - return - } - - try checkAccess() - - faqClient.pause() - } - - func destroy() throws { - if faqDestroyer.isDestroyed() { - return - } - - try checkAccess() - - faqDestroyer.destroy() - } - - // MARK: Private methods - private func checkAccess() throws { - try accessChecker.checkAccess() - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/LocationSettingsImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/LocationSettingsImpl.swift deleted file mode 100644 index 4ae91f1..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Implementation/LocationSettingsImpl.swift +++ /dev/null @@ -1,96 +0,0 @@ -// -// LocationSettingsImpl.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 09.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that encapsulates various location settings received form server when initializing session. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class LocationSettingsImpl { - - // MARK: - Constants - enum UserDefaultsKey: String { - case hintsEnabled = "hints_enabled" - } - - - // MARK: - Properties - private var hintsEnabled: Bool - - - // MARK: - Initialization - init(hintsEnabled: Bool) { - self.hintsEnabled = hintsEnabled - } - - - // MARK: - Methods - - static func getFrom(userDefaults userDefaultsKey: String) -> LocationSettingsImpl { - if let userDefaults = UserDefaults.standard.dictionary(forKey: userDefaultsKey) { - if let hintsEnabled = userDefaults[UserDefaultsKey.hintsEnabled.rawValue] as? Bool { - return LocationSettingsImpl(hintsEnabled: hintsEnabled) - } - } - - return LocationSettingsImpl(hintsEnabled: false) - } - - func saveTo(userDefaults userDefaultsKey: String) { - if var userDefaults = UserDefaults.standard.dictionary(forKey: userDefaultsKey) { - userDefaults[UserDefaultsKey.hintsEnabled.rawValue] = hintsEnabled - UserDefaults.standard.set(userDefaults, - forKey: userDefaultsKey) - } - - UserDefaults.standard.setValue([UserDefaultsKey.hintsEnabled.rawValue: hintsEnabled], - forKey: userDefaultsKey) - } - -} - -// MARK: - Equatable -extension LocationSettingsImpl: Equatable { - - static func == (lhs: LocationSettingsImpl, - rhs: LocationSettingsImpl) -> Bool { - return lhs.hintsEnabled == rhs.hintsEnabled - } - -} - -// MARK: - LocationSettings -extension LocationSettingsImpl: LocationSettings { - - func areHintsEnabled() -> Bool { - return hintsEnabled - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/MessageImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/MessageImpl.swift deleted file mode 100644 index cdd2ad6..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Implementation/MessageImpl.swift +++ /dev/null @@ -1,537 +0,0 @@ -// -// MessageImpl.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 15.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Internal messages representasion. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -class MessageImpl { - - // MARK: - Properties - private let attachment: MessageAttachment? - private let id: String - private let operatorID: String? - private let rawText: String? - private let senderAvatarURLString: String? - private let senderName: String - private let sendStatus: MessageSendStatus - private let serverURLString: String - private let text: String - private let timeInMicrosecond: Int64 - private let type: MessageType - private var currentChatID: String? - private var data: [String: Any?]? - private var historyID: HistoryID? - private var historyMessage: Bool - private var read: Bool - private var messageCanBeEdited: Bool - - // MARK: - Initialization - init(serverURLString: String, - id: String, - operatorID: String?, - senderAvatarURLString: String?, - senderName: String, - sendStatus: MessageSendStatus = .SENT, - type: MessageType, - data: [String: Any?]?, - text: String, - timeInMicrosecond: Int64, - attachment: MessageAttachment?, - historyMessage: Bool, - internalID: String?, - rawText: String?, - read: Bool, - messageCanBeEdited: Bool) { - self.attachment = attachment - self.data = data - self.id = id - self.operatorID = operatorID - self.rawText = rawText - self.senderAvatarURLString = senderAvatarURLString - self.senderName = senderName - self.sendStatus = sendStatus - self.serverURLString = serverURLString - self.text = text - self.timeInMicrosecond = timeInMicrosecond - self.type = type - self.read = read - self.messageCanBeEdited = messageCanBeEdited - - self.historyMessage = historyMessage - if historyMessage { - historyID = HistoryID(dbID: internalID!, - timeInMicrosecond: timeInMicrosecond) - } else { - currentChatID = internalID - } - } - - // MARK: - Methods - - func getRawText() -> String? { - return rawText - } - - func getSenderAvatarURLString() -> String? { - return senderAvatarURLString - } - - func getTimeInMicrosecond() -> Int64 { - return timeInMicrosecond - } - - func hasHistoryComponent() -> Bool { - return (historyID != nil) - } - - func getHistoryID() -> HistoryID? { - guard historyID != nil else { - WebimInternalLogger.shared.log(entry: "Message \(self.toString()) do not have history component.", - verbosityLevel: .DEBUG) - - return nil - } - - return historyID - } - - func getCurrentChatID() -> String? { - guard currentChatID != nil else { - WebimInternalLogger.shared.log(entry: "Message \(self.toString()) do not have an ID in current chat or do not exist in current chat or chat exists itself not.", - verbosityLevel: .DEBUG) - - return nil - } - - return currentChatID - } - - func getServerUrlString() -> String { - return serverURLString - } - - func getSource() -> MessageSource { - return (historyMessage ? MessageSource.history : MessageSource.currentChat) - } - - func transferToCurrentChat(message: MessageImpl) -> MessageImpl { - if self != message { - message.setSecondaryHistory(historyEquivalentMessage: self) - - return message - } - - setSecondaryCurrentChat(currentChatEquivalentMessage: message) - - invertHistoryStatus() - - return self - } - - func transferToHistory(message: MessageImpl) -> MessageImpl { - if self != message { - message.setSecondaryCurrentChat(currentChatEquivalentMessage: self) - - return message - } - - setSecondaryHistory(historyEquivalentMessage: message) - - invertHistoryStatus() - - return self - } - - func invertHistoryStatus() { - guard historyID != nil, - currentChatID != nil else { - WebimInternalLogger.shared.log(entry: "Message \(self.toString()) has not history component or does not belong to current chat.", - verbosityLevel: .DEBUG) - - return - } - - historyMessage = !historyMessage - } - - func setSecondaryHistory(historyEquivalentMessage: MessageImpl) { - guard !getSource().isHistoryMessage(), - historyEquivalentMessage.getSource().isHistoryMessage() else { - WebimInternalLogger.shared.log(entry: "Message \(self.toString()) is already has history component.", - verbosityLevel: .DEBUG) - - return - } - - historyID = historyEquivalentMessage.getHistoryID() - } - - func setSecondaryCurrentChat(currentChatEquivalentMessage: MessageImpl) { - guard getSource().isHistoryMessage(), - !currentChatEquivalentMessage.getSource().isHistoryMessage() else { - WebimInternalLogger.shared.log(entry: "Current chat equivalent of the message \(self.toString()) is already has history component.", - verbosityLevel: .DEBUG) - - return - } - - currentChatID = currentChatEquivalentMessage.getCurrentChatID() - } - - func setRead(isRead: Bool) { - read = isRead - } - - func getRead() -> Bool { - return read - } - - func setMessageCanBeEdited(messageCanBeEdited: Bool) { - self.messageCanBeEdited = messageCanBeEdited - } - - func toString() -> String { - return """ -MessageImpl { - serverURLString = \(serverURLString), - ID = \(id), - operatorID = \(operatorID ?? "nil"), - senderAvatarURLString = \(senderAvatarURLString ?? "nil"), - senderName = \(senderName), - type = \(type), - text = \(text), - timeInMicrosecond = \(timeInMicrosecond), - attachment = \(attachment?.getURL().absoluteString ?? "nil"), - historyMessage = \(historyMessage), - currentChatID = \(currentChatID ?? "nil"), - historyID = \(historyID?.getDBid() ?? "nil"), - rawText = \(rawText ?? "nil"), - read = \(read) -} -""" - } - - // MARK: - - enum MessageSource { - case history - case currentChat - - // MARK: - Methods - - func assertIsCurrentChat() throws { - guard isCurrentChatMessage() else { - throw MessageError.invalidState("Current message is not a part of current chat.") - } - } - - func assertIsHistory() throws { - guard isHistoryMessage() else { - throw MessageError.invalidState("Current message is not a part of the history.") - } - } - - func isHistoryMessage() -> Bool { - return (self == .history) - } - - func isCurrentChatMessage() -> Bool { - return (self == .currentChat) - } - - } - - // MARK: - - enum MessageError: Error { - case invalidState(String) - } - -} - -// MARK: - Message -extension MessageImpl: Message { - - func getAttachment() -> MessageAttachment? { - return attachment - } - - func getData() -> [String: Any?]? { - return data - } - - func getID() -> String { - return id - } - - func getOperatorID() -> String? { - return operatorID - } - - func getSenderAvatarFullURL() -> URL? { - guard let senderAvatarURLString = senderAvatarURLString else { - return nil - } - - return URL(string: (serverURLString + senderAvatarURLString)) - } - - func getSendStatus() -> MessageSendStatus { - return sendStatus - } - - func getSenderName() -> String { - return senderName - } - - func getText() -> String { - return text - } - - func getTime() -> Date { - return Date(timeIntervalSince1970: TimeInterval(timeInMicrosecond / 1_000_000)) - } - - func getType() -> MessageType { - return type - } - - func isEqual(to message: Message) -> Bool { - return (self == message as! MessageImpl) - } - - func isReadByOperator() -> Bool { - return getRead() //todo: maybe returns old value - } - - func canBeEdited() -> Bool { - return messageCanBeEdited - } - -} - -// MARK: - Equatable -extension MessageImpl: Equatable { - - static func == (lhs: MessageImpl, - rhs: MessageImpl) -> Bool { - return ((((((((lhs.id == rhs.id) - && (lhs.operatorID == rhs.operatorID)) - && (lhs.rawText == rhs.rawText)) - && (lhs.senderAvatarURLString == rhs.senderAvatarURLString)) - && (lhs.senderName == rhs.senderName)) - && (lhs.text == rhs.text)) - && (lhs.timeInMicrosecond == rhs.timeInMicrosecond)) - && (lhs.type == rhs.type)) - && (lhs.isReadByOperator() == rhs.isReadByOperator() - && (lhs.canBeEdited() == rhs.canBeEdited())) - } - -} - -// MARK: - -/** - Internal messages' attachments representation. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class MessageAttachmentImpl { - - // MARK: - Constants - private enum Period: Int64 { - case attachmentURLExpires = 300 // (seconds) = 5 (minutes). - } - - - // MARK: - Properties - private let urlString: String - private let size: Int64? - private let filename: String - private let contentType: String - private let imageInfo: ImageInfo? - - - // MARK: - Initialization - init(urlString: String, - size: Int64?, - filename: String, - contentType: String, - imageInfo: ImageInfo? = nil) { - self.urlString = urlString - self.size = size - self.filename = filename - self.contentType = contentType - self.imageInfo = imageInfo - } - - // MARK: - Methods - static func getAttachment(byServerURL serverURLString: String, - webimClient: WebimClient, - text: String) -> MessageAttachment? { - let textData = text.data(using: .utf8)! - guard let textDictionary = try? JSONSerialization.jsonObject(with: textData, - options: []) as? [String: Any?] else { - WebimInternalLogger.shared.log(entry: "Message attachment parameters parsing failed: \(text).", - verbosityLevel: .WARNING) - - return nil - } - - let fileParameters = FileParametersItem(jsonDictionary: textDictionary!) - guard let filename = fileParameters.getFilename(), - let guid = fileParameters.getGUID(), - let contentType = fileParameters.getContentType() else { - return nil - } - - guard let pageID = webimClient.getDeltaRequestLoop().getAuthorizationData()?.getPageID(), - let authorizationToken = webimClient.getDeltaRequestLoop().getAuthorizationData()?.getAuthorizationToken() else { - WebimInternalLogger.shared.log(entry: "Tried to access to message attachment without authorization data.") - - return nil - } - - let expires = Int64(Date().timeIntervalSince1970) + Period.attachmentURLExpires.rawValue - let data: String = guid + String(expires) - if let hash = data.hmacSHA256(withKey: authorizationToken) { - let fileURLString = serverURLString + WebimActions.ServerPathSuffix.downloadFile.rawValue + "/" - + guid + "/" - + filename.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)! + "?" - + "page-id" + "=" + pageID + "&" - + "expires" + "=" + String(expires) + "&" - + "hash" + "=" + hash - - return MessageAttachmentImpl(urlString: fileURLString, - size: fileParameters.getSize(), - filename: filename, - contentType: contentType, - imageInfo: extractImageInfoOf(fileParameters: fileParameters, - with: fileURLString)) - } else { - WebimInternalLogger.shared.log(entry: "Error creating message attachment link due to HMAC SHA256 encoding error.") - - return nil - } - } - - // MARK: Private methods - private static func extractImageInfoOf(fileParameters: FileParametersItem?, - with fileURLString: String?) -> ImageInfo? { - guard fileParameters != nil, - fileURLString != nil else { - return nil - } - - let imageSize = fileParameters?.getImageParameters()?.getSize() - guard imageSize != nil else { - return nil - } - - let thumbURLString = (fileURLString == nil) ? nil : (fileURLString! + "&thumb=ios") - guard thumbURLString != nil else { - return nil - } - - return ImageInfoImpl(withThumbURLString: thumbURLString!, - width: imageSize!.getWidth(), - height: imageSize!.getHeight()) - } - -} - -// MARK: - MessageAttachment -extension MessageAttachmentImpl: MessageAttachment { - - func getContentType() -> String { - return contentType - } - - func getFileName() -> String { - return filename - } - - func getImageInfo() -> ImageInfo? { - return imageInfo - } - - func getSize() -> Int64? { - return size - } - - func getURL() -> URL { - return URL(string: urlString)! - } - -} - -// MARK: - -/** - Internal image information representation. - - seealso: - `MessageAttachment` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class ImageInfoImpl: ImageInfo { - - // MARK: - Properties - private let thumbURLString: String - private let width: Int? - private let height: Int? - - // MARK: - Initialization - init(withThumbURLString thumbURLString: String, - width: Int?, - height: Int?) { - self.thumbURLString = thumbURLString - self.width = width - self.height = height - } - - // MARK: - Methods - // MARK: ImageInfo protocol methods - - func getThumbURL() -> URL { - return URL(string: thumbURLString)! - } - - func getHeight() -> Int? { - return height - } - - func getWidth() -> Int? { - return width - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/MessageStreamImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/MessageStreamImpl.swift deleted file mode 100644 index 8a299e2..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Implementation/MessageStreamImpl.swift +++ /dev/null @@ -1,700 +0,0 @@ -// -// MessageStreamImpl.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 08.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that responsible for handling full set of events inside message stream. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class MessageStreamImpl { - - // MARK: - Properties - private let accessChecker: AccessChecker - private let currentChatMessageFactoriesMapper: MessageMapper - private let locationSettingsHolder: LocationSettingsHolder - private let messageComposingHandler: MessageComposingHandler - private let messageHolder: MessageHolder - private let sendingMessageFactory: SendingFactory - private let serverURLString: String - private let webimActions: WebimActions - private var chat: ChatItem? - private weak var chatStateListener: ChatStateListener? - private var currentOperator: OperatorImpl? - private var departmentList: [Department]? - private weak var departmentListChangeListener: DepartmentListChangeListener? - private weak var currentOperatorChangeListener: CurrentOperatorChangeListener? - private var isChatIsOpening = false - private var lastChatState: ChatItem.ChatItemState = .unknown - private var lastOperatorTypingStatus: Bool? - private weak var locationSettingsChangeListener: LocationSettingsChangeListener? - private var operatorFactory: OperatorFactory - private weak var operatorTypingListener: OperatorTypingListener? - private var onlineStatus: OnlineStatusItem = .unknown - private weak var onlineStatusChangeListener: OnlineStatusChangeListener? - private var unreadByOperatorTimestamp: Date? - private weak var unreadByOperatorTimestampChangeListener: UnreadByOperatorTimestampChangeListener? - private var unreadByVisitorMessageCount: Int - private weak var unreadByVisitorMessageCountChangeListener: UnreadByVisitorMessageCountChangeListener? - private var unreadByVisitorTimestamp: Date? - private weak var unreadByVisitorTimestampChangeListener: UnreadByVisitorTimestampChangeListener? - private var visitSessionState: VisitSessionStateItem = .unknown - private weak var visitSessionStateListener: VisitSessionStateListener? - - // MARK: - Initialization - init(serverURLString: String, - currentChatMessageFactoriesMapper: MessageMapper, - sendingMessageFactory: SendingFactory, - operatorFactory: OperatorFactory, - accessChecker: AccessChecker, - webimActions: WebimActions, - messageHolder: MessageHolder, - messageComposingHandler: MessageComposingHandler, - locationSettingsHolder: LocationSettingsHolder) { - self.serverURLString = serverURLString - self.currentChatMessageFactoriesMapper = currentChatMessageFactoriesMapper - self.sendingMessageFactory = sendingMessageFactory - self.operatorFactory = operatorFactory - self.accessChecker = accessChecker - self.webimActions = webimActions - self.messageHolder = messageHolder - self.messageComposingHandler = messageComposingHandler - self.locationSettingsHolder = locationSettingsHolder - self.unreadByVisitorMessageCount = -1 - } - - // MARK: - Methods - - func getWebimActions() -> WebimActions { - return webimActions - } - - func set(visitSessionState: VisitSessionStateItem) { - let previousVisitSessionState = self.visitSessionState - self.visitSessionState = visitSessionState - - isChatIsOpening = false - - visitSessionStateListener?.changed(state: publicState(ofVisitSessionState: previousVisitSessionState), - to: publicState(ofVisitSessionState: visitSessionState)) - } - - func set(onlineStatus: OnlineStatusItem) { - self.onlineStatus = onlineStatus - } - - func set(unreadByOperatorTimestamp: Date?) { - let previousValue = self.unreadByOperatorTimestamp - - self.unreadByOperatorTimestamp = unreadByOperatorTimestamp - - if previousValue != unreadByOperatorTimestamp { - unreadByOperatorTimestampChangeListener?.changedUnreadByOperatorTimestampTo(newValue: self.unreadByOperatorTimestamp) - } - } - - func set(unreadByVisitorTimestamp: Date?) { - let previousValue = self.unreadByVisitorTimestamp - - self.unreadByVisitorTimestamp = unreadByVisitorTimestamp - - if previousValue != unreadByVisitorTimestamp { - unreadByVisitorTimestampChangeListener?.changedUnreadByVisitorTimestampTo(newValue: self.unreadByVisitorTimestamp) - } - } - - func set(unreadByVisitorMessageCount: Int) { - let previousValue = self.unreadByVisitorMessageCount - - self.unreadByVisitorMessageCount = unreadByVisitorMessageCount - - if previousValue != unreadByVisitorMessageCount { - unreadByVisitorMessageCountChangeListener?.changedUnreadByVisitorMessageCountTo(newValue: self.unreadByVisitorMessageCount) - } - } - - func changingChatStateOf(chat: ChatItem?) { - let previousChat = self.chat - self.chat = chat - - messageHolder.receiving(newChat: self.chat, - previousChat: previousChat, - newMessages: (self.chat == nil) ? [MessageImpl]() : currentChatMessageFactoriesMapper.mapAll(messages: self.chat!.getMessages())) - - let newChatState = (self.chat == nil) ? .closed : self.chat!.getState() - if let newChatState = newChatState { - // Recieved chat state can be unsupported by the library. - if lastChatState != newChatState { - chatStateListener?.changed(state: publicState(ofChatState: lastChatState), - to: publicState(ofChatState: newChatState)) - } - lastChatState = newChatState - } - - let newOperator = operatorFactory.createOperatorFrom(operatorItem: self.chat?.getOperator()) - if newOperator != currentOperator { - let previousOperator = currentOperator - currentOperator = newOperator - - currentOperatorChangeListener?.changed(operator: previousOperator, - to: newOperator) - } - - let operatorTypingStatus = ((chat != nil) - && chat!.isOperatorTyping()) - if lastOperatorTypingStatus != operatorTypingStatus { - operatorTypingListener?.onOperatorTypingStateChanged(isTyping: operatorTypingStatus) - } - lastOperatorTypingStatus = operatorTypingStatus - - if let unreadByOperatorTimestamp = chat?.getUnreadByOperatorTimestamp() { - set(unreadByOperatorTimestamp: Date(timeIntervalSince1970: unreadByOperatorTimestamp)) - } - - if let unreadByVisitorMessageCount = chat?.getUnreadByVisitorMessageCount() { - set(unreadByVisitorMessageCount: unreadByVisitorMessageCount) - } - - if let unreadByVisitorTimestamp = chat?.getUnreadByVisitorTimestamp() { - set(unreadByVisitorTimestamp: Date(timeIntervalSince1970: unreadByVisitorTimestamp)) - } - if chat?.getReadByVisitor() == true { - set(unreadByVisitorTimestamp: nil) - } - } - - func saveLocationSettingsOn(fullUpdate: FullUpdate) { - let hintsEnabled = (fullUpdate.getHintsEnabled() == true) - - let previousLocationSettings = locationSettingsHolder.getLocationSettings() - let newLocationSettings = LocationSettingsImpl(hintsEnabled: hintsEnabled) - - let newLocationSettingsReceived = locationSettingsHolder.receiving(locationSettings: newLocationSettings) - - if newLocationSettingsReceived { - locationSettingsChangeListener?.changed(locationSettings: previousLocationSettings, - to: newLocationSettings) - } - } - - func onOnlineStatusChanged(to newOnlineStatus: OnlineStatusItem) { - let previousPublicOnlineStatus = publicState(ofOnlineStatus: onlineStatus) - let newPublicOnlineStatus = publicState(ofOnlineStatus: newOnlineStatus) - - if onlineStatus != newOnlineStatus { - onlineStatusChangeListener?.changed(onlineStatus: previousPublicOnlineStatus, - to: newPublicOnlineStatus) - } - - onlineStatus = newOnlineStatus - } - - func onReceiving(departmentItemList: [DepartmentItem]) { - var departmentList = [Department]() - let departmentFactory = DepartmentFactory(serverURLString: serverURLString) - for departmentItem in departmentItemList { - let department = departmentFactory.convert(departmentItem: departmentItem) - departmentList.append(department) - } - self.departmentList = departmentList - - departmentListChangeListener?.received(departmentList: departmentList) - } - - // MARK: Private methods - - private func publicState(ofChatState chatState: ChatItem.ChatItemState) -> ChatState { - switch chatState { - case .queue: - return .QUEUE - case .chatting: - return .CHATTING - case .chattingWithRobot: - return .CHATTING_WITH_ROBOT - case .closed: - return .NONE - case .closedByVisitor: - return .CLOSED_BY_VISITOR - case .closedByOperator: - return .CLOSED_BY_OPERATOR - case .invitation: - return .INVITATION - default: - return .UNKNOWN - } - } - - private func publicState(ofOnlineStatus onlineStatus: OnlineStatusItem) -> OnlineStatus { - switch onlineStatus { - case .busyOffline: - return .BUSY_OFFLINE - case .busyOnline: - return .BUSY_ONLINE - case .offline: - return .OFFLINE - case .online: - return .ONLINE - default: - return .UNKNOWN - } - } - - private func publicState(ofVisitSessionState visitSessionState: VisitSessionStateItem) -> VisitSessionState { - switch visitSessionState { - case .chat: - return .CHAT - case .departmentSelection: - return .DEPARTMENT_SELECTION - case .idle: - return .IDLE - case .idleAfterChat: - return .IDLE_AFTER_CHAT - case .offlineMessage: - return .OFFLINE_MESSAGE - default: - return .UNKNOWN - } - } - -} - -// MARK: - MessageStream -extension MessageStreamImpl: MessageStream { - - // MARK: - Methods - - func getVisitSessionState() -> VisitSessionState { - return publicState(ofVisitSessionState: visitSessionState) - } - - func getChatState() -> ChatState { - return publicState(ofChatState: lastChatState) - } - - func getUnreadByOperatorTimestamp() -> Date? { - return unreadByOperatorTimestamp - } - - func getUnreadByVisitorMessageCount() -> Int { - return (unreadByVisitorMessageCount > 0) ? unreadByVisitorMessageCount : 0 - } - - func getUnreadByVisitorTimestamp() -> Date? { - return unreadByVisitorTimestamp - } - - func getDepartmentList() -> [Department]? { - return departmentList - } - - func getLocationSettings() -> LocationSettings { - return locationSettingsHolder.getLocationSettings() - } - - func getCurrentOperator() -> Operator? { - return currentOperator - } - - func getLastRatingOfOperatorWith(id: String) -> Int { - let rating = chat?.getOperatorIDToRate()?[id] - - return ((rating == nil) ? 0 : rating!.getRating()) - } - - - func rateOperatorWith(id: String?, - byRating rating: Int, - completionHandler: RateOperatorCompletionHandler?) throws { - guard rating >= 1, - rating <= 5 else { - WebimInternalLogger.shared.log(entry: "Rating must be within from 1 to 5 range. Passed value: \(rating)", - verbosityLevel: .WARNING) - - return - } - - try accessChecker.checkAccess() - - webimActions.rateOperatorWith(id: id, - rating: (rating - 3), // Accepted range: (-2, -1, 0, 1, 2). - completionHandler: completionHandler) - } - - func respondSentryCall(id: String) throws { - try accessChecker.checkAccess() - - webimActions.respondSentryCall(id: id) - } - - func startChat() throws { - try startChat(departmentKey: nil, - firstQuestion: nil) - } - - func startChat(firstQuestion: String?) throws { - try startChat(departmentKey: nil, - firstQuestion: firstQuestion) - } - - func startChat(departmentKey: String?) throws { - try startChat(departmentKey: departmentKey, - firstQuestion: nil) - } - - func startChat(customFields:String?) throws { - try startChat(departmentKey: nil, firstQuestion: nil, customFields: customFields) - } - - func startChat(firstQuestion:String?, customFields: String?) throws { - try startChat(departmentKey: nil, firstQuestion: firstQuestion, customFields: customFields) - } - - func startChat(departmentKey: String?, customFields: String?) throws { - try startChat(departmentKey: departmentKey, firstQuestion: nil, customFields: customFields) - } - - func startChat(departmentKey: String?, firstQuestion: String?) throws { - try startChat(departmentKey: departmentKey, firstQuestion: firstQuestion, customFields: nil) - } - - func startChat(departmentKey: String?, - firstQuestion: String?, - customFields: String?) throws { - try accessChecker.checkAccess() - - if (lastChatState.isClosed() - || (visitSessionState == .offlineMessage)) - && !isChatIsOpening { - webimActions.startChat(withClientSideID: ClientSideID.generateClientSideID(), - firstQuestion: firstQuestion, - departmentKey: departmentKey, - customFields: customFields) - } - } - - func closeChat() throws { - try accessChecker.checkAccess() - - let chatIsOpen = ((lastChatState != .closedByVisitor) - && (lastChatState != .closed)) - && (lastChatState != .unknown) - if chatIsOpen { - webimActions.closeChat() - } - } - - func setVisitorTyping(draftMessage: String?) throws { - try accessChecker.checkAccess() - - messageComposingHandler.setComposing(draft: draftMessage) - } - - func send(message: String) throws -> String { - return try sendMessageInternally(messageText: message) - } - - func send(message: String, - data: [String: Any]?, - completionHandler: DataMessageCompletionHandler?) throws -> String { - if data != nil, let jsonData = try? JSONSerialization.data(withJSONObject: data as Any, - options: []) { - let jsonString = String(data: jsonData, - encoding: .utf8) - - return try sendMessageInternally(messageText: message, - dataJSONString: jsonString, - dataMessageCompletionHandler: completionHandler) - } else { - return try sendMessageInternally(messageText: message) - } - } - - func send(message: String, - isHintQuestion: Bool?) throws -> String { - return try sendMessageInternally(messageText: message, - isHintQuestion: isHintQuestion) - } - - func send(file: Data, - filename: String, - mimeType: String, - completionHandler: SendFileCompletionHandler?) throws -> String { - try startChat() - - let messageID = ClientSideID.generateClientSideID() - messageHolder.sending(message: sendingMessageFactory.createFileMessageToSendWith(id: messageID)) - - webimActions.send(file: file, - filename: filename, - mimeType: mimeType, - clientSideID: messageID, - completionHandler: SendFileCompletionHandlerWrapper(sendFileCompletionHandler: completionHandler, - messageHolder: messageHolder)) - - return messageID - } - - func updateWidgetStatus(data: String) throws { - try accessChecker.checkAccess() - - webimActions.updateWidgetStatusWith(data: data) - } - - func edit(message: Message, text: String, completionHandler: EditMessageCompletionHandler?) throws -> Bool { - try accessChecker.checkAccess() - - if !message.canBeEdited() { - return false - } - let id = message.getID() - let oldMessage = messageHolder.changing(messageID: id, message: text) - if oldMessage != nil { - webimActions.send(message: text, - clientSideID: id, - dataJSONString: nil, - isHintQuestion: false, - editMessageCompletionHandler: EditMessageCompletionHandlerWrapper(editMessageCompletionHandler: completionHandler, - messageHolder: messageHolder, - message: oldMessage!)) - return true - } - return false - } - - func delete(message: Message, completionHandler: DeleteMessageCompletionHandler?) throws -> Bool { - try accessChecker.checkAccess() - - if !message.canBeEdited() { - return false - } - let id = message.getID() - let oldMessage = messageHolder.changing(messageID: id, message: nil) - - if oldMessage != nil { - webimActions.delete(clientSideID: id, - completionHandler: DeleteMessageCompletionHandlerWrapper(deleteMessageCompletionHandler: completionHandler, - messageHolder: messageHolder, - message: oldMessage!)) - return true - } - return false - } - - func setChatRead() throws { - try accessChecker.checkAccess() - - webimActions.setChatRead() - } - - func set(prechatFields: String) throws { - try accessChecker.checkAccess() - - webimActions.set(prechatFields: prechatFields) - } - - func newMessageTracker(messageListener: MessageListener) throws -> MessageTracker { - try accessChecker.checkAccess() - - return try messageHolder.newMessageTracker(withMessageListener: messageListener) as MessageTracker - } - - func set(visitSessionStateListener: VisitSessionStateListener) { - self.visitSessionStateListener = visitSessionStateListener - } - - func set(chatStateListener: ChatStateListener) { - self.chatStateListener = chatStateListener - } - - func set(currentOperatorChangeListener: CurrentOperatorChangeListener) { - self.currentOperatorChangeListener = currentOperatorChangeListener - } - - func set(operatorTypingListener: OperatorTypingListener) { - self.operatorTypingListener = operatorTypingListener - } - - func set(departmentListChangeListener: DepartmentListChangeListener) { - self.departmentListChangeListener = departmentListChangeListener - } - - func set(locationSettingsChangeListener: LocationSettingsChangeListener) { - self.locationSettingsChangeListener = locationSettingsChangeListener - } - - func set(onlineStatusChangeListener: OnlineStatusChangeListener) { - self.onlineStatusChangeListener = onlineStatusChangeListener - } - - func set(unreadByOperatorTimestampChangeListener: UnreadByOperatorTimestampChangeListener) { - self.unreadByOperatorTimestampChangeListener = unreadByOperatorTimestampChangeListener - } - - func set(unreadByVisitorMessageCountChangeListener: UnreadByVisitorMessageCountChangeListener) { - self.unreadByVisitorMessageCountChangeListener = unreadByVisitorMessageCountChangeListener - } - - func set(unreadByVisitorTimestampChangeListener: UnreadByVisitorTimestampChangeListener) { - self.unreadByVisitorTimestampChangeListener = unreadByVisitorTimestampChangeListener - } - - // MARK: Private methods - private func sendMessageInternally(messageText: String, - dataJSONString: String? = nil, - isHintQuestion: Bool? = nil, - dataMessageCompletionHandler: DataMessageCompletionHandler? = nil) throws -> String { - try startChat() - - let messageID = ClientSideID.generateClientSideID() - messageHolder.sending(message: sendingMessageFactory.createTextMessageToSendWith(id: messageID, - text: messageText)) - webimActions.send(message: messageText, - clientSideID: messageID, - dataJSONString: dataJSONString, - isHintQuestion: isHintQuestion, - dataMessageCompletionHandler: DataMessageCompletionHandlerWrapper(dataMessageCompletionHandler: dataMessageCompletionHandler, - messageHolder: messageHolder)) - - return messageID - } - -} - -// MARK: - -fileprivate final class SendFileCompletionHandlerWrapper: SendFileCompletionHandler { - - // MARK: - Properties - private let messageHolder: MessageHolder - private var sendFileCompletionHandler: SendFileCompletionHandler? - - // MARK: - Initialization - init(sendFileCompletionHandler: SendFileCompletionHandler?, - messageHolder: MessageHolder) { - self.sendFileCompletionHandler = sendFileCompletionHandler - self.messageHolder = messageHolder - } - - // MARK: - Methods - - func onSuccess(messageID: String) { - sendFileCompletionHandler?.onSuccess(messageID: messageID) - } - - func onFailure(messageID: String, - error: SendFileError) { - messageHolder.sendingCancelledWith(messageID: messageID) - sendFileCompletionHandler?.onFailure(messageID: messageID, - error: error) - } - -} - -fileprivate final class DataMessageCompletionHandlerWrapper: DataMessageCompletionHandler { - - // MARK: - Properties - private let messageHolder: MessageHolder - private weak var dataMessageCompletionHandler: DataMessageCompletionHandler? - - // MARK: - Initialization - init(dataMessageCompletionHandler: DataMessageCompletionHandler?, - messageHolder: MessageHolder) { - self.dataMessageCompletionHandler = dataMessageCompletionHandler - self.messageHolder = messageHolder - } - - // MARK: - Methods - - func onSuccess(messageID: String) { - dataMessageCompletionHandler?.onSuccess(messageID : messageID) - } - - func onFailure(messageID: String, error: DataMessageError) { - messageHolder.sendingCancelledWith(messageID: messageID) - dataMessageCompletionHandler?.onFailure(messageID: messageID, error: error) - } - -} - -fileprivate final class EditMessageCompletionHandlerWrapper: EditMessageCompletionHandler { - - // MARK: - Properties - private let messageHolder: MessageHolder - private weak var editMessageCompletionHandler: EditMessageCompletionHandler? - private let message: String - - // MARK: - Initialization - init(editMessageCompletionHandler: EditMessageCompletionHandler?, - messageHolder: MessageHolder, - message: String) { - self.editMessageCompletionHandler = editMessageCompletionHandler - self.messageHolder = messageHolder - self.message = message - } - - // MARK: - Methods - - func onSuccess(messageID: String) { - editMessageCompletionHandler?.onSuccess(messageID : messageID) - } - - func onFailure(messageID: String, error: EditMessageError) { - messageHolder.changingCancelledWith(messageID: messageID, message: message) - editMessageCompletionHandler?.onFailure(messageID: messageID, error: error) - } - -} - -fileprivate final class DeleteMessageCompletionHandlerWrapper: DeleteMessageCompletionHandler { - - // MARK: - Properties - private let messageHolder: MessageHolder - private weak var deleteMessageCompletionHandler: DeleteMessageCompletionHandler? - private let message: String - - // MARK: - Initialization - init(deleteMessageCompletionHandler: DeleteMessageCompletionHandler?, - messageHolder: MessageHolder, - message: String) { - self.deleteMessageCompletionHandler = deleteMessageCompletionHandler - self.messageHolder = messageHolder - self.message = message - } - - // MARK: - Methods - - func onSuccess(messageID: String) { - deleteMessageCompletionHandler?.onSuccess(messageID : messageID) - } - - func onFailure(messageID: String, error: DeleteMessageError) { - messageHolder.changingCancelledWith(messageID: messageID, message: message) - deleteMessageCompletionHandler?.onFailure(messageID: messageID, error: error) - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/MessageTrackerImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/MessageTrackerImpl.swift deleted file mode 100644 index 5a80fa6..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Implementation/MessageTrackerImpl.swift +++ /dev/null @@ -1,644 +0,0 @@ -// -// MessageTrackerImpl.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 09.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Class that is responsible for tracking changes of message stream. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class MessageTrackerImpl { - - // MARK: - Properties - private let messageHolder: MessageHolder - var idToHistoryMessageMap = [String: MessageImpl]() - weak var messageListener: MessageListener? - private var allMessageSourcesEnded = false - private var cachedCompletionHandler: MessageHolderCompletionHandlerWrapper? - private var cachedLimit: Int? - private var destroyed: Bool? - private var headMessage: MessageImpl? - private var firstHistoryUpdateReceived: Bool? - private var messagesLoading: Bool? - - // MARK: - Initialization - init(messageListener: MessageListener, - messageHolder: MessageHolder) { - self.messageListener = messageListener - self.messageHolder = messageHolder - } - - // MARK: - Methods - - func addedNew(message: MessageImpl, - of messageHolder: MessageHolder) { - do { - try message.getSource().assertIsCurrentChat() - } catch { - WebimInternalLogger.shared.log(entry: "Message which is being added is not a part of current chat: \(message.toString()).", - verbosityLevel: .DEBUG) - - return - } - - addNewOrMerge(message: message, - of: messageHolder) - - if (headMessage == nil) - || allMessageSourcesEnded { - // FIXME: Do it on endOfBatch only. - if let completionHandler = cachedCompletionHandler { - getNextUncheckedMessagesBy(limit: (cachedLimit ?? 0), - completion: completionHandler.getCompletionHandler()) - - cachedCompletionHandler = nil - } - } - } - - func addedNew(messages: [MessageImpl], - of messageHolder: MessageHolder) { - if !messages.isEmpty { - if (headMessage != nil) - || allMessageSourcesEnded { - for message in messages { - addNewOrMerge(message: message, - of: messageHolder) - } - } else { - var currentChatMessages = messageHolder.getCurrentChatMessages() - currentChatMessages.append(contentsOf: messages) - messageHolder.set(currentChatMessages: currentChatMessages) - - if let completionHandler = cachedCompletionHandler { - getNextUncheckedMessagesBy(limit: (cachedLimit ?? 0), - completion: completionHandler.getCompletionHandler()) - - cachedCompletionHandler = nil - } - } - } - } - - func changedCurrentChatMessage(from previousVersion: MessageImpl, - to newVersion: MessageImpl, - at index: Int, - of messageHolder: MessageHolder) { - do { - try previousVersion.getSource().assertIsCurrentChat() - } catch { - WebimInternalLogger.shared.log(entry: "Message which is being changed is not a part of current chat: \(previousVersion.toString()).", - verbosityLevel: .DEBUG) - - return - } - do { - try newVersion.getSource().assertIsCurrentChat() - } catch { - WebimInternalLogger.shared.log(entry: "Replacement message for a current chat message is not a part of current chat: \(newVersion.toString()).", - verbosityLevel: .DEBUG) - - return - } - - guard let headMessage = headMessage else { - return - } - - if headMessage.getSource().isHistoryMessage() { - if previousVersion == headMessage { - self.headMessage = newVersion - } - - messageListener?.changed(message: previousVersion, - to: newVersion) - } else { - let currentChatMessages = messageHolder.getCurrentChatMessages() - for (currentChatMessageIndex, currentChatMessage) in currentChatMessages.enumerated() { - if currentChatMessage.getID() == headMessage.getID() { - if index >= currentChatMessageIndex { - if previousVersion == headMessage { - self.headMessage = newVersion - } - - messageListener?.changed(message: previousVersion, - to: newVersion) - } - - return - } - } - } - } - - func deletedCurrentChat(message: MessageImpl, - at index: Int, - messageHolder: MessageHolder) { - do { - try message.getSource().assertIsCurrentChat() - } catch { - WebimInternalLogger.shared.log(entry: "Message which is being deleted is not a part of current chat: \(message.toString())", - verbosityLevel: .DEBUG) - } - - let currentChatMessages = messageHolder.getCurrentChatMessages() - - guard let headMessage = headMessage else { - return - } - - let headIndex = currentChatMessages.index(of: headMessage) ?? -1 - - if headMessage.getSource().isHistoryMessage() - || (index > headIndex) { - if headIndex == (index + 1) { - self.headMessage = (currentChatMessages.count < headIndex) ? nil : currentChatMessages[headIndex] - } - - messageListener?.removed(message: message) - } - } - - func endedHistoryBatch() { - guard firstHistoryUpdateReceived != true else { - return - } - - firstHistoryUpdateReceived = true - - if let completionHandler = cachedCompletionHandler { - getNextUncheckedMessagesBy(limit: (cachedLimit ?? 0), - completion: completionHandler.getCompletionHandler()) - - cachedCompletionHandler = nil - } - } - - func deletedHistoryMessage(withID messageID: String) { - guard let message = idToHistoryMessageMap[messageID] else { - return - } - idToHistoryMessageMap[messageID] = nil - - guard let headMessage = headMessage else { - return - } - if headMessage.getSource().isHistoryMessage() - && (message.getTimeInMicrosecond() >= headMessage.getTimeInMicrosecond()) { - messageListener?.removed(message: message) - } - } - - func changedHistory(message: MessageImpl) { - do { - try message.getSource().assertIsHistory() - } catch { - WebimInternalLogger.shared.log(entry: "Message which is being changed is not a part of history: \(message.toString()).", - verbosityLevel: .DEBUG) - } - - guard let headMessage = headMessage, - headMessage.getSource().isHistoryMessage(), - (message.getTimeInMicrosecond() >= headMessage.getTimeInMicrosecond()) else { - return - } - - let previousMessage: MessageImpl? = idToHistoryMessageMap[message.getHistoryID()!.getDBid()] - idToHistoryMessageMap[message.getHistoryID()!.getDBid()] = message - if previousMessage != nil { - messageListener?.changed(message: previousMessage!, - to: message) - } else { - WebimInternalLogger.shared.log(entry: "Unknown message was changed: \(message.toString())", - verbosityLevel: .DEBUG) - } - } - - func addedHistory(message: MessageImpl, - before id: HistoryID?) { - do { - try message.getSource().assertIsHistory() - } catch { - WebimInternalLogger.shared.log(entry: "Message which is being added is not a part of history: \(message.toString()).", - verbosityLevel: .DEBUG) - - return - } - - guard let headMessage = headMessage, - headMessage.getSource().isHistoryMessage() else { - return - } - - if let beforeID = id { - if let beforeMessage = idToHistoryMessageMap[beforeID.getDBid()] { - messageListener?.added(message: message, - after: beforeMessage) - } - } else { - let currentChatMessages = messageHolder.getCurrentChatMessages() - messageListener?.added(message: message, - after: (currentChatMessages.isEmpty ? nil : currentChatMessages.last!)) - } - - idToHistoryMessageMap[message.getHistoryID()!.getDBid()] = message - } - - // For testing purposes. - func set(messagesLoading: Bool) { - self.messagesLoading = messagesLoading - } - - // MARK: Private methods - - private func addNewOrMerge(message: MessageImpl, - of messageHolder: MessageHolder) { - do { - try message.getSource().assertIsCurrentChat() - } catch { - WebimInternalLogger.shared.log(entry: "Message which is being added is not a part of current chat: \(message.toString()).", - verbosityLevel: .DEBUG) - - return - } - - var toCallMessageAdded = true - - var currentChatMessages = messageHolder.getCurrentChatMessages() - - if headMessage == nil { - headMessage = message - } else if (headMessage!.getTimeInMicrosecond()) > message.getTimeInMicrosecond() { - toCallMessageAdded = false - - currentChatMessages.append(message) - } else { - for (historyID, historyMessage) in idToHistoryMessageMap { - if message.getID() == historyMessage.getID() { - toCallMessageAdded = false - - let replacingMessage = historyMessage.transferToCurrentChat(message: message) - currentChatMessages.append(replacingMessage) - if (replacingMessage != historyMessage) { - messageListener?.changed(message: historyMessage, - to: replacingMessage) - } - - idToHistoryMessageMap[historyID] = nil - - break - } - } - } - - if toCallMessageAdded { - for (currentChatMessageIndex, currentChatMessage) in currentChatMessages.enumerated() { - if currentChatMessage.getID() == message.getID() { - currentChatMessages[currentChatMessageIndex] = message - messageListener?.changed(message: currentChatMessage, - to: message) - messageHolder.set(currentChatMessages: currentChatMessages) - - break - } - } - - currentChatMessages.append(message) - - if let messageToSend = getToSendMirrorAndRemove(message: message, - of: messageHolder) { - messageListener?.changed(message: messageToSend, - to: message) - } else { - let messagesToSend = messageHolder.getMessagesToSend() - messageListener?.added(message: message, - after: (messageHolder.getMessagesToSend().isEmpty ? nil : messagesToSend.first!)) - } - } - - messageHolder.set(currentChatMessages: currentChatMessages) - } - - private func getToSendMirrorAndRemove(message: MessageImpl, - of messageHolder: MessageHolder) -> MessageToSend? { - var messagesToSend = messageHolder.getMessagesToSend() - - for i in 0.. ()) { - let completionHandler = { [weak self] (messages: [Message]) -> () in - self?.receive(messages: messages as! [MessageImpl], - limit: limit, - completion: completion) - - self?.messagesLoading = false - } - - if headMessage != nil { - messageHolder.getMessagesBy(limit: limit, - before: headMessage!, - completion: completionHandler) - } else { - messageHolder.getLatestMessages(byLimit: limit, - completion: completionHandler) - } - } - - private func receive(messages: [MessageImpl], - limit: Int, - completion: @escaping ([Message]) -> ()) { - var result: [MessageImpl]? - - if !messages.isEmpty { - let currentChatMessages = messageHolder.getCurrentChatMessages() - if !currentChatMessages.isEmpty { - if (messages.last!.getTime() >= currentChatMessages.first!.getTime()) { - // We received history that overlap current chat messages. Merging. - - var filteredMessages = [MessageImpl]() - - let firstMessage = messages.first! - - for message in messages { - var addToFilteredMessages = true - - if message.getSource().isHistoryMessage() { - let messageTime = message.getTime() - if (messageTime >= currentChatMessages.first!.getTime()) - && (messageTime <= currentChatMessages.last!.getTime()) { - for currentChatMessage in currentChatMessages { - if currentChatMessage.getID() == message.getID() { - addToFilteredMessages = false - - currentChatMessage.setSecondaryHistory(historyEquivalentMessage: message) - - break - } - } - } - } - - if addToFilteredMessages { - filteredMessages.append(message) - } - } - - if filteredMessages.isEmpty { - let completionHandler = { [weak self] (messages: [Message]) -> () in - self?.receive(messages: messages as! [MessageImpl], - limit: limit, - completion: completion) - - self?.messagesLoading = false - } - messageHolder.getMessagesBy(limit: limit, - before: firstMessage, - completion: completionHandler) - - return - } - - result = filteredMessages - } else { - result = messages - } - } else { - result = messages - } - - for message in messages { - if message.getSource().isHistoryMessage() { - idToHistoryMessageMap[message.getHistoryID()!.getDBid()] = message - } - } - - let firstMessage = result!.first! - - if headMessage == nil { - headMessage = firstMessage - } else if firstMessage.getTimeInMicrosecond() < headMessage!.getTimeInMicrosecond() { - headMessage = firstMessage - } - } else { // End `if !messages.isEmpty` - result = messages - - allMessageSourcesEnded = true - } - - completion(result!) - } - -} - -// MARK: - MessageTracker -extension MessageTrackerImpl: MessageTracker { - - func getLastMessages(byLimit limitOfMessages: Int, - completion: @escaping ([Message]) -> ()) throws { - try messageHolder.checkAccess() - guard destroyed != true else { - WebimInternalLogger.shared.log(entry: "MessageTracker object is destroyed. Unable to perform request to get new messages.") - completion([Message]()) - - return - } - guard messagesLoading != true else { - WebimInternalLogger.shared.log(entry: "Messages are already loading. Unable to perform a second request to get new messages.") - completion([Message]()) - - return - } - guard limitOfMessages > 0 else { - WebimInternalLogger.shared.log(entry: "Limit of messages to perform request to get new messages must be greater that zero. Passed value – \(limitOfMessages).") - completion([Message]()) - - return - } - - let wrappedCompletion: ([Message]) -> () = { [weak self] messages in - (self?.destroyed != false) ? completion(messages) : completion([Message]()) - } - - let currentChatMessages = messageHolder.getCurrentChatMessages() - if currentChatMessages.isEmpty { - messagesLoading = true - - cachedCompletionHandler = MessageHolderCompletionHandlerWrapper(completionHandler: wrappedCompletion) - cachedLimit = limitOfMessages - - messageHolder.getHistoryStorage().getLatestHistory(byLimit: limitOfMessages) { [weak self] messages in - if let cachedCompletionHandler = self?.cachedCompletionHandler, - !messages.isEmpty || self?.firstHistoryUpdateReceived == true { - self?.firstHistoryUpdateReceived = true - - let completionHandlerToPass = cachedCompletionHandler.getCompletionHandler() - self?.receive(messages: messages as! [MessageImpl], - limit: limitOfMessages, - completion: completionHandlerToPass) - - self?.cachedCompletionHandler = nil - - self?.messagesLoading = false - } - } - } else { - let result = Array(currentChatMessages.suffix(limitOfMessages)) - headMessage = result.first - - wrappedCompletion(result) - } - } - - func getNextMessages(byLimit limitOfMessages: Int, - completion: @escaping ([Message]) -> ()) throws { - try messageHolder.checkAccess() - guard destroyed != true else { - WebimInternalLogger.shared.log(entry: "MessageTracker object is destroyed. Unable to perform request to get new messages.") - completion([Message]()) - - return - } - guard messagesLoading != true else { - WebimInternalLogger.shared.log(entry: "Messages are already loading. Unable to perform a second request to get new messages.") - completion([Message]()) - - return - } - guard limitOfMessages > 0 else { - WebimInternalLogger.shared.log(entry: "Limit of messages to perform request to get new messages must be greater that zero. Passed value – \(limitOfMessages).") - completion([Message]()) - - return - } - - let wrappedCompletion: ([Message]) -> () = { [weak self] messages in - (self?.destroyed != false) ? completion(messages) : completion([Message]()) - } - - messagesLoading = true - - let currentChatMessages = messageHolder.getCurrentChatMessages() - if (firstHistoryUpdateReceived == true) - || (!currentChatMessages.isEmpty - && (currentChatMessages.first != headMessage)) { - getNextUncheckedMessagesBy(limit: limitOfMessages, - completion: wrappedCompletion) - } else { - cachedCompletionHandler = MessageHolderCompletionHandlerWrapper(completionHandler: wrappedCompletion) - cachedLimit = limitOfMessages - - messageHolder.getHistoryStorage().getLatestHistory(byLimit: limitOfMessages) { [weak self] messages in - if let cachedCompletionHandler = self?.cachedCompletionHandler, - !messages.isEmpty || self?.firstHistoryUpdateReceived == true { - self?.firstHistoryUpdateReceived = true - - let completionHandlerToPass = cachedCompletionHandler.getCompletionHandler() - self?.receive(messages: messages as! [MessageImpl], - limit: limitOfMessages, - completion: completionHandlerToPass) - - self?.cachedCompletionHandler = nil - - self?.messagesLoading = false - } - } - } - } - - func getAllMessages(completion: @escaping ([Message]) -> ()) throws { - try messageHolder.checkAccess() - guard destroyed != true else { - WebimInternalLogger.shared.log(entry: "MessageTracker object is destroyed. Unable to perform request to get new messages.") - completion([Message]()) - - return - } - - let wrappedCompletion: ([Message]) -> () = { [weak self] messages in - (self?.destroyed != false) ? completion(messages) : completion([Message]()) - } - - messageHolder.getHistoryStorage().getFullHistory(completion: wrappedCompletion) - } - - func resetTo(message: Message) throws { - try messageHolder.checkAccess() - guard destroyed != true else { - WebimInternalLogger.shared.log(entry: "MessageTracker object was destroyed. Unable to perform a request to reset to a message.") - - return - } - guard messagesLoading != true else { - WebimInternalLogger.shared.log(entry: "Messages is loading. Unable to perform a simultaneous request to reset to a message.") - - return - } - - let unwrappedMessage = message as! MessageImpl - if unwrappedMessage != headMessage { - messageHolder.set(reachedEndOfLocalHistory: false) - } - if unwrappedMessage.getSource().isHistoryMessage() { - var newIDToHistoryMessageMap = [String: MessageImpl]() - for (id, iteratedMessage) in idToHistoryMessageMap { - if iteratedMessage.getTimeInMicrosecond() >= unwrappedMessage.getTimeInMicrosecond() { - newIDToHistoryMessageMap[id] = iteratedMessage - } - } - idToHistoryMessageMap = newIDToHistoryMessageMap - } else { - idToHistoryMessageMap.removeAll() - } - - headMessage = unwrappedMessage - } - - func destroy() throws { - try messageHolder.checkAccess() - - if destroyed != true { - destroyed = true - - messageHolder.set(messagesToSend: [MessageToSend]()) - - messageHolder.set(messageTracker: nil) - } - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/OperatorImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/OperatorImpl.swift deleted file mode 100644 index d5f34bb..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Implementation/OperatorImpl.swift +++ /dev/null @@ -1,84 +0,0 @@ -// -// OperatorImpl.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 17.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Internal representation of a chat operator data. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -struct OperatorImpl: Operator { - - // MARK: - Properties - private let id: String - private let name: String - private let avatarURLString: String? - - // MARK: - Initialization - init(id: String, - name: String, - avatarURLString: String? = nil) { - self.id = id - self.name = name - self.avatarURLString = avatarURLString - } - - // MARK: - Methods - // MARK: Operator protocol methods - - func getID() -> String { - return id - } - - func getName() -> String { - return name - } - - func getAvatarURL() -> URL? { - guard let avatarURLString = avatarURLString else { - return nil - } - - return URL(string: avatarURLString) - } - -} - -// MARK: - Equatable -extension OperatorImpl: Equatable { - - // MARK: - Methods - static func == (lhs: OperatorImpl, - rhs: OperatorImpl) -> Bool { - return ((lhs.id == rhs.id) - && (lhs.name == rhs.name)) - && (lhs.avatarURLString == rhs.avatarURLString) - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/WebimErrorImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/WebimErrorImpl.swift deleted file mode 100644 index 4da19fb..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Implementation/WebimErrorImpl.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// WebimErrorImpl.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 09.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Public Webim service error representation. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class WebimErrorImpl: WebimError { - - // MARK: - Properties - private var errorType: FatalErrorType - private var errorString: String? - - // MARK: - Initialization - init(errorType: FatalErrorType, - errorString: String?) { - self.errorType = errorType - self.errorString = errorString - } - - // MARK: - Methods - // MARK: WebimError protocol methods - - func getErrorType() -> FatalErrorType { - return errorType - } - - func getErrorString() -> String { - return (errorString ?? String(describing: errorType)) - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/WebimRemoteNotificationImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/WebimRemoteNotificationImpl.swift deleted file mode 100644 index 8ea4dcc..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Implementation/WebimRemoteNotificationImpl.swift +++ /dev/null @@ -1,125 +0,0 @@ -// -// WebimRemoteNotificationImpl.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 09.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class WebimRemoteNotificationImpl { - - // MARK: - Constants - enum APNSField: String { - case aps = "aps" - case webim = "webim" - } - enum APSField: String { - case alert = "alert" - } - private enum AlertField: String { - case event = "event" - case parameters = "loc-args" - case type = "loc-key" - } - private enum InternalNotificationEvent: String { - case add = "add" - case delete = "del" - } - private enum InternalNotificationType: String { - case contactInformationRequest = "P.CR" - case operatorAccepted = "P.OA" - case operatorFile = "P.OF" - case operatorMessage = "P.OM" - case widget = "P.WM" - } - - // MARK: - Properties - private var event: InternalNotificationEvent? = nil - private lazy var parameters = [String]() - private var type: InternalNotificationType - - // MARK: - Initialization - init?(jsonDictionary: [String: Any?]) { - guard let typeString = jsonDictionary[AlertField.type.rawValue] as? String, - let type = InternalNotificationType(rawValue: typeString) else { - return nil - } - self.type = type - - if let eventString = jsonDictionary[AlertField.event.rawValue] as? String, - let event = InternalNotificationEvent(rawValue: eventString) { - self.event = event - } - - if let parameters = jsonDictionary[AlertField.parameters.rawValue] as? [String] { - self.parameters = parameters - } - } - -} - -// MARK: - WebimRemoteNotification -extension WebimRemoteNotificationImpl: WebimRemoteNotification { - - // MARK: - Methods - // MARK: WebimRemoteNotification protocol methods - - func getType() -> NotificationType { - switch type { - case .contactInformationRequest: - return .CONTACT_INFORMATION_REQUEST - case .operatorAccepted: - return .OPERATOR_ACCEPTED - case .operatorFile: - return .OPERATOR_FILE - case .operatorMessage: - return .OPERATOR_MESSAGE - case .widget: - return .WIDGET - } - } - - func getEvent() -> NotificationEvent? { - if let event = event { - switch event { - case .add: - return .ADD - case .delete: - return .DELETE - } - } - - return nil - } - - func getParameters() -> [String] { - return parameters - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Implementation/WebimSessionImpl.swift b/ios/libs/Webim/WebimClientLibrary/Implementation/WebimSessionImpl.swift deleted file mode 100644 index ae2ac75..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Implementation/WebimSessionImpl.swift +++ /dev/null @@ -1,765 +0,0 @@ -// -// WebimSessionImpl.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 02.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation -import UIKit - -// MARK: - Constants -fileprivate enum UserDefaultsName: String { - case guid = "ru.webim.WebimClientSDKiOS.guid" - case main = "ru.webim.WebimClientSDKiOS.visitor." -} -fileprivate enum UserDefaultsMainPrefix: String { - case authorizationToken = "auth_token" - case dbVersion = "db_version" - case deviceToken = "push_token" - case historyEnded = "history_ended" - case historyDBname = "history_db_name" - case historyMajorVersion = "history_major_version" - case historyRevision = "history_revision" - case pageID = "page_id" - case readBeforeTimestamp = "read_before_timestamp" - case sessionID = "session_id" - case visitor = "visitor" - case visitorExt = "visitor_ext" -} -fileprivate enum UserDefaultsGUIDPrefix: String { - case uuid = "guid" -} - -// MARK: - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class WebimSessionImpl { - - // MARK: - Constants - private enum DefaultSettings: String { - case pageTitle = "iOS Client" - } - - // MARK: - Properties - private var accessChecker: AccessChecker - private var clientStarted = false - private var historyPoller: HistoryPoller - private var messageStream: MessageStreamImpl - private var sessionDestroyer: SessionDestroyer - private var webimClient: WebimClient - - // MARK: - Initialization - private init(accessChecker: AccessChecker, - sessionDestroyer: SessionDestroyer, - webimClient: WebimClient, - historyPoller: HistoryPoller, - messageStream: MessageStreamImpl) { - self.accessChecker = accessChecker - self.sessionDestroyer = sessionDestroyer - self.webimClient = webimClient - self.historyPoller = historyPoller - self.messageStream = messageStream - } - - // MARK: - Methods - - static func newInstanceWith(accountName: String, - location: String, - appVersion: String?, - visitorFields: ProvidedVisitorFields?, - providedAuthorizationTokenStateListener: ProvidedAuthorizationTokenStateListener?, - providedAuthorizationToken: String?, - pageTitle: String?, - fatalErrorHandler: FatalErrorHandler?, - deviceToken: String?, - isLocalHistoryStoragingEnabled: Bool, - isVisitorDataClearingEnabled: Bool, - webimLogger: WebimLogger?, - verbosityLevel: SessionBuilder.WebimLoggerVerbosityLevel?, - prechat: String?) -> WebimSessionImpl { - WebimInternalLogger.setup(webimLogger: webimLogger, - verbosityLevel: verbosityLevel) - - let queue = DispatchQueue.global(qos: .userInteractive) - - let userDefaultsKey = UserDefaultsName.main.rawValue + (visitorFields?.getID() ?? "anonymous") - let userDefaults = UserDefaults.standard.dictionary(forKey: userDefaultsKey) - - if isVisitorDataClearingEnabled { - clearVisitorDataFor(userDefaultsKey: userDefaultsKey) - } - - checkSavedSessionFor(userDefaultsKey: userDefaultsKey, - newProvidedVisitorFields: visitorFields) - - let sessionDestroyer = SessionDestroyer(userDefaultsKey: userDefaultsKey) - - let visitorJSON = (userDefaults?[UserDefaultsMainPrefix.visitor.rawValue] ?? nil) - - let visitorFieldsJSONString = visitorFields?.getJSONString() - - let serverURLString = InternalUtils.createServerURLStringBy(accountName: accountName) - WebimInternalLogger.shared.log(entry: "Specified Webim server – \(serverURLString).", - verbosityLevel: .DEBUG) - - let currentChatMessageMapper: MessageMapper = CurrentChatMessageMapper(withServerURLString: serverURLString) - - let sessionID = userDefaults?[UserDefaultsMainPrefix.sessionID.rawValue] ?? nil - - let pageID = userDefaults?[UserDefaultsMainPrefix.pageID.rawValue] as! String? - let authorizationToken = userDefaults?[UserDefaultsMainPrefix.authorizationToken.rawValue] as! String? - let authorizationData = AuthorizationData(pageID: pageID, - authorizationToken: authorizationToken) - - let deltaCallback = DeltaCallback(currentChatMessageMapper: currentChatMessageMapper) - - let webimClient = WebimClientBuilder() - .set(baseURL: serverURLString) - .set(location: location) - .set(appVersion: appVersion) - .set(visitorFieldsJSONString: visitorFieldsJSONString) - .set(deltaCallback: deltaCallback) - .set(sessionParametersListener: SessionParametersListenerImpl(withUserDefaultsKey: userDefaultsKey)) - .set(internalErrorListener: DestroyOnFatalErrorListener(sessionDestroyer: sessionDestroyer, - internalErrorListener: ErrorHandlerToInternalAdapter(fatalErrorHandler: fatalErrorHandler))) - .set(visitorJSONString: visitorJSON as! String?) - .set(providedAuthenticationTokenStateListener: providedAuthorizationTokenStateListener, - providedAuthenticationToken: providedAuthorizationToken) - .set(sessionID: sessionID as! String?) - .set(authorizationData: authorizationData) - .set(completionHandlerExecutor: ExecIfNotDestroyedHandlerExecutor(sessionDestroyer: sessionDestroyer, - queue: queue)) - .set(title: (pageTitle ?? DefaultSettings.pageTitle.rawValue)) - .set(deviceToken: deviceToken) - .set(deviceID: getDeviceID()) - .set(prechat: prechat) - .build() as WebimClient - - var historyStorage: HistoryStorage - var historyMetaInformationStoragePreferences: HistoryMetaInformationStorage - if isLocalHistoryStoragingEnabled { - var dbName = userDefaults?[UserDefaultsMainPrefix.historyDBname.rawValue] as? String - - if dbName == nil { - dbName = "webim_" + ClientSideID.generateClientSideID() + ".db" - if let userDefaults = userDefaults { - var renewedUserDefaults = userDefaults - renewedUserDefaults[UserDefaultsMainPrefix.historyDBname.rawValue] = dbName - UserDefaults.standard.set(renewedUserDefaults, - forKey: userDefaultsKey) - } else { - UserDefaults.standard.setValue([UserDefaultsMainPrefix.historyDBname.rawValue: dbName], - forKey: userDefaultsKey) - } - } - - historyMetaInformationStoragePreferences = HistoryMetaInformationStoragePreferences(userDefaultsKey: userDefaultsKey) - - let sqlhistoryStorage = SQLiteHistoryStorage(dbName: dbName!, - serverURL: serverURLString, - webimClient: webimClient, - reachedHistoryEnd: historyMetaInformationStoragePreferences.isHistoryEnded(), - queue: queue, - readBeforeTimestamp: Int64(UserDefaults.standard.integer(forKey: UserDefaultsMainPrefix.readBeforeTimestamp.rawValue))) - historyStorage = sqlhistoryStorage - - let historyMajorVersion = historyStorage.getMajorVersion() - if (userDefaults?[UserDefaultsMainPrefix.historyMajorVersion.rawValue] as? Int) != historyMajorVersion { - if var userDefaults = UserDefaults.standard.dictionary(forKey: userDefaultsKey) { - userDefaults.removeValue(forKey: UserDefaultsMainPrefix.historyRevision.rawValue) - userDefaults.removeValue(forKey: UserDefaultsMainPrefix.historyEnded.rawValue) - userDefaults.removeValue(forKey: UserDefaultsMainPrefix.historyMajorVersion.rawValue) - UserDefaults.standard.setValue(userDefaults, - forKey: userDefaultsKey) - } - } - - if (userDefaults?[UserDefaultsMainPrefix.dbVersion.rawValue] as? Int) != sqlhistoryStorage.getVersionDB() { - sqlhistoryStorage.updateDB() - UserDefaults.standard.set(sqlhistoryStorage.getVersionDB(), forKey: UserDefaultsMainPrefix.dbVersion.rawValue) - } - } else { - historyStorage = MemoryHistoryStorage(readBeforeTimestamp: Int64(UserDefaults.standard.integer(forKey: UserDefaultsMainPrefix.readBeforeTimestamp.rawValue))) - historyMetaInformationStoragePreferences = MemoryHistoryMetaInformationStorage() - } - - let accessChecker = AccessChecker(thread: Thread.current, - sessionDestroyer: sessionDestroyer) - - let webimActions = webimClient.getActions() - let historyMessageMapper: MessageMapper = HistoryMessageMapper(withServerURLString: serverURLString) - let messageHolder = MessageHolder(accessChecker: accessChecker, - remoteHistoryProvider: RemoteHistoryProvider(webimActions: webimActions, - historyMessageMapper: historyMessageMapper, - historyMetaInformationStorage: historyMetaInformationStoragePreferences), - historyStorage: historyStorage, - reachedEndOfRemoteHistory: historyMetaInformationStoragePreferences.isHistoryEnded()) - let messageStream = MessageStreamImpl(serverURLString: serverURLString, - currentChatMessageFactoriesMapper: currentChatMessageMapper, - sendingMessageFactory: SendingFactory(withServerURLString: serverURLString), - operatorFactory: OperatorFactory(withServerURLString: serverURLString), - accessChecker: accessChecker, - webimActions: webimActions, - messageHolder: messageHolder, - messageComposingHandler: MessageComposingHandler(webimActions: webimActions, - queue: queue), - locationSettingsHolder: LocationSettingsHolder(userDefaultsKey: userDefaultsKey)) - - let historyPoller = HistoryPoller(withSessionDestroyer: sessionDestroyer, - queue: queue, - historyMessageMapper: historyMessageMapper, - webimActions: webimActions, - messageHolder: messageHolder, - historyMetaInformationStorage: historyMetaInformationStoragePreferences) - - deltaCallback.set(messageStream: messageStream, - messageHolder: messageHolder, - historyPoller: historyPoller) - - sessionDestroyer.add() { - webimClient.stop() - } - sessionDestroyer.add() { - historyPoller.pause() - } - - // Needed for message attachment secure download link generation. - currentChatMessageMapper.set(webimClient: webimClient) - historyMessageMapper.set(webimClient: webimClient) - - return WebimSessionImpl(accessChecker: accessChecker, - sessionDestroyer: sessionDestroyer, - webimClient: webimClient, - historyPoller: historyPoller, - messageStream: messageStream) - } - - // MARK: Private methods - - private static func clearVisitorDataFor(userDefaultsKey: String) { - deleteDBFileFor(userDefaultsKey: userDefaultsKey) - UserDefaults.standard.removeObject(forKey: userDefaultsKey) - } - - private static func deleteDBFileFor(userDefaultsKey: String) { - if let dbName = UserDefaults.standard.dictionary(forKey: userDefaultsKey)?[UserDefaultsMainPrefix.historyDBname.rawValue] as? String { - let fileManager = FileManager.default - let documentsDirectory = try! fileManager.url(for: .documentDirectory, - in: .userDomainMask, - appropriateFor: nil, - create: false) - let dbURL = documentsDirectory.appendingPathComponent(dbName) - - do { - try fileManager.removeItem(at: dbURL) - } catch { - WebimInternalLogger.shared.log(entry: "Error deleting DB file at \(dbURL) or file doesn't exist.", - verbosityLevel: .VERBOSE) - } - } - } - - private static func checkSavedSessionFor(userDefaultsKey: String, - newProvidedVisitorFields: ProvidedVisitorFields?) { - let newVisitorFieldsJSONString = newProvidedVisitorFields?.getJSONString() - let previousVisitorFieldsJSONString = UserDefaults.standard.dictionary(forKey: userDefaultsKey)?[UserDefaultsMainPrefix.visitorExt.rawValue] as? String - - var previousProvidedVisitorFields: ProvidedVisitorFields? = nil - if previousVisitorFieldsJSONString != nil { - previousProvidedVisitorFields = ProvidedVisitorFields(withJSONString: previousVisitorFieldsJSONString!) - - if (newProvidedVisitorFields == nil) - || (previousProvidedVisitorFields?.getID() != newProvidedVisitorFields?.getID()) { - clearVisitorDataFor(userDefaultsKey: userDefaultsKey) - } - } - - if newVisitorFieldsJSONString != previousVisitorFieldsJSONString { - UserDefaults.standard.removeObject(forKey: userDefaultsKey) - - let newVisitorFieldsDictionary = [UserDefaultsMainPrefix.visitorExt.rawValue: newVisitorFieldsJSONString] - UserDefaults.standard.set(newVisitorFieldsDictionary, - forKey: userDefaultsKey) - } - } - - private static func getDeviceID() -> String { - let userDefaults = UserDefaults.standard.dictionary(forKey: UserDefaultsName.guid.rawValue) - var uuidString = (userDefaults?[UserDefaultsGUIDPrefix.uuid.rawValue] ?? nil) - - if uuidString == nil { - uuidString = UIDevice.current.identifierForVendor!.uuidString - if var userDefaults = UserDefaults.standard.dictionary(forKey: UserDefaultsName.guid.rawValue) { - userDefaults[UserDefaultsGUIDPrefix.uuid.rawValue] = uuidString - UserDefaults.standard.set(userDefaults, - forKey: UserDefaultsName.guid.rawValue) - } else { - UserDefaults.standard.setValue([UserDefaultsGUIDPrefix.uuid.rawValue: uuidString], - forKey: UserDefaultsName.guid.rawValue) - } - } - - return uuidString as! String - } - -} - -// MARK: - WebimSession -extension WebimSessionImpl: WebimSession { - - func resume() throws { - try checkAccess() - - if !clientStarted { - webimClient.start() - clientStarted = true - } - - webimClient.resume() - historyPoller.resume() - } - - func pause() throws { - if sessionDestroyer.isDestroyed() { - return - } - - try checkAccess() - - webimClient.pause() - historyPoller.pause() - } - - func destroy() throws { - if sessionDestroyer.isDestroyed() { - return - } - - try checkAccess() - - sessionDestroyer.destroy() - } - - func destroyWithClearVisitorData() throws { - if sessionDestroyer.isDestroyed() { - return - } - - try checkAccess() - - sessionDestroyer.destroy() - WebimSessionImpl.clearVisitorDataFor(userDefaultsKey: sessionDestroyer.getUserDefaulstKey()) - } - - func getStream() -> MessageStream { - return messageStream - } - - func change(location: String) throws { - try checkAccess() - - try webimClient.getDeltaRequestLoop().change(location: location) - } - - func set(deviceToken: String) throws { - try checkAccess() - - webimClient.set(deviceToken: deviceToken) - } - - - // MARK: Private methods - private func checkAccess() throws { - try accessChecker.checkAccess() - } - -} - -// MARK: - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class HistoryPoller { - - // MARK: - Constants - private enum TimeInterval: Int64 { - case historyPolling = 60_000 // ms - } - - // MARK: - Properties - private let historyMessageMapper: MessageMapper - private let historyMetaInformationStorage: HistoryMetaInformationStorage - private let queue: DispatchQueue - private let messageHolder: MessageHolder - private let sessionDestroyer: SessionDestroyer - private let webimActions: WebimActions - private var dispatchWorkItem: DispatchWorkItem? - private var historySinceCompletionHandler: ((_ messageList: [MessageImpl], _ deleted: Set, _ hasMore: Bool, _ isInitial: Bool, _ revision: String?) -> ())? - private var lastPollingTime = -TimeInterval.historyPolling.rawValue - private var lastRevision: String? - private var running: Bool? - private var hasHistoryRevision = false - - // MARK: - Initialization - init(withSessionDestroyer sessionDestroyer: SessionDestroyer, - queue: DispatchQueue, - historyMessageMapper: MessageMapper, - webimActions: WebimActions, - messageHolder: MessageHolder, - historyMetaInformationStorage: HistoryMetaInformationStorage) { - self.sessionDestroyer = sessionDestroyer - self.queue = queue - self.historyMessageMapper = historyMessageMapper - self.webimActions = webimActions - self.messageHolder = messageHolder - self.historyMetaInformationStorage = historyMetaInformationStorage - } - - // MARK: - Methods - - func pause() { - dispatchWorkItem?.cancel() - dispatchWorkItem = nil - - running = false - } - - func resume() { - pause() - - running = true - - historySinceCompletionHandler = createHistorySinceCompletionHandler() - - let uptime = Int64(ProcessInfo.processInfo.systemUptime) * 1000 - if (uptime - lastPollingTime) > TimeInterval.historyPolling.rawValue { - requestHistory(since: lastRevision, - completion: historySinceCompletionHandler!) - } else { - if !self.hasHistoryRevision { - // Setting next history polling in TimeInterval.HISTORY_POLL after lastPollingTime. - - let dispatchTime = DispatchTime(uptimeNanoseconds: (UInt64((lastPollingTime + TimeInterval.historyPolling.rawValue) * 1_000_000) - UInt64((uptime) * 1_000_000))) - - dispatchWorkItem = DispatchWorkItem() { [weak self] in - guard let `self` = self else { - return - } - - self.requestHistory(since: self.lastRevision, - completion: self.historySinceCompletionHandler!) - } - - queue.asyncAfter(deadline: dispatchTime, - execute: dispatchWorkItem!) - } - } - } - - func set(hasHistoryRevision: Bool) { - self.hasHistoryRevision = hasHistoryRevision - } - - func updateReadBeforeTimestamp(timestamp: Int64) { - self.messageHolder.updateReadBeforeTimestamp(timestamp: timestamp) - } - - // MARK: Private methods - - private func createHistorySinceCompletionHandler() -> (_ messageList: [MessageImpl], _ deleted: Set, _ hasMore: Bool, _ isInitial: Bool, _ revision: String?) -> () { - return { [weak self] (messageList: [MessageImpl], deleted: Set, hasMore: Bool, isInitial: Bool, revision: String?) in - guard let `self` = self, - !self.sessionDestroyer.isDestroyed() else { - return - } - - self.lastPollingTime = Int64(ProcessInfo.processInfo.systemUptime) * 1000 - self.lastRevision = revision - - if isInitial - && !hasMore { - self.messageHolder.set(reachedEndOfLocalHistory: true) - self.historyMetaInformationStorage.set(historyEnded: true) - } - - self.messageHolder.receiveHistoryUpdateWith(messages: messageList, - deleted: deleted, - completion: { [weak self] in - // Revision is saved after history is saved only. - // I.e. if history will not be saved, then revision will not be overwritten. History will be re-requested. - self?.historyMetaInformationStorage.set(revision: revision) - }) - - if self.running != true { - if !isInitial - && hasMore { - self.lastPollingTime = -TimeInterval.historyPolling.rawValue - } - - return - } - - if !isInitial && hasMore { - self.requestHistory(since: revision, - completion: self.createHistorySinceCompletionHandler()) - } else { - if !self.hasHistoryRevision { - self.dispatchWorkItem = DispatchWorkItem() { [weak self] in - guard let `self` = self, self.hasHistoryRevision == false else { - return - } - self.requestHistory(since: revision, - completion: self.createHistorySinceCompletionHandler()) - - - } - let interval = Int(TimeInterval.historyPolling.rawValue) - self.queue.asyncAfter(deadline: (.now() + .milliseconds(interval)), - execute: self.dispatchWorkItem!) - } - } - } - } - - public func requestHistory(since: String) { - if self.lastRevision == nil || self.lastRevision != since { - requestHistory(since: lastRevision, completion: historySinceCompletionHandler!) - } - } - - private func requestHistory(since: String?, - completion: @escaping (_ messageList: [MessageImpl], _ deleted: Set, _ hasMore: Bool, _ isInitial: Bool, _ revision: String?) -> ()) { - webimActions.requestHistory(since: since) { data in - if data != nil { - let json = try? JSONSerialization.jsonObject(with: data!, - options: []) - if let historySinceResponseDictionary = json as? [String: Any?] { - let historySinceResponse = HistorySinceResponse(jsonDictionary: historySinceResponseDictionary) - - var deletes = Set() - var messageChanges = [MessageItem]() - - if let messages = historySinceResponse.getData()?.getMessages() { - for message in messages { - if message.isDeleted() { - if let id = message.getID() { - deletes.insert(id) - } - } else { - messageChanges.append(message) - } - } - } - - completion(self.historyMessageMapper.mapAll(messages: messageChanges), deletes, (historySinceResponse.getData()?.isHasMore() == true), (since == nil), historySinceResponse.getData()?.getRevision()) - } - } else { - completion([MessageImpl](), Set(), false, (since == nil), since) - } - } - } - -} - -// MARK: - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final class SessionParametersListenerImpl: SessionParametersListener { - - // MARL: - Constants - private enum VisitorFieldsJSONField: String { - case id = "id" - } - - // MARK: - Properties - private let userDefaultsKey: String - - // MARK: - Initialization - init(withUserDefaultsKey userDefaultsKey: String) { - self.userDefaultsKey = userDefaultsKey - } - - // MARK: - Methods - // MARK: SessionParametersListener methods - func onSessionParametersChanged(visitorFieldsJSONString: String, - sessionID: String, - authorizationData: AuthorizationData) { - if var userDefaults = UserDefaults.standard.dictionary(forKey: userDefaultsKey) { - userDefaults[UserDefaultsMainPrefix.visitor.rawValue] = visitorFieldsJSONString - userDefaults[UserDefaultsMainPrefix.sessionID.rawValue] = sessionID - userDefaults[UserDefaultsMainPrefix.pageID.rawValue] = authorizationData.getPageID() - userDefaults[UserDefaultsMainPrefix.authorizationToken.rawValue] = authorizationData.getAuthorizationToken() - UserDefaults.standard.set(userDefaults, - forKey: userDefaultsKey) - } else { - UserDefaults.standard.setValue([UserDefaultsMainPrefix.visitor.rawValue: visitorFieldsJSONString, - UserDefaultsMainPrefix.sessionID.rawValue: sessionID, - UserDefaultsMainPrefix.pageID.rawValue: authorizationData.getPageID(), - UserDefaultsMainPrefix.authorizationToken.rawValue: authorizationData.getAuthorizationToken()], - forKey: userDefaultsKey) - } - } - -} - -// MARK: - -/** - Class that responsible on destroying session on service fatal error occured. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final private class DestroyOnFatalErrorListener: InternalErrorListener { - - // MARK: - Properties - private let internalErrorListener: InternalErrorListener? - private var sessionDestroyer: SessionDestroyer - - // MARK: - Initialization - init(sessionDestroyer: SessionDestroyer, - internalErrorListener: InternalErrorListener?) { - self.sessionDestroyer = sessionDestroyer - self.internalErrorListener = internalErrorListener - } - - // MARK: - Methods - // MARK: InternalErrorListener protocol methods - func on(error: String) { - if !sessionDestroyer.isDestroyed() { - sessionDestroyer.destroy() - - internalErrorListener?.on(error: error) - } - } - -} - -// MARK: - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final private class ErrorHandlerToInternalAdapter: InternalErrorListener { - - // MARK: - Parameters - private var fatalErrorHandler: FatalErrorHandler? - - // MARK: - Initialization - init(fatalErrorHandler: FatalErrorHandler?) { - self.fatalErrorHandler = fatalErrorHandler - } - - // MARK: - Methods - - // MARK: InternalErrorListener protocol methods - func on(error: String) { - let webimError = WebimErrorImpl(errorType: toPublicErrorType(string: error), - errorString: error) - fatalErrorHandler?.on(error: webimError) - } - - // MARK: Private methods - private func toPublicErrorType(string: String) -> FatalErrorType { - switch string { - case WebimInternalError.accountBlocked.rawValue: - return .ACCOUNT_BLOCKED - case WebimInternalError.visitorBanned.rawValue: - return .VISITOR_BANNED - case WebimInternalError.wrongProvidedVisitorFieldsHashValue.rawValue: - return .WRONG_PROVIDED_VISITOR_HASH - case WebimInternalError.providedVisitorFieldsExpired.rawValue: - return .PROVIDED_VISITOR_FIELDS_EXPIRED - default: - return .UNKNOWN - } - } - -} - -// MARK: - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -final private class HistoryMetaInformationStoragePreferences: HistoryMetaInformationStorage { - - // MARK: - Properties - var userDefaultsKey: String - - // MARK: - Initialization - init(userDefaultsKey: String) { - self.userDefaultsKey = userDefaultsKey - } - - // MARK: - Methods - // MARK: HistoryMetaInformationStorage protocol methods - - func isHistoryEnded() -> Bool { - if let historyEnded = UserDefaults.standard.dictionary(forKey: userDefaultsKey)?[UserDefaultsMainPrefix.historyEnded.rawValue] as? Bool { - return historyEnded - } - - return false - } - - func set(historyEnded: Bool) { - if var userDefaults = UserDefaults.standard.dictionary(forKey: userDefaultsKey) { - userDefaults[UserDefaultsMainPrefix.historyEnded.rawValue] = historyEnded - UserDefaults.standard.set(userDefaults, - forKey: userDefaultsKey) - } else { - UserDefaults.standard.setValue([UserDefaultsMainPrefix.historyEnded.rawValue: historyEnded], - forKey: userDefaultsKey) - } - } - - func set(revision: String?) { - if let revision = revision { - if var userDefaults = UserDefaults.standard.dictionary(forKey: userDefaultsKey) { - userDefaults[UserDefaultsMainPrefix.historyRevision.rawValue] = revision - UserDefaults.standard.set(userDefaults, - forKey: userDefaultsKey) - } else { - UserDefaults.standard.setValue([UserDefaultsMainPrefix.historyRevision.rawValue: revision], - forKey: userDefaultsKey) - } - } - } - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Message.swift b/ios/libs/Webim/WebimClientLibrary/Message.swift deleted file mode 100644 index f3b8023..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Message.swift +++ /dev/null @@ -1,446 +0,0 @@ -// -// Message.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 09.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - - -import Foundation - - -/** - Abstracts a single message in the message history. - A message is an immutable object. It means that changing some of the message fields creates a new object. Messages can be compared by using `isEqual(to:)` method for searching messages with the same set of fields or by ID (`message1.getID() == message2.getID()`) for searching logically identical messages. ID is formed on the client side when sending a message (`MessageStream.send(message:isHintQuestion:)` or `MessageStream.sendFile(atPath:mimeType:completion:)). - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol Message { - - /** - Messages of the types `MessageType.FILE_FROM_OPERATOR` and `MessageType.FILE_FROM_VISITOR` can contain attachments. - - important: - Notice that this method may return nil even in the case of previously listed types of messages. E.g. if a file is being sent. - - seealso: - `MessageAttachment` protocol. - - returns: - The attachment of the message. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getAttachment() -> MessageAttachment? - - /** - Messages of type `MessageType.ACTION_REQUEST` contain custom dictionary. - - returns: - Dictionary which contains custom fields or `nil` if there's no such custom fields. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getData() -> [String: Any?]? - - /** - Every message can be uniquefied by its ID. Messages also can be lined up by its IDs. - - important: - ID doesn’t change while changing the content of a message. - - returns: - Unique ID of the message. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getID() -> String - - /** - - returns: - ID of a message sender, if the sender is an operator. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getOperatorID() -> String? - - /** - - returns: - URL of a sender's avatar or `nil` if one does not exist. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getSenderAvatarFullURL() -> URL? - - /** - - returns: - Name of a message sender. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getSenderName() -> String - - /** - - returns: - `MessageSendStatus.SENT` if a message had been sent to the server, was received by the server and was delivered to all the clients; `MessageSendStatus.SENDING` if not. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getSendStatus() -> MessageSendStatus - - /** - - returns: - Text of the message. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getText() -> String - - /** - - returns: - Timestamp of the moment the message was processed by the server. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getTime() -> Date - - /** - - seealso: - `MessageType` enum. - - returns: - Type of a message. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getType() -> MessageType - - /** - Method which can be used to compare if two Message objects have identical contents. - - parameter message: - Second `Message` object. - - returns: - True if two `Message` objects are identical and false otherwise. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func isEqual(to message: Message) -> Bool - - /** - - returns: - True if visitor message read by operator or this message is not by visitor and false otherwise. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - func isReadByOperator() -> Bool - - /** - - returns: - True if this message can be edited or deleted. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - func canBeEdited() -> Bool - -} - -/** - Contains information about an attachment file. - - seealso: - `Message.getAttachment()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol MessageAttachment { - - /** - - returns: - MIME-type of an attachment file. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getContentType() -> String - - /** - - returns: - Name of an attachment file. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getFileName() -> String - - /** - - seealso: - `ImageInfo` protocol. - - returns: - If a file is an image, returns information about an image; in other cases returns nil. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getImageInfo() -> ImageInfo? - - /** - - returns: - Attachment file size in bytes. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getSize() -> Int64? - - /** - - important: - Notice that this URL is short-living and is tied to a session. - - returns: - URL of attached file. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getURL() -> URL - -} - -/** - Provides information about an image. - - seealso: - `MessageAttachment.getImageInfo()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol ImageInfo { - - /** - Returns a URL String of an image thumbnail. - The maximum width and height is usually 300 px but it can be adjusted at server settings. - To get an actual preview size before file uploading is completed, use the following code: - ```` - let THUMB_SIZE = 300 - var width = imageInfo.getWidth() - var height = imageInfo.getHeight() - if (height > width) { - width = (THUMB_SIZE * width) / height - height = THUMB_SIZE - } else { - height = (THUMB_SIZE * height) / width - width = THUMB_SIZE - } - ```` - - important: - Notice that this URL is short-living and is tied to a session. - - returns: - URL of reduced image. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getThumbURL() -> URL - - /** - - returns: - Height of an image in pixels. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getHeight() -> Int? - - /** - - returns: - Width of an image in pixels. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getWidth() -> Int? -} - -// MARK: - -/** - Supported message types. - - seealso: - `Message.getType()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public enum MessageType { - - /** - A message from operator which requests some actions from a visitor. - E.g. choose an operator group by clicking on a button in this message. - - seealso: - `Message.getData()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case ACTION_REQUEST - - /** - Message type that is received after operator clicked contacts request button. - - important: - There's no this functionality automatic support yet. All payload is transfered inside standard text field. - - seealso: - `Message.getText()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case CONTACTS_REQUEST - - /** - A message sent by an operator which contains an attachment. - - important: - Notice that the method `Message.getAttachment()` may return nil even for messages of this type. E.g. if a file is being sent. - - seealso: - `Message.getAttachment()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case FILE_FROM_OPERATOR - - /** - A message sent by a visitor which contains an attachment. - - important: - Notice that the method `Message.getAttachment()` may return nil even for messages of this type. E.g. if a file is being sent. - - seealso: - `Message.getAttachment()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case FILE_FROM_VISITOR - - /** - A system information message. - Messages of this type are automatically sent at specific events. E.g. when starting a chat, closing a chat or when an operator joins a chat. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case INFO - - /** - A text message sent by an operator. - - seealso: - `Message.getText()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case OPERATOR - - /** - A system information message which indicates that an operator is busy and can't reply to a visitor at the moment. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case OPERATOR_BUSY - - /** - A text message sent by a visitor. - - seealso: - `Message.getText()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case VISITOR - -} - -/** - Until a message is sent to the server, is received by the server and is spreaded among clients, message can be seen as "being send"; at the same time `Message.getSendStatus()` will return `SENDING`. In other cases - `SENT`. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public enum MessageSendStatus { - - /** - A message is being sent. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case SENDING - - /** - A message had been sent to the server, received by the server and was spreaded among clients. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case SENT - -} diff --git a/ios/libs/Webim/WebimClientLibrary/MessageListener.swift b/ios/libs/Webim/WebimClientLibrary/MessageListener.swift deleted file mode 100644 index a6270a0..0000000 --- a/ios/libs/Webim/WebimClientLibrary/MessageListener.swift +++ /dev/null @@ -1,98 +0,0 @@ -// -// MessageListener.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 09.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Delegate protocol that provide methods to handle changes in message stream. - - seealso: - `MessageStream.newMessageTracker(messageListener:)` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol MessageListener: class { - - /** - Called when added a new message. - If `previousMessage == nil` then it should be added to the end of message history (the lowest message is added), in other cases the message should be inserted before the message (i.e. above in history) which was given as a parameter `previousMessage`. - - important: - Notice that this is a logical insertion of a message. I.e. calling this method does not necessarily mean receiving a new (unread) message. Moreover, at the first call `MessageTracker.getNextMessages(byLimit:completion:)` most often the last messages of a local history (i.e. which is stored on a user's device) are returned, and this method will be called for each message received from a server after a successful connection. - - seealso: - `Message` protocol. - - parameter newMessage: - Added message. - - parameter previousMessage: - A message after which it is needed to make a message insert. If `nil` then an insert is performed at the end of the list. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func added(message newMessage: Message, - after previousMessage: Message?) - - /** - Called when removing a message. - - seealso: - `Message` protocol. - - parameter message: - A message to be removed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func removed(message: Message) - - /** - Called when removed all the messages. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func removedAllMessages() - - /** - Called when changing a message. - `Message` is an immutable type and field values can not be changed. That is why message changing occurs as replacing one object with another. Thereby you can find out, for example, which certain message fields have changed by comparing an old and a new object values. - - seealso: - `Message` protocol. - - parameter oldVersion: - Message changed from. - - parameter newVersion: - Message changed to. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func changed(message oldVersion: Message, - to newVersion: Message) - -} diff --git a/ios/libs/Webim/WebimClientLibrary/MessageStream.swift b/ios/libs/Webim/WebimClientLibrary/MessageStream.swift deleted file mode 100644 index d28ecc2..0000000 --- a/ios/libs/Webim/WebimClientLibrary/MessageStream.swift +++ /dev/null @@ -1,1633 +0,0 @@ -// -// MessageStream.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 07.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - seealso: - `WebimSession.getStream()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol MessageStream: class { - - /** - - seealso: - `VisitSessionState` type. - - returns: - Current session state. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getVisitSessionState() -> VisitSessionState - - /** - - returns: - Current chat state. - - seealso: - `ChatState` type. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getChatState() -> ChatState - - /** - - returns: - Timestamp after which all chat messages are unread by operator (at the moment of last server update recieved). - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getUnreadByOperatorTimestamp() -> Date? - - /** - - returns: - Timestamp after which all chat messages are unread by visitor (at the moment of last server update recieved) or `nil` if there's no unread by visitor messages. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getUnreadByVisitorTimestamp() -> Date? - - /** - - returns: - Count of unread by visitor messages (at the moment of last server update recieved). - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - func getUnreadByVisitorMessageCount() -> Int - - /** - - seealso: - `Department` protocol. - `DepartmentListChangeListener` protocol. - - returns: - List of departments or `nil` if there're any or department list is not received yet. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getDepartmentList() -> [Department]? - - /** - - returns: - Current LocationSettings of the MessageStream. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getLocationSettings() -> LocationSettings - - /** - - returns: - Operator of the current chat. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getCurrentOperator() -> Operator? - - /** - - parameter id: - ID of the operator. - - returns: - Previous rating of the operator or 0 if it was not rated before. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getLastRatingOfOperatorWith(id: String) -> Int - - /** - Rates an operator. - To get an ID of the current operator call `getCurrentOperator()`. - - important: - Requires existing chat. - - seealso: - `RateOperatorCompletionHandler` protocol. - - parameter id: - ID of the operator to be rated. If passed `nil` current chat operator will be rated. - - parameter rate: - A number in range (1...5) that represents an operator rating. If the number is out of range, rating will not be sent to a server. - - parameter comletionHandler: - `RateOperatorCompletionHandler` object. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func rateOperatorWith(id: String?, - byRating rating: Int, - completionHandler: RateOperatorCompletionHandler?) throws - - /** - Respond sentry call - - important: - Id of redirect to sentry message - - parameter id: - ID of the operator to be rated. If passed `nil` current chat operator will be rated. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - func respondSentryCall(id: String) throws - - /** - Changes `ChatState` to `ChatState.QUEUE`. - Can cause `VisitSessionState.DEPARTMENT_SELECTION` session state. It means that chat must be started by `startChat(departmentKey:)` method. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func startChat() throws - - /** - Starts chat and sends first message simultaneously. - Changes `ChatState` to `ChatState.QUEUE`. - - parameter firstQuestion: - First message to send. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func startChat(firstQuestion: String?) throws - - /** - Starts chat with particular department. - Changes `ChatState` to `ChatState.QUEUE`. - - seealso: - `Department` protocol. - - parameter departmentKey: - Department key (see `getKey()` of `Department` protocol). Calling this method without this parameter passed is the same as `startChat()` method is called. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func startChat(departmentKey: String?) throws - - - /** - Starts chat with custom fields. - Changes `ChatState` to `ChatState.QUEUE`. - - parameter customFields: - Custom fields in JSON format. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - func startChat(customFields:String?) throws - - /** - Starts chat with particular department and sends first message simultaneously. - Changes `ChatState` to `ChatState.QUEUE`. - - seealso: - `Department` protocol. - - parameter departmentKey: - Department key (see `getKey()` of `Department` protocol). Calling this method without this parameter passed is the same as `startChat()` method is called. - - parameter firstQuestion: - First message to send. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Lazarev - - copyright: - 2017 Webim - */ - func startChat(departmentKey: String?, - firstQuestion: String?) throws - - /** - Starts chat with custom fields and sends first message simultaneously. - Changes `ChatState` to `ChatState.QUEUE`. - - parameter firstQuestion: - First message to send. - - parameter customFields: - Custom fields in JSON format. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - func startChat(firstQuestion:String?, - customFields: String?) throws - - /** - Starts chat with particular department and custom fields. - Changes `ChatState` to `ChatState.QUEUE`. - - seealso: - `Department` protocol. - - parameter departmentKey: - Department key (see `getKey()` of `Department` protocol). Calling this method without this parameter passed is the same as `startChat()` method is called. - - parameter customFields: - Custom fields in JSON format. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - func startChat(departmentKey: String?, - customFields: String?) throws - - /** - Starts chat with particular department and custom fields and sends first message simultaneously. - Changes `ChatState` to `ChatState.QUEUE`. - - seealso: - `Department` protocol. - - parameter departmentKey: - Department key (see `getKey()` of `Department` protocol). Calling this method without this parameter passed is the same as `startChat()` method is called. - - parameter firstQuestion: - First message to send. - - parameter customFields: - Custom fields in JSON format. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - func startChat(departmentKey: String?, - firstQuestion: String?, - customFields: String?) throws - - - /** - Changes `ChatState` to `ChatState.CLOSED_BY_VISITOR`. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func closeChat() throws - - /** - This method must be called whenever there is a change of the input field of a message transferring current content of a message as a parameter. - - parameter draftMessage: - Current message content. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func setVisitorTyping(draftMessage: String?) throws - - /** - Sends prechat fields to server. - - parameter prechatFields: - Custom fields. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - func set(prechatFields: String) throws - - /** - Sends a text message. - When calling this method, if there is an active `MessageTracker` (see newMessageTracker(messageListener:)). `MessageListener.added(message:after:)`) with a message `MessageSendStatus.SENDING` in the status is also called. - - important: - Maximum length of message is 32000 characters. Longer messages will be clipped. - - parameter message: - Text of the message. - - returns: - ID of the message. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func send(message: String) throws -> String - - /** - Sends a text message. - When calling this method, if there is an active `MessageTracker` object (see `newMessageTracker(messageListener:)` method). `MessageListener.added(message:after:)`) with a message `MessageSendStatus.SENDING` in the status is also called. - - important: - Maximum length of message is 32000 characters. Longer messages will be clipped. - - parameter message: - Text of the message. - - parameter data: - Optional. Custom message parameters dictionary. Note that this functionality does not work as is – server version must support it. - - parameter completionHandler: - Completion handler that executes when operation is done. - - returns: - ID of the message. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func send(message: String, - data: [String: Any]?, - completionHandler: DataMessageCompletionHandler?) throws -> String - - /** - Sends a text message. - When calling this method, if there is an active `MessageTracker` object (see `newMessageTracker(messageListener:)` method). `MessageListener.added(message:after:)`) with a message `MessageSendStatus.SENDING` in the status is also called. - - important: - Maximum length of message is 32000 characters. Longer messages will be clipped. - - parameter message: - Text of the message. - - parameter isHintQuestion: - Optional. Shows to server if a visitor chose a hint (true) or wrote his own text (false). - - returns: - ID of the message. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func send(message: String, - isHintQuestion: Bool?) throws -> String - - /** - Sends a file message. - When calling this method, if there is an active `MessageTracker` object (see `newMessageTracker(messageListener:)` method), `MessageListener.added(message:after:)` with a message `MessageSendStatus.SENDING` in the status is also called. - - seealso: - Method could fail. See `SendFileError`. - - parameter file: - File data to send - - parameter filename: - File name with file extension. - - parameter mimeType: - MIME type of the file to send. - - parameter completionHandler: - Completion handler that executes when operation is done. - - returns: - ID of the message. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func send(file: Data, - filename: String, - mimeType: String, - completionHandler: SendFileCompletionHandler?) throws -> String - - /** - Update widget status. The change is displayed by the operator. - - parameter data: - JSON string with new widget status. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - func updateWidgetStatus(data: String) throws - - /** - Edits a text message. - When calling this method, if there is an active `MessageTracker` object (see `newMessageTracker(messageListener:)` method). `MessageListener.changed(oldVersion:newVersion:)`) with a message `MessageSendStatus.SENDING` in the status is also called. - - important: - Maximum length of message is 32000 characters. Longer messages will be clipped. - - parameter message: - ID of the message to edit. - - parameter text: - Text of the message. - - parameter completionHandler: - Completion handler that executes when operation is done. - - returns: - True if the message can be edited. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - func edit(message: Message, - text: String, - completionHandler: EditMessageCompletionHandler?) throws -> Bool - - /** - Deletes a message. - When calling this method, if there is an active `MessageTracker` object (see `newMessageTracker(messageListener:)` method). `MessageListener.removed(message:)`) with a message `MessageSendStatus.SENT` in the status is also called. - - parameter message: - The message to delete. - - parameter completionHandler: - Completion handler that executes when operation is done. - - returns: - True if the message can be deleted. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - func delete(message: Message, - completionHandler: DeleteMessageCompletionHandler?) throws -> Bool - - /** - Set chat has been read by visitor. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Aleksej Lapenok - - copyright: - 2018 Webim - */ - func setChatRead() throws - - /** - `MessageTracker` (via `MessageTracker.getNextMessages(byLimit:completion:)`) allows to request the messages which are above in the history. Each next call `MessageTracker.getNextMessages(byLimit:completion:)` returns earlier messages in relation to the already requested ones. - Changes of user-visible messages (e.g. ever requested from `MessageTracker`) are transmitted to `MessageListener`. That is why `MessageListener` is needed when creating `MessageTracker`. - - important: - For each `MessageStream` at every single moment can exist the only one active `MessageTracker`. When creating a new one at the previous there will be automatically called `MessageTracker.destroy()`. - - parameter messageListener: - A listener of message changes in the tracking range. - - returns: - A new `MessageTracker` for this stream. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func newMessageTracker(messageListener: MessageListener) throws -> MessageTracker - - /** - Sets `VisitSessionStateListener` object. - - seealso: - `VisitSessionStateListener` protocol. - `VisitSessionState` type. - - parameter visitSessionStateListener: - `VisitSessionStateListener` object. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func set(visitSessionStateListener: VisitSessionStateListener) - - /** - Sets the `ChatState` change listener. - - parameter chatStateListener: - The `ChatState` change listener. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func set(chatStateListener: ChatStateListener) - - /** - Sets the current `Operator` change listener. - - parameter currentOperatorChangeListener: - Current `Operator` change listener. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func set(currentOperatorChangeListener: CurrentOperatorChangeListener) - - /** - Sets `DepartmentListChangeListener` object. - - seealso: - `DepartmentListChangeListener` protocol. - `Department` protocol. - - parameter departmentListChangeListener: - `DepartmentListChangeListener` object. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func set(departmentListChangeListener: DepartmentListChangeListener) - - /** - Sets the listener of the MessageStream LocationSettings changes. - - parameter locationSettingsChangeListener: - The listener of MessageStream LocationSettings changes. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func set(locationSettingsChangeListener: LocationSettingsChangeListener) - - /** - Sets the listener of the "operator typing" status changes. - - parameter operatorTypingListener: - The listener of the "operator typing" status changes. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func set(operatorTypingListener: OperatorTypingListener) - - /** - Sets the listener of session status changes. - - parameter onlineStatusChangeListener: - `OnlineStatusChangeListener` object. - - seealso: - `OnlineStatusChangeListener` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func set(onlineStatusChangeListener: OnlineStatusChangeListener) - - /** - Sets listener for parameter that is to be returned by `MessageStream.getUnreadByOperatorTimestamp()` method. - - parameter unreadByOperatorTimestampChangeListener: - `UnreadByOperatorTimestampChangeListener` object. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - func set(unreadByOperatorTimestampChangeListener: UnreadByOperatorTimestampChangeListener) - - /** - Sets listener for parameter that is to be returned by `MessageStream.getUnreadByVisitorMessageCount()` method. - - parameter unreadByVisitorMessageCountChangeListener: - `UnreadByVisitorMessageCountChangeListener` object. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - func set(unreadByVisitorMessageCountChangeListener: UnreadByVisitorMessageCountChangeListener) - - /** - Sets listener for parameter that is to be returned by `MessageStream.getUnreadByVisitorTimestamp()` method. - - parameter unreadByVisitorTimestampChangeListener: - `UnreadByVisitorTimestampChangeListener` object. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - func set(unreadByVisitorTimestampChangeListener: UnreadByVisitorTimestampChangeListener) - -} - -/** - Interface that provides methods for handling MessageStream LocationSettings which are received from server. - - seealso: - `LocationSettingsChangeListener` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol LocationSettings { - - /** - This method shows to an app if it should show hint questions to visitor. - - returns: - True if an app should show hint questions to visitor, false otherwise. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func areHintsEnabled() -> Bool - -} - -// MARK: - -/** - - seealso: - `MessageStream.send(message:data:completionHandler:)`. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ -public protocol DataMessageCompletionHandler: class { - - /** - Executed when operation is done successfully. - - parameter messageID: - ID of the message. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - func onSuccess(messageID: String) - - /** - Executed when operation is failed. - - parameter messageID: - ID of the message. - - parameter error: - Error. - - seealso: - `DataMessageError`. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - func onFailure(messageID: String, - error: DataMessageError) - -} - -/** - - seealso: - `MessageStream.edit(message:messageID:completionHandler:)`. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ -public protocol EditMessageCompletionHandler: class { - /** - Executed when operation is done successfully. - - parameter messageID: - ID of the message. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - func onSuccess(messageID: String) - - /** - Executed when operation is failed. - - parameter messageID: - ID of the message. - - parameter error: - Error. - - seealso: - `EditMessageError`. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - func onFailure(messageID: String, - error: EditMessageError) -} - -/** - - seealso: - `MessageStream.delete(messageID:completionHandler:)`. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ -public protocol DeleteMessageCompletionHandler: class { - /** - Executed when operation is done successfully. - - parameter messageID: - ID of the message. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - func onSuccess(messageID: String) - - /** - Executed when operation is failed. - - parameter messageID: - ID of the message. - - parameter error: - Error. - - seealso: - `DeleteMessageError`. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - func onFailure(messageID: String, - error: DeleteMessageError) -} - -/** - - seealso: - `MessageStream.send(file:filename:mimeType:completionHandler:)` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol SendFileCompletionHandler: class { - - /** - Executed when operation is done successfully. - - parameter messageID: - ID of the message. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func onSuccess(messageID: String) - - /** - Executed when operation is failed. - - parameter messageID: - ID of the message. - - parameter error: - Error. - - seealso: - `SendFileError`. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func onFailure(messageID: String, - error: SendFileError) - -} - -/** - - seealso: - `MessageStream.rateOperatorWith(id:byRating:completionHandler:)`. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol RateOperatorCompletionHandler: class { - - /** - Executed when operation is done successfully. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func onSuccess() - - /** - Executed when operation is failed. - - parameter error: - Error. - - seealso: - `RateOperatorError`. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func onFailure(error: RateOperatorError) - -} - -/** - Provides methods to track changes of `VisitSessionState` status. - - seealso: - `VisitSessionState` protocol. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol VisitSessionStateListener: class { - - /** - Called when `VisitSessionState` status is changed. - - parameter previousState: - Previous value of `VisitSessionState` status. - - parameter newState: - New value of `VisitSessionState` status. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func changed(state previousState: VisitSessionState, - to newState: VisitSessionState) - -} - -/** - Delegate protocol that provides methods to handle changes of chat state. - - seealso: - `MessageStream.set(chatStateListener:)` - `MessageStream.getChatState()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol ChatStateListener: class { - - /** - Called during `ChatState` transition. - - parameter previousState: - Previous state. - - parameter newState: - New state. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func changed(state previousState: ChatState, - to newState: ChatState) - -} - -/** - - seealso: - `MessageStream.set(currentOperatorChangeListener:)` - `MessageStream.getCurrentOperator()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol CurrentOperatorChangeListener: class { - - /** - Called when `Operator` of the current chat changed. - - parameter previousOperator: - Previous operator. - - parameter newOperator: - New operator or nil if doesn't exist. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func changed(operator previousOperator: Operator?, - to newOperator: Operator?) - -} - -/** - Provides methods to track changes in departments list. - - seealso: - `Department` protocol. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol DepartmentListChangeListener: class { - - /** - Called when department list is received. - - seealso: - `Department` protocol. - - parameter departmentList: - Current department list. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func received(departmentList: [Department]) - -} - -/** - Interface that provides methods for handling changes in LocationSettings. - - seealso: - `LocationSettings` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol LocationSettingsChangeListener: class { - - /** - Method called by an app when new LocationSettings object is received. - - parameter previousLocationSettings: - Previous LocationSettings state. - - parameter newLocationSettings: - New LocationSettings state. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func changed(locationSettings previousLocationSettings: LocationSettings, - to newLocationSettings: LocationSettings) - -} - -/** - - seealso: - `MessageStream.set(operatorTypingListener:)` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol OperatorTypingListener: class { - - /** - Called when operator typing state changed. - - parameter isTyping: - True if operator is typing, false otherwise. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func onOperatorTypingStateChanged(isTyping: Bool) - -} - -/** - Interface that provides methods for handling changes of session status. - - seealso: - `MessageStream.set(onlineStatusChangeListener:)` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol OnlineStatusChangeListener: class { - - /** - Called when new session status is received. - - parameter previousOnlineStatus: - Previous value. - - parameter newOnlineStatus: - New value. - - seealso: - `OnlineStatus` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func changed(onlineStatus previousOnlineStatus: OnlineStatus, - to newOnlineStatus: OnlineStatus) - -} - -/** - Interface that provides methods for handling changes of parameter that is to be returned by `MessageStream.getUnreadByOperatorTimestamp()` method. - - seealso: - `MessageStream.set(unreadByOperatorTimestampChangeListener:)`. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ -public protocol UnreadByOperatorTimestampChangeListener: class { - - /** - Method to be called when parameter that is to be returned by `MessageStream.getUnreadByOperatorTimestamp()` method is changed. - - parameter newValue: - New unread by operator timestamp value. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - func changedUnreadByOperatorTimestampTo(newValue: Date?) - -} - -/** - Interface that provides methods for handling changes of parameter that is to be returned by `MessageStream.getUnreadByVisitorMessageCount()` method. - - seealso: - `MessageStream.set(unreadByVisitorMessageCountChangeListener:)`. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ -public protocol UnreadByVisitorMessageCountChangeListener: class { - - /** - Interface that provides methods for handling changes of parameter that is to be returned by `MessageStream.getUnreadByVisitorMessageCount()` method. - - parameter newValue: - New unread by visitor message count value. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - func changedUnreadByVisitorMessageCountTo(newValue: Int) - -} - -/** - Interface that provides methods for handling changes of parameter that is to be returned by `MessageStream.getUnreadByVisitorTimestamp()` method. - - seealso: - `MessageStream.set(unreadByVisitorTimestampChangeListener:)`. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ -public protocol UnreadByVisitorTimestampChangeListener: class { - - /** - Interface that provides methods for handling changes of parameter that is to be returned by `MessageStream.getUnreadByVisitorTimestamp()` method. - - parameter newValue: - New unread by visitor timestamp value. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - func changedUnreadByVisitorTimestampTo(newValue: Date?) - -} - -// MARK: - - -/** - A chat is seen in different ways by an operator depending on ChatState. - The initial state is `NONE`. - Then if a visitor sends a message (`MessageStream.send(message:isHintQuestion:)`), the chat changes it's state to `QUEUE`. The chat can be turned into this state by calling `MessageStream.startChat()`. - After that, if an operator takes the chat to process, the state changes to `CHATTING`. The chat is being in this state until the visitor or the operator closes it. - When closing a chat by the visitor `MessageStream.closeChat()`, it turns into the state `CLOSED_BY_VISITOR`, by the operator - `CLOSED_BY_OPERATOR`. - When both the visitor and the operator close the chat, it's state changes to the initial – `NONE`. A chat can also automatically turn into the initial state during long-term absence of activity in it. - Furthermore, the first message can be sent not only by a visitor but also by an operator. In this case the state will change from the initial to `INVITATION`, and then, after the first message of the visitor, it changes to `CHATTING`. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public enum ChatState { - - /** - Means that an operator has taken a chat for processing. - From this state a chat can be turned into: - * `CLOSED_BY_OPERATOR`, if an operator closes the chat; - * `CLOSED_BY_VISITOR`, if a visitor closes the chat (`MessageStream.closeChat()`); - * `NONE`, automatically during long-term absence of activity. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case CHATTING - - /** - Means that chat is picked up by a bot. - From this state a chat can be turned into: - * `CHATTING`, if an operator intercepted the chat; - * `CLOSED_BY_VISITOR`, if a visitor closes the chat (`MessageStream.closeChat()`); - * `NONE`, automatically during long-term absence of activity. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - case CHATTING_WITH_ROBOT - - /** - Means that an operator has closed the chat. - From this state a chat can be turned into: - * `NONE`, if the chat is also closed by a visitor (`MessageStream.closeChat()`), or automatically during long-term absence of activity; - * `QUEUE`, if a visitor sends a new message (`MessageStream.send(message:isHintQuestion:)`). - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case CLOSED_BY_OPERATOR - - /** - Means that a visitor has closed the chat. - From this state a chat can be turned into: - * `NONE`, if the chat is also closed by an operator or automatically during long-term absence of activity; - * `QUEUE`, if a visitor sends a new message (`MessageStream.send(message:isHintQuestion:)`). - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case CLOSED_BY_VISITOR - - /** - Means that a chat has been started by an operator and at this moment is waiting for a visitor's response. - From this state a chat can be turned into: - * `CHATTING`, if a visitor sends a message (`MessageStream.send(message:isHintQuestion:)`); - * `NONE`, if an operator or a visitor closes the chat (`MessageStream.closeChat()`). - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case INVITATION - - /** - Means the absence of a chat as such, e.g. a chat has not been started by a visitor nor by an operator. - From this state a chat can be turned into: - * `QUEUE`, if the chat is started by a visitor (by the first message or by calling `MessageStream.startChat()`; - * `INVITATION`, if the chat is started by an operator. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case NONE - - /** - Means that a chat has been started by a visitor and at this moment is being in the queue for processing by an operator. - From this state a chat can be turned into: - * `CHATTING`, if an operator takes the chat for processing; - * `NONE`, if a visitor closes the chat (by calling (`MessageStream.closeChat()`) before it is taken for processing; - * `CLOSED_BY_OPERATOR`, if an operator closes the chat without taking it for processing. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case QUEUE - - /** - The state is undefined. - This state is set as the initial when creating a new session, until the first response of the server containing the actual state is got. This state is also used as a fallback if WebimClientLibrary can not identify the server state (e.g. if the server has been updated to a version that contains new states). - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case UNKNOWN - -} - -/** - Online state possible cases. - - seealso: - `OnlineStatusChangeListener` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public enum OnlineStatus { - - /** - Offline state with chats' count limit exceeded. - Means that visitor is not able to send messages at all. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case BUSY_OFFLINE - - /** - Online state with chats' count limit exceeded. - Visitor is able send offline messages, but the server can reject it. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case BUSY_ONLINE - - /** - Visitor is able to send offline messages. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case OFFLINE - - /** - Visitor is able to send both online and offline messages. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case ONLINE - - /** - First status is not recieved yet or status is not supported by this version of the library. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case UNKNOWN - -} - -/** - Session possible states. - - seealso: - `getVisitSessionState()` method of `MessageStream` protocol. - `VisitSessionStateListener` protocol. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public enum VisitSessionState { - - /** - Chat in progress. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case CHAT - - /** - Chat must be started with department selected (there was a try to start chat without department selected). - - seealso: - `startChat(departmentKey:)` of `MessageStream` protocol. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case DEPARTMENT_SELECTION - - /** - Session is active but no chat is occuring (chat was not started yet). - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case IDLE - - /** - Session is active but no chat is occuring (chat was closed recently). - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case IDLE_AFTER_CHAT - - /** - Offline state. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case OFFLINE_MESSAGE - - /** - First status is not received yet or status is not supported by this version of the library. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case UNKNOWN - -} - -/** - - seealso: - `DataMessageCompletionHandler.onFailure(messageID:error:)`. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ -public enum DataMessageError: Error { - - /** - Received error is not supported by current WebimClientLibrary version. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - case UNKNOWN - - // MARK: Quoted message errors - // Note that quoted message mechanism is not a standard feature – it must be implemented by a server. For more information please contact with Webim support service. - - /** - To be raised when quoted message ID belongs to a message without `canBeReplied` flag set to `true` (this flag is to be set on the server-side). - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - case QUOTED_MESSAGE_CANNOT_BE_REPLIED - - /** - To be raised when quoted message ID belongs to another visitor's chat. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - case QUOTED_MESSAGE_FROM_ANOTHER_VISITOR - - /** - To be raised when quoted message ID belongs to multiple messages (server DB error). - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - case QUOTED_MESSAGE_MULTIPLE_IDS - - /** - To be raised when one or more required arguments of quoting mechanism are missing. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - case QUOTED_MESSAGE_REQUIRED_ARGUMENTS_MISSING - - /** - To be raised when wrong quoted message ID is sent. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - case QUOTED_MESSAGE_WRONG_ID - -} - -/** - - seealso: - `EditMessageCompletionHandler.onFailure(messageID:error:)` - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ -public enum EditMessageError: Error { - /** - Received error is not supported by current WebimClientLibrary version. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - case UNKNOWN - /** - Editing messages by visitor is turned off on the server. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - case NOT_ALLOWED - /** - Editing message is empty. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - case MESSAGE_EMPTY - /** - Visitor can edit only his messages. - The specified id belongs to someone else's message. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - case MESSAGE_NOT_OWNED - /** - The server may deny a request if the message size exceeds a limit. - The maximum size of a message is configured on the server. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - case MAX_LENGTH_EXCEEDED - /** - Visitor can edit only text messages. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - case WRONG_MESSAGE_KIND -} - -/** - - seealso: - `DeleteMessageCompletionHandler.onFailure(messageID:error:)` - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ -public enum DeleteMessageError: Error { - /** - Received error is not supported by current WebimClientLibrary version. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - case UNKNOWN - /** - Deleting messages by visitor is turned off on the server. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - case NOT_ALLOWED - /** - Visitor can delete only his messages. - The specified id belongs to someone else's message. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - case MESSAGE_NOT_OWNED - /** - Message with the specified id is not found in history. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - case MESSAGE_NOT_FOUND -} - -/** - - seealso: - `SendFileCompletionHandler.onFailure(messageID:error:)` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public enum SendFileError: Error { - - /** - The server may deny a request if the file size exceeds a limit. - The maximum size of a file is configured on the server. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case FILE_SIZE_EXCEEDED - - /** - The server may deny a request if the file type is not allowed. - The list of allowed file types is configured on the server. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case FILE_TYPE_NOT_ALLOWED - - /** - Sending files in body is not supported. Use multipart form only. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - case UPLOADED_FILE_NOT_FOUND - /** - Received error is not supported by current WebimClientLibrary version. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - case UNKNOWN - -} - -/** - - seealso: - `RateOperatorCompletionHandler.onFailure(error:)` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public enum RateOperatorError: Error { - - /** - Arised when trying to send operator rating request if no chat is exists. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case NO_CHAT - - /** - Arised when trying to send operator rating request if passed operator ID doesn't belong to existing chat operator (or, in the same place, chat doesn't have an operator at all). - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case WRONG_OPERATOR_ID - -} diff --git a/ios/libs/Webim/WebimClientLibrary/MessageTracker.swift b/ios/libs/Webim/WebimClientLibrary/MessageTracker.swift deleted file mode 100644 index 0bb48c1..0000000 --- a/ios/libs/Webim/WebimClientLibrary/MessageTracker.swift +++ /dev/null @@ -1,151 +0,0 @@ -// -// MessageTracker.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 09.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - MessageTracker allows to request the messages which are above in the history. - - seealso: - `MessageStream.newMessageTracker(messageListener:)` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol MessageTracker: class { - - /** - Requests last messages from history. Returns not more than `limitOfMessages` of messages. If an empty list is passed inside completion, there no messages in history yet. - If there is any previous `MessageTracker` request that is not completed, or limit of messages is less than 1, or current `MessageTracker` has been destroyed, this method will do nothing. - Following history request can be fulfilled by `getLastMessages(byLimit:completion:)` method. - - important: - Notice that this method can not be called again until the callback for the previous call will be invoked. - When an error occurs (e.g. there's one request is still running) an empty list will be returned inside completion block. - - seealso: - `getLastMessages(byLimit:completion:)` method. - `destroy()` method. - `Message` protocol. - - parameter limitOfMessages: - A number of messages will be returned (not more than this specified number). - - parameter completion: - Completion to be called on resulting array of messages if method call succeeded. It is guaranteed that completion will be called with empty or not result if call didn't throw an error. If current `MessageTracker` is destroyed completion will be called on empty result. - - parameter result: - Resulting array of messages if method call succeeded. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the `WebimSession` was created in. - `AccessError.INVALID_SESSION` if the method was called after `WebimSession` object was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getLastMessages(byLimit limitOfMessages: Int, - completion: @escaping (_ result: [Message]) -> ()) throws - - /** - Requests the messages above in history. Returns not more than `limitOfMessages` of messages. If an empty list is passed inside completion, the end of the message history is reached. - If there is any previous `MessageTracker` request that is not completed, or limit of messages is less than 1, or current `MessageTracker` has been destroyed, this method will do nothing. - - seealso: - `destroy()` method. - `Message` protocol. - - important: - Notice that this method can not be called again until the callback for the previous call will be invoked. - When an error occurs (e.g. there's one request is still running) an empty list will be returned inside completion block. - - parameter limitOfMessages: - A number of messages will be returned (not more than this specified number). - - parameter completion: - Completion to be called on resulting array of messages if method call succeeded. It is guaranteed that completion will be called with empty or not result if call didn't throw an error. If current `MessageTracker` is destroyed completion will be called on empty result. - - parameter result: - Resulting array of messages if method call succeeded. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the `WebimSession` was created in. - `AccessError.INVALID_SESSION` if the method was called after `WebimSession` object was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getNextMessages(byLimit limitOfMessages: Int, - completion: @escaping (_ result: [Message]) -> ()) throws - - /** - Requests all messages from history. If an empty list is passed inside completion, there no messages in history yet. - If there is any previous `MessageTracker` request that is not completed, or current `MessageTracker` has been destroyed, this method will do nothing. - - important: - This method is totally independent on `getNextMessages(byLimit:completion:)` and `getLastMessages(byLimit:completion:)` methods' calls. - When an error occurs (e.g. `MessageTracker` object is destroyed) an empty list will be returned inside completion block. - - seealso: - `destroy()` method. - `Message` protocol. - - parameter completion: - Completion to be called on resulting array of messages if method call succeeded. It is guaranteed that completion will be called with empty or not result if call didn't throw an error. If current `MessageTracker` is destroyed completion will be called on empty result. - - parameter result: - Resulting array of messages if method call succeeded. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the `WebimSession` was created in. - `AccessError.INVALID_SESSION` if the method was called after `WebimSession` object was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getAllMessages(completion: @escaping (_ result: [Message]) -> ()) throws - - /** - `MessageTracker` retains some range of messages. By using this method one can move the upper limit of this range to another message. - If there is any previous `MessageTracker` request that is not completed, this method will do nothing. - - important: - Notice that this method can not be used unless the previous call `getNextMessages(byLimit:completion:)` was finished (completion handler was invoked). - - seealso: - `Message` protocol. - - parameter message: - A message reset to. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the `WebimSession` was created in. - `AccessError.INVALID_SESSION` if the method was called after `WebimSession` object was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func resetTo(message: Message) throws - - /** - Destroys the `MessageTracker`. - It is impossible to use any `MessageTracker` methods after it was destroyed. - - seealso: - `Message` protocol. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the `WebimSession` was created in. - `AccessError.INVALID_SESSION` if the method was called after `WebimSession` object was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func destroy() throws - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Operator.swift b/ios/libs/Webim/WebimClientLibrary/Operator.swift deleted file mode 100644 index c0cba02..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Operator.swift +++ /dev/null @@ -1,73 +0,0 @@ -// -// Operator.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 09.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Abstracts a chat operator. - - seealso: - `MessageStream.getCurrentOperator()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol Operator { - - /** - - returns: - Unique ID of the operator. - - seealso: - `MessageStream.rateOperatorWith(id:byRate:completionHandler:)` - `MessageStream.getLastRatingOfOperatorWith(id:)` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getID() -> String - - /** - - returns: - Display name of the operator. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getName() -> String - - /** - - returns: - URL of the operator’s avatar or `nil` if does not exist. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getAvatarURL() -> URL? - -} diff --git a/ios/libs/Webim/WebimClientLibrary/ProvidedAuthorizationTokenStateListener.swift b/ios/libs/Webim/WebimClientLibrary/ProvidedAuthorizationTokenStateListener.swift deleted file mode 100644 index b2ead88..0000000 --- a/ios/libs/Webim/WebimClientLibrary/ProvidedAuthorizationTokenStateListener.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// ProvidedAuthorizationTokenStateListener.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 06.12.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - When client provides custom visitor authorization mechanism, it can be realised by providing custom authorization token which is used instead of visitor fields. - When provided authorization token is generated (or passed to session by client app), `update(providedAuthorizationToken:)` method is called. This method call indicates that client app must send provided authorisation token to its server which is responsible to send it to Webim service. - - important: - This mechanism can't be used as is. It requires that client server to support this mecahnism. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol ProvidedAuthorizationTokenStateListener: class { - - /** - Method is called in two cases: - 1. Provided authorization token is genrated (or set by client app) and must be sent to client server which is responsible to send it to Webim service. - 2. Passed provided authorization token is not valid. Provided authorization token can be invalid if Webim service did not receive it from client server yet. - When this method is called, client server must send provided authorization token to Webim service. - - parameter providedAuthorizationToken: - Provided authorization token which corresponds to session. - - seealso: - `set(providedAuthorizationTokenStateListener:providedAuthorizationToken:)` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func update(providedAuthorizationToken: String) - -} diff --git a/ios/libs/Webim/WebimClientLibrary/Webim.swift b/ios/libs/Webim/WebimClientLibrary/Webim.swift deleted file mode 100644 index 7fdf6d6..0000000 --- a/ios/libs/Webim/WebimClientLibrary/Webim.swift +++ /dev/null @@ -1,759 +0,0 @@ -// -// Webim.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 02.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Main point of WebimClientLibrary. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public final class Webim { - - /** - Returns new SessionBuilder object for creating WebimSession object. - - returns: - The instance of WebimSession builder. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - static public func newSessionBuilder() -> SessionBuilder { - return SessionBuilder() - } - - /** - Returns new FAQBuilder object for creating FAQ object. - - returns: - The instance of FAQ builder. - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - static public func newFAQBuilder() -> FAQBuilder { - return FAQBuilder() - } - - /** - Deserializes received remote notification. - This method can be called with `userInfo` parameter of your UIApplicationDelegate method `application(_:didReceiveRemoteNotification:)`. - Remote notification dictionary must be stored inside standard APNs key "aps". - - parameter remoteNotification: - User info of received remote notification. - - returns: - Remote notification object or nil if there's no useful payload or this notification is sent not by Webim service. - - seealso: - `SessionBuilder.set(remoteNotificationsSystem:)` - `isWebim(remoteNotification:)` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - static public func parse(remoteNotification: [AnyHashable : Any], visitorId: String? = nil) -> WebimRemoteNotification? { - return InternalUtils.parse(remoteNotification: remoteNotification, visitorId: visitorId) - } - - /** - If remote notifications (SessionBuilder.setRemoteNotificationSystem) are enabled for the session, then you can receive remote notifications belonging to this session. - This method can be called with `userInfo` parameter of your UIApplicationDelegate method `application(_:didReceiveRemoteNotification:)`. - Remote notification dictionary must be stored inside standard APNs key "aps". - - parameter remoteNotification: - User info of received remote notification. - - returns: - Boolean value that indicates is received remote notification is sent by Webim service. - - seealso: - `SessionBuilder.set(remoteNotificationSystem:)` - `parseRemoteNotification()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - static public func isWebim(remoteNotification: [AnyHashable: Any]) -> Bool { - return InternalUtils.isWebim(remoteNotification: remoteNotification) - } - - - // MARK: - - /** - - seealso: - `SessionBuilder.setRemoteNotificationSystem()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - public enum RemoteNotificationSystem { - case APNS - case NONE - } - -} - -// MARK: - -/** - `WebimSession` builder. - - seealso: - `Webim.newSessionBuilder()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public final class SessionBuilder { - - // MARK: - Properties - private var accountName: String? - private var appVersion: String? - private var deviceToken: String? - private var fatalErrorHandler: FatalErrorHandler? - private var localHistoryStoragingEnabled = true - private var location: String? - private var pageTitle: String? - private var providedAuthorizationToken: String? - private weak var providedAuthorizationTokenStateListener: ProvidedAuthorizationTokenStateListener? - private var remoteNotificationSystem: Webim.RemoteNotificationSystem = .NONE - private var visitorDataClearingEnabled = false - private var visitorFields: ProvidedVisitorFields? - private weak var webimLogger: WebimLogger? - private var webimLoggerVerbosityLevel: WebimLoggerVerbosityLevel? - private var prechat: String? - - // MARK: - Methods - - /** - Sets company account name in Webim system. - Usually presented by full domain URL of the server (e.g "https://demo.webim.ru"). - For testing purposes it is possible to use account name "demo". - - parameter accountName: - Webim account name. - - returns: - `SessionBuilder` object with account name set. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - public func set(accountName: String) -> SessionBuilder { - self.accountName = accountName - - return self - } - - /** - Location on server. - You can use "mobile" or contact support for creating new one. - - parameter location: - Location name. - - returns: - `SessionBuilder` object with location set. - - seealso: - https://webim.ru/help/help-terms/#location - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - public func set(location: String) -> SessionBuilder { - self.location = location - - return self - } - - /** - Set prechat fields with extra information. - - parameter prechat: - Prechat fields in JSON format. - - returns: - `SessionBuilder` object with location set. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - public func set(prechat: String) -> SessionBuilder { - self.prechat = prechat - return self - } - - /** - You can differentiate your app versions on server by setting this parameter. E.g. "2.9.11". - This is optional. - - parameter appVersion: - Client app version name. - - returns: - `SessionBuilder` object with app version set. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - public func set(appVersion: String?) -> SessionBuilder { - self.appVersion = appVersion - - return self - } - - /** - A visitor can be anonymous or authorized. Without calling this method when creating a session visitor is anonymous. - In this case visitor receives a random ID, which is written in `UserDefaults`. If the data is lost (for example when application was reinstalled), the user ID is also lost, as well as the message history. - Authorizing of a visitor can be useful when there are internal mechanisms of authorization in your application and you want the message history to exist regardless of a device communication occurs from. - This method takes as a parameter a string containing the signed fields of a user in JSON format. Since the fields are necessary to be signed with a private key that can never be included into the code of a client's application, this string must be created and signed somewhere on your backend side. Read more about forming a string and a signature here: https://webim.ru/help/identification/ - - important: - Can't be used simultanously with `set(providedAuthorizationTokenStateListener:providedAuthorizationToken:)`. - - parameter jsonString: - JSON-string containing the signed fields of a visitor. - - returns: - `SessionBuilder` object with visitor fields set. - - SeeAlso: - https://webim.ru/help/identification/ - set(visitorFieldsJSONdata:) - - Author: - Nikita Lazarev-Zubov - - Copyright: - 2017 Webim - */ - public func set(visitorFieldsJSONString: String) -> SessionBuilder { - self.visitorFields = ProvidedVisitorFields(withJSONString: visitorFieldsJSONString) - - return self - } - - /** - A visitor can be anonymous or authorized. Without calling this method when creating a session visitor is anonymous. - In this case visitor receives a random ID, which is written in `UserDefaults`. If the data is lost (for example when application was reinstalled), the user ID is also lost, as well as the message history. - Authorizing of a visitor can be useful when there are internal mechanisms of authorization in your application and you want the message history to exist regardless of a device communication occurs from. - This method takes as a parameter a string containing the signed fields of a user in JSON format. Since the fields are necessary to be signed with a private key that can never be included into the code of a client's application, this string must be created and signed somewhere on your backend side. Read more about forming a string and a signature here: https://webim.ru/help/identification/ - - important: - Can't be used simultanously with `set(providedAuthorizationTokenStateListener:providedAuthorizationToken:)`. - - parameter jsonData: - JSON-data containing the signed fields of a visitor. - - returns: - `SessionBuilder` object with visitor fields set. - - SeeAlso: - `set(visitorFieldsJSONstring:)` - - Author: - Nikita Lazarev-Zubov - - Copyright: - 2017 Webim - */ - public func set(visitorFieldsJSONData: Data) -> SessionBuilder { - self.visitorFields = ProvidedVisitorFields(withJSONObject: visitorFieldsJSONData) - - return self - } - - /** - When client provides custom visitor authorization mechanism, it can be realised by providing custom authorization token which is used instead of visitor fields. - - important: - Can't be used simultaneously with `set(visitorFields:)`. - - parameter providedAuthorizationTokenStateListener: - `ProvidedAuthorizationTokenStateListener` object. - - parameter providedAuthorizationToken: - Optional. Client generated provided authorization token. If it is not passed, library generates its own. - - seealso: - `ProvidedAuthorizationTokenStateListener` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - public func set(providedAuthorizationTokenStateListener: ProvidedAuthorizationTokenStateListener?, - providedAuthorizationToken: String? = nil) -> SessionBuilder { - self.providedAuthorizationTokenStateListener = providedAuthorizationTokenStateListener - self.providedAuthorizationToken = providedAuthorizationToken - - return self - } - - /** - Sets the page title visible to an operator. In the web version of a chat it is a title of a web page a user opens a chat from. - By default "iOS Client". - - parameter pageTitle: - Page title that visible to an operator. - - returns: - `SessionBuilder` object with page title set. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - public func set(pageTitle: String?) -> SessionBuilder { - self.pageTitle = pageTitle - - return self - } - - /** - Sets a fatal error handler. An error is considered fatal if after processing it the session can not be continued anymore. - - parameter fatalErrorHandler: - Fatal error handler. - - returns: - `SessionBuilder` object with fatal error handler set. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - public func set(fatalErrorHandler: FatalErrorHandler?) -> SessionBuilder { - self.fatalErrorHandler = fatalErrorHandler - - return self - } - - /** - Webim service can send remote notifications when new messages are received in chat. - By default it does not. You have to handle receiving by yourself. - To differentiate notifications from your app and from Webim service check the field "from" (see `Webim.isWebim(remoteNotification:)`). - - important: - If remote notification system is set you must set device token. - - parameter remoteNotificationSystem: - Enum that indicates which system of remote notification is used. By default – `NONE` (remote notifications are not to be sent). - - returns: - `SessionBuilder` object with remote notification system set. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - public func set(remoteNotificationSystem: Webim.RemoteNotificationSystem) -> SessionBuilder { - self.remoteNotificationSystem = remoteNotificationSystem - - return self - } - - /** - Sets device token. - Example that shows how to change device token for the proper formatted one: - `let deviceToken = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()` - - parameter deviceToken: - Device token in hexadecimal format and without any spaces and service symbols. - - returns: - `SessionBuilder` object with device token set. - - seealso: - `setRemoteNotificationsSystem` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - public func set(deviceToken: String?) -> SessionBuilder { - self.deviceToken = deviceToken - - return self - } - - /** - By default a session stores a message history locally. This method allows to disable history storage. - - important: - Use only for debugging! - - parameter isLocalHistoryStoragingEnabled: - Boolean parameter that indicated if an app should enable or disable local history storing. - - returns: - `SessionBuilder` object with isLocalHistoryStoragingEnabled parameter set. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - public func set(isLocalHistoryStoragingEnabled: Bool) -> SessionBuilder { - self.localHistoryStoragingEnabled = isLocalHistoryStoragingEnabled - - return self - } - - /** - If set to true, all the visitor data is cleared before the session starts. - - important: - Use only for debugging! - - parameter isVisitorDataClearingEnabled: - Boolean parameter that indicated if an app should clear visitor data before session starts. - - returns: - `SessionBuilder` object with isVisitorDataClearingEnabled parameter set. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - public func set(isVisitorDataClearingEnabled: Bool) -> SessionBuilder { - self.visitorDataClearingEnabled = isVisitorDataClearingEnabled - - return self - } - - /** - Method to pass WebimLogger object. - - parameter webimLogger: - `WebimLogger` object. - - returns: - `SessionBuilder` object with `WebimLogger` object set. - - seealso: - `WebimLogger` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - public func set(webimLogger: WebimLogger?, - verbosityLevel: WebimLoggerVerbosityLevel = .WARNING) -> SessionBuilder { - self.webimLogger = webimLogger - webimLoggerVerbosityLevel = verbosityLevel - - return self - } - - /** - Builds new `WebimSession` object. - - important: - All the follow-up work with the session must be implemented from the same thread this method was called in. - Notice that a session is created as a paused. To start using it the first thing to do is to call `WebimSession.resume()`. - - returns: - New `WebimSession` object. - - throws: - `SessionBuilder.SessionBuilderError.NIL_ACCOUNT_NAME` if account name wasn't set to a non-nil value. - `SessionBuilder.SessionBuilderError.NIL_LOCATION` if location wasn't set to a non-nil value. - `SessionBuilder.SessionBuilderError.INVALID_REMOTE_NOTIFICATION_CONFIGURATION` if there is a try to pass device token with `RemoteNotificationSystem` not set (or set to `.NONE`). - `SessionBuilder.SessionBuilderError.INVALID_AUTHENTICATION_PARAMETERS` if methods `set(visitorFieldsJSONString:)` or `set(visitorFieldsJSONData:)` are called with `set(providedAuthorizationTokenStateListener:,providedAuthorizationToken:)` simultaneously. - - seealso: - `SessionBuilder.SessionBuilderError` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - public func build() throws -> WebimSession { - guard let accountName = accountName else { - throw SessionBuilderError.NIL_ACCOUNT_NAME - } - guard let location = location else { - throw SessionBuilderError.NIL_LOCATION - } - - let remoteNotificationsEnabled = (self.remoteNotificationSystem != Webim.RemoteNotificationSystem.NONE) - if (deviceToken != nil) - && !remoteNotificationsEnabled { - throw SessionBuilderError.INVALID_REMOTE_NOTIFICATION_CONFIGURATION - } - - if (visitorFields != nil) - && (providedAuthorizationTokenStateListener != nil) { - throw SessionBuilderError.INVALID_AUTHENTICATION_PARAMETERS - } - - var providedAuthorizationToken = self.providedAuthorizationToken - - if let listener = providedAuthorizationTokenStateListener { - providedAuthorizationToken = providedAuthorizationToken ?? ClientSideID.generateClientSideID() - listener.update(providedAuthorizationToken: providedAuthorizationToken!) - } - - if var prechat = self.prechat { - if !prechat.contains(":") { - //not json or string data - if prechat.count % 2 != 0 { - throw SessionBuilderError.INVALIDE_HEX - } - var byteArray = [UInt8]() - var index = prechat.startIndex - byteArray.reserveCapacity(prechat.count/2) - for _ in 0.. FAQBuilder { - self.accountName = accountName - - return self - } - - /** - Builds new `FAQ` object. - - important: - All the follow-up work with the FAQ must be implemented from the same thread this method was called in. - Notice that a FAQ is created as a paused. To start using it the first thing to do is to call `FAQ.resume()`. - - returns: - New `FAQ` object. - - throws: - `SessionBuilder.SessionBuilderError.NIL_ACCOUNT_NAME` if account name wasn't set to a non-nil value. - - seealso: - `FAQBuilder.FAQBuilderError` - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - public func build() throws -> FAQ { - guard let accountName = accountName else { - throw FAQBuilderError.NIL_ACCOUNT_NAME - } - - return FAQImpl.newInstanceWith(accountName: accountName) as FAQ - } - - /** - Error types that can be thrown by `FAQBuilder` `build()` method. - - seealso: - `FAQBuilder.build()` - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - public enum FAQBuilderError: Error { - - /** - Error that is thrown when trying to create faq object with `nil` account name. - - seealso: - `set(accountName:)` - - author: - Nikita Kaberov - - copyright: - 2019 Webim - */ - case NIL_ACCOUNT_NAME - - } - -} - diff --git a/ios/libs/Webim/WebimClientLibrary/WebimClientLibrary.h b/ios/libs/Webim/WebimClientLibrary/WebimClientLibrary.h deleted file mode 100644 index ea6bc77..0000000 --- a/ios/libs/Webim/WebimClientLibrary/WebimClientLibrary.h +++ /dev/null @@ -1,37 +0,0 @@ -// -// WebimClientLibrary.h -// WebimClientLibrary -// -// Created by Sergey Maslov on 15.01.2018. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -#import - -//! Project version number for WebimClientLibrary. -FOUNDATION_EXPORT double WebimClientLibraryVersionNumber; - -//! Project version string for WebimClientLibrary. -FOUNDATION_EXPORT const unsigned char WebimClientLibraryVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/ios/libs/Webim/WebimClientLibrary/WebimError.swift b/ios/libs/Webim/WebimClientLibrary/WebimError.swift deleted file mode 100644 index 13a4fe0..0000000 --- a/ios/libs/Webim/WebimClientLibrary/WebimError.swift +++ /dev/null @@ -1,144 +0,0 @@ -// -// WebimError.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 09.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Abstracts Webim service possible error responses. - - seealso: - `FatalErrorHandler` protocol. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol WebimError { - - /** - - returns: - Parsed type of the error. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getErrorType() -> FatalErrorType - - /** - - returns: - String representation of an error. Mostly useful if the error type is unknown. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getErrorString() -> String - -} - -// MARK: - -/** - Webim service error types. - - important: - Mind that most of this errors causes session to destroy. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public enum FatalErrorType { - - /** - Indicates that the account in Webim service has been disabled (e.g. for non-payment). The error is unrelated to the user’s actions. - Recommended response is to show the user an error message with a recommendation to try using the chat later. - - important: - Notice that the session will be destroyed if this error occured. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case ACCOUNT_BLOCKED - - /** - Indicates an expired authorization of a visitor. - The recommended response is to re-authorize it and to re-create session object. - - important: - Notice that the session will be destroyed if this error occured. - - seealso: - `Webim.SessionBuilder.set(visitorFieldsJSONstring:)` - `Webim.SessionBuilder.set(visitorFieldsJSONdata:)` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case PROVIDED_VISITOR_FIELDS_EXPIRED - - /** - Indicates the occurrence of an unknown error. - Recommended response is to send an automatic bug report and show to a user an error message with the recommendation to try using the chat later. - - important: - Notice that the session will be destroyed if this error occured. - - seealso: - `WebimError.getErrorString()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case UNKNOWN - - /** - Indicates that a visitor was banned by an operator and can't send messages to a chat anymore. - Occurs when a user tries to open the chat or write a message after that. - Recommended response is to show the user an error message with the recommendation to try using the chat later or explain to the user that it was blocked for some reason. - - important: - Notice that the session will be destroyed if this error occured. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case VISITOR_BANNED - - /** - Indicates a problem of your application authorization mechanism and is unrelated to the user’s actions. - Occurs when trying to authorize a visitor with a non-valid signature. - Recommended response is to send an automatic bug report and show the user an error message with the recommendation to try using the chat later. - - important: - Notice that the session will be destroyed if this error occured. - - seealso: - `Webim.SessionBuilder.set(visitorFieldsJSONstring:)` - `Webim.SessionBuilder.set(visitorFieldsJSONdata:)` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case WRONG_PROVIDED_VISITOR_HASH - -} diff --git a/ios/libs/Webim/WebimClientLibrary/WebimLogger.swift b/ios/libs/Webim/WebimClientLibrary/WebimLogger.swift deleted file mode 100644 index 1c2f570..0000000 --- a/ios/libs/Webim/WebimClientLibrary/WebimLogger.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// WebimLogger.swift -// Cosmos -// -// Created by Nikita Lazarev-Zubov on 08.12.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Protocol that provides methods for implementing custom WebimClientLibrary network requests logging. - It can be useful for debugging production releases if debug logs are not available. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol WebimLogger: class { - - /** - Method which is called after new WebimClientLibrary network request log entry came out. - - parameter entry: - New WebimClientLibrary network request log entry. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func log(entry: String) - -} diff --git a/ios/libs/Webim/WebimClientLibrary/WebimRemoteNotification.swift b/ios/libs/Webim/WebimClientLibrary/WebimRemoteNotification.swift deleted file mode 100644 index 68928f2..0000000 --- a/ios/libs/Webim/WebimClientLibrary/WebimRemoteNotification.swift +++ /dev/null @@ -1,176 +0,0 @@ -// -// WebimRemoteNotification.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 08.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - Abstracts a remote notifications from Webim service. - - seealso: - `Webim.parseRemoteNotification()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol WebimRemoteNotification { - - /** - - seealso: - `NotificationType` enum. - - returns: - Type of this remote notification. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getType() -> NotificationType - - /** - - seealso: - `NotificationEvent` enum. - - returns: - Event of this remote notification. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getEvent() -> NotificationEvent? - - /** - - returns: - Parameters of this remote notification. Each `NotificationType` has specific list of parameters. - - seealso: - `NotificationType` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getParameters() -> [String] - -} - -// MARK: - -/** - - seealso: - `WebimRemoteNotification.getType()` - `WebimRemoteNotification.getParameters()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public enum NotificationType { - - /** - This notification type indicated that contact information request is sent to a visitor. - Parameters: empty. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - case CONTACT_INFORMATION_REQUEST - - /** - This notification type indicated that an operator has connected to a dialogue. - Parameters: - * Operator's name. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case OPERATOR_ACCEPTED - - /** - This notification type indicated that an operator has sent a file. - Parameters: - * Operator's name; - * File name. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case OPERATOR_FILE - - /** - This notification type indicated that an operator has sent a text message. - Parameters: - * Operator's name; - * Message text. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case OPERATOR_MESSAGE - - /** - This notification type indicated that an operator has sent a widget message. - Parameters: empty. - - important: - This type can be received only if server supports this functionality. - - author: - Nikita Lazarev-Zubov - - copyright: - 2018 Webim - */ - case WIDGET -} - -/** - - seealso: - `WebimRemoteNotification.getEvent()` - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public enum NotificationEvent { - - /** - Means that a notification should be added by current remote notification. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case ADD - - /** - Means that a notification should be deleted by current remote notification. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case DELETE - -} diff --git a/ios/libs/Webim/WebimClientLibrary/WebimSession.swift b/ios/libs/Webim/WebimClientLibrary/WebimSession.swift deleted file mode 100644 index 1099274..0000000 --- a/ios/libs/Webim/WebimClientLibrary/WebimSession.swift +++ /dev/null @@ -1,160 +0,0 @@ -// -// WebimSession.swift -// WebimClientLibrary -// -// Created by Nikita Lazarev-Zubov on 02.08.17. -// Copyright © 2017 Webim. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -import Foundation - -/** - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public protocol WebimSession: class { - - /** - Resumes session networking. - - important: - Session is created as paused. To start using it firstly you should call this method. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func resume() throws - - /** - Pauses session networking. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func pause() throws - - /** - Destroys session. After that any session methods are not available. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func destroy() throws - - /** - Destroys session, performing a cleanup.. After that any session methods are not available. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Kaberov - - copyright: - 2018 Webim - */ - func destroyWithClearVisitorData() throws - - /** - - returns: - A `MessageStream` object attached to this session. Each invocation of this method returns the same object. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func getStream() -> MessageStream - - /** - Changes location without creating a new session. - - parameter location: - New location name. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - seealso: - `FatalErrorHandler`. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func change(location: String) throws - - /** - This method allows to manually set device token after the session is created. - Example that shows how to change device token for the proper formatted one: - `let deviceToken = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()` - - parameter deviceToken: - Device token in hexadecimal format and without any spaces and service symbols. - - throws: - `AccessError.INVALID_THREAD` if the method was called not from the thread the WebimSession was created in. - `AccessError.INVALID_SESSION` if WebimSession was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - func set(deviceToken: String) throws - -} - -// MARK: - -/** - Error types that can be throwed by MessageStream methods. - - seealso: - `WebimSession` and `MessageStream` methods. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ -public enum AccessError: Error { - - /** - Error that is thrown if the method was called not from the thread the WebimSession was created in. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case INVALID_THREAD - - /** - Error that is thrown if WebimSession was destroyed. - - author: - Nikita Lazarev-Zubov - - copyright: - 2017 Webim - */ - case INVALID_SESSION -} From 517109f27556105f40183727c3ad3e0fd002288b Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Thu, 10 Oct 2019 10:46:35 +0300 Subject: [PATCH 05/32] Fix swift imports at RNWEBIM.h --- ios/RNWebim.h | 19 ++++++++++++++++-- .../UserInterfaceState.xcuserstate | Bin 19492 -> 19492 bytes 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/ios/RNWebim.h b/ios/RNWebim.h index 5d421cd..5309877 100644 --- a/ios/RNWebim.h +++ b/ios/RNWebim.h @@ -6,8 +6,23 @@ #endif #import -#import "RNWebim-Swift.h" -@interface webim : RCTEventEmitter +@class MessageListener; +@class SendFileCompletionHandler; +@class RateOperatorCompletionHandler; +@protocol UIImagePickerControllerDelegate; +@protocol UINavigationControllerDelegate; +@protocol RCTBridgeModule; +@interface MyObjcClass : RCTEventEmitter +- (MessageListener *)returnSwiftClassInstance; +- (SendFileCompletionHandler *)returnSwiftClassInstance2; +- (RateOperatorCompletionHandler *)returnSwiftClassInstance3; +- (id )returnInstanceAdoptingSwiftProtocol; @end + +//#import "RNWebim-Swift.h" +// +//@interface webim : RCTEventEmitter +// +//@end diff --git a/ios/RNWebim.xcodeproj/project.xcworkspace/xcuserdata/alfclausen.xcuserdatad/UserInterfaceState.xcuserstate b/ios/RNWebim.xcodeproj/project.xcworkspace/xcuserdata/alfclausen.xcuserdatad/UserInterfaceState.xcuserstate index 08dfdf3f61d47c3cebc3d6fad9120e0e5958d201..7372fa76543c907606011e52e98a3d5da2b37934 100644 GIT binary patch delta 31 mcmZ27gK^0W#tr47tUVd*fr*=IL>GwwnQVVwZ&ub~R006LObcxQ delta 31 lcmZ27gK^0W#tr47tnI}`6`wZOh%OQVF{SQrR@P!v0szn>3>g3b From 56a8d42ff7e104de7af9e9ad83652e15bedeb088 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Thu, 10 Oct 2019 15:31:00 +0300 Subject: [PATCH 06/32] Add WebimClientLibrary --- RNWebim.podspec | 2 ++ .../UserInterfaceState.xcuserstate | Bin 19492 -> 19492 bytes 2 files changed, 2 insertions(+) diff --git a/RNWebim.podspec b/RNWebim.podspec index 5220ef1..a2739d6 100644 --- a/RNWebim.podspec +++ b/RNWebim.podspec @@ -19,4 +19,6 @@ Pod::Spec.new do |s| s.source_files = "ios/**/*.{h,m,swift}" s.dependency 'React' + s.dependency 'WebimClientLibrary' + end diff --git a/ios/RNWebim.xcodeproj/project.xcworkspace/xcuserdata/alfclausen.xcuserdatad/UserInterfaceState.xcuserstate b/ios/RNWebim.xcodeproj/project.xcworkspace/xcuserdata/alfclausen.xcuserdatad/UserInterfaceState.xcuserstate index 7372fa76543c907606011e52e98a3d5da2b37934..9cc9c20865b639f8179f4e3c234887cbbbce166d 100644 GIT binary patch delta 31 lcmZ27gK^0W#tr47tTS~l&+Ob>Bf3Zg#B^%htgOYT1OU$43-tg1 delta 31 mcmZ27gK^0W#tr47tUVd*fr*=IL>GwwnQVVwZ&ub~R006LObcxQ From ef18e65134aa2934257b3b28c7605169039f38c5 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Thu, 10 Oct 2019 17:02:09 +0300 Subject: [PATCH 07/32] Fix RNWebim.h --- ios/RNWebim.h | 28 +++++++++--------- ios/RNWebim.xcodeproj/project.pbxproj | 6 ++-- .../UserInterfaceState.xcuserstate | Bin 19492 -> 20612 bytes 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/ios/RNWebim.h b/ios/RNWebim.h index 5309877..7fe8f00 100644 --- a/ios/RNWebim.h +++ b/ios/RNWebim.h @@ -7,22 +7,22 @@ #import -@class MessageListener; -@class SendFileCompletionHandler; -@class RateOperatorCompletionHandler; -@protocol UIImagePickerControllerDelegate; -@protocol UINavigationControllerDelegate; -@protocol RCTBridgeModule; +#import "RNWebim-Swift.h" + +@interface webim : RCTEventEmitter -@interface MyObjcClass : RCTEventEmitter -- (MessageListener *)returnSwiftClassInstance; -- (SendFileCompletionHandler *)returnSwiftClassInstance2; -- (RateOperatorCompletionHandler *)returnSwiftClassInstance3; -- (id )returnInstanceAdoptingSwiftProtocol; @end -//#import "RNWebim-Swift.h" -// -//@interface webim : RCTEventEmitter +//@class MessageListener; +//@class SendFileCompletionHandler; +//@class RateOperatorCompletionHandler; +//@protocol UIImagePickerControllerDelegate; +//@protocol UINavigationControllerDelegate; +//@protocol RCTBridgeModule; // +//@interface MyObjcClass : RCTEventEmitter +//- (MessageListener *)returnSwiftClassInstance; +//- (SendFileCompletionHandler *)returnSwiftClassInstance2; +//- (RateOperatorCompletionHandler *)returnSwiftClassInstance3; +//- (id )returnInstanceAdoptingSwiftProtocol; //@end diff --git a/ios/RNWebim.xcodeproj/project.pbxproj b/ios/RNWebim.xcodeproj/project.pbxproj index 35c2eae..4eb12e8 100644 --- a/ios/RNWebim.xcodeproj/project.pbxproj +++ b/ios/RNWebim.xcodeproj/project.pbxproj @@ -205,6 +205,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + DEFINES_MODULE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -249,6 +250,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; + DEFINES_MODULE = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -271,7 +273,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; - DEFINES_MODULE = YES; + DEFINES_MODULE = NO; HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, @@ -295,7 +297,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; - DEFINES_MODULE = YES; + DEFINES_MODULE = NO; HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, diff --git a/ios/RNWebim.xcodeproj/project.xcworkspace/xcuserdata/alfclausen.xcuserdatad/UserInterfaceState.xcuserstate b/ios/RNWebim.xcodeproj/project.xcworkspace/xcuserdata/alfclausen.xcuserdatad/UserInterfaceState.xcuserstate index 9cc9c20865b639f8179f4e3c234887cbbbce166d..c4a1a0ec9b1f059a412230715b17f7fad2f6b43f 100644 GIT binary patch delta 9758 zcmaJ`33yXQ*Pbm~lV)w2G=(N<+O%1lKv@Opl28hzg_g3HQfPoeq0kngAY?9!A|L`m zHrcuW0)mJNDx$I@Aj%@5B0I9lrl`pJPns6=)8|i~G|jzp=Du_0opa7RQ@0pStA=yc zgcr_}&Wp0Z3G>n&{sEv63*LO2i>!9j2^EQ6!r z7+4M~U?m&}C&9^ZDtsNzfp5UMa2}iwm%-(51sD&j;ad1M+yvi+AHdJx=kN=75FUbu z;WzLH_#-?Ge}cE+9e5Z13V(z5;P3Dc_$Tx~hEEVdJj6#5q(oX2gJO{hwMQ?a4k!hs zqBN9_JjjbWq72jtWuaWu7xhE^Q2`o&hM=Kn7#fWxpo!>ZGzm>cQ_x&A4=qHC&|@H==j_HV-<;g9hrco*J{_uy~v zQG5&^$0zV9d=_89SMfFcJN^UziSOgT@MA)VgoKkQq9f6y3291?n!k#r^bq$lY`3djIbNGeDr8B1OwP=i_9jklQ+pq zvWirb8d6K@$R_eG*-YLe+sUV72iZ>!kT1z$a+>@^&XBX@9JxfUkgMbxxk-K_f0740 z%oFg0JV`*nymEr(1v=rE#Uto3%BKVA2wL#|*EknO52UZsJ#;_2WTpiLnI5mVxTLbI zJhj|c6v*IB3^;jF#m9jNgaI+g1bM)`4s-@xKo;l8c8)&OQWccM$;y= zDUDeNdVqWo2Rg8KAJ7-{14gQ+&Fi0HrbToTeI*E?Z)s6g+1Sb+L;*F>W+%aDFoxYK2Nj@_-5vqP zf$^XUOb7^LvSX5{TMnsF4!#91gGsE}WZ(xBa9|3U3OWSlXmdq2YNAdWOU;36+E#tR zt6*jgm;qj+aWs)ykAvCZb!Ik)4PtKJ%wpfD%90@^zViIcQN_OTG@f}Zp-*mhFW;b& zk96Xt-~1W#bc; z2A@DJ!47*hbQtPxC0NxfJ1@1oyr`-MtOSdXgBk{?7Sw^&ptN6c+2FAw8LIr;tUi?` zBYhQ>MI%R3J9SV{DDNCFsx#voV66k|3*{5nzon8;qtC$Sg>qAUqbj{v0KNz|s{d`udPa*z>g@u1fVmp%rpeV{ zFKs~!0;gn2Dd0-Rob4uNITFJno84X z`dV-u+yK8YZp;CN=wr-kZTq=%s7m`9ByP;%?wtygMDHv7x4eQs@PBYza6A6;=59vF~zUDI@Mn zK1RR()EcG4|~F1us0n<2h(EetAl-EKiD4@&>?groj@nj zg5FuaA(cH#eB%P$qO~3ShKSp>tk~Blw`AzB`a6w%7Q>QYpFTJQ4u!+$P&$m3(BXB! z$fmLs#Ibm2rll-G76g_=k24EHkjK_fQezk6;RHr^SVc!w!-=$vHGMZ+*UAs4)IbV3 zI-0&js~X!*gEJWU;dJ;4e3g!&<+P#}z6RppELzDPGM2G`NS*#?_)RGj4gX+I051BM z{bFXnl#XNe<7wXW5i(nOy=}<#E8(gE*?C>ZRu&B^_0`9&TDUS4z3P`2tbujGVbs!> z1=WnhEb#;^O`?@>9o!JSzMf95hVM{+Xn6k3!Qs6Jw@^x_J|EtP@Z*2M`-H*!lyVH- z6bA2EE;FT+4E)E?cEY{?vfT%a@Bp30W??$bE0oKabtnx5N}EPDhhM=Xz`SY|EogM_ zQTQz|*TQ4)I6OgT(AVh9T6hwE2T##ibOl|>u)FxCh(fs{&sWMKy{|aC=%tdOMJ%-j z9`Ovl8@o9Je`b*eo`vV&d3XU{gqPrDI-9;u=g>FkTsn`=Ukk4=XxA7`jPMtDlLi>X z1?)3|E}_e4!2kxdXGui~b9F9zPGG46FZyORd`K6vsoo*c`JW=lyo&%` zRE-c_ObZ%QO}7RxNPt9*b|{Q4rFo4v!jbHmshqy`%nL|`)a(YBL*pCzY_y0%EcS#T zpeA%V>q;Jqtw@gyAx|;~S^X#uxqx{Ciic-W0!l;{WJNY)M-JpfNpux+MK!IVwX}|| zrfcY0`Zis+0T@v;5Qmac3)C|B4!Q=lWDZ%+W_|syC`VOrM{q72<)S_&ZgSyd;bPN6P89`AV>dB%n>VfjV$&{lj1|DyHw#4}xrr&dmqxx`&HqryMAk;ex7`5m< zv<1CSzoduh*Ut^MqEG&J;iK)0N;~L5Mx8@JSIZd-o-Ng26>LfwQy)CQao`VO+lBW1 ztC#((moMp8td}D+@1JF~DP@-7@8Jg>LC5}Of1KHWOTS_EM;lS(SC*8PRF?QELMTS3 z0Bf+DW9SDqQ9q*7!K_$ZR9TdxAgu?DE-k63bh%DIgb9zI+#*ntl&De)grYF9BwVU# z8l#W5*&VLt0j0qf_Pl5fbT??@(mly-l3S*`9NyG)wKaOkzg8N=6lzjcYJ+ z#vL;l-Oc`4uDIg@6Jm|VvvOI>R;}B#eW6|Z7dxb+rlotl9Wy#*cFxS|nw`_Fdv0D} zYitWG^Ic{|7hhFRRyJg2dKiYxieTj!_%(L2Uqq3Jl^28xm3OP^$SyV3|1PY)7 zCg1?gKr5zza+&%V$K=F9Ci}l-LjMx01pi5hvQI?-6>5*s-)5&${Bea`o<6~^PZ=nY` z97o|K+!m+fTqbaPHi+B)xPS@VA|`QtOyri}5%pvPEZT=&JsQ3nzVK*zJhbx8ptA+f z^0bFBsTQ3<=fJSV%qzj4jcf4&`i03pbP-)bm(kDY3c8A}q3h@d{g$4j-_cX_d-?Iue=q~yd{f6$L-x;INa4?mF9uDSma0~~_IatZTv2017i@U9Zm;iGP zMi|qx^jr<*VLm<2LBekPbZuEF*g8&(!`U*&5_+K;OX($+eV!MGSXEyLUJS&j^IJ3k z#*sLhRa#hswaj5UdYS%Auh6S?xCw5GW3ZlHqu1#T4#Hq^a0J#Vqm|vt%Yu3=qCjRQ0ob7XEKb5G3>xjtirB774>MIlD@zT(u_3Qk_sGJj z!Kb9rd(ZR;_TnsHUV}U04BQE4;?B4W{hj_n|D^ZnU-ZEm+!bfD(wejc%*JET>gtMjBL&U*aHU<8o``{e^N} zNJcX`;7B*5m6sF`WrHzv3aYI}G%~6hI3HI!8i^&ILM^r-&r;*$TAM{3+28cC8fT$Nl8ihfdX?u)IT%SNa8ScMv^H_Je`AnIn>eUy(2n>$rXBGX z{C@Dm!3YkjLw}iml*mP^!6qDR%E6dAd_QM&Y!KMxATZOvfXRn7;<}D+2XWoNzu=qr z76;=w$N(g8FtHA+?$qP@jf0jDE?Wbx2SHp9IcRP4;FJGU-wn?oJR+>eMFc@y_P=TF z|M6F&ft08iC?X?rq9APgoE%Kzpo@drJ#khx?Y znNI>7?8U(X4i<5+m}46NjY^#?Buj%`E+UJ`5)Ss}ARAZTTJjcIhL{B#UVoMy3Iewr z0e_%(vWM*DppSz?I5?Eqc4*j*8Vn5a2pHV!6ec*D*V}cUdoYEGjvE-ZGP*mwhPvM0P-SSaw`?N_JUxRrb5=fgH(s@-Vqx z9xHDp&y;7$y9eG)(Ra?x_nK)Y1G|2&(M3*=%@4FvaqgGI-*Hk;ah#KBSZ z*_B)-KZgoBUk$ko77yrAR$NqND5^BL+O%z+EFWGkn#gq~Y(Y3h&uMv!++k@qc&(b; zLOnHC@>k}=#z)~#-S?V6oLele;$>WF8 z-nhS|Ox53Ri$k}of+~|`dscz4lHFIFT0VFfOZnwTc`}|nKd-W=(nley&Z9squz?n! zEsKM#*jZ3#Rwfs)DutEA^(Q}-_$7Awvl4G*hdRgDVa`c*obv-djnA-javR^pzp+D| zKiPrKL;M&&B~p^Zj%I4fUUHs1;;H?-Se~2LoY#Wair0qs0IRcvtv-MWBGA>Ge41U<=gpAzKh?C@8xIkGx=TkUHLiu z?)*G{KED^g55Jf{i9d^9!{5l?&Hs-7KoBm75i}Qc6$}#$7nBM{3H+l4uLbuK zAlxeaNcf3xkMJwuDdBk$5b;EDB8RB0sGaCVQHrROsJp0-Xn<&hXq<=>O%+WSy(&5( z`bqSg=zf?qOcR#o56cKE51SSCde|Fb^TGmQ%feQMRfpAvy%Tma>_;(AEEOk<+lULr zrQ$O27;&ZeCGmLiD)C0~X7LvBhvIGGkHw#f4~dV7Pl!*7Pl?Zp&xhL&-Oi zOW`0qCfpj{E<7_lH@ru9&+y*ieZvQb`@)BYmxPZ99~nL~d~^7T@ZZ88g+G--DV9p4 zYN;nGrRnRL8#x^$*=rLzA&RZjo-2ek|QC-61_FJuE#U{YLte^sMx}^rG~J^uF|g^pW(5%qe?8mM+VY zb(iJI@?`^L#j+Avxon2)4cTJZTe9V{m9nj}ZL&SGuVi1#jXLeWamM)888y`qbvw_=2%QZY#}Q!!5w zP`s&Fq*$R?rKnNVDb^@9D?V22QXEyBQe0MCRa{rxRNPkFRq~WdrCO;`>io(k${1xc zZ3RR1;N` zRDKnwnyZ?xTA*5}TCDOfRV`DkP_0tEt2&~(93hHGj_4RMHezU_vu|ML=h{F*_BEE?@74dz<&k@%mZbaOQxD)Yf#8Wj=6SY7sQj67Eb+o#v+MteA z$En@wWOYk*8}$q7_Ug{+F6u0Gwt9?uvieQ+BJ~pWTk7TNmFjB0x>mhfy;i+Wy+OT8 zy+^%IeL#IseOP@&{f+vV`h@zV`jq+y_3x1pk@mqre=55V-%{!V+nh!PGG#_iWYj$XMX-;Y`X#Ub7 zEl(@ZinPtNnc4x`a_w~OV(mulPVH{(UhRJEm)b+xBT+4*Iz;t}8W=SpYHrllsE?v{ zMjebg6!lfq$*9v&=c8^#-HrM!>W`@VQ4e%6x&&RK&dLrMbZvF*bRBf5x^!KZE>D-Q z>!s_X>!%y0E7Oh9Rp`d*Ue-<4QQZ{XG~FWID&0oi2fD4gk942tcItNP_UiWQzSMoE zJEyy;yQlj@cVG7)8b;%2UbG-u6x}2`KH3@GQeUpG)KAjS($Ci~(XY{etlzHRq5oXJ zQ@>lkSMT4i|5ATQe@1^!e?fm)e^q}&e@lN?e^39X{x5^v;4ri`bT>>hEHu1t*lRdv zxM}#+aL@3E;i2KNk?jr}+ZjuZRmPW%lZ~8ls&Tq;zHxzZp>eVCrtv{6j^)J)Vnwmy z*ofH3SZ%B>wrQ+BHYav+?8exiV*fI!O)(~;-()hyn_8MuOlc;MsiP^=lxr$94KWQf z4L6mVDokTd<4jeiiKZ#0*G!vC2TjLKCrzhJKbWqV?wS5D-8VfjJu*Fs199PTvN%PY zDo!1ziHnMhj!TUzh?^F-KJH-L?YR4KkK>-k!+0DoiI0re#^=QMjvpRBCVoQv)Oi2& z_+9ab;t$6kiT^JC&-f?i7;~~Y)$B26m^+)hnsdyR=6U87=5^+G%lV2s*^+1JZz;44vJ_iJT3)hLSzfmI zEmJJhEU#E*Sms$)SZXb+EpJ;kTHdv6v3y|JZP{lzZaHl^Yq?;#Y`JQ=Yq@9n!*bv9 z(DK--v!+;!ty8VDt#4T8TNhZDTi00Mwyw9nW8GxkY~5kqW!+=lZ#`^1Vm)d-ZuMWV zUb5b`KCnKv0UNgQZ8DqE7GaCDMcJZlt!)ErQ*70?^|p<+&9*JJ?Y2F(eYOL(gSNxA zBeoxH=WG{jmu=T=zu0cs?%1B%C3dx4Ymc_a*o}6p-C<9%yY0#Lmi9b*m3_JWQ~O@~ z0sA5QSN48DM@vT=M>|IcN1CIH zBiqrmO4Ij{N(uAan13Iw679j-52yIp%-`(1b3G49Up zJa=FBQ1>XmdyKo%JFd+CrGJvXBmIl?-Rb+%zf3=w z{(bt7>1Wc4%^x1~4T>-A=MJA2o9Kk#n# fe&pTW(bTa;$F?0CBOAt{6L=i>!-H>0ay&)0B?e~z!IT5bOdUf!*L^upb-;C%`Fi7MueY!6k47Tm|>Q zpWrWWAN&m-fQJx3Aq;^MD1|bpf_fi}f$`7*6JZi;1KYxmuq*5ayTcsV0~W!)umlc+ zrEmhA2q(ek;AA)jPKDE;4-z;7z6f82bK&c7F?<8Q375i6a5LNjx5D?}Hn<(W4|l*% z;b-u3_yznD9)!o>ad-lL2T#JE;Lq>|`~}{Gx1jGf{1x7Xf55-s1B8$eg&{GLAr(?1 z4T?drC=QuXJhGv5)E;#}9Z@IL8FfLKs2j=!U!y!!hz6o!GzbkwBhW}R8a<0@(0DWf zO-4R69o3^3&>S=uy@LE`DO!daP$OzW8_-6y32jDO&<-E^0DX)Opu^~EbP}CH7tj@S z6Wv0$(S7tcdVmoQ!%7^9O*j_EVKcU3Cr-g_a60aU-MBv8HT*hWj2mzxZo(_^D!c{zw&M5jHoP70#C!2R z{3Sk!58-Bf0e_Ew#Mkj}_;-94|HX(I856;%7&T*HjEsp%Wm++B%Tsh?XIn@sI4ols>?2~sH?82?O8ghdR(2qQZTvGkesaS;8S;vx0D5; z%^(zn0Wru0`M}ZydV*dck7$XGL^grmAP*D}J&7b;dA>$}AC)FDr?z&Sx3+|p7kVqb zWp&>2ywdR%BTMN#uPEYtE$jw>a$s2t27+QR2n+^8z)(;EhJjKr9F!3QF%lDrBGDv< z#F98-Ch>$0_JR>028;q`@C?27((4%DB?-hvSL&dP%cj=}^x97UQ*ku>QYMZqtt$7H z_o^=UR^|_XMnNU29ZFyHtEjCQUg<5M_x_VAqgq9uJt;7KTkHQ#73EJ<$NNX9v;2M3 z3g6LyE~bKM%ZT+TAbQqsX=}a)Y0n8$aBrACT5}4ftUIuf)JmMs+NL!NC z41B@8cm=!)A{v1oEF>puS}z8o=@=c&z{{No&%Eq?WMyM|=t=RE(&L&a56Y)<06C$OLP_ z`X@*>fQ=-LWRlbto?F0n-d47P_rNyNj--?JP2hd71AIU_kdDMnJpNr8cLvx4_BDXL zq!Yx?#ir~}B;QOI@g}uhrl~T(H&^3X} zJf-5{qfg87e*iauWfisTAHj9-6Zje20KZU+?nb(k9MXg2lAf!;Eo!^J1}yk@aF_I= zHk%i)+(Ocqw_O7@NB?_@b3O<$h-iR_eY z07FTi1}G*4#M5F2y<0}GFyb*Y1u1&GVNeaVPm;D!bTB~EW0EM+?;ny_7zZrNmJv_O zPz$v3JQB!&252J#=_dcFvqeKEn7xcQ-GJr7WSGhiN+E+9U@J114l+eVc1WY94%@+W z*q#g_!%6u+<2yk&h-iYHVHcP|hLRF8tO>LNW|&1->hPsB;B}I_%HuMg1%Xe?G`TSU zDY7(5RzQ@Ltc;|_Wz30wf}$TR{!a=xh*At8UP>{7P86y)v_vmB999C$8dwI)p%;#T zBjG4m0iS`R$tY4mo*|=2B^g7iNHrO|2E@QB8nMzrI;?@Uunvx+`}{2BsiNP{$tiM) zT;_M2EgV%nAYI88S?7>oJvRZ>{zpCFuWF0Kqj>woV&2dDE|eV)`b zzKq^<$ZA>)Xrs8?x4Rf~@1K|jCZ`EUVzg^VW?$iybNkV?6T zOrnx~N>_YUTv`O*qD~5zkmpE73*j=jnwmFkfQ_&TE{7}NO1O$lCR4~%GL85MA>1ms z2EGH=!gch!9&RAdlj&p!*+;+o$pI?eTjBGIG-cIeT%}{jR(f3%%joi4V{5AUAlWj@ z2k>JMu>$UdAHrSmBeUamDYK4y^}JlD=SOK)_Tix>bzrUGK_js zsGv+)6}4mOX7ZaG2>I|Eux}a3D0Ej=wrJrLyaX)1Rq!-C1JA;9@I1T#FOqp=K3PCs zA%3!uyt)crhTp?0@GATPUV}f9MdUT|I(dVAai?du&1}~u zIXR_uTHCa?C2Vw1tfyArwW6}lTSM1T!a4?&`FMRkHHJ!GR#{D#m`C$oEghTcO8#fE zw5KO)kt6+ozj8nQ$})O@FR-Cc2~b#8L$%zyx}vI%&fcQ2JMgz)T`y}g;O6v60($J z978NkUI%~}$x#GSAmzZ?01Bdsmo$VVrTQ> zS&xK4T4bO(6zNbT(vv2#oUCX@;jcg#B193=2worz8^LKG5gTfHxCL4Je zB1Ty#8+9F+SLmv(tEs3ONj8`X-Lu_U*##we?q1meEu-!z zhbF0i^cYS+p(IsQ2V;wK$|;6=5L;zY8Gs^p`V+!>Uu7S;JL zh@u%ZjtX``6cw-VJ8qqXLL$8A10ujXd zHDQSiqJ~E=9HN$){3xbjmjLn!Sr(k) zCG;|dnG^{%qL)B@P^0tsRn8}$kqrM*nI^x*niitPz_J{@iWZ^Q(Cg$2@+CP)4lPG- zpf^z(T0*`e&C~>r6VHI2-Vt^ED!da07F3KJ6}T!6mIr*8^52qaQ(AZ~M{9VVE6_@` z3auuG$=BovIl7#Jnsj&sm}#0*(dek=_l%vOYoXeTw(&dq9y!(k(&-3~|CU_uLp#wf zK3DO;0DVMG5KnM9d%)~Qv={9o-;nPfqXP5^`r<#6HF_18(IL7pHTjlL?~^nBo!-$A zbo?obMU>)Ost7eXNr6OM#&b8HAUTcBK9=YlIo%@BMP8yy=rTD&&i^CPRdoF+{y$Ov zH^^Da{~S%G)e(`g=vQ?2sbPPB81yH(K-G1T4qF=$t49y|$%jJ_7)2=FylfbRZTA$h)^$PIGkU(SJ5Sj{^J){*Pv zYQQmm4Col^smWji`Qfo+;3(cP$hCj_!T)FQPY8l-RFnu{>rMfCck(k8^#<<}w1mVi zej*VSJtJVhI2E@lVH5mvaa?#FHLgb78q_~}AmJYbN43RieyKQt!R@HSNW~V*QQV#~ z>wr7*{!w09SDG(p77ZU;NlV(~Wk*d@Nv)z%H)TV7( z`%eBDdPi?spgw{G{{-O@HiAN~{?#?3YsZ$BdHYvXl~+$FVa-{|X(^elle3-KscqXh zTc>8Wakk59o8`<(PidXisLGQ;D8AM+MFy}^Nsb^@Z~m*GXI1c z63QkJQU8*>!uBbtDMvM0UF3hOB1>3PUSaRY^nG)(tN2`4Uf>6A6*}Cm32AHCm^O z7B@7bdc9RacW-p+o0C&ysjXW3zc+LdutZKG{P!81-(%D{G}?CQbbL@jkH)vt(`9t% z_++KoLGPbojM1OTaC^Oel(2bmH=# z4OG%v#suS_3#P#Va1aIPqbcg1M!R6o!+P2Yn+fMpXu6w1$bIkt?Qi`7|3=}ojish} zktQ27z(;#jwX_p8pLU@dX<*xmw$pg?E&3Hh9Ey#!t(1g4I1iWNF?c$jOB+Qi@oM}I zUWebs8}KIDD0+|fh<4B}(XK!^0SE?vX+8MF2k#}ff)?HxcNy|HUHY=9MK{rIP6nu_ zYT@r5g-$wcPg-^0Oq_+YaaY_8cgH!n2hJtGk~`!#@;kXp{vh|rpX9GKz)VHV$GveM zT!0I45$;RF(0vX%IOyVFM-C3*;7|?@<6tQd5tSZVaEu_~`O7N9$i2Uife`AM9I>7vNX;KMsa*P#pYEGT3l7G%h1H zxE(FpeFHC{T@Cyuev5-r4$2zw+juDlSq{o+T+Wq7dhl|<<8!(A?G~EV_+4JmHFW>i z;&mKUa8SuX6$jPJ@p`-gq~lE-)NoKo=(EV6puYEcL3eOa+al4+?7OJl>tyvmq5q6*f zAK{>h_*yDrimj7L1;WKbQKF60>9E>9Gagg>CgPOg_uiz2~qyGhX@fCcP2fQ4N ztl4w$OD-6pB7g| zrMD*98QsnAj90|`50p!-i%|riD-S{SkJiU%7#;1EFj@{KHZYMKbW*!1cA5G`F;)<< znu%s&m{=x`F*EUug`wglageS#g@dUaY{kLW9BjkEwyPN%?H9x_iHwtRF-gG8!8Gc; zb`G}VU^)lebFc%wPu=pBOA8Y+m@KMO#?5$`Ob&M9U}p|?X=1XOu1q%$W^iyY2Xm=b zCCOv@^a8V2FnLTq)0^qT6mZbZ!R{RF$-&+nEP9M(n7+(Fo@GC#KQn-X9u88*Sxrna zGl-$gvN_n5gWdS3Ve!YLnEXE^*Z5j6Y>OtmOvQg=@eDJXmnw&YJpxk2Wjug>u4=n zkM_`H|pUdV0@<0v_qQwMtx)L@vU?QR{pRbYnOcS%5 z2Pb^XmJbf~>Fe9S&%xqA7Gzd3tAhE?+sLd0^+SuQ%S$Ikm)1omr?+p_nhk$Akq0;_L4{9?AQ@Pt5FiRBZCzOG9oG+<+_bXmWsqkUS(A zftr;z61?T^nzB)})T%kc>|^%#4YYI!qzFU@Vu1s+0qsE-9717tBt2uga|?fVu3^;6PN_if>?oBU=dgac0r=RCFmw77K{-P!3M!z!PkPLf@Z;a z!BxRE!F9pUf;)oW1%C+s6xiYe;cORmk%pZ-;CN`7mTx z$nKEOLYhNPhg=M~8gf$Yv$p&_B+q0ym~`2+V(b%(#4d4~xReOyj#3Syia^U{Hgeg`0wzT@SfpA!(R?x z9=<7jYxuVC9pO8}cZDAgKOKH9{6hHU@GIdzgx?Im75+d1C0HVqh$LYWjU-ZHkVHvh zByo~tiLaHUjijBVy`-ZgN76%*E9oUEmJE@UNQO(wB_kxWC4R|5$s$RUWTj-aWUb^~ z$p*D@NMDrBmCpA`Uy&}9E|RX1ZkFzr9+e)Go{)YkJt;jc zJu5vgy(qmby(_&Z{Y(0{^q~yOuuLEek%h{{GLtM#mMt4B8!4MATOivi+bugtqsS2& zM^4DTWdSQ;SvG=Iu^LuKBZ-4eWm~gt*>-Ff*3D+pxYCWSW#_O>tZyB=f!)MzVLxUM zvq#uw_Bi_u`yG3VJ;VOQ-e7OCx7j=F@9ZD!pX_~ks9YsamS@R_$*0L@%a_YH$v>2T zB>z~xSH55ViTsGXS$ z6lsbKg)GKBvW-4YYUQ*0e%vY>ce5JUr z)F@Mxy_DmX)0Oqg7nCn5XDSycUr{bpE>XUt+@$SLHK|sp)~U9r zzE#~({jCOSq-NA|wMiYVj#Zo07PVDvSEs4d)g9EG)LqnWb*4I7JzD*udcFFX`i@4Y ziPgkw5;QhVs-~l+vu3iUUb9HEM6*(}L9`Vj9(gkI zQskA$A0mI$L%me5(d+bjy-^>f_gVFJeWKo_Pu8dEJLt3Zz4fE?NQ+uo*fTdKh{c@(l%sB11nziJ{yu!Z6D4 zjA4Rdnt>ReH`E*E7+yBaGb}Lp4R0CN7&aO<8@3v@8Fm?V8}=CX`3wgPUl~pr&Kk}e zE*ZWzTs7P@{ARdoxM%pwC^E{7a-+hiG8&8~W3(~WXg0cxX~ryLuCbRf-`K}Ez*uY? zY#eGFW~?zzHqJE8GR`)>WL#q0Y&>YZYP@E=Zv5H!i%DdXo3tjgshg?L)YsJCG|)82 zG}csOsxyr@`6im4Gfg+mFwHd0HoazAYS)lmz!(Mlgz~YvU!=g(Y)Ne(!ARI zj(MGVy?LW~v-yDeQ}gHMgXY8Lqvqr0Z_TI7XU*r$cYX27_?Y;1@uTCX#=jB2F8TR+nJ7hcTvmLQD+m74L+b-HJ+pgNK*?zL!u-&!& zY5Uvu(9YTwcC}q=kF>|xlkI8tbbAMTXM482yS<0Kmp$KJXP<9hY=6tX)ZSoUZ{KO( zW#4VzW8Y^#VE@#9%>Ir2r2Vx0to^+GqW!Y{XZub2ulC>U4;;YJ$Nh;MnE(*s;&?iQ{v}LB|=#dB;V^Wye*=kB*-mHyyVf zcN`BALla{Y(-ZR&%MvFiE=+tU@p|Iz#CuN0DR*j}dZ)=5$vNL} zHaXWjH#xUDw>v*@?sD#S9&|SQoF|;$IZrz;Ij=acIe&8AaA{oGu4i4(xj5G>*CN*v z*D_a=Yo+U5*GAVC*EZMtu05`OuFqX3TxVS8U6))}TtB;Rx_)*2?)oDMCNW9jNxG!y zq_`wYk}WAYsZ~)d*GhTH3&=icGo>;A&s>^|W>=f2{;?*7w#-y`sdJYk-2kIrN8m^?8av&Z5| y@}zoNd)j)scrrX5Pp+rHQ{?II8R!}08RMz(ObnJ0h@Ri@ALc;tx8=X*x&H(Ez-Qh7 From 2df44726d0d2ebde37b9a4aa6bc6c1fa853e9d8b Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Thu, 10 Oct 2019 17:13:08 +0300 Subject: [PATCH 08/32] Fix swift.h --- ios/RNWebim.xcodeproj/project.pbxproj | 6 ++++-- .../UserInterfaceState.xcuserstate | Bin 20612 -> 20837 bytes 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ios/RNWebim.xcodeproj/project.pbxproj b/ios/RNWebim.xcodeproj/project.pbxproj index 4eb12e8..b178bac 100644 --- a/ios/RNWebim.xcodeproj/project.pbxproj +++ b/ios/RNWebim.xcodeproj/project.pbxproj @@ -188,6 +188,7 @@ 58B511ED1A9E6C8500147676 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -233,6 +234,7 @@ 58B511EE1A9E6C8500147676 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -273,7 +275,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; - DEFINES_MODULE = NO; + DEFINES_MODULE = YES; HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, @@ -297,7 +299,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; - DEFINES_MODULE = NO; + DEFINES_MODULE = YES; HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, diff --git a/ios/RNWebim.xcodeproj/project.xcworkspace/xcuserdata/alfclausen.xcuserdatad/UserInterfaceState.xcuserstate b/ios/RNWebim.xcodeproj/project.xcworkspace/xcuserdata/alfclausen.xcuserdatad/UserInterfaceState.xcuserstate index c4a1a0ec9b1f059a412230715b17f7fad2f6b43f..224f79280d1d6c7d4d5fd86423aba220bb9471bc 100644 GIT binary patch delta 9018 zcmai22UyeB*S;$Q60#FQAP9y8$b`7DZla=s$`HkYpb=4)fLojUtD|*~Sa(&1t5&PE z)~(g5b#H53tyMd;{X1)0_jf}8+pquU`^ZCn$<4XfApb}JpwO|9-3_b@tz#ecAdLv+SOUx8NH_{kfF3vrPKHz9JUAbE;R5&} ztbmoU3Rc6_a1C4!KZTp&Hn<;t2@k-7@GE!-o`z@OS@;dS3~#{i;BELHcppB1&){?T z0=_{3C=iK|7=@z-C;~;IhR9<;QOJl)$ck*J5o(N@pq8i|>V&$YZfFR~LqkzM8it0W z0#t~KP%$b&BhW}R9!)}%(G)Zl%|>(3T(lTfqAFC4R--lOW3&V9MElTw^d&lg4xz8n zDRdg0LzmGF^fUSe-9=B(@8~Idg8_yf%)mR57|rhk)z}oIZiH;OXM4J zh1@0g$gku#@*nbu{7#;dKge?);1QmHC*!GjYF>!98E%d5&^+%LJVE54wMQxDDE z`Ua=MpmMr|UZj`VkcsAc2k`F6oi(3LbR?Za7uN{(;me@FP63Ue@!k?a9=6js?^S^g zPWC<(qz0I&f!b(88td&LOlUQ&0(?NDXv_sL1Iz>>FblK+bFz{KyNk;6hvd6UGm?r1 zyT?!?(-)nYnv&_x%`ZF;<^wNS06z4d5;nmL!6NSu!UpNRQ_{NU4s#DG_y4>EEX_^ zElc&D)3)=@b_taBF@uT+yGu%ohxu2p2CKc{CJnC=tYPZervU%>IjUingY0Xj|HjwqFZ=1V4eF!7uD}5By3y&_p_v z7O__`En(P}i{~Z<4=OIS=aiHbxc#)+eY`Tm)oJ+yya0-7@F(~SJOj_Ei*}@)Xy zW@a5^Xm?=k&c`=y=xUWgB@70pDyV{LsG;3y58AT|YGDY}(Nvm7(;4LPhVFgdx*jtg zZ0OTypc(bVKohh9(;65JV_+;aLkqOhUNn>TrhRA@?Yjorp@Y%OUa%4EM+Y*JeXkt0 zdT7)Y1AGUzu7Is*f0})sE#DTlgYEmIq}j{LOY@8J=zwflBX6iN!jqJemfo&gx9sli zyL8Cz>}r?jO0Dq=m+yZx6&Aci$+z~8dapC{&7wrs_2Gk4Ighv(Z z>s3A!EW%(4?4B)C)(aE#7MSGM)>Cc2h6VY zt$ztj025i5ybC-q2j+tJz$ECVg*3k=brkrq=K0Jpln$%U9&k9Lcn%%TsI5;H|0V9_ zEb#pyUT0P>icIKw0gh(mj{ya699YS6hdno^%-xqgOWg%In zvPLDGSjQdp;o)c*jq$FOM#N5qGk~cYz7Icu)8KSEijJmZ=-6sF6V8H-;2b)Ra?Ar} zF;0GwwvJs0m-(a@!NqV1TuR5&33MWTw;Dt;pIHH-SY|a*%5p7ZQ1)(vwP4z+x8C&93wJFW@c~`fxkk0e8|VbSizn3ho9` za4-FUtv-zfRV#VtcsgraDlbT8M`lROP4K44L?;dSvJ6;BSe{~wp!3#b# z=jrSU(1xMT^*)k^$-jkHeWO?C+zNP&&a1`vy$|C}_ye6!KYWYv4*ca`+V3*$zfv#L zzJOsYR)j`Agunkw>M4kXf6|4Ftwl^~gTml^310!zs#P?%79IkKuz*JpA%y8tx{NNb zLOjGr0{RjCly0WE^OXbIqadVanGQ*i6v>brDUcGW=nA@$uA&vRl2*~`wMYXZk(L=K z5{05Lx|%6n!~Q*V1Kr5Bw@UfMgQ8I^P*k88y0!wD={lOn!Zaz-)hnl9q`RzLS$e74 zU5Cq#;ut~5LDyHHc=|ETt#i&EbrMZc^ZLbF&`)Sy-4E}e*8iMZ`-1_sM~U@QTy)dh zDVC;cx|M!Tx6v=?cDjS^ zq`Nk-&G!XSs6QHjvVE@_Iy}snbax5AJTUVjcXbc)l_tAs&aJ_e+3CIH!m1rV*m+q%uR>Ba( zu}pn{=B4HjPAwnXv!0gs(e%Fyq8Vr={fZv)86mW`lt>$$KcqaOLvf*ZNU*y7Jhb2+ z6Fx)>=@EMNEo)2AM?T+Kik6|}^lN&Q9;-qt&`Pw59;YYh8D{mp!R;Hd;H*IF=t&xL z6?}v?pij_7w25u$Q?LSUMqAKlXe-*vih?odbF>WJ-i|R~x6dm`u!ZCWO z0-d1WFhtKo%mdHVWc50k^XQ^46n*IeU83L8TtDOA`WU~0uA*!73cXIhf6MrH=+^&^ zG<2I;{YQG0S@{}^w8^@t$b0DizoZ^8sYmn%llqQH9n&?4`~yAzm(&X;^@`qPQa>=M zfKa^=BOt;U6JHu0oKv3DT~2o7mK5ZdmB++; z7OSI4(`E^+yi-Fhs%)9O*356qH}CGyJ|3m2SJa?_oU*dsqw|Xf7mrR#%$BK2+@)n~ zeO3#;tv+dh9A2ct%+91CW_`G{L8QUAx8d%wWm)W5TvNH0RYXuxMMEm3$_qx5G&&~M z+b%4gC#FGE;vF5%y8hd{XYr~UKIaPRH zk`QlueTXGk+q?yn&#c*Ht$g!PwvCqW{Nn_#Y#HjEs*eh9+pc|wL|4a7os+tB?UtO< zy+_Z~wDh!InZ5gD_3hW+dsKhcBcOx^%A}M>RWhIe(vVCb1ahDQ24DkD&v;1;Bj{x;WUGgS|L7l7pi-IEI5`eVJ3$ zzSNyF+zTUq*2Q8gFjZnRw$KOkVI{V)7V8lQ0gHANS=zo4Zo=Z572hQlxG8;HfArxN zn4J^s;?9LzwqQ!?3+4Ybq5oHYwyaBCFB)PW`uF)u{Sv}|NEH5E zVx?aqFk9B2t&!=S6C;VM#A}%+;3`~=SK~Dt6mu|$gAxu(tMNL#9yY=oI4I+wiso=o z&5U&_W~S#epP{yLQ0{A5eUyCxrd8wZc!%$wg9;8R{qHnJCYA*l+BWouQJqVCiN9jU zD?We^a!|v;;7YgxAEu02EzQdqQd}^&Y(QN*-pyTNGLQsu&|C|W@O-rHU^Za?j8mTp*c**8v^Dr)%7nE# ziG;{&fD&daMyb7$Cx5P-HFAAlEH3Phtg4Fe8&5B(1w}aM>~6~4`R}kwD3b~UIVR# z4_eC_XbB9O#HNdDOI$u6?MQplfh2P99S*kQU~3MxsU{t3fFyCSZ7q=Yejv%DhYv_k z4z{ZUlKx+9TDRN2WPl$={~8z_d@u&qz(`~;Y<8W}P4ZZcOoni7HAxKS#sGE6$oB^hm{|0-OoFnHsn9sps930N( zwy6!wK_J42K*V`pT}UotvNg;}7p+aqN=<(cVIv$XRzWU5}CFr{{n%rVj z0!wkFHN^mVOrH3UeRm~!3>FPYFCLsTHX^4yBCbV3qsB6JN64}x`I8+(Ac&&3CVD|w zFIqEJL0)rkbZzC$gY}ZWnVm&EUhORmTZYH3x7L7P{ihHwh$o>X^`{UA$8m513%R!^ z4o~UN_T&F{o+#?i6Q0)p>qPHq?NG0wqskM;(`TfW=ajoCWOZB!Xb3Ez2}odJ-G<$d zr?OJYjSKJyT!u%od+`Yj2E}VxNp*tVbYEw8-8b=oQ@Y?Y@@Lar3yj~t&Z(bI!A8!C}ATO6Um^Xx1 z&U>G?l(&(0o%et*5{wbd6D$=}2sR4N3a$&j6WkQs z5_s+ieiHm5cqNnx8wj1k6k!ixsxV#HOW0dDUFa1q6fPDn6|NP2Cfp(1CEO$2Cp;oN zBfKiS9e@G^0j2;)K=XjM0j_|QfW85F0V4v+0!9Xm4mcTbDd5+Dhk^V+X<$NNo4{d# zlLDs%z8^R(a7N&Qz(s*e0+$6=2c8bR5ctX?;)|@Jcu}TkuqaQIFDeifiAqF^MXN>Y zL?4Sbiar%>5q%;0N_1RwQgm8$R&-f(MRZMcL-f5^BsPd!iW9}1#7W|=;@;vsalUxC zxKLay9w9Chj}%W9PZfV4o-Up#o-Lj$o-bY?t`Kh&9~EC0{}rSOY8doRP*PB8kS9H; zS5WVute`+45!b74lW`D*0;pTKP%&E%~qVhYFrT zpa@Wi6hR89LaPW>=oJkVR)t*=r*J9~6de>j6sd}IMK8qw#bSkLwPK@Ur((BauVTOA zsN%HZg5tX3d&Lim+luFk7fPX0u2d@3%3x)PvY|3cX;Q{0%}T4Xi85K)TbZjYR*q4Q zQ%+F6tE9?l${EU8$~nq;O0RN@^0e}iDo`a-sZ?rJuqsLwt%_AyRd!XJDp8fJN>!z+ zdZ~J=+#Xedsz_C$DpieDjaN-nc~qQgj%vB;Q`HXD0o7^MCDmos71cG>E!7>>PpV&3 z_f)^DUa14sL29X5p;oCiYO}hTIzj!8x{bP>x`R4XJy7jd=c)76!_{Nd9yO<)q@JRl zsh+K#tDdi3pkAR~tNvWQTfJAkUwuG*RP8ygKB+#fKC8Z^{#E^#`kDH<`lTj7Bhx4} zDvd^?*EG;XY782qrn9D>W`bs#X0c|eX1QjCW|gK=Q>|H}*{0d9*{RvB*{j*FIiUGU zb69gx^CUPh*dE*`czE#A;4Q)Xf)50L6?`Q4Xz=mi>%n(}e+#}J{3!TI@YCQ|!LL19 zkyfIWX_Z>FHdq^_jn>9$ty;S_PTNY`R@+|d(st4&X?tliwY{}j+KJlf+6rxzcC~h` zcD;6kcBA%F?H27;?KbUp?P={*95d zbxn00be(lwblr44b!oZ`U8ZiNZnSQ)Zkld}ZkBGoZh>y0Zn18)?i1Z6-Dcfqx}Cb+ zy1lynx&yi+x~saMbgx4Bp#h5_&lF>(FDK&=aAjLeGSr z4@(H^5Y|6zaM-(H3&M7V?Fl;^b~@}#*txK)VK>8m40{~*H0;l?=V33yUh5m`Eqbfo zu5YPtt#7OEpm*sz>3iri^?mex_5JnP`T~8Kex!c1eypDA-_uXlPt|{*U#73tZ_)42 z@6zwl@6#XFf2}{JKcPRR_gvH8(Ld7vrGKt}sec{L3m1e3gp0z1!Xv_C!=2#?4gYBP zmjN2228}^)FdJGK+8EjyIv8ArPKG2yS3|O)yCK&w*f7M9ZzwPn8%hl$4Py-B4HFFu z3|kEQ440yWQM#yRQAtsQqeeuHiW(C&F3JCstBQPQ(&nPek7&XQQ z#z>>VXf#F}iKd>WG*gBt)6~b**VNyX zZ5nDCZt@hGicMoo<4l`PJ59SxdrZen7fqKw7F#}?9Vm8I>j@cWtKjvU;!&pab z^VpWLtz+B8CdMYm_J~c3&4}$Cn-x1c_M_MXu{UGydSZWzeGvO7_PH6G`Q`w#*eo^6 z%}TS{9B#Il2fo*<-n4d1EzL+grO@Q>;C$Y1V#Lw{@s>n6=PaY#m`8 zXPsc3W}R)FXI)@jVqI=sX|1qsw(hjof^C3pqHU^enr)_Swr!DZm95HSTWwos``Gr0ZKrLY?SSo&?U?PP?Tqc5?WXOv z?V;_N?WOIF9oczyiCu12*){eMd#Js+eSrNvdxiaD`$qd_`)Bsu_Cxj~_M`UW_LKJ0 z_G|W=_S^QK?7!OY+aKAVIFN(qP&m{Mts~SC?uc;M9Zek_9O;fsN0!6W-!afJ$T7r` z?(Sq9n&4N9CID>9Sa;Q9P1qi9akLp<8WMPT;sSdaWmrP$1RDgj@uHq zBW`!xzPJN%N8?V!osK&fcOjl19~qwz-yuFFzGr-Td}e%BeE<0D_=5Pd_)+m=<0r&V zik})kEq+G)toSeD?>J@75RWs$X>&GqHghI8TR9V*ot#~q$xIA%XVnt$g;@ZUZi5n6(CZ13H(-rCJ>PmO@bB%YqhPp<$#<(WB zX1Zp(7P*$Xmb+HCHn=vqHoLaEzHseu9dI3T9dR9XopYUcU3A@W-E;lsdfG)p9dmUePf}I5Zt^pzclNVmwMbthz1^f?dxWfVf delta 8760 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 Bhh_i( From 2ba3bb18344fc376c4eab61b593b98671fb9a6a7 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Fri, 11 Oct 2019 10:05:06 +0300 Subject: [PATCH 09/32] Move swift files to root --- RNWebim.podspec | 2 +- ios/{swift_bridging => }/Department.swift | 0 .../FatalErrorHandler.swift | 0 ios/{swift_bridging => }/Message.swift | 0 .../MessageListener.swift | 0 ios/{swift_bridging => }/MessageStream.swift | 0 ios/{swift_bridging => }/MessageTracker.swift | 0 ios/{swift_bridging => }/Operator.swift | 0 ...videdAuthorizationTokenStateListener.swift | 0 .../UserInterfaceState.xcuserstate | Bin 20837 -> 16817 bytes ios/{swift_bridging => }/Webim.swift | 0 ios/{swift_bridging => }/WebimError.swift | 0 ios/{swift_bridging => }/WebimLogger.swift | 0 .../WebimRemoteNotification.swift | 0 ios/{swift_bridging => }/WebimSession.swift | 0 15 files changed, 1 insertion(+), 1 deletion(-) rename ios/{swift_bridging => }/Department.swift (100%) rename ios/{swift_bridging => }/FatalErrorHandler.swift (100%) rename ios/{swift_bridging => }/Message.swift (100%) rename ios/{swift_bridging => }/MessageListener.swift (100%) rename ios/{swift_bridging => }/MessageStream.swift (100%) rename ios/{swift_bridging => }/MessageTracker.swift (100%) rename ios/{swift_bridging => }/Operator.swift (100%) rename ios/{swift_bridging => }/ProvidedAuthorizationTokenStateListener.swift (100%) rename ios/{swift_bridging => }/Webim.swift (100%) rename ios/{swift_bridging => }/WebimError.swift (100%) rename ios/{swift_bridging => }/WebimLogger.swift (100%) rename ios/{swift_bridging => }/WebimRemoteNotification.swift (100%) rename ios/{swift_bridging => }/WebimSession.swift (100%) diff --git a/RNWebim.podspec b/RNWebim.podspec index a2739d6..cdc96de 100644 --- a/RNWebim.podspec +++ b/RNWebim.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |s| s.platform = :ios, '9.0' s.preserve_paths = 'LICENSE', 'README.md', 'package.json', 'index.js' - s.source_files = "ios/**/*.{h,m,swift}" + s.source_files = "ios/*.{h,m,swift}" s.dependency 'React' s.dependency 'WebimClientLibrary' diff --git a/ios/swift_bridging/Department.swift b/ios/Department.swift similarity index 100% rename from ios/swift_bridging/Department.swift rename to ios/Department.swift diff --git a/ios/swift_bridging/FatalErrorHandler.swift b/ios/FatalErrorHandler.swift similarity index 100% rename from ios/swift_bridging/FatalErrorHandler.swift rename to ios/FatalErrorHandler.swift diff --git a/ios/swift_bridging/Message.swift b/ios/Message.swift similarity index 100% rename from ios/swift_bridging/Message.swift rename to ios/Message.swift diff --git a/ios/swift_bridging/MessageListener.swift b/ios/MessageListener.swift similarity index 100% rename from ios/swift_bridging/MessageListener.swift rename to ios/MessageListener.swift diff --git a/ios/swift_bridging/MessageStream.swift b/ios/MessageStream.swift similarity index 100% rename from ios/swift_bridging/MessageStream.swift rename to ios/MessageStream.swift diff --git a/ios/swift_bridging/MessageTracker.swift b/ios/MessageTracker.swift similarity index 100% rename from ios/swift_bridging/MessageTracker.swift rename to ios/MessageTracker.swift diff --git a/ios/swift_bridging/Operator.swift b/ios/Operator.swift similarity index 100% rename from ios/swift_bridging/Operator.swift rename to ios/Operator.swift diff --git a/ios/swift_bridging/ProvidedAuthorizationTokenStateListener.swift b/ios/ProvidedAuthorizationTokenStateListener.swift similarity index 100% rename from ios/swift_bridging/ProvidedAuthorizationTokenStateListener.swift rename to ios/ProvidedAuthorizationTokenStateListener.swift diff --git a/ios/RNWebim.xcodeproj/project.xcworkspace/xcuserdata/alfclausen.xcuserdatad/UserInterfaceState.xcuserstate b/ios/RNWebim.xcodeproj/project.xcworkspace/xcuserdata/alfclausen.xcuserdatad/UserInterfaceState.xcuserstate index 224f79280d1d6c7d4d5fd86423aba220bb9471bc..c48b7a904680b5f888f025bbcae8294c0e884c8b 100644 GIT binary patch delta 8866 zcmaJ_2V9d^*S{+XAt93_5F8(IJt+i^^TE}-oK;OQ8zc>v_(-=YRj_+%xWtO1Nb*oTtVfUb4SS z0~40R8S`7W_ss(H!2;k1OTlt57OVi3U@ce&J_cLB4zL^S2ZzB|;A?Okd=Jin^WXxw z2(Ew!;34=6JOYow6Yw{93jTot7y^Yb6pEk}s-XrpggO`v4KNnQK|4%@$*?JW3$}nQ zVO!V%c81+xcbEY);b0%kg4r+!mcZd~1T2MRupEwp6W~NR8P0)o;k$4ioDUbkW$;6| z9E^q)a1C4wH^NPD8{7{Mz=QB8{01I_-@|k8JiGue!av|W_$Ry%AHaw3FZc*PhR@*( zL=X@0kr*jZ1ZsfvCWa5LN- zr{ESi75BhBaWC8(_rZN}KRgI$<2+n|i*Y#~iQmRE@N7H>&&Lb!BK$u7058KUaRpw5 zSL3bt6TA&?$2;(Dd`HMW_@p%GX2v5ih<%xJwo`R?3h4WOrNM1u;4A01O z@sj*0jIq-+!%y*e(J*?F^66kYj1K%nK)S=Q!E`!3Lce6U%yghXk9S+{uK8`IS#$!O zRwJ0jmqCG(0;;2l{?UT`22PqFgEU$O&Vcb?0uX_Tzy~Pcz$7pkr1+l;x(lr|hB~O8 zn*Du3nsl3431)zIsDZ{&%PBA$%wc2Zf_K5Ze(iI;#pMNg1>Vx0?Td50qiHNPQd6c( z+1XoGmX+_#C@=M971_&1737u6_$R?a@E%wM-uKIs!u{7mqVZy|#4ixW4Xm5>1CRpd z(Rj8RQ}6ESy}j85MZrNUK}GNMjFzRPSz{`}O0eVIRFm&T_Ph>d5BH#64~XSfzN@l0vw@972pf%VTK$oa;6*w#{zf1 zp~)5CTiS>Y?9n-^p!gIJ)@VM#jHjq#FiwHfv@vZ$n^u7z7hhR0)C~gwGlc03;aY^w=k=`;B7B+v;ou> zgx(Ie@0p&#+`AIC151MUI>Ju=7qW;!9Rte<;!F>a*@b3OOQtM*+&HII=bT{Gjcep- zWYr}%c2AfftmCf->aB+TV1GCO4y1Xsh>oS>n7ysa=JC0( zARz69c`zRiq4{(OEucfIK{T^yAuzBoW2S{H@C@|(l@l9|tf9S5(`Y!B`7sd9nK}%^_6?_L6;4E6sW*^CXh6``! z^TYSwkXp>7meNs7YBbI0+r1!vNO`XU@2Hp-<772{6QpbfTsbH`qw~n}tn5N>O)#l~ zD}v#qW_!R&SRDXcMaNfw6t<{=nKF6nlH#(GLT_3@VY#=ob4jkY&eh>M_)$Q5J)Kwq zH&9=2X}-;YrEP&*DW#KNFKs*A^#gG0>A3==P~?+T<3Lmz2h|C>Z=NXFmi# ze`D+yAR2x}r!eZL(u_=*l#NdHW{=Fz_g_$HlD>uC0prS*lm*t{!cM?5z*q%O!c*`x zok8EBGppba@JD!-&Z5idioim3{!F#TpQ27}1uwyyEK0!3@Mm}hUWM1-b$El$rgP|A z`YxSE=hFpi;4KE=SLOlH@DBW)`WcXg>^+Pwq01N%pQ|7E;1l>1C@SFJ^t}rB4_#D; zvsYH(NN-uovL2=0S5&@4kWq;MeZK-Bx|j~E3;$hfSAYaaST`98rAui>-GeYBeKk}@ zKX|p~6r@Bd_5{qOv9*)d4T(f7dIW)?di2BBb2UV|AaAef5c(%Xgk%|z6Bs{2vG6i7 zp*R$e%*cYQ$cF65L02+vDrhCGqSbU2T}{`}wRGJ_AQ~kA19GDzu8@Z@w4NFK zBYKD)uDJr79cKCbW&{uV+QUf|r~}PkPRTj};!{)946FBSk% z57d)xq?;;HZ`6lwrdw!6_k!H+y}@)=1i3RuK_tImwrOG1&k6^8>uq<+1mQ8 z3Q*y{1dC8H-9Zn&CTRp3$$SZwqB2xYKczeAt}6648ihvF-E2*twfapKdGRfSD-5T1%vsbo_X*ZIBDf;R@b8qOr|DSp^xcTbYRd7 zY)e<6EodwHgnmtr(c`ZN>_EH!duyUS%Vc6g+R*4%_`68A}5Re%^Qpl|Nm+( z|FH(|2zq6vXEbp){$yao-7xB6iu(gD zB3Bbmh)pbAvY+Ke4& z7y1gFLw{k6MYth0vu+_3cf~ol1W)zhd3Xt4i`U}~cq86~x3C6aJN^{!!h7&Oe4r*$ z0v0}kuYR@PwO{xMJr#6{OX%{zSFt~p5m$vSp`XDLw&1|OIxo43?f~ODbPZicH_%OV z3;mLYenq#@Z}bfPf&NI((x2!#dY)dO7uPY{+(mz&d+1MeA3Z=1(O=9?mpIs$g9A7? zl!F`xCvk8J2d6S`n-KGd7GeU7l^9`6FVmkZF%R?U6%Jzdc#xtAD+?MKL^zDOAQscB z6<9*AvvBshP{7KXqTrf;l(1()En=+3Q7k!Q4UWK(SW9ovoAeg_r5e}6^>G8-kp4<< z)89B&iVgG^h5a)a$FYrx!o8AJND33H_TsU5z{A^kCr!2he}$3zmNa*H|{^aOqDv z+@A$UJb*q61V<6h#Dj5GU$zO#%1aB1^XYT{SYxB+EM_pT$z=)gm91IT&z@JY+g`Aw z4~q*m|7$ij&ac`1H4cJ@;$eQ5JerRSaZ#W$m+Sl!>#6;7<$`eLh9d$-8O}jiflE1v z7^ZJy>-j&EH}uspGYb1y(!`_j7(5n_1ApQPcp?W02l*Tf;b183&p|NLj-F-S(lSR@VP1}Z zw$Ral6(`8|`Q<}o@70YthED`=eT%=t$MN?ZjN)KD4%X*jgX(a6vIf{04mJz|iw*+oh%W?y zUF2X**T-5G{PX_=b_?GQ0{b-pOdkMtCjcyl#q&~&M^U5ZDF@?&YOFPC=60G{K@bPc zwTmY_ri1W7O5n{wOMof%K`k3sMn0N!AvPd?`A-NoE&B0U-G8}2uB#-3F z;Q&&=!L}UiK*w^hV=b!T0aPP6*scy$d5zV`+k{WvW(MP6``{$P!w$Gc;@R2%b z8^}ghWRs6M*sp?Y;$VN8F_3jB=~;fGBcj(fvJWWMlI>&%`IPJ=yU1>`hwSCxKn@P# zU?v9#b1;j8*&NK_VD4J79~eM1IYbVV&&UzLf~A+`+F=~b<6u4qhj6ff{m=Mhp(6sC z&XAv2jv_yhAIVt`G9kudQ588y&XWrqEasq(gOqV`%2||hm33?68oAEF5)Qs@MaeDl zTVRe~$gku!2ZwWz*|oHa+#$b{yBsXzU^xdzvN`6srsmhy8aY50i-2xW>q2i(QIZ8j^W_g)#N1{z=J%*dhh`pYnPdG zjpyJ*mIDJ>@Z;3wzL*vvL3Jm2Vj$v$@g#vlFmUJ@#*^{n!Rp3a z$&-O4gL;(YW{uHhmFrx|Oh_%(og2G%~8ap}hmewRjo|@%a5Ju6fN|&eQ zvG`Hp3*4;Wu^2hIwm9bLUWo>W8ftSY3ynM$K-RKMD6Ywha1-}(Pm7m6M$M3-J#82mE@pJfIem=i|Ka5|*FX4~im+?pPDSrun z4SzrXYyM^a1A$r)FK8m@A}A0{5lj=z5X=u5q;U?jhP)(>V)Dzk?v|DJu z(5ay_L$`;17y5nZ$%|7KQ5+{Wi+hQS#nZ&^iWi6%iWiBi z#9PJN#5=@0#k<9O#rwqv#mB`b#HYk(#6OCE5}y}e6kitK5kCo2hMB@zhh>Eog-s5d z7q%qqgRl?7R)kfAtqGlG~CylDm?} zl4p_^QXoZAsZ=giN>x(5)F3rVJEsKz8Wihf?nMoEev&d{Rk1So*SC%6iE*m2o zCz~Mi$vD|e*=*Td**w_-*+SV?*>Tx@xkxUStK@2VggjOrCpXJ&a);a{ZzE5aXUKcX zd&~REeR=XCd5L_4yi7h;K3+aiPUVy2^W-1OH_La)56h3se~_P*pOasZUz6XE-;)0- z|4sgv{DnfGP%G*y%nF;rp-51;6&^(gMQ=qv#Q;U7B1@5@7^R?!sfy`}cNDV}ixn#r z6^bgwD#ZrHM#W~uR>d~Oe#MuH(~9$oi$29=#TCUbirb1iio1$?N~9DiBb1R!t+Jjn zUg=aODBVhrvY9eP*;3hB*+w};IbOL;xlXxLxm&qcxnFrud02Tw`GxX~@<-)Q%Ja&L z%FD_t%4^CS%7@{~aC3Ni_?Yln;k(06gkK835`HcGX814Rx5J;QgetL0qLQn8N|j1g zU)4ZmQQ1{aRiY|Mm8?otwNX_^d8A5A~a z08N%AN8{DxYldoyG$S>mG*dM1Xl7~VXclM|Y8Gi0Yj$XMYChK-)g04&r#YoLqxn(u zljf%8cg-J~KQ#|DPc_dpFCst$iV#FZMVKO*N3@OT5YZ{ZmmV=HVs1oL#HSHQBQ8eV zkK{*&M21F+BPEftNM+=>$SIM_BUeQph&&VdPvmngUn|whvP5vyB}6rjY8urnDkUl{s$Eovs7_Jo zQCU$#qspSj=`^}XonGhECF`2&I_d`L2J5nQxw<^v5ZzE+p{`grTsK)aRX1HXQ#VI9 zPv_Sy(k;;~(=FF+*PYZ|);)@jk8T>>Cwge~)M(#===YXt{$Wf^O!t^c zG0S6i$9xv^Ma)+*M`O;%+=#gq^J~m+F~7$=GGIffL2Qs1WCo2P(hy~+Z)j*R8f=E{ zhGL&#lwqu4ykVkYmSM4BsbQI6xnZTD(ok*KV)(?c-SDYlmtl`#pW%SvMl6hti%pL$ zj`hbbi(L_05nC0zA$CXX&e*%LkBvg3%ou6Z8)J;IM!PZH*wZ-DILo-$_mx{LuKq_>%a&@n6TE zj6V~9HvWA4rTAO%x8v``-;Mt>{()I$_L%#b$CxLXrW zkd4>`HlZ!T7G;aGxomD*vaN}&nJvxM-qz99+1Az8-Bx0I&$i2U)^^2q-FD0NtL?t+ zAKP==OFOh+B1CiUiQBB0d}u_h<&KN&|YF6 zVV`T?W;Mkz;5$Mba);JY&(Xl4bLbrghs)t{G;%a`v~aX?q&m_ZJssJOVUA+Q z2uHbNl!H1ZJEl2iIA%HKIMzG9cRX||o%NgzoqDIiX>)ph>FVI> z?CR?3?&|N#b>+JXT!pS;*KpSa*Cf{z*L2rx*Id_pm)}+CTIJg6+V0xv+T+^qI_Ub& z^@Ho0>!Ith>#6H`0!Y9K`~+cw*q2a0L6@LUFeI1~%n7yxXF@`PJE3_(`-JR-F$r@M zsuK1joKCo%Xh}>+Y@C>y*e$V7V*kWJiCKw55{D%gCyq!gOI)3JDDhn4wZvZ%e@ncZ zcrWp}o45t;Pe$C8dGolUx&bUo=o(qEoXkJ6*|M0m6w zlgI3_dK{hvkK5DC)56orlj`a0N%wU1^z{t&6nct1BRu7vQJ%4$2_EX1$-M*Cm`s(d++zX-$#BVlbJI!=Q(BaKj+N)(ePd+oGQmkmYZ#= zn;#azk<+5%EEB*~FceG!v%x$tA5?-WuoSEW>%h-oE7%G4g9G3gI1bK(3*aKS1g?TV zz*F!HJO?kppWr3<3%r65B8VXaS&$7mkOxIj4Bep$dO%O;1-+p!YzjkRGZ+S&!*JLF zM!;y;7Pbe2VLVK-z%F&;m!pF>oxL2B$+CoB@A? z6|fRk!D_e|E`iJ8TDT5wf_vazxDW1!2jD??3Z8~%;6-=|UWdQIJMa(q6h4D*;XC*q zenyUni+G5SJdh{yLf)tmvZ#>{@!AI~>d<-AQ7x5+hE53}c;NS2)d>>n$;%E3d{(wK?Pxvzf7>407e8!29F>=P0 zQ8F6FkMU;$7%gL9nli1J)=UJ`f$7M^GYL#0lfrakvY2cphv~=kXYv`sSea4GXl4vE zmKn!<$9&I>XC^QcnMuqK%q(U$Gl!YWR5GiW)yx`ZEwheUAI9upb~3w|-ON$u7;~IC z&s<M8^Mv_>dBOa}ykh=l-mw6SVR2YOmXsx9x!O{2YkZgF+GgP4JPWx^ z*rbeDNY+L-CK)=FkvZf%xkS4(B+E9G^+;r_ZEHw5nL=jQ5|*=tkYgZ#c##m>Bu=h} zfdmU7@fK2B9}Y$U9vBHMfB-8P1xAB0HjzWJqn4;iAZbJbZ21o1vhfw*d*Va<&w+_x z5~cqEM1U!_Jq|9S^yGweb5>qK4VVsWUsNt%Fo?Q- zJ{U@Zs1$+;r~zEM@p?d?tAI+yzi#3tu-W#EtH)dD#AjUXm*uvB?Y1PIKi)xmlXx1} zbHK57_AamoXez*N(zpWbB~7UGckqHE4uZq>-b18m1vo-NNmgonW?o_aoD<+Q5Lbbd z;1_U;G$Uc8c@;QAWm!YQss2i+lC}J-lwa+9T_!E;@~+$K8n_EIOTl&U8@K^(f?MD= zxIH{dOJM@%G^v?cAT!3XdWd;*_I9BEHFkQ~b8!A9?U zLkG$xbR->#|9Qx#TBN#!PS6=Fgu5lM zfTjvcp$y7NBI!hus-Ob8LM2HiDI}G$?CF!(^{aVNg~3Ml9o3|BgJ7Tr1_I3z=m-5_ z0MtSq)RQ!lPP&k;q#NnJ1R7uv6)%0k#-s=7O@(ZKWzyC6_+0jaEn({l*oyQd88vkI zNEij%bWKPxl$Mp`73Pv&wynNl7HZcp2AVR2f`pX#^0LgVd~-_ecoprA1+%&&q||+{ zH6qv!#`S6-thM-YI}?B?1f-k0=iaDCXHN^=V7Po?Nrubltv z&vl+#Pm>{RW?SLi%;_8)L?t~K zXi5_zQZ`!;TUWvja3dK*CXkGJp>KxUsaL}-a4XzK#*%U5yDGQ?_`qG{d%F5~>Mx^2 z?JS4jv42nVxyeRpq$0Um`pi&Wkn_G$h_YF!r629*FWaI0^aa7nMvh4i{w(jp|fMm zS>?I8whv;LrXS!(pjottWPRZm0mRUg06~NhCUeO=GQSG35F2sGPh>4wXXoF`W|6qq zG9)o=kQ0*8qYybG0TLn+5+ezck_BWTSwt#GC8;9SOOYISBL!8nH*!PnWHDuA3H`T_ zm1H$lCClphOv}tKHwRAgsdQ0 z^)}t9{s}@+Si@q?$tsdtKhP4j{@1Br1~jM*ifNc)B5S@*X@}zK#Pjv39rNnfi$~PG zSE2;^_?=J^N=7Lt6?H~wC>?bn>!}zvkd5SLvWaXaTgX8VhLGK4KRMK3 zI%qhu0C6Q6fku)&WN#&OMOJ!x?<2X%c{#~tLy{UK@g17*Eg_nSCXoZ=pk3~6Um!%v zpu9e1UeQGbwv{fjHq+3If0^(jnn@0mGhYQY2mNF>o4IHnnoo|9qvTi>T7VX!MdUa+ zK~7UeBSo9W)T=AdGIEmmUjaX%m1q@Ojn>ddS_>ASb!a`>fHtCy6dVjjKch_`A8kTg zY=ab2S-%K54Wv)Mz`}ks)-6NlQ&N4=#)Of>SycWoO!d;;PV2w2Pj_i(PXY z??(p~k#n`@89Iax)AKCFTvmw=fm!t`Jc^FnP2w22P=QX6irMCC!+Mk7bni_Q8 z?!orM2VEe)lB_y4{AyRjWpo8yC6~!Ha^tHSenYqa-3!qjs`Y#13f1yedIB9&`glJ= zPya#nj8eTI*D2L+l*-x7)BA7q?jKa|Db+`ElTzKHR0(b>DMo;YF=i;RGvs8JWhRQ4 ztu~9>aIxr%HtQgU9bwo6?&BTOGZIq5LyRFC7rJkU-ZzAT$f!2aF{aqI?c&;Z=op`n z*eNMFB{d~2y-U|_-Fx)3m3cH((6!@AJD7*0(O-qQxET6F8&_&aQ?_*;BN<169Bsj# zTFYb_$sMPF=pl{O-a;Xb$z;%lMr1xPh(=;vY0zbc`83e7Kr0Qh#?l{;@o*|!Nkggq zG>ke-1E;s}6FpXh$c4s5ovABzMcq*unuMmIMKsn~Mr~p%jcqQYch~_7Y2Xrsn^8#K zmIf((@DK|gOXHCxG!EH~_u~EdAU=c-*Tx_x@Gtl@K8w%c3;0s)p$QPI`vkqde17@B z*T|h(qrq&<>G>5AP{CHwE(b7+${>b*`(h!Oi={xb9P=tV|v{E6F}k! z9EqbSfP6{*BCjZbq`Roy>3^dxZK-?WcI5AGFeL7PJK8ZMc|%@*gB)j$sDJh(-1!S~ z#HqE&@og1OgRZy>c}LHl_g^tjoR6+gPx}VF$cKhscASa({+}Qt&cpp0Amc~!nf}^- zfsD0IhzHQK5toop4UiEJtOJTU^rXatzx8803|oO_F&>Ub;E~vZi4{^C#8$|%LXH(W zF2H`dDFz6}F%v{fd+DL>jaVutJm}G}9<3%628x$K~7csdeK_ zhOiqQZ)bbsClxoKEc|2LDBD&PkRbVH)wy;34z$0ctl-=A7S@e$Z5IE`W_1w=uEa~J zYH<~=#*6V1E96_DlNCB!p`aQs!^>e~ywVDVRwyNzRw$zy7U?GS*kBj_Mk^HABP_dk zHiPlicnjWY|F=T16-w&fiNBC9bW}$+s`H0>P4C4A=x+ethxc2d+zMSP;R1Y!P%$d# zDKynt)q`cLIy7ax5i{_03|-JU{+FOSGL zGospE87gNg4nrj)W~cyztT345_Not`JDLk~%lg*Jn{lbdv?6@4eu-c=#*2!Hac5MF z2jgjlMyq|>CRW(An(?-aiJ>MK`bA7(Uzpa}nWhiXte)whT0K&kZUGTggLaY9w+0_$ zLYd}uoQBnM+T6}*i&{>@|G}xqIJ%y@NXBGmE{bWxL^Cl~*wPAHSz&AH7ZKG=Y%OtyFH$qJ+Dxl8?zO03_cJJYLk*v>gsnq!lm&fp{5H$P_Wf%mAi@DP_tSdahD-+go7=E9_{6 z@m82%g^563raUh{r+)q(=D>fNe~>w3XMhSh z*Uo@CQrM?%f#mRptxqtg|I^en%vq+!3iGV6pB46}b0fa^>=({!?1+WAgqcKo)qjM3m(#^9tf<=UE@zq$9y@69I9_5Gp8x zsdi2~$8|2v%r!SWd2L3+K453|n_jQ_39;tPvhor$#l>Yb$x`~2#3B^dE!ieNGrNE7 zsx@M6c*}|wL`dXzep*MlRz^e;5fN9mi6#;vB{CX5&`I@6+LKO2C2=`4iGYc%{E_H2lt!x{zF_j$?sL&H@6-K9YO8WQwPA3X^ zzvMURcxvbWlGI7N@~R#Z@HN41@8L%f3ND+ zFpy^Tx3_7!fwoI1hqSG*w{vUT7NoBwsvC&3w{r>#b10FW>*Ab(9DDm9ZGS(o+)UdP zrvfl;AWhiN_IcX&$uBR+qwP1eEiEu-mIA==?fqru?7p-eOxygD)Z}Q|ZV7+`Klht< zmgSo-Wz=0MF^DcI9#UdY3wilx2Y7`vZyx5=&O9ie`c7ac>Li&ZIrf0LIJ0mF0Ci7o zp9REr@p@4?hlVr{4GlCJs0JGT{@b9Xf#QGBu}67|+MxX8*S@a{eC;c$1R(4c zmCn?!eOYq=*fJIX#TD9T`LdwTA^-$q0N8x`nYr-k?;WSv4D=i27PvPOapcYO!xe~&iZSYsdehwR>K>bLYt^GFW1Z76`h>wm0ez9 z8EF4PUBmvyqVa+NNP#Qx0BYb50)Y`U11&%#FoE_U5u}2yG>FayeL(>zq2-<7w0bp; zR;Q+dAHiH&P^t#Y!5XjuY@xN?eY7TXg4S6s(5miDS|@o-GX=EP0U@p8I?+OeE6o=8 zLY)N~X~Lj2G{KHAnI;Z;!(3XWEvMDl(QqQI%g%)rv=X}>Zlg8WWAH4z3~#}Q@K5*- zVOnXGA{8yJ2B9!oRP8{say@BDbpRSli>H%oi>9m4W?CdYfi9q%=rMXlOQJj)mV49K zIt)kCnrAm`>4QsXoH&7&I4fykb2}|%p2Iis6a1E8GZMy&31nI@?U>HA3ORroNh^(W zDPY^o9AwThx0vV5Czcb-ouy-iv*K7?Sh=i0tZ}TFtR<{XtV65|tb44#*=)9)?ZVYfq#!|x979fgj*j^U1pjyaA)9H%%|J8pM8?Rd}eJy*o_ znRKh&f`7*d)#o zj}cdi4~XwbutY71mSkHbqb1dnLy~(^w$x7=C+#PlC|xZ*C4DXv%bLj2WP@e%WV>WH zfoy( z;*jHas-EEPO-wvlf9Z`nOoo;z3Kl zmgbh#E$_5y)GD)8MXQ^wy;}Efy{Prg2=9o@h{}lDk?P2t$R&}#M+HRni&_=+v`uiE zk~W*#yp9f!9ud7a2FJ9u#7u}eWfGe@o93E+i)|E}8@n?0dE2IKhqc|?j@7P1yJ_t% z#i`=55NQxvSBV|R(->Gdzt^K_k8wRN_VnvHxaYB6%3k@s zc4Y`MGBY;zX7x_*y`uMr%*4#f%vV`)S@W}=XGdqx%6^;^nKL8jp}CcLy7~7$t@=#w z^B}iXt}XXr--y05`##Bw&YPR}qF=jy3oZR#_fPDOd~%3($oL_@4~-qVco;J*d)WTr-ovfKZ;gl=Q85yZ%o@4hqPC2&+@m$-Wmc}W zzt!@~sNhl4NBuQAef0J*sxf5Dow04lt{mq)u4LS$?^=Af@O$R_yzftqZ#;g^_)imZ zCLEs_JaOj450kPd9seQZhuJ@Tp4?~hsVSjT7EEPNEu4CBTEw(v(?!#VPQPP|w{4!` zHDkhzzkba4@z~5JGZ)U{&MKdEb9TqsTj%)9nL6jg+`e-!%xhzrw|2h!{PFW&|CIAn z&4S1UYZj^&PF(nIQQo3oE813UuGCb{tYTLUth!&FR()h~*y80&luITq`M9)j>CI)y z%MLDYwtV>t_Z3rCqLt+dfkx)mzsDuBlinUpsLfSXaL8(fZ!&FK+0tVgJUk zjcb1P{dxW-$)*XL;pQQmpKs~A#d33N*R5x_wcoaXdyDOxb{KXn-RZq^-Y(g$DZ9D5 z$L#*RXXu_+dyDrz*_XTT&i;)3R}XYKaQ}b#20R;q{rnx&KyqBjCo`o1r&%-HN$& z@^;GYt9P>RJic3c_rtw0_nq#~{N3~S}NB15VKYssY+#jMp=0Ej+ z`t!5MXD6R`d4BIj$&1f_PI~G3a_L`9{@VYl)2rY9F8KTX>j`gM-zqN0&dN$I~O#!Jc)Xl!K9iqp}7gZ?G{sT`c}FW)J} z&|&pKb>&cdAU0xTZIILuf96=~%J`KQ8jI2B>FYpUf9(YTT8%L0M3rRs%^PSgIXh}} zYDrO18G*n7h=7s;l{%Qx9b{5qG5`z)W5IV|JcT9G=?#DiunMfDmrgc<&GgFIb_z@m zP*`%2-s-pyUV?Y@h7`S5<^Z{nPj8f|>1~8I^nyVLmXwIG6soZW3%4 z92J}toD=*ixF>iZcqMozL_(I3EA$jL5;haY2|Egt?AVP$yL!w=Vf?p$!W43+J_U4z zxkdBvGzWE!xy~$MZZIJ?Yg17LR#-^0QC3)Fg~dylWw0@Gm$^sF`!r9PVNZ|JRCp=P zklHVC1UL1z>6?zQ)G$wJa_1TI+#Z(N?+)3on~Z6`CY)xOOKJ-%%%9B5I%_dkGJk?u zy;6&EGKY9&mU#s?4{zK=NN*I;1U2)TX7_;;P2SWO_nG$$Emzm}RWP5daL|`x91Av3 z)`0eODvR~yW{15^uf{9^kL!~D6qY%Y;)bNZ6%Mt+;WSnHH5Jd2klFdcJu@c>+k%jxa8;gl1C zm(mK=33?yy8od#B6W_*n>8-d2_%%&bzo(btJ~NP^xiE%9ufwG?gjvb_!aSt+&{Qlf zt2wI$s}(DP6~&5XnOJREX%>nwyRmw(da-)5vRFB+KCCjeJA<9c&S#Hh+t@4Eo7gAVH#mqR z<7hZ7IGs7goDvE{2XY2;rg7$SDmbe-XE@h5zj1DIZgVVmIrljaI3FE^wYW6Fp_4$HlJ6>E2e;UF>e`f1#dNPEpI(f067Mqa zD(^b)2A{`Q^IPy^_-*-d{0{ss{9Jw>zdyf#U&J54FQxc*41XN|d;SFeB#MNm@~87> z@GJPM`A7NJ_-~x#PK}&eI>k99J6Tel(ww?baGdRAcFJ|ibL#I@;PjKzNvHSDI_I{| z+0OaSMa~19OP$9!Pj;T_Jl%PQ^GxT3&a0d^I&X5`;=Ijyuk(KAgU*MYk2;@rzUcg3 z;3Du8_zQG`KtYh8r65kwK@cxU6eI~!1f2z0f*e5~L0>^XLB60+P)vdL28-ab;4^jm z7-77ylQ3DBD(orD73K*S3YQ7D3-<|+3(pB}3m*#q6uuO`5`Gd%MQ$R0io%mbT||RL zlST7H3q*@VRieeBrJ|Ff+oH#!=VBJc<&I*W*hwr9E5vSMmDp3P7aPREVxu@*94+o7 zP8O$%)5N{Rv&ELh;??49;vM2$;yvP{;#1;t;%nj?;#=Z7;&E)rKs zBZ-ehBk`ALC3;CyNxY(qA(HWuiIN{AQzX+QHpzO)Dai{dSIU!0 zr823D)Q83a0aCrxAPttrNaLl+(o|`hw2Rbik>*ParNz<`=@98K=?JMsYL!lr&X=y0 zZk6t%A;SgfCFy19Rq1W%UFm)41L-5_U($~y8u*j^k(Xz3!NwUeZsj}&^8L|bkrLv!8J81Z^N48IPRAxCYJ1ILQ zJ0rU-dn|h+dnk4 zb9w0U#O0~W3zwHJuUtO5e6lEb3TK5-AyLQ_E(#xopCUk^R~Qt*idHoIX`?VH+A87{ zX^M137ezP42pSGmD5?~T6-yP%6)P31X>hb&u~D%}u|;u8aYj+2IIp;<_*HR5aZT}? z;-=!Z;;!PpE2P0wm}^_t?ykkIV_avu{_J|n^`7ff*B7oYT`jL%KPg#Cj?z)dQ#vV? zN>8P?Qmyo-5td$QP=+X*C_|Oe%67{3%8oSVN>O%JrYp;7>@`L?UO7?ugL1lZhH|EI zwsNs@m2!=8opOV6n{tP8mvWDCpYpKsit@hlqZ`}J(T(TkHf<7 zwfj5w5AL5-jZ`|7US&|VP_-l*QGKBzu(jvhP@ zCl4==01u-_c%#1?y-`E8KrL6R)LL~bb%Z)f9j!L0+p6Q#9n|saM0J)rhlYoF>U?#P zxr8V}|>t`Ih(&^Bw6+d`J1(e1D`d=N#X8 zzSX|#eYg5<_uc8c+xHNSLXY{L@cqU2PmQz2MWfWXYdkbMO_(NJ(^At~6RByViP0o! zQZ$`uq}o-}UDH#Oq3NsXudx(piZp{YLpAF(+ceuXJ2l5N=QWo!S2Wi(H#K)OPc<(z ze`#K8-f2E+KKt?goc)A;62D=7-}_DQo8&je?}^`AzxRG0{egeHe>eXg{=NJ&{nz;K z@ZaUX$A5o7qkte9`L+mX9S{`|6A&NJDIg`Fb3m7XZUKX6G`uh1X23&Bz>|Py0WSjH zX|a~Ab=2~;0T^#oAKsK3|tbggs|x+q<=&ZJAwb=URQW$XIr`s)gG z#kvxmRX18URcD!_o3C4_tJE#lt9^~5>i6hR>M!Vj)nC>BroW|s zr2j+zT>q#3mHu_0G%!4{SKx@iae?ClCk0LpoE5kzu*wp+IB;3uiojKY+X8n7?h8B^ zcr5T_;OW4#fj0y11U?UZ8~7pcvjG`c24{oFAf<@`SA&}&%+QOb2PzCJ466<63>yqP z3f4JQq!3|9>|4R;Lp4UY{^4KEBYgHRAFNE{>!QUtjLc?5X{8G=HCqJvU{ z(rIeJ(le-cP+HE4R!jGzTU%Y*g@T@HF0jDy{R zn*_HHo)|nmcn-}(tPkEAyd!vb@V?-q!6$-G1)mK*7s3wl4hav54oL_}3P}w~59t=t zGbAG z))+4vZ^vZDWXBZ8jEEsIqhrR!jE|WVGbLtz%)*$8nCh6NG0S6C#;lI1iFs}EHgzzi zntGUqnN59715ATWBTSP_lTEW|#$vu{foY{_jcJ`}qiM5gt7)I Date: Fri, 11 Oct 2019 15:18:17 +0300 Subject: [PATCH 10/32] Remove unused imports --- ios/RNWebim.h | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/ios/RNWebim.h b/ios/RNWebim.h index 7fe8f00..04266e9 100644 --- a/ios/RNWebim.h +++ b/ios/RNWebim.h @@ -7,22 +7,6 @@ #import -#import "RNWebim-Swift.h" - -@interface webim : RCTEventEmitter +@interface webim : RCTEventEmitter @end - -//@class MessageListener; -//@class SendFileCompletionHandler; -//@class RateOperatorCompletionHandler; -//@protocol UIImagePickerControllerDelegate; -//@protocol UINavigationControllerDelegate; -//@protocol RCTBridgeModule; -// -//@interface MyObjcClass : RCTEventEmitter -//- (MessageListener *)returnSwiftClassInstance; -//- (SendFileCompletionHandler *)returnSwiftClassInstance2; -//- (RateOperatorCompletionHandler *)returnSwiftClassInstance3; -//- (id )returnInstanceAdoptingSwiftProtocol; -//@end From 1ab85f7119d4b035f8200524992583f39ffa678e Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Sun, 13 Oct 2019 23:39:21 +0300 Subject: [PATCH 11/32] Set public methods & fix iOS build issue --- ios/Department.swift | 2 +- ios/FatalErrorHandler.swift | 2 +- ios/Message.swift | 58 ++++---- ios/MessageListener.swift | 12 +- ios/MessageStream.swift | 128 +++++++++--------- ios/MessageTracker.swift | 14 +- ios/Operator.swift | 10 +- ...videdAuthorizationTokenStateListener.swift | 8 +- ios/RNWebim.h | 4 +- ios/RNWebim.m | 4 +- ios/Webim.swift | 41 +++--- ios/WebimError.swift | 4 +- ios/WebimLogger.swift | 8 +- ios/WebimRemoteNotification.swift | 14 +- ios/WebimSession.swift | 18 +-- 15 files changed, 163 insertions(+), 164 deletions(-) diff --git a/ios/Department.swift b/ios/Department.swift index 125b91f..5c4edfb 100755 --- a/ios/Department.swift +++ b/ios/Department.swift @@ -29,7 +29,7 @@ import WebimClientLibrary // MARK: - Department @objc(Department) -final class _ObjCDepartment: NSObject { +public final class _ObjCDepartment: NSObject { // MARK: - Properties private let department: Department diff --git a/ios/FatalErrorHandler.swift b/ios/FatalErrorHandler.swift index 524fa84..4cae51f 100755 --- a/ios/FatalErrorHandler.swift +++ b/ios/FatalErrorHandler.swift @@ -29,7 +29,7 @@ import WebimClientLibrary // MARK: - FatalErrorHandler @objc(FatalErrorHandler) -protocol _ObjCFatalErrorHandler { +public protocol _ObjCFatalErrorHandler { @objc(onError:) func on(error: _ObjCWebimError) diff --git a/ios/Message.swift b/ios/Message.swift index 71b3d5a..ffe93bd 100755 --- a/ios/Message.swift +++ b/ios/Message.swift @@ -31,21 +31,21 @@ import WebimClientLibrary // MARK: - Message @objc(Message) -final class _ObjCMessage: NSObject { +public final class _ObjCMessage: NSObject { // MARK: - Properties private (set) var message: Message // MARK: - Initialization - init(message: Message) { + public init(message: Message) { self.message = message } // MARK: - Methods @objc(getAttachment) - func getAttachment() -> _ObjCMessageAttachment? { + public func getAttachment() -> _ObjCMessageAttachment? { if let attachment = message.getAttachment() { return _ObjCMessageAttachment(messageAttachment: attachment) } @@ -54,7 +54,7 @@ final class _ObjCMessage: NSObject { } @objc(getData) - func getData() -> [String: Any]? { + public func getData() -> [String: Any]? { if let data = message.getData() { var objCData = [String: Any]() for key in data.keys { @@ -70,27 +70,27 @@ final class _ObjCMessage: NSObject { } @objc(getID) - func getID() -> String { + public func getID() -> String { return message.getID() } @objc(getOperatorID) - func getOperatorID() -> String? { + public func getOperatorID() -> String? { return message.getOperatorID() } @objc(getSenderAvatarFullURL) - func getSenderAvatarFullURL() -> URL? { + public func getSenderAvatarFullURL() -> URL? { return message.getSenderAvatarFullURL() } @objc(getSenderName) - func getSenderName() -> String { + public func getSenderName() -> String { return message.getSenderName() } @objc(getSendStatus) - func getSendStatus() -> _ObjCMessageSendStatus { + public func getSendStatus() -> _ObjCMessageSendStatus { switch message.getSendStatus() { case .SENDING: return .SENDING @@ -100,17 +100,17 @@ final class _ObjCMessage: NSObject { } @objc(getText) - func getText() -> String { + public func getText() -> String { return message.getText() } @objc(getTime) - func getTime() -> Date { + public func getTime() -> Date { return message.getTime() } @objc(getType) - func getType() -> _ObjCMessageType { + public func getType() -> _ObjCMessageType { switch message.getType() { case .ACTION_REQUEST: return .ACTION_REQUEST @@ -132,17 +132,17 @@ final class _ObjCMessage: NSObject { } @objc(isEqualTo:) - func isEqual(to message: _ObjCMessage) -> Bool { + public func isEqual(to message: _ObjCMessage) -> Bool { return self.message.isEqual(to: message.message) } @objc(isReadByOperator) - func isReadByOperator() -> Bool { + public func isReadByOperator() -> Bool { return message.isReadByOperator() } @objc(canBeEdited) - func canBeEdited() -> Bool { + public func canBeEdited() -> Bool { return message.canBeEdited() } @@ -150,14 +150,14 @@ final class _ObjCMessage: NSObject { // MARK: - MessageAttachment @objc(MessageAttachment) -final class _ObjCMessageAttachment: NSObject { +public final class _ObjCMessageAttachment: NSObject { // MARK: - Properties private let messageAttachment: MessageAttachment // MARK: - Initialization - init(messageAttachment: MessageAttachment) { + public init(messageAttachment: MessageAttachment) { self.messageAttachment = messageAttachment } @@ -165,17 +165,17 @@ final class _ObjCMessageAttachment: NSObject { // MARK: - Methods @objc(getContentType) - func getContentType() -> String { + public func getContentType() -> String { return messageAttachment.getContentType() } @objc(getFileName) - func getFileName() -> String { + public func getFileName() -> String { return messageAttachment.getFileName() } @objc(getImageInfo) - func getImageInfo() -> _ObjCImageInfo? { + public func getImageInfo() -> _ObjCImageInfo? { if let imageInfo = messageAttachment.getImageInfo() { return _ObjCImageInfo(imageInfo: imageInfo) } @@ -184,12 +184,12 @@ final class _ObjCMessageAttachment: NSObject { } @objc(getSize) - func getSize() -> NSNumber? { + public func getSize() -> NSNumber? { return messageAttachment.getSize() as NSNumber? } @objc(getURL) - func getURL() -> URL { + public func getURL() -> URL { return messageAttachment.getURL() } @@ -197,14 +197,14 @@ final class _ObjCMessageAttachment: NSObject { // MARK: - ImageInfo @objc(ImageInfo) -final class _ObjCImageInfo: NSObject { +public final class _ObjCImageInfo: NSObject { // MARK: - Properties private let imageInfo: ImageInfo // MARK: - Initialization - init(imageInfo: ImageInfo) { + public init(imageInfo: ImageInfo) { self.imageInfo = imageInfo } @@ -212,17 +212,17 @@ final class _ObjCImageInfo: NSObject { // MARK: - Methods @objc(getThumbURLString) - func getThumbURLString() -> URL { + public func getThumbURLString() -> URL { return imageInfo.getThumbURL() } @objc(getHeight) - func getHeight() -> NSNumber? { + public func getHeight() -> NSNumber? { return imageInfo.getHeight() as NSNumber? } @objc(getWidth) - func getWidth() -> NSNumber? { + public func getWidth() -> NSNumber? { return imageInfo.getWidth() as NSNumber? } @@ -231,7 +231,7 @@ final class _ObjCImageInfo: NSObject { // MARK: - MessageType @objc(MessageType) -enum _ObjCMessageType: Int { +public enum _ObjCMessageType: Int { case ACTION_REQUEST case CONTACTS_REQUEST case FILE_FROM_OPERATOR @@ -244,7 +244,7 @@ enum _ObjCMessageType: Int { // MARK: - MessageSendStatus @objc(MessageSendStatus) -enum _ObjCMessageSendStatus: Int { +public enum _ObjCMessageSendStatus: Int { case SENDING case SENT } diff --git a/ios/MessageListener.swift b/ios/MessageListener.swift index 30a087b..ed4b486 100755 --- a/ios/MessageListener.swift +++ b/ios/MessageListener.swift @@ -31,7 +31,7 @@ import WebimClientLibrary // MARK: - MessageListener @objc(MessageListener) -protocol _ObjCMessageListener { +public protocol _ObjCMessageListener { @objc(addedMessage:after:) func added(message newMessage: _ObjCMessage, @@ -52,7 +52,7 @@ protocol _ObjCMessageListener { // MARK: - Protocols' wrappers // MARK: - MessageListener -final class MessageListenerWrapper: MessageListener { +public final class MessageListenerWrapper: MessageListener { // MARK: - Properties private weak var messageListener: _ObjCMessageListener? @@ -67,21 +67,21 @@ final class MessageListenerWrapper: MessageListener { // MARK: - Methods // MARK: MessageListener methods - func added(message newMessage: Message, + public func added(message newMessage: Message, after previousMessage: Message?) { messageListener?.added(message: _ObjCMessage(message: newMessage), after: ((previousMessage == nil) ? nil : _ObjCMessage(message: previousMessage!))) } - func removed(message: Message) { + public func removed(message: Message) { messageListener?.removed(message: _ObjCMessage(message: message)) } - func removedAllMessages() { + public func removedAllMessages() { messageListener?.removedAllMessages() } - func changed(message oldVersion: Message, + public func changed(message oldVersion: Message, to newVersion: Message) { messageListener?.changed(message: _ObjCMessage(message: oldVersion), to: _ObjCMessage(message: newVersion)) diff --git a/ios/MessageStream.swift b/ios/MessageStream.swift index 061f1e0..4380790 100755 --- a/ios/MessageStream.swift +++ b/ios/MessageStream.swift @@ -31,7 +31,7 @@ import WebimClientLibrary // MARK: - MessageStream @objc(MessageStream) -final class _ObjCMessageStream: NSObject { +public final class _ObjCMessageStream: NSObject { // MARK: - Properties private let messageStream: MessageStream @@ -61,7 +61,7 @@ final class _ObjCMessageStream: NSObject { // MARK: - Methods @objc(getVisitSessionState) - func getVisitSessionState() -> _ObjCVisitSessionState { + public func getVisitSessionState() -> _ObjCVisitSessionState { switch messageStream.getVisitSessionState() { case .CHAT: return .CHAT @@ -79,7 +79,7 @@ final class _ObjCMessageStream: NSObject { } @objc(getChatState) - func getChatState() -> _ObjCChatState { + public func getChatState() -> _ObjCChatState { switch messageStream.getChatState() { case .CHATTING: return .CHATTING @@ -101,17 +101,17 @@ final class _ObjCMessageStream: NSObject { } @objc(getUnreadByOperatorTimestamp) - func getUnreadByOperatorTimestamp() -> Date? { + public func getUnreadByOperatorTimestamp() -> Date? { return messageStream.getUnreadByOperatorTimestamp() } @objc(getUnreadByVisitorTimestamp) - func getUnreadByVisitorTimestamp() -> Date? { + public func getUnreadByVisitorTimestamp() -> Date? { return messageStream.getUnreadByVisitorTimestamp() } @objc(getDepartmentList) - func getDepartmentList() -> [_ObjCDepartment]? { + public func getDepartmentList() -> [_ObjCDepartment]? { if let departmentList = messageStream.getDepartmentList() { var objCDepartmentList = [_ObjCDepartment]() for department in departmentList { @@ -126,12 +126,12 @@ final class _ObjCMessageStream: NSObject { } @objc(getLocationSettings) - func getLocationSettings() -> _ObjCLocationSettings { + public func getLocationSettings() -> _ObjCLocationSettings { return _ObjCLocationSettings(locationSettings: messageStream.getLocationSettings()) } @objc(getCurrentOperator) - func getCurrentOperator() -> _ObjCOperator? { + public func getCurrentOperator() -> _ObjCOperator? { if let `operator` = messageStream.getCurrentOperator() { return _ObjCOperator(operator: `operator`) } @@ -140,12 +140,12 @@ final class _ObjCMessageStream: NSObject { } @objc(getLastRatingOfOperatorWithID:) - func getLastRatingOfOperatorWith(id: String) -> Int { + public func getLastRatingOfOperatorWith(id: String) -> Int { return messageStream.getLastRatingOfOperatorWith(id: id) } @objc(rateOperatorWithID:byRating:completionHandler:error:) - func rateOperatorWith(id: String?, + public func rateOperatorWith(id: String?, byRating rating: Int, completionHandler: _ObjCRateOperatorCompletionHandler) throws { try messageStream.rateOperatorWith(id: id, @@ -154,55 +154,55 @@ final class _ObjCMessageStream: NSObject { } @objc(respondSentryCall:error:) - func respondSentryCall(id: String) throws { + public func respondSentryCall(id: String) throws { try respondSentryCall(id: id) } @objc(startChat:) - func startChat() throws { + public func startChat() throws { try messageStream.startChat() } @objc(startChatWithDepartmentKey:error:) - func startChat(departmentKey: String?) throws { + public func startChat(departmentKey: String?) throws { try messageStream.startChat(departmentKey: departmentKey) } @objc(startChatWithCustomFields:error:) - func startChat(customFields: String?) throws { + public func startChat(customFields: String?) throws { try messageStream.startChat(customFields: customFields) } @objc(startChatWithFirstQuestion:error:) - func startChat(firstQuestion: String?) throws { + public func startChat(firstQuestion: String?) throws { try messageStream.startChat(firstQuestion: firstQuestion) } @objc(startChatWithDepartmentKey:firstQuestion:error:) - func startChat(departmentKey: String?, + public func startChat(departmentKey: String?, firstQuestion: String?) throws { try messageStream.startChat(departmentKey: departmentKey, firstQuestion: firstQuestion) } @objc(startChatWithFirstQuestion:customFields:error:) - func startChat(firstQuestion: String?, + public func startChat(firstQuestion: String?, customFields: String?) throws { try messageStream.startChat(firstQuestion: firstQuestion, customFields: customFields) } @objc(startChatWithDepartmentKey:customFields:error:) - func startChat(departmentKey: String?, + public func startChat(departmentKey: String?, customFields: String?) throws { try messageStream.startChat(departmentKey: departmentKey, customFields: customFields) } @objc(startChatWithDepartmentKey:firstQuestion:customFields:error:) - func startChat(departmentKey: String?, + public func startChat(departmentKey: String?, firstQuestion: String?, customFields: String?) throws { try messageStream.startChat(departmentKey: departmentKey, @@ -211,27 +211,27 @@ final class _ObjCMessageStream: NSObject { } @objc(closeChat:) - func closeChat() throws { + public func closeChat() throws { try messageStream.closeChat() } @objc(setVisitorTypingDraftMessage:error:) - func setVisitorTyping(draftMessage: String?) throws { + public func setVisitorTyping(draftMessage: String?) throws { try messageStream.setVisitorTyping(draftMessage: draftMessage) } @objc(setPrechatFields:error:) - func set(prechatFields: String) throws { + public func set(prechatFields: String) throws { try messageStream.set(prechatFields: prechatFields) } @objc(sendMessage:error:) - func send(message: String) throws -> String { + public func send(message: String) throws -> String { return try messageStream.send(message: message) } @objc(sendMessage:data:completionHandler:error:) - func send(message: String, + public func send(message: String, data: [String: Any]?, completionHandler: _ObjCDataMessageCompletionHandler?) throws -> String { return try messageStream.send(message: message, @@ -240,14 +240,14 @@ final class _ObjCMessageStream: NSObject { } @objc(sendMessage:isHintQuestion:error:) - func send(message: String, + public func send(message: String, isHintQuestion: Bool) throws -> String { return try messageStream.send(message: message, isHintQuestion: isHintQuestion) } @objc(sendFile:filename:mimeType:completionHandler:error:) - func send(file: Data, + public func send(file: Data, filename: String, mimeType: String, completionHandler: _ObjCSendFileCompletionHandler?) throws -> String { @@ -258,7 +258,7 @@ final class _ObjCMessageStream: NSObject { } @objc(editMessage:text:completionHandler:error:) - func edit(message: _ObjCMessage, + public func edit(message: _ObjCMessage, text: String, completionHandler: _ObjCEditMessageCompletionHandler?) throws -> NSNumber { let canBeEdited = try messageStream.edit(message: message.message, @@ -272,7 +272,7 @@ final class _ObjCMessageStream: NSObject { } @objc(deleteMessage:completionHandler:error:) - func delete(message: _ObjCMessage, + public func delete(message: _ObjCMessage, completionHandler: _ObjCDeleteMessageCompletionHandler?) throws -> NSNumber { let canBeEdited = try messageStream.delete(message: message.message, completionHandler: ((completionHandler == nil) ? nil : DeleteMessageCompletionHandlerWrapper(deleteMessageCompletionHandler: completionHandler!))) @@ -284,82 +284,82 @@ final class _ObjCMessageStream: NSObject { } @objc(setChatRead:) - func setChatRead() throws { + public func setChatRead() throws { try messageStream.setChatRead() } @objc(newMessageTrackerWithMessageListener:error:) - func newMessageTracker(messageListener: _ObjCMessageListener) throws -> _ObjCMessageTracker { + public func newMessageTracker(messageListener: _ObjCMessageListener) throws -> _ObjCMessageTracker { let wrapper = MessageListenerWrapper(messageListener: messageListener) messageListenerWrapper = wrapper return try _ObjCMessageTracker(messageTracker: messageStream.newMessageTracker(messageListener: wrapper)) } @objc(setVisitSessionStateListener:) - func set(visitSessionStateListener: _ObjCVisitSessionStateListener) { + public func set(visitSessionStateListener: _ObjCVisitSessionStateListener) { let wrapper = VisitSessionStateListenerWrapper(visitSessionStateListener: visitSessionStateListener) visitSessionStateListenerWrapper = wrapper messageStream.set(visitSessionStateListener: wrapper) } @objc(setChatStateListener:) - func set(chatStateListener: _ObjCChatStateListener) { + public func set(chatStateListener: _ObjCChatStateListener) { let wrapper = ChatStateListenerWrapper(chatStateListener: chatStateListener) chatStateListenerWrapper = wrapper messageStream.set(chatStateListener: wrapper) } @objc(setCurrentOperatorChangeListener:) - func set(currentOperatorChangeListener: _ObjCCurrentOperatorChangeListener) { + public func set(currentOperatorChangeListener: _ObjCCurrentOperatorChangeListener) { let wrapper = CurrentOperatorChangeListenerWrapper(currentOperatorChangeListener: currentOperatorChangeListener) currentOperatorChangeListenerWrapper = wrapper messageStream.set(currentOperatorChangeListener: wrapper) } @objc(setDepartmentListChangeListener:) - func set(departmentListChangeListener: _ObjCDepartmentListChangeListener) { + public func set(departmentListChangeListener: _ObjCDepartmentListChangeListener) { let wrapper = DepartmentListChangeListenerWrapper(departmentListChangeListener: departmentListChangeListener) departmentListChangeListenerWrapper = wrapper messageStream.set(departmentListChangeListener: wrapper) } @objc(LocationSettingsChangeListener:) - func set(locationSettingsChangeListener: _ObjCLocationSettingsChangeListener) { + public func set(locationSettingsChangeListener: _ObjCLocationSettingsChangeListener) { let wrapper = LocationSettingsChangeListenerWrapper(locationSettingsChangeListener: locationSettingsChangeListener) locationSettingsChangeListenerWrapper = wrapper messageStream.set(locationSettingsChangeListener: wrapper) } @objc(setOperatorTypingListener:) - func set(operatorTypingListener: _ObjCOperatorTypingListener) { + public func set(operatorTypingListener: _ObjCOperatorTypingListener) { let wrapper = OperatorTypingListenerWrapper(operatorTypingListener: operatorTypingListener) operatorTypingListenerWrapper = wrapper messageStream.set(operatorTypingListener: wrapper) } @objc(setOnlineStatusChangeListener:) - func set(onlineStatusChangeListener: _ObjCOnlineStatusChangeListener) { + public func set(onlineStatusChangeListener: _ObjCOnlineStatusChangeListener) { let wrapper = OnlineStatusChangeListenerWrapper(onlineStatusChangeListener: onlineStatusChangeListener) onlineStatusChangeListenerWrapper = wrapper messageStream.set(onlineStatusChangeListener: wrapper) } @objc(setUnreadByOperatorTimestampChangeListener:) - func set(unreadByOperatorTimestampChangeListener: _ObjCUnreadByOperatorTimestampChangeListener) { + public func set(unreadByOperatorTimestampChangeListener: _ObjCUnreadByOperatorTimestampChangeListener) { let wrapper = UnreadByOperatorTimestampChangeListenerWrapper(unreadByOperatorTimestampChangeListener: unreadByOperatorTimestampChangeListener) unreadByOperatorTimestampChangeListenerWrapper = wrapper messageStream.set(unreadByOperatorTimestampChangeListener: wrapper) } @objc(setUnreadByVisitorTimestampChangeListener:) - func set(unreadByVisitorTimestampChangeListener: _ObjCUnreadByVisitorTimestampChangeListener) { + public func set(unreadByVisitorTimestampChangeListener: _ObjCUnreadByVisitorTimestampChangeListener) { let wrapper = UnreadByVisitorTimestampChangeListenerWrapper(unreadByVisitorTimestampChangeListener: unreadByVisitorTimestampChangeListener) unreadByVisitorTimestampChangeListenerWrapper = wrapper messageStream.set(unreadByVisitorTimestampChangeListener: wrapper) } @objc(setUnreadByVisitorMessageCountChangeListener:) - func set(unreadByVisitorMessageCountChangeListener: _ObjCUnreadByVisitorMessageCountChangeListener) { + public func set(unreadByVisitorMessageCountChangeListener: _ObjCUnreadByVisitorMessageCountChangeListener) { let wrapper = UnreadByVisitorMessageCountChangeListenerWrapper(unreadByVisitorMessageCountChangeListener: unreadByVisitorMessageCountChangeListener) unreadByVisitorMessageCountChangeListenerWrapper = wrapper messageStream.set(unreadByVisitorMessageCountChangeListener: wrapper) @@ -369,7 +369,7 @@ final class _ObjCMessageStream: NSObject { // MARK: - LocationSettings @objc(LocationSettings) -final class _ObjCLocationSettings: NSObject { +public final class _ObjCLocationSettings: NSObject { // MARK: - Properties private let locationSettings: LocationSettings @@ -390,7 +390,7 @@ final class _ObjCLocationSettings: NSObject { // MARK: - DataMessageCompletionHandler @objc(DataMessageCompletionHandler) -protocol _ObjCDataMessageCompletionHandler { +public protocol _ObjCDataMessageCompletionHandler { @objc(onSuccessWithMessageID:) func onSuccess(messageID: String) @@ -403,7 +403,7 @@ protocol _ObjCDataMessageCompletionHandler { // MARK: - EditMessageCompletionHandler @objc(EditMessageCompletionHandler) -protocol _ObjCEditMessageCompletionHandler { +public protocol _ObjCEditMessageCompletionHandler { @objc(onSuccessWithMessageID:) func onSuccess(messageID: String) @@ -416,7 +416,7 @@ protocol _ObjCEditMessageCompletionHandler { // MARK: - DeleteMessageCompletionHandler @objc(DeleteMessageCompletionHandler) -protocol _ObjCDeleteMessageCompletionHandler { +public protocol _ObjCDeleteMessageCompletionHandler { @objc(onSuccessWithMessageID:) func onSuccess(messageID: String) @@ -429,7 +429,7 @@ protocol _ObjCDeleteMessageCompletionHandler { // MARK: - SendFileCompletionHandler @objc(SendFileCompletionHandler) -protocol _ObjCSendFileCompletionHandler { +public protocol _ObjCSendFileCompletionHandler { @objc(onSuccessWithMessageID:) func onSuccess(messageID: String) @@ -442,7 +442,7 @@ protocol _ObjCSendFileCompletionHandler { // MARK: - RateOperatorCompletionHandler @objc(RateOperatorCompletionHandler) -protocol _ObjCRateOperatorCompletionHandler { +public protocol _ObjCRateOperatorCompletionHandler { @objc(onSuccess) func onSuccess() @@ -454,7 +454,7 @@ protocol _ObjCRateOperatorCompletionHandler { // MARK: - VisitSessionStateListener @objc(VisitSessionStateListener) -protocol _ObjCVisitSessionStateListener { +public protocol _ObjCVisitSessionStateListener { @objc(changedState:to:) func changed(state previousState: _ObjCVisitSessionState, @@ -464,7 +464,7 @@ protocol _ObjCVisitSessionStateListener { // MARK: - ChatStateListener @objc(ChatStateListener) -protocol _ObjCChatStateListener { +public protocol _ObjCChatStateListener { @objc(changedState:to:) func changed(state previousState: _ObjCChatState, @@ -474,7 +474,7 @@ protocol _ObjCChatStateListener { // MARK: - CurrentOperatorChangeListener @objc(CurrentOperatorChangeListener) -protocol _ObjCCurrentOperatorChangeListener { +public protocol _ObjCCurrentOperatorChangeListener { @objc(changedOperator:to:) func changed(operator previousOperator: _ObjCOperator?, @@ -484,7 +484,7 @@ protocol _ObjCCurrentOperatorChangeListener { // MARK: - DepartmentListChangeListener @objc(DepartmentListChangeListener) -protocol _ObjCDepartmentListChangeListener { +public protocol _ObjCDepartmentListChangeListener { @objc(receivedDepartmentList:) func received(departmentList: [_ObjCDepartment]) @@ -493,7 +493,7 @@ protocol _ObjCDepartmentListChangeListener { // MARK: - LocationSettingsChangeListener @objc(LocationSettingsChangeListener) -protocol _ObjCLocationSettingsChangeListener { +public protocol _ObjCLocationSettingsChangeListener { @objc(changedLocationSettings:to:) func changed(locationSettings previousLocationSettings: _ObjCLocationSettings, @@ -503,7 +503,7 @@ protocol _ObjCLocationSettingsChangeListener { // MARK: - OperatorTypingListener @objc(OperatorTypingListener) -protocol _ObjCOperatorTypingListener { +public protocol _ObjCOperatorTypingListener { @objc(onOperatorTypingStateChangedTo:) func onOperatorTypingStateChanged(isTyping: Bool) @@ -512,7 +512,7 @@ protocol _ObjCOperatorTypingListener { // MARK: - OnlineStatusChangeListener @objc(SessionOnlineStatusChangeListener) -protocol _ObjCOnlineStatusChangeListener { +public protocol _ObjCOnlineStatusChangeListener { @objc(changedOnlineStatus:to:) func changed(onlineStatus previousOnlineStatus: _ObjCOnlineStatus, @@ -522,7 +522,7 @@ protocol _ObjCOnlineStatusChangeListener { // MARK: - UnreadByOperatorTimestampChangeListener @objc(UnreadByOperatorTimestampChangeListener) -protocol _ObjCUnreadByOperatorTimestampChangeListener { +public protocol _ObjCUnreadByOperatorTimestampChangeListener { @objc(changedUnreadByOperatorTimestampTo:) func changedUnreadByOperatorTimestampTo(newValue: Date?) @@ -531,7 +531,7 @@ protocol _ObjCUnreadByOperatorTimestampChangeListener { // MARK: - UnreadByVisitorTimestampChangeListener @objc(UnreadByVisitorTimestampChangeListener) -protocol _ObjCUnreadByVisitorTimestampChangeListener { +public protocol _ObjCUnreadByVisitorTimestampChangeListener { @objc(changedUnreadByVisitorTimestampTo:) func changedUnreadByVisitorTimestampTo(newValue: Date?) @@ -540,7 +540,7 @@ protocol _ObjCUnreadByVisitorTimestampChangeListener { // MARK: - UnreadByVisitorMessageCountChangeListener @objc(UnreadByVisitorMessageCountChangeListener) -protocol _ObjCUnreadByVisitorMessageCountChangeListener { +public protocol _ObjCUnreadByVisitorMessageCountChangeListener { @objc(changedUnreadByVisitorMessageCountTo:) func changedUnreadByVisitorMessageCountTo(newValue: Int) @@ -549,7 +549,7 @@ protocol _ObjCUnreadByVisitorMessageCountChangeListener { // MARK: - ChatState @objc(ChatState) -enum _ObjCChatState: Int { +public enum _ObjCChatState: Int { case CHATTING case CHATTING_WITH_ROBOT case CLOSED_BY_OPERATOR @@ -562,7 +562,7 @@ enum _ObjCChatState: Int { // MARK: - OnlineStatus @objc(OnlineStatus) -enum _ObjCOnlineStatus: Int { +public enum _ObjCOnlineStatus: Int { case BUSY_OFFLINE case BUSY_ONLINE case OFFLINE @@ -572,7 +572,7 @@ enum _ObjCOnlineStatus: Int { // MARK: - VisitSessionState @objc(VisitSessionState) -enum _ObjCVisitSessionState: Int { +public enum _ObjCVisitSessionState: Int { case CHAT case DEPARTMENT_SELECTION case IDLE @@ -583,7 +583,7 @@ enum _ObjCVisitSessionState: Int { // MARK: - DataMessageError @objc(DataMessageError) -enum _ObjCDataMessageError: Int, Error { +public enum _ObjCDataMessageError: Int, Error { case QUOTED_MESSAGE_CANNOT_BE_REPLIED case QUOTED_MESSAGE_FROM_ANOTHER_VISITOR case QUOTED_MESSAGE_MULTIPLE_IDS @@ -594,7 +594,7 @@ enum _ObjCDataMessageError: Int, Error { // MARK: - EditMessageError @objc(EditMessageError) -enum _ObjCEditMessageError: Int, Error { +public enum _ObjCEditMessageError: Int, Error { case UNKNOWN case NOT_ALLOWED case MESSAGE_EMPTY @@ -605,7 +605,7 @@ enum _ObjCEditMessageError: Int, Error { // MARK: - DeleteMessageError @objc(DeleteMessageError) -enum _ObjCDeleteMessageError: Int, Error { +public enum _ObjCDeleteMessageError: Int, Error { case UNKNOWN case NOT_ALLOWED case MESSAGE_NOT_OWNED @@ -614,7 +614,7 @@ enum _ObjCDeleteMessageError: Int, Error { // MARK: - SendFileError @objc(SendFileError) -enum _ObjCSendFileError: Int, Error { +public enum _ObjCSendFileError: Int, Error { case FILE_SIZE_EXCEEDED case FILE_TYPE_NOT_ALLOWED case UPLOADED_FILE_NOT_FOUND @@ -623,7 +623,7 @@ enum _ObjCSendFileError: Int, Error { // MARK: - RateOperatorError @objc(RateOperatorError) -enum _ObjCRateOperatorError: Int, Error { +public enum _ObjCRateOperatorError: Int, Error { case NO_CHAT case WRONG_OPERATOR_ID } diff --git a/ios/MessageTracker.swift b/ios/MessageTracker.swift index c563538..98a945b 100755 --- a/ios/MessageTracker.swift +++ b/ios/MessageTracker.swift @@ -31,14 +31,14 @@ import WebimClientLibrary // MARK: - MessageTracker @objc(MessageTracker) -final class _ObjCMessageTracker: NSObject { +public final class _ObjCMessageTracker: NSObject { // MARK: - Properties private let messageTracker: MessageTracker // MARK: - Initialization - init(messageTracker: MessageTracker) { + public init(messageTracker: MessageTracker) { self.messageTracker = messageTracker } @@ -46,7 +46,7 @@ final class _ObjCMessageTracker: NSObject { // MARK: - Methods @objc(getLastMessagesByLimit:completion:error:) - func getLastMessages(byLimit limitOfMessages: Int, + public func getLastMessages(byLimit limitOfMessages: Int, completion: @escaping (_ result: [_ObjCMessage]) -> ()) throws { try messageTracker.getLastMessages(byLimit: limitOfMessages) { messages in var objCMessages = [_ObjCMessage]() @@ -58,7 +58,7 @@ final class _ObjCMessageTracker: NSObject { } @objc(getNextMessagesByLimit:completion:error:) - func getNextMessages(byLimit limitOfMessages: Int, + public func getNextMessages(byLimit limitOfMessages: Int, completion: @escaping ([_ObjCMessage]) -> ()) throws { try messageTracker.getNextMessages(byLimit: limitOfMessages) { messages in var objCMessages = [_ObjCMessage]() @@ -70,7 +70,7 @@ final class _ObjCMessageTracker: NSObject { } @objc(getAllMessagesWithCompletion:error:) - func getAllMessages(completion: @escaping (_ result: [_ObjCMessage]) -> ()) throws { + public func getAllMessages(completion: @escaping (_ result: [_ObjCMessage]) -> ()) throws { try messageTracker.getAllMessages() { messages in var objCMessages = [_ObjCMessage]() for message in messages { @@ -81,12 +81,12 @@ final class _ObjCMessageTracker: NSObject { } @objc(resetToMessage:error:) - func resetTo(message: _ObjCMessage) throws { + public func resetTo(message: _ObjCMessage) throws { try messageTracker.resetTo(message: message.message) } @objc(destroy:) - func destroy() throws { + public func destroy() throws { try messageTracker.destroy() } diff --git a/ios/Operator.swift b/ios/Operator.swift index 2332428..7790a08 100755 --- a/ios/Operator.swift +++ b/ios/Operator.swift @@ -31,14 +31,14 @@ import WebimClientLibrary // MARK: - Operator @objc(Operator) -final class _ObjCOperator: NSObject { +public final class _ObjCOperator: NSObject { // MARK: - Private private let `operator`: Operator // MARK: - Initialization - init(operator: Operator) { + public init(operator: Operator) { self.`operator` = `operator` } @@ -46,17 +46,17 @@ final class _ObjCOperator: NSObject { // MARK: - Methods @objc(getID) - func getID() -> String { + public func getID() -> String { return `operator`.getID() } @objc(getName) - func getName() -> String { + public func getName() -> String { return `operator`.getName() } @objc(getAvatarURL) - func getAvatarURL() -> URL? { + public func getAvatarURL() -> URL? { return `operator`.getAvatarURL() } diff --git a/ios/ProvidedAuthorizationTokenStateListener.swift b/ios/ProvidedAuthorizationTokenStateListener.swift index 06f360c..bb7369a 100755 --- a/ios/ProvidedAuthorizationTokenStateListener.swift +++ b/ios/ProvidedAuthorizationTokenStateListener.swift @@ -28,7 +28,7 @@ import Foundation import WebimClientLibrary @objc(ProvidedAuthorizationTokenStateListener) -protocol _ObjCProvidedAuthorizationTokenStateListener { +public protocol _ObjCProvidedAuthorizationTokenStateListener { @objc(updateProvidedAuthorizationToken:) func update(providedAuthorizationToken: String) @@ -37,19 +37,19 @@ protocol _ObjCProvidedAuthorizationTokenStateListener { // MARK: - Protocols' wrappers // MARK: - ProvidedAuthorizationTokenStateListener -final class ProvidedAuthorizationTokenStateListenerWrapper: ProvidedAuthorizationTokenStateListener { +public final class ProvidedAuthorizationTokenStateListenerWrapper: ProvidedAuthorizationTokenStateListener { // MARK: - Properties private let providedAuthorizationTokenStateListener: _ObjCProvidedAuthorizationTokenStateListener // MARK: - Initialization - init(providedAuthorizationTokenStateListener: _ObjCProvidedAuthorizationTokenStateListener) { + public init(providedAuthorizationTokenStateListener: _ObjCProvidedAuthorizationTokenStateListener) { self.providedAuthorizationTokenStateListener = providedAuthorizationTokenStateListener } // MARK: - Methods // MARK: ProvidedAuthorizationTokenStateListener protocol methods - func update(providedAuthorizationToken: String) { + public func update(providedAuthorizationToken: String) { providedAuthorizationTokenStateListener.update(providedAuthorizationToken: providedAuthorizationToken) } diff --git a/ios/RNWebim.h b/ios/RNWebim.h index 04266e9..3b3ffda 100644 --- a/ios/RNWebim.h +++ b/ios/RNWebim.h @@ -6,7 +6,7 @@ #endif #import +#import "RNWebim-Swift.h" -@interface webim : RCTEventEmitter - +@interface RNWebim : RCTEventEmitter @end diff --git a/ios/RNWebim.m b/ios/RNWebim.m index 4704d9c..d0ca9cc 100644 --- a/ios/RNWebim.m +++ b/ios/RNWebim.m @@ -2,7 +2,7 @@ #import "RNWebim.h" #import -@implementation webim +@implementation RNWebim WebimSession *webimSession; MessageStream *stream; @@ -90,7 +90,7 @@ - (dispatch_queue_t)methodQueue { NSError *err = nil; [tracker getLastMessagesByLimit:[limit intValue] completion:^(NSArray * _Nonnull arr) { - resolve(@[@{@"messages": [self messagesToJsonArray:arr] }]); + resolve(@[@{@"messages": [self messagesToJsonArray:arr] }]); } error:&err]; if (err) { reject(@[@{@"message": [err localizedDescription]}]); diff --git a/ios/Webim.swift b/ios/Webim.swift index d215c2b..c195e4a 100755 --- a/ios/Webim.swift +++ b/ios/Webim.swift @@ -28,20 +28,19 @@ import Foundation import WebimClientLibrary - // MARK: - Webim @objc(Webim) -final class _ObjCWebim: NSObject { +public final class _ObjCWebim: NSObject { // MARK: - Methods @objc - static func newSessionBuilder() -> _ObjCSessionBuilder { + public static func newSessionBuilder() -> _ObjCSessionBuilder { return _ObjCSessionBuilder(sessionBuilder: Webim.newSessionBuilder()) } @objc(parseRemoteNotification:) - static func parse(remoteNotification: [AnyHashable: Any]) -> _ObjCWebimRemoteNotification? { + public static func parse(remoteNotification: [AnyHashable: Any]) -> _ObjCWebimRemoteNotification? { if let webimRemoteNotification = Webim.parse(remoteNotification: remoteNotification) { return _ObjCWebimRemoteNotification(webimRemoteNotification: webimRemoteNotification) } else { @@ -66,7 +65,7 @@ final class _ObjCWebim: NSObject { // MARK: - RemoteNotificationSystem @objc(RemoteNotificationSystem) - enum _ObjCRemoteNotificationSystem: Int { + public enum _ObjCRemoteNotificationSystem: Int { case APNS case NONE } @@ -75,7 +74,7 @@ final class _ObjCWebim: NSObject { // MARK: - SessionBuilder @objc(SessionBuilder) -final class _ObjCSessionBuilder: NSObject { +public final class _ObjCSessionBuilder: NSObject { // MARK: - Properties private (set) var sessionBuilder: SessionBuilder @@ -91,49 +90,49 @@ final class _ObjCSessionBuilder: NSObject { // MARK: - Methods @objc(setAccountName:) - func set(accountName: String) -> _ObjCSessionBuilder { + public func set(accountName: String) -> _ObjCSessionBuilder { sessionBuilder = sessionBuilder.set(accountName: accountName) return self } @objc(setLocation:) - func set(location: String) -> _ObjCSessionBuilder { + public func set(location: String) -> _ObjCSessionBuilder { sessionBuilder = sessionBuilder.set(location: location) return self } @objc(setPrechat:) - func set(prechat: String) -> _ObjCSessionBuilder { + public func set(prechat: String) -> _ObjCSessionBuilder { sessionBuilder = sessionBuilder.set(prechat: prechat) return self } @objc(setAppVersion:) - func set(appVersion: String) -> _ObjCSessionBuilder { + public func set(appVersion: String) -> _ObjCSessionBuilder { sessionBuilder = sessionBuilder.set(appVersion: appVersion) return self } @objc(setVisitorFieldsJSONString:) - func set(visitorFieldsJSONString: String) -> _ObjCSessionBuilder { + public func set(visitorFieldsJSONString: String) -> _ObjCSessionBuilder { sessionBuilder = sessionBuilder.set(visitorFieldsJSONString: visitorFieldsJSONString) return self } @objc(setVisitorFieldsJSONData:) - func set(visitorFieldsJSONData: Data) -> _ObjCSessionBuilder { + public func set(visitorFieldsJSONData: Data) -> _ObjCSessionBuilder { sessionBuilder = sessionBuilder.set(visitorFieldsJSONData: visitorFieldsJSONData) return self } @objc(setProvidedAuthorizationTokenStateListener:providedAuthorizationToken:) - func set(providedAuthorizationTokenStateListener: _ObjCProvidedAuthorizationTokenStateListener, + public func set(providedAuthorizationTokenStateListener: _ObjCProvidedAuthorizationTokenStateListener, providedAuthorizationToken: String? = nil) -> _ObjCSessionBuilder { sessionBuilder = sessionBuilder.set(providedAuthorizationTokenStateListener: ProvidedAuthorizationTokenStateListenerWrapper(providedAuthorizationTokenStateListener: providedAuthorizationTokenStateListener), providedAuthorizationToken: providedAuthorizationToken) @@ -142,21 +141,21 @@ final class _ObjCSessionBuilder: NSObject { } @objc(setPageTitle:) - func set(pageTitle: String) -> _ObjCSessionBuilder { + public func set(pageTitle: String) -> _ObjCSessionBuilder { sessionBuilder = sessionBuilder.set(pageTitle: pageTitle) return self } @objc(setFatalErrorHandler:) - func set(fatalErrorHandler: _ObjCFatalErrorHandler) -> _ObjCSessionBuilder { + public func set(fatalErrorHandler: _ObjCFatalErrorHandler) -> _ObjCSessionBuilder { sessionBuilder = sessionBuilder.set(fatalErrorHandler: FatalErrorHandlerWrapper(fatalErrorHandler: fatalErrorHandler)) return self } @objc(setRemoteNotificationSystem:) - func set(remoteNotificationSystem: _ObjCWebim._ObjCRemoteNotificationSystem) -> _ObjCSessionBuilder { + public func set(remoteNotificationSystem: _ObjCWebim._ObjCRemoteNotificationSystem) -> _ObjCSessionBuilder { var webimRemoteNotificationSystem: Webim.RemoteNotificationSystem? switch remoteNotificationSystem { case .APNS: @@ -170,7 +169,7 @@ final class _ObjCSessionBuilder: NSObject { } @objc(setDeviceToken:) - func set(deviceToken: String?) -> _ObjCSessionBuilder { + public func set(deviceToken: String?) -> _ObjCSessionBuilder { sessionBuilder = sessionBuilder.set(deviceToken: deviceToken) return self @@ -184,14 +183,14 @@ final class _ObjCSessionBuilder: NSObject { } @objc(setIsVisitorDataClearingEnabled:) - func set(isVisitorDataClearingEnabled: Bool) -> _ObjCSessionBuilder { + public func set(isVisitorDataClearingEnabled: Bool) -> _ObjCSessionBuilder { sessionBuilder = sessionBuilder.set(isVisitorDataClearingEnabled: isVisitorDataClearingEnabled) return self } @objc(setWebimLogger:verbosityLevel:) - func set(webimLogger: _ObjCWebimLogger, + public func set(webimLogger: _ObjCWebimLogger, verbosityLevel: _ObjCWebimLoggerVerbosityLevel) -> _ObjCSessionBuilder { var internalVerbosityLevel: SessionBuilder.WebimLoggerVerbosityLevel? switch verbosityLevel { @@ -215,13 +214,13 @@ final class _ObjCSessionBuilder: NSObject { } @objc(build:) - func build() throws -> _ObjCWebimSession { + public func build() throws -> _ObjCWebimSession { return try _ObjCWebimSession(webimSession: sessionBuilder.build()) } // MARK: - @objc(WebimLoggerVerbosityLevel) - enum _ObjCWebimLoggerVerbosityLevel: Int { + public enum _ObjCWebimLoggerVerbosityLevel: Int { case VERBOSE case DEBUG case INFO diff --git a/ios/WebimError.swift b/ios/WebimError.swift index 4155b8f..ddf22ff 100755 --- a/ios/WebimError.swift +++ b/ios/WebimError.swift @@ -31,7 +31,7 @@ import WebimClientLibrary // MARK: - WebimError @objc(WebimError) -final class _ObjCWebimError: NSObject { +public final class _ObjCWebimError: NSObject { // MARK: - Properties private let webimError: WebimError @@ -71,7 +71,7 @@ final class _ObjCWebimError: NSObject { // MARK: - FatalErrorType @objc(FatalErrorType) -enum _ObjCFatalErrorType: Int { +public enum _ObjCFatalErrorType: Int { case ACCOUNT_BLOCKED case PROVIDED_VISITOR_FIELDS_EXPIRED case UNKNOWN diff --git a/ios/WebimLogger.swift b/ios/WebimLogger.swift index 307ee59..8f57030 100755 --- a/ios/WebimLogger.swift +++ b/ios/WebimLogger.swift @@ -29,7 +29,7 @@ import WebimClientLibrary // MARK: - WebimLogger @objc(WebimLogger) -protocol _ObjCWebimLogger { +public protocol _ObjCWebimLogger { @objc(logEntry:) func log(entry: String) @@ -38,17 +38,17 @@ protocol _ObjCWebimLogger { // MARK: - Protocols' wrappers // MARK: - WebimLogger -final class WebimLoggerWrapper: WebimLogger { +public final class WebimLoggerWrapper: WebimLogger { // MARK: - Properties private let webimLogger: _ObjCWebimLogger // MARK: - Initialization - init(webimLogger: _ObjCWebimLogger) { + public init(webimLogger: _ObjCWebimLogger) { self.webimLogger = webimLogger } - func log(entry: String) { + public func log(entry: String) { webimLogger.log(entry: entry) } diff --git a/ios/WebimRemoteNotification.swift b/ios/WebimRemoteNotification.swift index c84f7c9..bdfcf5a 100755 --- a/ios/WebimRemoteNotification.swift +++ b/ios/WebimRemoteNotification.swift @@ -29,14 +29,14 @@ import WebimClientLibrary // MARK: - WebimRemoteNotification @objc(WebimRemoteNotification) -final class _ObjCWebimRemoteNotification: NSObject { +public final class _ObjCWebimRemoteNotification: NSObject { // MARK: - Properties private let webimRemoteNotification: WebimRemoteNotification // MARK: - Initialization - init(webimRemoteNotification: WebimRemoteNotification) { + public init(webimRemoteNotification: WebimRemoteNotification) { self.webimRemoteNotification = webimRemoteNotification } @@ -44,7 +44,7 @@ final class _ObjCWebimRemoteNotification: NSObject { // MARK: - Methods @objc(getType) - func getType() -> _ObjCNotificationType { + public func getType() -> _ObjCNotificationType { switch webimRemoteNotification.getType() { case .CONTACT_INFORMATION_REQUEST: return .CONTACT_INFORMATION_REQUEST @@ -60,7 +60,7 @@ final class _ObjCWebimRemoteNotification: NSObject { } @objc(getEvent) - func getEvent() -> _ObjCNotificationEvent { + public func getEvent() -> _ObjCNotificationEvent { if let event = webimRemoteNotification.getEvent() { switch event { case .ADD: @@ -74,7 +74,7 @@ final class _ObjCWebimRemoteNotification: NSObject { } @objc(getParameters) - func getParameters() -> [String] { + public func getParameters() -> [String] { return webimRemoteNotification.getParameters() } @@ -83,7 +83,7 @@ final class _ObjCWebimRemoteNotification: NSObject { // MARK: - NotificationType @objc(NotificationType) -enum _ObjCNotificationType: Int { +public enum _ObjCNotificationType: Int { case CONTACT_INFORMATION_REQUEST case OPERATOR_ACCEPTED case OPERATOR_FILE @@ -93,7 +93,7 @@ enum _ObjCNotificationType: Int { // MARK: - NotificationEvent @objc(NotificationEvent) -enum _ObjCNotificationEvent: Int { +public enum _ObjCNotificationEvent: Int { case NONE case ADD case DELETE diff --git a/ios/WebimSession.swift b/ios/WebimSession.swift index a9dd78d..3feb422 100755 --- a/ios/WebimSession.swift +++ b/ios/WebimSession.swift @@ -31,14 +31,14 @@ import WebimClientLibrary // MARK: - WebimSession @objc(WebimSession) -final class _ObjCWebimSession: NSObject { +public final class _ObjCWebimSession: NSObject { // MARK: - Properties private let webimSession: WebimSession // MARK: - Initializers - init(webimSession: WebimSession) { + public init(webimSession: WebimSession) { self.webimSession = webimSession } @@ -46,37 +46,37 @@ final class _ObjCWebimSession: NSObject { // MARK: - Methods @objc(resume:) - func resume() throws { + public func resume() throws { try webimSession.resume() } @objc(pause:) - func pause() throws { + public func pause() throws { try webimSession.pause() } @objc(destroy:) - func destry() throws { + public func destry() throws { try webimSession.destroy() } @objc(destroyWithClearVisitorData:) - func destroyWithClearVisitorData() throws { + public func destroyWithClearVisitorData() throws { try webimSession.destroyWithClearVisitorData() } @objc(getStream) - func getStream() -> _ObjCMessageStream { + public func getStream() -> _ObjCMessageStream { return _ObjCMessageStream(messageStream: webimSession.getStream()) } @objc(changeLocation:error:) - func change(location: String) throws { + public func change(location: String) throws { try webimSession.change(location: location) } @objc(setDeviceToken:error:) - func set(deviceToken: String) throws { + public func set(deviceToken: String) throws { try webimSession.set(deviceToken: deviceToken) } From 87fc377974b06e92fa570fd00546a0bd8e80b353 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Mon, 14 Oct 2019 00:00:14 +0300 Subject: [PATCH 12/32] Fix RNWebim-Swift.h error --- ios/RNWebim.h | 3 +-- ios/RNWebim.m | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/RNWebim.h b/ios/RNWebim.h index 3b3ffda..5482013 100644 --- a/ios/RNWebim.h +++ b/ios/RNWebim.h @@ -6,7 +6,6 @@ #endif #import -#import "RNWebim-Swift.h" -@interface RNWebim : RCTEventEmitter +@interface RNWebim : RCTEventEmitter @end diff --git a/ios/RNWebim.m b/ios/RNWebim.m index d0ca9cc..ac56b21 100644 --- a/ios/RNWebim.m +++ b/ios/RNWebim.m @@ -1,6 +1,7 @@ #import "RNWebim.h" #import +#import "RNWebim-Swift.h" @implementation RNWebim From fecc4acaa62686e1e62a3238e191b53c380f26ff Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Mon, 14 Oct 2019 00:07:06 +0300 Subject: [PATCH 13/32] Increase version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8edb92d..1d6016a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-webim", - "version": "0.0.5", + "version": "0.0.6", "author": "AlfClausen", "license": "MIT", "description": "RN Webim implementation", From 8255a03f2e29fb151ecf35bbe3b034479ff6829f Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Mon, 14 Oct 2019 00:19:50 +0300 Subject: [PATCH 14/32] Fix code after upgrade to WebimClientLibrary 3.29.0 --- ios/Message.swift | 6 ++++++ ios/RNWebim.m | 2 +- ios/WebimRemoteNotification.swift | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/ios/Message.swift b/ios/Message.swift index ffe93bd..8b1884e 100755 --- a/ios/Message.swift +++ b/ios/Message.swift @@ -128,6 +128,10 @@ public final class _ObjCMessage: NSObject { return .OPERATOR_BUSY case .VISITOR: return .VISITOR + case .KEYBOARD: + return .KEYBOARD + case .KEYBOARD_RESPONSE: + return .KEYBOARD_RESPONSE } } @@ -240,6 +244,8 @@ public enum _ObjCMessageType: Int { case OPERATOR case OPERATOR_BUSY case VISITOR + case KEYBOARD + case KEYBOARD_RESPONSE } // MARK: - MessageSendStatus diff --git a/ios/RNWebim.m b/ios/RNWebim.m index ac56b21..b398a5c 100644 --- a/ios/RNWebim.m +++ b/ios/RNWebim.m @@ -1,7 +1,7 @@ #import "RNWebim.h" #import -#import "RNWebim-Swift.h" +#import "RNWebim-Swift.h" // If use see compile error at this line, to fix repeat compile second time @implementation RNWebim diff --git a/ios/WebimRemoteNotification.swift b/ios/WebimRemoteNotification.swift index bdfcf5a..b276425 100755 --- a/ios/WebimRemoteNotification.swift +++ b/ios/WebimRemoteNotification.swift @@ -56,6 +56,8 @@ public final class _ObjCWebimRemoteNotification: NSObject { return .OPERATOR_MESSAGE case .WIDGET: return .WIDGET + case .none: + return .NONE } } @@ -89,6 +91,7 @@ public enum _ObjCNotificationType: Int { case OPERATOR_FILE case OPERATOR_MESSAGE case WIDGET + case NONE } // MARK: - NotificationEvent From 789ba48baf176430b68f6291d925bd22629bf208 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Mon, 14 Oct 2019 00:24:04 +0300 Subject: [PATCH 15/32] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f9d4215..a161229 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Implementation of [webim sdk](https://webim.ru/) for [react-native](https://github.com/facebook/react-native) -**Important:** last tested react-native version is 59.9 +**Important:** Updated version for RN 0.60+ ## Installation From cfa7af6a69b339b696769c89962df97ee37db3b3 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Mon, 14 Oct 2019 11:03:24 +0300 Subject: [PATCH 16/32] Update README.md --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a161229..597963b 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,8 @@ react-native link react-native-webim iOS: - - add `Libraries/RNWebim/Libraries/WebimClientLibrary/Product/WebimClientLibrary.framework` into **Link Binary With Libraries** - - to be done - - move `WebimClientLibrary.framework` and `SQLite.framework` to **Embedded binaries** - - create empty swift file in ios project root and agree with creating bridging header. +- react-native link react-native-webim +- pod install ## Usage From 061107a255460b06536b4cd27eb235bedc6eedb5 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Mon, 14 Oct 2019 11:05:47 +0300 Subject: [PATCH 17/32] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 597963b..b369851 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,11 @@ Implementation of [webim sdk](https://webim.ru/) for [react-native](https://gith ## Installation ``` -yarn add react-native-webim +yarn add react-native-webim@git+${currentRepoUrl}.git#master react-native link react-native-webim ``` -iOS: +iOS & android: - react-native link react-native-webim - pod install From fc18c36ab5eb8a4acbfef085460870e59d911c7e Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Mon, 14 Oct 2019 11:07:52 +0300 Subject: [PATCH 18/32] Update README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b369851..2c1b44d 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,8 @@ yarn add react-native-webim@git+${currentRepoUrl}.git#master react-native link react-native-webim ``` -iOS & android: - -- react-native link react-native-webim +iOS +- add to PodFile ```pod 'WebimClientLibrary', :git => 'https://github.com/webim/webim-client-sdk-ios.git', :tag => '3.29.0'``` - pod install ## Usage From af24d489561f29ca4ef41f9dea7b6129e7406e26 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Tue, 29 Oct 2019 12:53:07 +0300 Subject: [PATCH 19/32] Fix RNWebim-Swift.h header import --- ios/RNWebim.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/RNWebim.m b/ios/RNWebim.m index b398a5c..72b1078 100644 --- a/ios/RNWebim.m +++ b/ios/RNWebim.m @@ -1,7 +1,7 @@ #import "RNWebim.h" #import -#import "RNWebim-Swift.h" // If use see compile error at this line, to fix repeat compile second time +#import // If use see compile error at this line, to fix repeat compile second time @implementation RNWebim From c18f3762c8d2150500b4d4a5ce36c9f1eeb99927 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Tue, 29 Oct 2019 12:58:28 +0300 Subject: [PATCH 20/32] Increase version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1d6016a..d918edf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-webim", - "version": "0.0.6", + "version": "0.0.7", "author": "AlfClausen", "license": "MIT", "description": "RN Webim implementation", From 391603d7df4adfd3c3469c48e9098d5915482801 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Tue, 29 Oct 2019 19:32:05 +0300 Subject: [PATCH 21/32] Rename Class name --- index.d.ts | 4 ++-- index.js | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/index.d.ts b/index.d.ts index d5533ff..78944b2 100644 --- a/index.d.ts +++ b/index.d.ts @@ -26,7 +26,7 @@ declare module 'webim-react-native' { export type WebimListener = (msg: T) => void; - class webim { + class RNWebim { resumeSession(accountName: string, location: string, acc?: string): Promise; destroySession(): Promise; @@ -52,7 +52,7 @@ declare module 'webim-react-native' { removeAllListeners(event: string): void; } - const Webim: webim; + const Webim: RNWebim; export default Webim; } diff --git a/index.js b/index.js index 69b0015..66866b3 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,7 @@ import { NativeModules, NativeEventEmitter, Platform } from 'react-native'; -const { webim: WebimNative } = NativeModules; -const emitter = new NativeEventEmitter(NativeModules.webim); +const { RNWebim: WebimNative } = NativeModules; +const emitter = new NativeEventEmitter(NativeModules.RNWebim); export const webimEvents = { NEW_MESSAGE: 'newMessage', @@ -18,7 +18,7 @@ function processError(e) { return new Error(e.message); } -class webim { +class RNWebim { static resumeSession(accountName, location, account) { return new Promise((resolve, reject) => { WebimNative.resumeSession(accountName, location, account, e => reject(processError(e)), res => resolve(parseNativeResponse(res))); @@ -72,7 +72,7 @@ class webim { [uri, name, mime, extension] = args; } try { - await webim.sendFile(uri, name, mime, extension); + await RNWebim.sendFile(uri, name, mime, extension); resolve(); } catch (e) { reject(processError(e)); @@ -98,4 +98,4 @@ class webim { } } -export default webim; +export default RNWebim; From 2a3010ab8bf584511bba321403084663225c7370 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Tue, 19 Nov 2019 11:39:14 +0300 Subject: [PATCH 22/32] Provide Authorization Token --- ios/RNWebim.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ios/RNWebim.m b/ios/RNWebim.m index 72b1078..32c81dd 100644 --- a/ios/RNWebim.m +++ b/ios/RNWebim.m @@ -2,12 +2,14 @@ #import "RNWebim.h" #import #import // If use see compile error at this line, to fix repeat compile second time +@class ProvidedAuthorizationTokenStateListener; @implementation RNWebim WebimSession *webimSession; MessageStream *stream; MessageTracker *tracker; +ProvidedAuthorizationTokenStateListener *instance; RCTResponseSenderBlock attachmentResolve; RCTResponseSenderBlock attachmentReject; @@ -35,7 +37,7 @@ - (dispatch_queue_t)methodQueue { sessionBuilder = [sessionBuilder setAccountName:accountName]; sessionBuilder = [sessionBuilder setLocation:location]; if (account != nil) { - sessionBuilder = [sessionBuilder setVisitorFieldsJSONString:account]; + sessionBuilder = [sessionBuilder setProvidedAuthorizationTokenStateListener:instance providedAuthorizationToken:account]; } webimSession = [sessionBuilder build:&error]; if (error) { From e1eca7c929bb0257856bcca66e390265b4fd42f1 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Wed, 27 Nov 2019 17:22:17 +0300 Subject: [PATCH 23/32] Fix android naming & upgrade versions --- .gitignore | 1 + .../.gradle/4.6/fileChanges/last-build.bin | Bin 0 -> 1 bytes android/.gradle/4.6/fileHashes/fileHashes.bin | Bin 0 -> 18597 bytes .../.gradle/4.6/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes android/.gradle/vcsWorkingDirs/gc.properties | 0 android/build.gradle | 30 ++++++++---------- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../main/java/ru/vvdev/webim/WebimModule.java | 2 +- index.d.ts | 2 +- 9 files changed, 18 insertions(+), 19 deletions(-) create mode 100644 android/.gradle/4.6/fileChanges/last-build.bin create mode 100644 android/.gradle/4.6/fileHashes/fileHashes.bin create mode 100644 android/.gradle/4.6/fileHashes/fileHashes.lock create mode 100644 android/.gradle/vcsWorkingDirs/gc.properties diff --git a/.gitignore b/.gitignore index dcd2777..0a10fe1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ .vscode build *.iml +local.properties \ No newline at end of file diff --git a/android/.gradle/4.6/fileChanges/last-build.bin b/android/.gradle/4.6/fileChanges/last-build.bin new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/android/.gradle/4.6/fileHashes/fileHashes.bin b/android/.gradle/4.6/fileHashes/fileHashes.bin new file mode 100644 index 0000000000000000000000000000000000000000..57ecbca9a66e3da1e0fd335626d84c9b6f96ccc5 GIT binary patch literal 18597 zcmeI&y-Gtd6ae5@w^Fo&g^r3tD~KpAf;be4f0Iim7X{r^1O;bj#mRTj!SN0Xf}=S3 z09Lv?3N8+6F6pKC0uJ&8k{nJrB>C2)9YVeO-EU#gYJ*TjfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF{1<^vyhu4+raoQDgVB=^W-Bo$J@xLg$!_x_Ew3IG?+1&Y<;UAbw$snI zihME0d@HRP2@oJafB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5;&zZ95{n@z<&k@xEE!&2?^xN+XQYA=6ny=EZ{9bCW6J*N{@^56e6zbp36 e)>cL~H!io|7Vf+6`{Q}V&Dh0Zsu*6+D}Dd~NJDx6 literal 0 HcmV?d00001 diff --git a/android/.gradle/4.6/fileHashes/fileHashes.lock b/android/.gradle/4.6/fileHashes/fileHashes.lock new file mode 100644 index 0000000000000000000000000000000000000000..26993aba32ce459f5aa16f32cfdbd5436114d404 GIT binary patch literal 17 UcmZS9+W6W}`HF)R0|dwb04>1-tpET3 literal 0 HcmV?d00001 diff --git a/android/.gradle/vcsWorkingDirs/gc.properties b/android/.gradle/vcsWorkingDirs/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/android/build.gradle b/android/build.gradle index ed07952..33be08c 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,33 +1,31 @@ apply plugin: 'com.android.library' +def safeExtGet(prop, fallback) { + rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback +} + android { - compileSdkVersion rootProject.ext.compileSdkVersion - buildToolsVersion rootProject.ext.buildToolsVersion + compileSdkVersion safeExtGet('compileSdkVersion', 28) + buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3') defaultConfig { - minSdkVersion rootProject.ext.minSdkVersion - targetSdkVersion rootProject.ext.targetSdkVersion + minSdkVersion safeExtGet('minSdkVersion', 16) + targetSdkVersion safeExtGet('targetSdkVersion', 28) versionCode 1 - versionName "1.0" - ndk { - abiFilters "armeabi-v7a", "x86" - } + versionName "0.0.7" } lintOptions { - warning 'InvalidPackage' + warning 'InvalidPackage' } } -allprojects { - repositories { - jcenter() - } +repositories { + mavenCentral() } dependencies { - implementation 'com.webimapp.sdk:webimclientsdkandroid:3.26.2' + implementation 'com.webimapp.sdk:webimclientsdkandroid:3.32.5' implementation 'com.facebook.react:react-native:+' implementation 'com.google.android.gms:play-services-wallet:16.0.0' - // todo: - implementation "com.android.support:appcompat-v7:25.0.1" + implementation "com.android.support:appcompat-v7:$support_version" } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 9a4163a..e0c4de3 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/android/src/main/java/ru/vvdev/webim/WebimModule.java b/android/src/main/java/ru/vvdev/webim/WebimModule.java index 659481d..178c9d6 100644 --- a/android/src/main/java/ru/vvdev/webim/WebimModule.java +++ b/android/src/main/java/ru/vvdev/webim/WebimModule.java @@ -35,7 +35,7 @@ public class WebimModule extends ReactContextBaseJavaModule implements MessageListener { private static final int FILE_SELECT_CODE = 0; - private static final String REACT_CLASS = "webim"; + private static final String REACT_CLASS = "RNWebim"; private static ReactApplicationContext reactContext = null; private Callback fileCbSuccess; diff --git a/index.d.ts b/index.d.ts index 78944b2..aa14e95 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,4 +1,4 @@ -declare module 'webim-react-native' { +declare module 'react-native-webim' { export type WebimEvents = 'NEW_MESSAGE' | 'REMOVE_MESSAGE' | 'EDIT_MESSAGE' | 'CLEAR_DIALOG'; export const webimEvents: { [K in WebimEvents]: string }; From 7546a08020fe597bc139f7886f23238147664de9 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Wed, 27 Nov 2019 18:25:28 +0300 Subject: [PATCH 24/32] Account -> providedAuthorizationToken --- android/.gradle/5.5/fileChanges/last-build.bin | Bin 0 -> 1 bytes android/.gradle/5.5/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes android/.gradle/5.5/gc.properties | 0 android/.gradle/vcs-1/gc.properties | 0 .../src/main/java/ru/vvdev/webim/WebimModule.java | 12 ++++++------ index.d.ts | 2 +- ios/RNWebim.m | 8 +++----- 7 files changed, 10 insertions(+), 12 deletions(-) create mode 100644 android/.gradle/5.5/fileChanges/last-build.bin create mode 100644 android/.gradle/5.5/fileHashes/fileHashes.lock create mode 100644 android/.gradle/5.5/gc.properties create mode 100644 android/.gradle/vcs-1/gc.properties diff --git a/android/.gradle/5.5/fileChanges/last-build.bin b/android/.gradle/5.5/fileChanges/last-build.bin new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/android/.gradle/5.5/fileHashes/fileHashes.lock b/android/.gradle/5.5/fileHashes/fileHashes.lock new file mode 100644 index 0000000000000000000000000000000000000000..a0ce78a65619586e1cdd205b4cc959dd0b0f953a GIT binary patch literal 17 TcmZSHUGD$GEpXyT1}FdkIK2dx literal 0 HcmV?d00001 diff --git a/android/.gradle/5.5/gc.properties b/android/.gradle/5.5/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/android/.gradle/vcs-1/gc.properties b/android/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/android/src/main/java/ru/vvdev/webim/WebimModule.java b/android/src/main/java/ru/vvdev/webim/WebimModule.java index 178c9d6..233cea9 100644 --- a/android/src/main/java/ru/vvdev/webim/WebimModule.java +++ b/android/src/main/java/ru/vvdev/webim/WebimModule.java @@ -3,8 +3,8 @@ import android.app.Activity; import android.content.Intent; import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.webkit.MimeTypeMap; import com.facebook.react.bridge.ActivityEventListener; import com.facebook.react.bridge.Arguments; @@ -32,6 +32,7 @@ import com.webimapp.android.sdk.Webim; import com.webimapp.android.sdk.WebimError; import com.webimapp.android.sdk.WebimSession; +import com.webimapp.android.sdk.ProvidedAuthorizationTokenStateListener; public class WebimModule extends ReactContextBaseJavaModule implements MessageListener { private static final int FILE_SELECT_CODE = 0; @@ -42,6 +43,7 @@ public class WebimModule extends ReactContextBaseJavaModule implements MessageLi private Callback fileCbFailure; private MessageTracker tracker; private WebimSession session; + private ProvidedAuthorizationTokenStateListener providedAuthorizationTokenStateListener; WebimModule(ReactApplicationContext context) { super(context); @@ -97,16 +99,14 @@ public Map getConstants() { return new HashMap<>(); } - private void init(String accountName, String location, String account) { + private void init(String accountName, String location, String providedAuthorizationToken) { Webim.SessionBuilder builder = Webim.newSessionBuilder() .setContext(reactContext) .setAccountName(accountName) .setLocation(location) + .setProvidedAuthorizationTokenStateListener(providedAuthorizationTokenStateListener, providedAuthorizationToken) .setPushSystem(Webim.PushSystem.FCM) .setPushToken("none"); - if (account != null) { - builder.setVisitorFieldsJson(account); - } session = builder.build(); } diff --git a/index.d.ts b/index.d.ts index aa14e95..d0f6c6d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -27,7 +27,7 @@ declare module 'react-native-webim' { export type WebimListener = (msg: T) => void; class RNWebim { - resumeSession(accountName: string, location: string, acc?: string): Promise; + resumeSession(accountName: string, location: string, providedAuthorizationToken: string): Promise; destroySession(): Promise; diff --git a/ios/RNWebim.m b/ios/RNWebim.m index 32c81dd..b063f9b 100644 --- a/ios/RNWebim.m +++ b/ios/RNWebim.m @@ -9,7 +9,7 @@ @implementation RNWebim WebimSession *webimSession; MessageStream *stream; MessageTracker *tracker; -ProvidedAuthorizationTokenStateListener *instance; +ProvidedAuthorizationTokenStateListener *providedAuthorizationTokenStateListener; RCTResponseSenderBlock attachmentResolve; RCTResponseSenderBlock attachmentReject; @@ -30,15 +30,13 @@ - (dispatch_queue_t)methodQueue { return @[@"newMessage", @"removeMessage", @"changedMessage", @"allMessagesRemoved"]; } -RCT_EXPORT_METHOD(resumeSession:(NSString*) accountName location:(NSString*) location account:(NSString*) account reject:(RCTResponseSenderBlock) reject resolve:(RCTResponseSenderBlock) resolve) { +RCT_EXPORT_METHOD(resumeSession:(NSString*) accountName location:(NSString*) location providedAuthorizationToken:(NSString*) providedAuthorizationToken reject:(RCTResponseSenderBlock) reject resolve:(RCTResponseSenderBlock) resolve) { NSError *error = nil; if (webimSession == nil) { SessionBuilder *sessionBuilder = [Webim newSessionBuilder]; sessionBuilder = [sessionBuilder setAccountName:accountName]; sessionBuilder = [sessionBuilder setLocation:location]; - if (account != nil) { - sessionBuilder = [sessionBuilder setProvidedAuthorizationTokenStateListener:instance providedAuthorizationToken:account]; - } + sessionBuilder = [sessionBuilder setProvidedAuthorizationTokenStateListener:providedAuthorizationTokenStateListener providedAuthorizationToken:providedAuthorizationToken]; webimSession = [sessionBuilder build:&error]; if (error) { reject(@[@{ @"message": [error localizedDescription]}]); From 8a11b0eac96aa676e16699ee4f14bd15f5393851 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Wed, 27 Nov 2019 18:36:28 +0300 Subject: [PATCH 25/32] Fix index --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 66866b3..55577a4 100644 --- a/index.js +++ b/index.js @@ -19,9 +19,9 @@ function processError(e) { } class RNWebim { - static resumeSession(accountName, location, account) { + static resumeSession(accountName, location, providedAuthorizationToken) { return new Promise((resolve, reject) => { - WebimNative.resumeSession(accountName, location, account, e => reject(processError(e)), res => resolve(parseNativeResponse(res))); + WebimNative.resumeSession(accountName, location, providedAuthorizationToken, e => reject(processError(e)), res => resolve(parseNativeResponse(res))); }); } From 054020a835ab56e30e19ca787d0ff48056071428 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Wed, 27 Nov 2019 18:45:44 +0300 Subject: [PATCH 26/32] Increase version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d918edf..63405d3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-webim", - "version": "0.0.7", + "version": "0.0.8", "author": "AlfClausen", "license": "MIT", "description": "RN Webim implementation", From 19627750ab84d73e4eb1c2cee91ecc886cc70793 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Mon, 2 Dec 2019 08:55:56 +0300 Subject: [PATCH 27/32] Set android providedAuthorizationToken --- android/src/main/java/ru/vvdev/webim/WebimModule.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/ru/vvdev/webim/WebimModule.java b/android/src/main/java/ru/vvdev/webim/WebimModule.java index 233cea9..dc3f1c9 100644 --- a/android/src/main/java/ru/vvdev/webim/WebimModule.java +++ b/android/src/main/java/ru/vvdev/webim/WebimModule.java @@ -104,6 +104,8 @@ private void init(String accountName, String location, String providedAuthorizat .setContext(reactContext) .setAccountName(accountName) .setLocation(location) + .setClearVisitorData(true) + .setStoreHistoryLocally(false) .setProvidedAuthorizationTokenStateListener(providedAuthorizationTokenStateListener, providedAuthorizationToken) .setPushSystem(Webim.PushSystem.FCM) .setPushToken("none"); @@ -111,9 +113,9 @@ private void init(String accountName, String location, String providedAuthorizat } @ReactMethod - public void resumeSession(String accountName, String location, String account, final Callback errorCallback, final Callback successCallback) { + public void resumeSession(String accountName, String location, String providedAuthorizationToken, final Callback errorCallback, final Callback successCallback) { if (session == null) { - init(accountName, location, account); + init(accountName, location, providedAuthorizationToken); } session.resume(); session.getStream().startChat(); @@ -127,7 +129,7 @@ public void destroySession(final Callback errorCallback, final Callback successC if (session != null) { session.getStream().closeChat(); tracker.destroy(); - session.destroy(); + session.destroyWithClearVisitorData(); session = null; } successCallback.invoke(Arguments.createMap()); From df1a2d14915b071712255686a6c7e5b3a55795a2 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Mon, 2 Dec 2019 09:54:24 +0300 Subject: [PATCH 28/32] Fix iOS destroy chat --- ios/RNWebim.m | 12 +++++++++++- ios/WebimSession.swift | 28 ++++++++++++++-------------- package.json | 2 +- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/ios/RNWebim.m b/ios/RNWebim.m index b063f9b..1ecf984 100644 --- a/ios/RNWebim.m +++ b/ios/RNWebim.m @@ -36,6 +36,8 @@ - (dispatch_queue_t)methodQueue { SessionBuilder *sessionBuilder = [Webim newSessionBuilder]; sessionBuilder = [sessionBuilder setAccountName:accountName]; sessionBuilder = [sessionBuilder setLocation:location]; + sessionBuilder = [sessionBuilder setIsVisitorDataClearingEnabled:true]; + sessionBuilder = [sessionBuilder setIsLocalHistoryStoragingEnabled:false]; sessionBuilder = [sessionBuilder setProvidedAuthorizationTokenStateListener:providedAuthorizationTokenStateListener providedAuthorizationToken:providedAuthorizationToken]; webimSession = [sessionBuilder build:&error]; if (error) { @@ -78,7 +80,15 @@ - (dispatch_queue_t)methodQueue { } stream = nil; if (webimSession) { - [webimSession pause:&err]; + [webimSession destroyWithClearVisitorData:&err]; + } + if (err) { + reject(@[@{ @"message": [err localizedDescription]}]); + return; + } + webimSession = nil; + if (tracker) { + [webimSession destroy:&err]; } if (err) { reject(@[@{ @"message": [err localizedDescription]}]); diff --git a/ios/WebimSession.swift b/ios/WebimSession.swift index 3feb422..5fcaf26 100755 --- a/ios/WebimSession.swift +++ b/ios/WebimSession.swift @@ -32,52 +32,52 @@ import WebimClientLibrary // MARK: - WebimSession @objc(WebimSession) public final class _ObjCWebimSession: NSObject { - + // MARK: - Properties private let webimSession: WebimSession - - + + // MARK: - Initializers public init(webimSession: WebimSession) { self.webimSession = webimSession } - - + + // MARK: - Methods - + @objc(resume:) public func resume() throws { try webimSession.resume() } - + @objc(pause:) public func pause() throws { try webimSession.pause() } - + @objc(destroy:) - public func destry() throws { + public func destroy() throws { try webimSession.destroy() } - + @objc(destroyWithClearVisitorData:) public func destroyWithClearVisitorData() throws { try webimSession.destroyWithClearVisitorData() } - + @objc(getStream) public func getStream() -> _ObjCMessageStream { return _ObjCMessageStream(messageStream: webimSession.getStream()) } - + @objc(changeLocation:error:) public func change(location: String) throws { try webimSession.change(location: location) } - + @objc(setDeviceToken:error:) public func set(deviceToken: String) throws { try webimSession.set(deviceToken: deviceToken) } - + } diff --git a/package.json b/package.json index 63405d3..7160400 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-webim", - "version": "0.0.8", + "version": "0.0.9", "author": "AlfClausen", "license": "MIT", "description": "RN Webim implementation", From de781981d2bd5f6572c7c55dc4bf2e04148c0379 Mon Sep 17 00:00:00 2001 From: AlfClausen Date: Mon, 2 Dec 2019 11:09:02 +0300 Subject: [PATCH 29/32] Fix android bad time issue --- android/src/main/java/ru/vvdev/webim/WebimModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/ru/vvdev/webim/WebimModule.java b/android/src/main/java/ru/vvdev/webim/WebimModule.java index dc3f1c9..ab64c8d 100644 --- a/android/src/main/java/ru/vvdev/webim/WebimModule.java +++ b/android/src/main/java/ru/vvdev/webim/WebimModule.java @@ -305,7 +305,7 @@ private static void emitDeviceEvent(String eventName, @Nullable WritableMap even private WritableMap messageToJson(Message msg) { final WritableMap map = Arguments.createMap(); map.putString("id", msg.getId().toString()); - map.putInt("time", (int) msg.getTime()); + map.putDouble("time", msg.getTime()); map.putString("type", msg.getType().toString()); map.putString("text", msg.getText()); map.putString("name", msg.getSenderName()); From dfd8fc22dabf1bc7707336b1ee06574aeca5921d Mon Sep 17 00:00:00 2001 From: ownikss Date: Mon, 13 Jul 2020 12:17:27 +0300 Subject: [PATCH 30/32] Merge Alf's fork. Reverse account info removing. Update readme --- README.md | 22 ++++++++++--------- android/build.gradle | 1 - .../main/java/ru/vvdev/webim/WebimModule.java | 17 +++++++++----- index.d.ts | 6 ++++- index.js | 11 ++++++++-- ios/RNWebim.m | 13 +++++++---- 6 files changed, 46 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 2c1b44d..2fa0c16 100644 --- a/README.md +++ b/README.md @@ -7,13 +7,18 @@ Implementation of [webim sdk](https://webim.ru/) for [react-native](https://gith ## Installation ``` -yarn add react-native-webim@git+${currentRepoUrl}.git#master -react-native link react-native-webim +yarn add react-native-webim ``` iOS -- add to PodFile ```pod 'WebimClientLibrary', :git => 'https://github.com/webim/webim-client-sdk-ios.git', :tag => '3.29.0'``` -- pod install +- add to PodFile + ``` + use_frameworks! + pod 'WebimClientLibrary', :git => 'https://github.com/webim/webim-client-sdk-ios.git', :tag => '3.29.0' +``` +- pod install + + ## Usage @@ -26,9 +31,11 @@ iOS - Init events listeners: ```js -webim.addListener(webimEvents.NEW_MESSAGE, ({ msg }) => { +сonst listener = webim.addListener(webimEvents.NEW_MESSAGE, ({ msg }) => { // do something }); +// usubscribe +listener.remove(); ``` Supported events: `NEW_MESSAGE, REMOVE_MESSAGE, EDIT_MESSAGE, CLEAR_DIALOG` @@ -124,8 +131,3 @@ acc.hash = await getHash(acc.fields); await webim.resumeSession('accountName', 'location', JSON.stringify(acc)); ``` - -## TODO: - -- screenshots for installation guide -- example diff --git a/android/build.gradle b/android/build.gradle index 33be08c..974979f 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -27,5 +27,4 @@ dependencies { implementation 'com.webimapp.sdk:webimclientsdkandroid:3.32.5' implementation 'com.facebook.react:react-native:+' implementation 'com.google.android.gms:play-services-wallet:16.0.0' - implementation "com.android.support:appcompat-v7:$support_version" } diff --git a/android/src/main/java/ru/vvdev/webim/WebimModule.java b/android/src/main/java/ru/vvdev/webim/WebimModule.java index ab64c8d..e9cdd1c 100644 --- a/android/src/main/java/ru/vvdev/webim/WebimModule.java +++ b/android/src/main/java/ru/vvdev/webim/WebimModule.java @@ -99,23 +99,28 @@ public Map getConstants() { return new HashMap<>(); } - private void init(String accountName, String location, String providedAuthorizationToken) { + private void init(String accountName, String location, String accountJson, String providedAuthorizationToken) { Webim.SessionBuilder builder = Webim.newSessionBuilder() .setContext(reactContext) .setAccountName(accountName) .setLocation(location) - .setClearVisitorData(true) - .setStoreHistoryLocally(false) - .setProvidedAuthorizationTokenStateListener(providedAuthorizationTokenStateListener, providedAuthorizationToken) .setPushSystem(Webim.PushSystem.FCM) .setPushToken("none"); + if (accountJson != null) { + builder = builder.setVisitorFieldsJson(accountJson); + } + if (providedAuthorizationToken != null) { + builder = builder.setClearVisitorData(true) + .setStoreHistoryLocally(false) + .setProvidedAuthorizationTokenStateListener(providedAuthorizationTokenStateListener, providedAuthorizationToken); + } session = builder.build(); } @ReactMethod - public void resumeSession(String accountName, String location, String providedAuthorizationToken, final Callback errorCallback, final Callback successCallback) { + public void resumeSession(String accountName, String location, String accountJson, String providedAuthorizationToken, final Callback errorCallback, final Callback successCallback) { if (session == null) { - init(accountName, location, providedAuthorizationToken); + init(accountName, location, accountJson, providedAuthorizationToken); } session.resume(); session.getStream().startChat(); diff --git a/index.d.ts b/index.d.ts index d0f6c6d..cf71fc8 100644 --- a/index.d.ts +++ b/index.d.ts @@ -26,6 +26,10 @@ declare module 'react-native-webim' { export type WebimListener = (msg: T) => void; + export interface Listener { + remove: () => void; + } + class RNWebim { resumeSession(accountName: string, location: string, providedAuthorizationToken: string): Promise; @@ -45,7 +49,7 @@ declare module 'react-native-webim' { sendFile(uri: string, name: string, mime: string, extension: string): Promise; - addListener(event: string, listener: WebimListener): void; + addListener(event: string, listener: WebimListener): Listener; removeListener(event: string, listener: WebimListener): void; diff --git a/index.js b/index.js index 55577a4..710aa64 100644 --- a/index.js +++ b/index.js @@ -18,10 +18,16 @@ function processError(e) { return new Error(e.message); } +class Listener { + constructor(remove) { + this.remove = remove; + } +} + class RNWebim { - static resumeSession(accountName, location, providedAuthorizationToken) { + static resumeSession(accountName, location, userInfo, authToken) { return new Promise((resolve, reject) => { - WebimNative.resumeSession(accountName, location, providedAuthorizationToken, e => reject(processError(e)), res => resolve(parseNativeResponse(res))); + WebimNative.resumeSession(accountName, location, userInfo, authToken, e => reject(processError(e)), res => resolve(parseNativeResponse(res))); }); } @@ -87,6 +93,7 @@ class RNWebim { static addListener(event, listener) { emitter.addListener(event, listener); + return new Listener(() => RNWebim.removeListener(event, listener)); } static removeListener(event, listener) { diff --git a/ios/RNWebim.m b/ios/RNWebim.m index 1ecf984..30a9766 100644 --- a/ios/RNWebim.m +++ b/ios/RNWebim.m @@ -30,15 +30,20 @@ - (dispatch_queue_t)methodQueue { return @[@"newMessage", @"removeMessage", @"changedMessage", @"allMessagesRemoved"]; } -RCT_EXPORT_METHOD(resumeSession:(NSString*) accountName location:(NSString*) location providedAuthorizationToken:(NSString*) providedAuthorizationToken reject:(RCTResponseSenderBlock) reject resolve:(RCTResponseSenderBlock) resolve) { +RCT_EXPORT_METHOD(resumeSession:(NSString*) accountName location:(NSString*) location account:(NSString*) account providedAuthorizationToken:(NSString*) providedAuthorizationToken reject:(RCTResponseSenderBlock) reject resolve:(RCTResponseSenderBlock) resolve) { NSError *error = nil; if (webimSession == nil) { SessionBuilder *sessionBuilder = [Webim newSessionBuilder]; sessionBuilder = [sessionBuilder setAccountName:accountName]; sessionBuilder = [sessionBuilder setLocation:location]; - sessionBuilder = [sessionBuilder setIsVisitorDataClearingEnabled:true]; - sessionBuilder = [sessionBuilder setIsLocalHistoryStoragingEnabled:false]; - sessionBuilder = [sessionBuilder setProvidedAuthorizationTokenStateListener:providedAuthorizationTokenStateListener providedAuthorizationToken:providedAuthorizationToken]; + if (account != nil) { + sessionBuilder = [sessionBuilder setVisitorFieldsJSONString:account]; + } + if (providedAuthorizationToken != nil) { + sessionBuilder = [sessionBuilder setIsVisitorDataClearingEnabled:true]; + sessionBuilder = [sessionBuilder setIsLocalHistoryStoragingEnabled:false]; + sessionBuilder = [sessionBuilder setProvidedAuthorizationTokenStateListener:providedAuthorizationTokenStateListener providedAuthorizationToken:providedAuthorizationToken]; + } webimSession = [sessionBuilder build:&error]; if (error) { reject(@[@{ @"message": [error localizedDescription]}]); From 99d75fa25b21ab71eb2cc684d39b5b541f299a9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B8=D1=80=D0=BE=D1=82=D0=BA=D0=B8=D0=BD=20=D0=9D?= =?UTF-8?q?=D0=B8=D0=BA=D0=B8=D1=82=D0=B0?= Date: Wed, 22 Jul 2020 14:10:01 +0300 Subject: [PATCH 31/32] improve session builder. tokenUpdated and error events. Fix clear data on destroy session. Rewrite with ts and fix interfaces --- README.md | 89 +++++++--- RNWebim.podspec | 4 +- .../main/java/ru/vvdev/webim/WebimModule.java | 87 ++++++++-- index.d.ts | 62 ------- index.js | 108 ------------ ios/RNWebim.h | 8 +- ios/RNWebim.m | 66 +++++-- ios/RNWebim.xcodeproj/project.pbxproj | 125 ++++++++------ .../UserInterfaceState.xcuserstate | Bin 0 -> 18808 bytes .../xcschemes/xcschememanagement.plist | 2 +- node_modules/.bin/react-native | 1 + package.json | 18 +- src/index.ts | 7 + src/types.ts | 54 ++++++ src/utils.ts | 17 ++ src/webim.ts | 163 ++++++++++++++++++ tsconfig.json | 18 ++ 17 files changed, 543 insertions(+), 286 deletions(-) delete mode 100644 index.d.ts delete mode 100644 index.js create mode 100644 ios/RNWebim.xcodeproj/project.xcworkspace/xcuserdata/nikitasirotkin.xcuserdatad/UserInterfaceState.xcuserstate create mode 120000 node_modules/.bin/react-native create mode 100644 src/index.ts create mode 100644 src/types.ts create mode 100644 src/utils.ts create mode 100644 src/webim.ts create mode 100644 tsconfig.json diff --git a/README.md b/README.md index 2fa0c16..810399c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# react-native-webim +# webim-react-native Implementation of [webim sdk](https://webim.ru/) for [react-native](https://github.com/facebook/react-native) @@ -18,43 +18,89 @@ iOS ``` - pod install - +**Note:** Flipper doesn't work with use_frameworks flag ## Usage **Important:** All methods are promise based and can throw exceptions -- Init chat: - ```js - webim.resumeSession("accountName", "location") +### Init chat + + ```ts +import webim from 'webim-react-native'; + +webim.resumeSession(builderParams) +``` + +```ts +type SessionBuilderParams = { + accountName: string; + location: string; + accountJSON?: string; + providedAuthorizationToken?: string; + appVersion?: string; + clearVisitorData?: boolean; + storeHistoryLocally?: boolean; + title?: string; + pushToken?: string; +}; ``` +- accountName (required) - name of your account in webim system +- location (required) - name of location. For example "mobile" +- accountJSON - encrypted json with user data. See **Start chat with user data** +- clearVisitorData - clear visitor data before start chat +- storeHistoryLocally - cache messages in local store +- title - title for chat in webim web panel +- providedAuthorizationToken - user token. Session will not start with wrong token. Read webim documentation +- pushToken +- appVersion + + +### Init events listeners -- Init events listeners: ```js -сonst listener = webim.addListener(webimEvents.NEW_MESSAGE, ({ msg }) => { - // do something +import webim, { WebimEvents} from 'webim-react-native'; + +const listener = webim.addNewMessageListener(({ msg }) => { + // do something }); // usubscribe listener.remove(); + +// or +const listener2 = webim.addListener(WebimEvents.NEW_MESSAGE, ({ msg }) => { + // do something +}); ``` -Supported events: `NEW_MESSAGE, REMOVE_MESSAGE, EDIT_MESSAGE, CLEAR_DIALOG` +Supported events (`WebimEvents`): +- WebimEvents.NEW_MESSAGE; +- WebimEvents.REMOVE_MESSAGE; +- WebimEvents.EDIT_MESSAGE; +- WebimEvents.CLEAR_DIALOG; +- WebimEvents.TOKEN_UPDATED; +- WebimEvents.ERROR; + +### Get messages -- Get messages: ```js -const { messages } = await webim.getLastMessages(100); +const { messages } = await webim.getLastMessages(limit); // or -const { messages } = await webim.getNextMessages(100); +const { messages } = await webim.getNextMessages(limit); // or const { messages } = await webim.getAllMessages(); ``` Note: method `getAllMessages` works strange on iOS, and sometimes returns empty array. We recommend to use `getLastMessages` instead -- Send text message: +### Send text message + ``` webim.send(message); ``` -- Use build in method for file attaching: +### Attach files + +#### Use build in method for file attaching: + ```js try { await webim.tryAttachFile(); @@ -68,7 +114,8 @@ try { } ``` -- or attach files by yourself: +#### or attach files by yourself + ```js try { webim.sendFile(uri, name, mime, extension) @@ -77,19 +124,20 @@ try { } ``` -- rate current operator: +### Rate current operator ```js webim.rateOperator() ``` -- destroy session: +### Destroy session ```js -webim.destroySession(); +webim.destroySession(clearData); ``` -See `index.d.ts` for getting types information +- clearData (optional) boolean - If true wil ## Start chat with user data + See [webim documentation](https://webim.ru/kb/dev/identification/8265-id-2-0/) for client identification. Example: @@ -97,9 +145,10 @@ Example: - install [react-native-crypto](https://github.com/tradle/react-native-crypto) with all dependencies and run `rn-nodeify --hack --install` - run `rn-nodeify --hack --install` after each `npm install` (add in postinstall script) -```js +```ts import './shim'; // set your path to shim.js import crypto from 'crypto'; + const getHmac_sha256 = (str: string, privateKey: string) => { const hmac = crypto.createHmac('sha256', privateKey); const promise = new Promise((resolve: (hash: string) => void) => hmac.on('readable', () => { diff --git a/RNWebim.podspec b/RNWebim.podspec index cdc96de..9f2e098 100644 --- a/RNWebim.podspec +++ b/RNWebim.podspec @@ -8,12 +8,12 @@ Pod::Spec.new do |s| s.summary = package['description'] s.license = package['license'] s.author = package['author'] - s.source = { :git => "https://github.com/AlfClausen/react-native-webim.git", :tag => "v#{s.version}" } + s.source = { :git => "https://github.com/volga-volga/react-native-webim.git", :tag => "v#{s.version}" } s.homepage = package['repository']['url'] s.requires_arc = true - s.platform = :ios, '9.0' + s.platform = :ios, '10.0' s.preserve_paths = 'LICENSE', 'README.md', 'package.json', 'index.js' s.source_files = "ios/*.{h,m,swift}" diff --git a/android/src/main/java/ru/vvdev/webim/WebimModule.java b/android/src/main/java/ru/vvdev/webim/WebimModule.java index e9cdd1c..8276c2a 100644 --- a/android/src/main/java/ru/vvdev/webim/WebimModule.java +++ b/android/src/main/java/ru/vvdev/webim/WebimModule.java @@ -13,6 +13,7 @@ import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableMap; import com.facebook.react.modules.core.DeviceEventManagerModule; @@ -24,17 +25,20 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import com.webimapp.android.sdk.FatalErrorHandler; import com.webimapp.android.sdk.Message; import com.webimapp.android.sdk.MessageListener; import com.webimapp.android.sdk.MessageStream; import com.webimapp.android.sdk.MessageTracker; +import com.webimapp.android.sdk.NotFatalErrorHandler; import com.webimapp.android.sdk.Operator; import com.webimapp.android.sdk.Webim; import com.webimapp.android.sdk.WebimError; import com.webimapp.android.sdk.WebimSession; import com.webimapp.android.sdk.ProvidedAuthorizationTokenStateListener; -public class WebimModule extends ReactContextBaseJavaModule implements MessageListener { +@SuppressWarnings("unused") +public class WebimModule extends ReactContextBaseJavaModule implements MessageListener, ProvidedAuthorizationTokenStateListener, FatalErrorHandler, NotFatalErrorHandler { private static final int FILE_SELECT_CODE = 0; private static final String REACT_CLASS = "RNWebim"; private static ReactApplicationContext reactContext = null; @@ -43,7 +47,6 @@ public class WebimModule extends ReactContextBaseJavaModule implements MessageLi private Callback fileCbFailure; private MessageTracker tracker; private WebimSession session; - private ProvidedAuthorizationTokenStateListener providedAuthorizationTokenStateListener; WebimModule(ReactApplicationContext context) { super(context); @@ -65,7 +68,12 @@ public void onActivityResult(Activity activity, int requestCode, int resultCode, ? null : uri.getLastPathSegment() + "." + extension; if (fileCbSuccess != null) { - fileCbSuccess.invoke(uri.toString(), name, mime, extension); + WritableMap _data = Arguments.createMap(); + _data.putString("uri", uri.toString()); + _data.putString("name", name); + _data.putString("mime", mime); + _data.putString("extension", extension); + fileCbSuccess.invoke(_data); } } else { fileCbFailure.invoke(getSimpleMap("message", "unknown")); @@ -99,28 +107,58 @@ public Map getConstants() { return new HashMap<>(); } - private void init(String accountName, String location, String accountJson, String providedAuthorizationToken) { + private void init(String accountName, String location, @Nullable String accountJSON, @Nullable String providedAuthorizationToken, @Nullable String appVersion, @Nullable Boolean clearVisitorData, @Nullable Boolean storeHistoryLocally, @Nullable String title, @Nullable String pushToken) { Webim.SessionBuilder builder = Webim.newSessionBuilder() .setContext(reactContext) .setAccountName(accountName) .setLocation(location) - .setPushSystem(Webim.PushSystem.FCM) - .setPushToken("none"); - if (accountJson != null) { - builder = builder.setVisitorFieldsJson(accountJson); + .setErrorHandler(this) + .setNotFatalErrorHandler(this) + .setPushSystem(Webim.PushSystem.FCM); + if (pushToken != null) { + builder.setPushToken(pushToken); + } + if (accountJSON != null) { + builder.setVisitorFieldsJson(accountJSON); + } + if (appVersion != null) { + builder.setAppVersion(appVersion); + } + if (clearVisitorData != null) { + builder.setClearVisitorData(clearVisitorData); + } + if (storeHistoryLocally != null) { + builder.setStoreHistoryLocally(storeHistoryLocally); + } + if (title != null) { + builder.setTitle(title); } if (providedAuthorizationToken != null) { - builder = builder.setClearVisitorData(true) - .setStoreHistoryLocally(false) - .setProvidedAuthorizationTokenStateListener(providedAuthorizationTokenStateListener, providedAuthorizationToken); + builder.setProvidedAuthorizationTokenStateListener(this, providedAuthorizationToken); } session = builder.build(); } @ReactMethod - public void resumeSession(String accountName, String location, String accountJson, String providedAuthorizationToken, final Callback errorCallback, final Callback successCallback) { + public void resumeSession(ReadableMap builderData, final Callback errorCallback, final Callback successCallback) { + String accountName = builderData.getString("accountName"); + String location = builderData.getString("location"); + + // optional + String accountJSON = builderData.hasKey("accountJSON") ? builderData.getString("accountJSON") : null; + String providedAuthorizationToken = builderData.hasKey("providedAuthorizationToken") ? builderData.getString("providedAuthorizationToken") : null; + String appVersion = builderData.hasKey("appVersion") ? builderData.getString("appVersion") : null; + Boolean clearVisitorData = builderData.hasKey("clearVisitorData") ? builderData.getBoolean("clearVisitorData") : null; + Boolean storeHistoryLocally = builderData.hasKey("storeHistoryLocally") ? builderData.getBoolean("storeHistoryLocally") : null; + String title = builderData.hasKey("title") ? builderData.getString("title") : null; + String pushToken = builderData.hasKey("pushToken") ? builderData.getString("pushToken") : null; + + if (session == null) { + init(accountName, location, accountJSON, providedAuthorizationToken, appVersion, clearVisitorData, storeHistoryLocally, title, pushToken); + } + if (session == null) { - init(accountName, location, accountJson, providedAuthorizationToken); + errorCallback.invoke(getSimpleMap("message", "resume null session")); } session.resume(); session.getStream().startChat(); @@ -130,11 +168,15 @@ public void resumeSession(String accountName, String location, String accountJso } @ReactMethod - public void destroySession(final Callback errorCallback, final Callback successCallback) { + public void destroySession(Boolean clearData, final Callback errorCallback, final Callback successCallback) { if (session != null) { session.getStream().closeChat(); tracker.destroy(); - session.destroyWithClearVisitorData(); + if (clearData) { + session.destroyWithClearVisitorData(); + } else { + session.destroy(); + } session = null; } successCallback.invoke(Arguments.createMap()); @@ -357,4 +399,19 @@ private WritableMap getSimpleMap(String key, String value) { map.putString(key, value); return map; } + + @Override + public void updateProvidedAuthorizationToken(@NonNull String providedAuthorizationToken) { + emitDeviceEvent("tokenUpdated", getSimpleMap("token", providedAuthorizationToken)); + } + + @Override + public void onError(@NonNull WebimError error) { + emitDeviceEvent("error", getSimpleMap("message", error.getErrorString())); + } + + @Override + public void onNotFatalError(@NonNull WebimError error) { + emitDeviceEvent("error", getSimpleMap("message", error.getErrorString())); + } } diff --git a/index.d.ts b/index.d.ts deleted file mode 100644 index cf71fc8..0000000 --- a/index.d.ts +++ /dev/null @@ -1,62 +0,0 @@ -declare module 'react-native-webim' { - export type WebimEvents = 'NEW_MESSAGE' | 'REMOVE_MESSAGE' | 'EDIT_MESSAGE' | 'CLEAR_DIALOG'; - - export const webimEvents: { [K in WebimEvents]: string }; - - export interface Attachment { - contentType: string; - info: string; - name: string; - size: number; - url: string; - } - - export interface Message { - id: string; - avatar?: string; - time: number; - type: 'OPERATOR' | 'VISITOR' | 'INFO'; - text: string; - name: string; - status: 'SENT'; - read: boolean; - canEdit: boolean; - attachment?: Attachment; - } - - export type WebimListener = (msg: T) => void; - - export interface Listener { - remove: () => void; - } - - class RNWebim { - resumeSession(accountName: string, location: string, providedAuthorizationToken: string): Promise; - - destroySession(): Promise; - - getLastMessages(limit: number): Promise<{ messages: Message[] }>; - - getNextMessages(limit: number): Promise<{ messages: Message[] }>; - - getAllMessages(): Promise<{ messages: Message[] }>; - - send(message: string): Promise<{ id: string }>; - - rateOperator(rate: number): Promise; - - tryAttachFile(): Promise; - - sendFile(uri: string, name: string, mime: string, extension: string): Promise; - - addListener(event: string, listener: WebimListener): Listener; - - removeListener(event: string, listener: WebimListener): void; - - removeAllListeners(event: string): void; - } - - const Webim: RNWebim; - - export default Webim; -} diff --git a/index.js b/index.js deleted file mode 100644 index 710aa64..0000000 --- a/index.js +++ /dev/null @@ -1,108 +0,0 @@ -import { NativeModules, NativeEventEmitter, Platform } from 'react-native'; - -const { RNWebim: WebimNative } = NativeModules; -const emitter = new NativeEventEmitter(NativeModules.RNWebim); - -export const webimEvents = { - NEW_MESSAGE: 'newMessage', - REMOVE_MESSAGE: 'removeMessage', - EDIT_MESSAGE: 'changedMessage', - CLEAR_DIALOG: 'allMessagesRemoved', -}; - -function parseNativeResponse(response) { - return response || null; -} - -function processError(e) { - return new Error(e.message); -} - -class Listener { - constructor(remove) { - this.remove = remove; - } -} - -class RNWebim { - static resumeSession(accountName, location, userInfo, authToken) { - return new Promise((resolve, reject) => { - WebimNative.resumeSession(accountName, location, userInfo, authToken, e => reject(processError(e)), res => resolve(parseNativeResponse(res))); - }); - } - - static destroySession() { - return new Promise((resolve, reject) => { - WebimNative.destroySession(e => reject(processError(e)), res => resolve(parseNativeResponse(res))); - }); - } - - static getLastMessages(limit) { - return new Promise((resolve, reject) => { - WebimNative.getLastMessages(limit, e => reject(processError(e)), messages => resolve(parseNativeResponse(messages))); - }); - } - - static getNextMessages(limit) { - return new Promise((resolve, reject) => { - WebimNative.getNextMessages(limit, e => reject(processError(e)), messages => resolve(parseNativeResponse(messages))); - }); - } - - static getAllMessages() { - return new Promise((resolve, reject) => { - WebimNative.getAllMessages(e => reject(processError(e)), messages => resolve(parseNativeResponse(messages))); - }); - } - - static send(message) { - return new Promise((resolve, reject) => WebimNative.send(message, e => reject(processError(e)), id => resolve(id))); - } - - static rateOperator(rate) { - return new Promise((resolve, reject) => { - WebimNative.rateOperator(rate, e => reject(processError(e)), () => resolve()); - }); - } - - static tryAttachFile() { - return new Promise((resolve, reject) => { - WebimNative.tryAttachFile(e => reject(processError(e)), async (...args) => { - let uri; - let name; - let mime; - let extension; - if (Platform.OS === 'ios') { - [{ uri, name, mime, extension }] = args; - } else { - [uri, name, mime, extension] = args; - } - try { - await RNWebim.sendFile(uri, name, mime, extension); - resolve(); - } catch (e) { - reject(processError(e)); - } - }); - }); - } - - static sendFile(uri, name, mime, extension) { - return new Promise((resolve, reject) => WebimNative.sendFile(uri, name, mime, extension, reject, resolve)); - } - - static addListener(event, listener) { - emitter.addListener(event, listener); - return new Listener(() => RNWebim.removeListener(event, listener)); - } - - static removeListener(event, listener) { - emitter.removeListener(event, listener); - } - - static removeAllListeners(event) { - emitter.removeAllListeners(event); - } -} - -export default RNWebim; diff --git a/ios/RNWebim.h b/ios/RNWebim.h index 5482013..86a8431 100644 --- a/ios/RNWebim.h +++ b/ios/RNWebim.h @@ -1,11 +1,11 @@ +#ifndef RNWebim_h +#define RNWebim_h -#if __has_include("React/RCTBridgeModule.h") -#import "React/RCTBridgeModule.h" -#else #import -#endif #import @interface RNWebim : RCTEventEmitter @end + +#endif /* RNWebim_h */ diff --git a/ios/RNWebim.m b/ios/RNWebim.m index 30a9766..3aa5c11 100644 --- a/ios/RNWebim.m +++ b/ios/RNWebim.m @@ -2,14 +2,12 @@ #import "RNWebim.h" #import #import // If use see compile error at this line, to fix repeat compile second time -@class ProvidedAuthorizationTokenStateListener; @implementation RNWebim WebimSession *webimSession; MessageStream *stream; MessageTracker *tracker; -ProvidedAuthorizationTokenStateListener *providedAuthorizationTokenStateListener; RCTResponseSenderBlock attachmentResolve; RCTResponseSenderBlock attachmentReject; @@ -27,23 +25,51 @@ - (dispatch_queue_t)methodQueue { RCT_EXPORT_MODULE() - (NSArray *)supportedEvents { - return @[@"newMessage", @"removeMessage", @"changedMessage", @"allMessagesRemoved"]; + return @[@"newMessage", @"removeMessage", @"changedMessage", @"allMessagesRemoved", @"tokenUpdated", @"error"]; } -RCT_EXPORT_METHOD(resumeSession:(NSString*) accountName location:(NSString*) location account:(NSString*) account providedAuthorizationToken:(NSString*) providedAuthorizationToken reject:(RCTResponseSenderBlock) reject resolve:(RCTResponseSenderBlock) resolve) { +RCT_EXPORT_METHOD(resumeSession:(NSDictionary*) builderData reject:(RCTResponseSenderBlock) reject resolve:(RCTResponseSenderBlock) resolve) { NSError *error = nil; if (webimSession == nil) { SessionBuilder *sessionBuilder = [Webim newSessionBuilder]; + NSString* accountName = [builderData valueForKey:@"accountName"]; + NSString* location = [builderData valueForKey:@"location"]; + + // optional + NSString* accountJSON = [builderData valueForKey:@"accountJSON"]; + NSString* providedAuthorizationToken = [builderData valueForKey: @"providedAuthorizationToken"]; + NSString* appVersion = [builderData valueForKey:@"appVersion"]; + NSNumber* clearVisitorData = [builderData valueForKey:@"clearVisitorData"]; + NSNumber* storeHistoryLocally = [builderData valueForKey:@"storeHistoryLocally"]; + NSString* title = [builderData valueForKey:@"title"]; + NSString* pushToken = [builderData valueForKey:@"pushToken"]; sessionBuilder = [sessionBuilder setAccountName:accountName]; sessionBuilder = [sessionBuilder setLocation:location]; - if (account != nil) { - sessionBuilder = [sessionBuilder setVisitorFieldsJSONString:account]; + sessionBuilder = [sessionBuilder setFatalErrorHandler:(id)self]; + + if (accountJSON != nil) { + sessionBuilder = [sessionBuilder setVisitorFieldsJSONString:accountJSON]; } if (providedAuthorizationToken != nil) { - sessionBuilder = [sessionBuilder setIsVisitorDataClearingEnabled:true]; - sessionBuilder = [sessionBuilder setIsLocalHistoryStoragingEnabled:false]; - sessionBuilder = [sessionBuilder setProvidedAuthorizationTokenStateListener:providedAuthorizationTokenStateListener providedAuthorizationToken:providedAuthorizationToken]; + sessionBuilder = [sessionBuilder setProvidedAuthorizationTokenStateListener:(id)self providedAuthorizationToken:providedAuthorizationToken]; + } + if (appVersion != nil) { + sessionBuilder = [sessionBuilder setAppVersion:appVersion]; + } + if (clearVisitorData != nil) { + sessionBuilder = [sessionBuilder setIsVisitorDataClearingEnabled:[clearVisitorData boolValue]]; + } + if (storeHistoryLocally != nil) { + sessionBuilder = [sessionBuilder setIsLocalHistoryStoragingEnabled:[storeHistoryLocally boolValue]]; + } + if (title != nil) { + sessionBuilder = [sessionBuilder setPageTitle:title]; + } + if (pushToken != nil) { + sessionBuilder = [sessionBuilder setDeviceToken:pushToken]; } + sessionBuilder = [sessionBuilder setIsVisitorDataClearingEnabled:true]; + sessionBuilder = [sessionBuilder setIsLocalHistoryStoragingEnabled:false]; webimSession = [sessionBuilder build:&error]; if (error) { reject(@[@{ @"message": [error localizedDescription]}]); @@ -61,7 +87,7 @@ - (dispatch_queue_t)methodQueue { reject(@[@{ @"message": [error localizedDescription]}]); return; } - tracker = [stream newMessageTrackerWithMessageListener:self error:&error]; + tracker = [stream newMessageTrackerWithMessageListener:(id)self error:&error]; if (error) { reject(@[@{ @"message": [error localizedDescription]}]); return; @@ -74,7 +100,7 @@ - (dispatch_queue_t)methodQueue { resolve(@[@{}]); } -RCT_EXPORT_METHOD(destroySession:(RCTResponseSenderBlock) reject resolve:(RCTResponseSenderBlock) resolve) { +RCT_EXPORT_METHOD(destroySession:(NSNumber*) clearUserData reject:(RCTResponseSenderBlock) reject resolve:(RCTResponseSenderBlock) resolve) { NSError *err = nil; if (stream) { [stream closeChat:&err]; @@ -85,7 +111,11 @@ - (dispatch_queue_t)methodQueue { } stream = nil; if (webimSession) { - [webimSession destroyWithClearVisitorData:&err]; + if ([clearUserData boolValue]) { + [webimSession destroyWithClearVisitorData:&err]; + } else { + [webimSession destroy:&err]; + } } if (err) { reject(@[@{ @"message": [err localizedDescription]}]); @@ -141,7 +171,7 @@ - (dispatch_queue_t)methodQueue { NSError *err = nil; Operator* operator = [stream getCurrentOperator]; [stream rateOperatorWithID: [operator getID] byRating:[rating intValue] - completionHandler:self error:&err]; + completionHandler:(id)self error:&err]; if (err) { reject(@[@{ @"message": [err localizedDescription] }]); } else { @@ -184,7 +214,7 @@ - (dispatch_queue_t)methodQueue { NSString *_id = [stream sendFile:imageData filename:name mimeType:mime - completionHandler:self + completionHandler:(id) self error:&err]; if (err) { reject(@[@{ @"message": err.localizedDescription }]); @@ -380,4 +410,12 @@ -(void)clearRateResolvers { rateOperatorResolve = nil; } +- (void)updateProvidedAuthorizationToken:(NSString * _Nonnull)providedAuthorizationToken { + [self sendEventWithName:@"tokenUpdated" body:@{@"token": providedAuthorizationToken}]; +} + +- (void)onError:(WebimError * _Nonnull)error { + [self sendEventWithName:@"error" body:@{@"message": @"err"}]; +} + @end diff --git a/ios/RNWebim.xcodeproj/project.pbxproj b/ios/RNWebim.xcodeproj/project.pbxproj index b178bac..2386aee 100644 --- a/ios/RNWebim.xcodeproj/project.pbxproj +++ b/ios/RNWebim.xcodeproj/project.pbxproj @@ -8,19 +8,21 @@ /* Begin PBXBuildFile section */ B3E7B58A1CC2AC0600A0062D /* RNWebim.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* RNWebim.m */; }; - D65659C522A156A200B76477 /* Department.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65659B822A156A000B76477 /* Department.swift */; }; - D65659C622A156A200B76477 /* WebimLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65659B922A156A000B76477 /* WebimLogger.swift */; }; - D65659C722A156A200B76477 /* WebimError.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65659BA22A156A000B76477 /* WebimError.swift */; }; - D65659C822A156A200B76477 /* Operator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65659BB22A156A100B76477 /* Operator.swift */; }; - D65659C922A156A200B76477 /* Webim.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65659BC22A156A100B76477 /* Webim.swift */; }; - D65659CA22A156A200B76477 /* WebimSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65659BD22A156A100B76477 /* WebimSession.swift */; }; - D65659CB22A156A200B76477 /* MessageTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65659BE22A156A100B76477 /* MessageTracker.swift */; }; - D65659CC22A156A200B76477 /* WebimRemoteNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65659BF22A156A100B76477 /* WebimRemoteNotification.swift */; }; - D65659CD22A156A200B76477 /* FatalErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65659C022A156A100B76477 /* FatalErrorHandler.swift */; }; - D65659CE22A156A200B76477 /* MessageListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65659C122A156A100B76477 /* MessageListener.swift */; }; - D65659CF22A156A200B76477 /* ProvidedAuthorizationTokenStateListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65659C222A156A100B76477 /* ProvidedAuthorizationTokenStateListener.swift */; }; - D65659D022A156A200B76477 /* MessageStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65659C322A156A200B76477 /* MessageStream.swift */; }; - D65659D122A156A200B76477 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65659C422A156A200B76477 /* Message.swift */; }; + D69EFDD624C836CC00728191 /* ProvidedAuthorizationTokenStateListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69EFDC924C836CC00728191 /* ProvidedAuthorizationTokenStateListener.swift */; }; + D69EFDD724C836CC00728191 /* Operator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69EFDCA24C836CC00728191 /* Operator.swift */; }; + D69EFDD824C836CC00728191 /* Department.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69EFDCB24C836CC00728191 /* Department.swift */; }; + D69EFDD924C836CC00728191 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69EFDCC24C836CC00728191 /* Message.swift */; }; + D69EFDDA24C836CC00728191 /* WebimSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69EFDCD24C836CC00728191 /* WebimSession.swift */; }; + D69EFDDB24C836CC00728191 /* WebimError.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69EFDCE24C836CC00728191 /* WebimError.swift */; }; + D69EFDDC24C836CC00728191 /* MessageTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69EFDCF24C836CC00728191 /* MessageTracker.swift */; }; + D69EFDDD24C836CC00728191 /* WebimLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69EFDD024C836CC00728191 /* WebimLogger.swift */; }; + D69EFDDE24C836CC00728191 /* WebimRemoteNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69EFDD124C836CC00728191 /* WebimRemoteNotification.swift */; }; + D69EFDDF24C836CC00728191 /* FatalErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69EFDD224C836CC00728191 /* FatalErrorHandler.swift */; }; + D69EFDE024C836CC00728191 /* MessageListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69EFDD324C836CC00728191 /* MessageListener.swift */; }; + D69EFDE124C836CC00728191 /* Webim.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69EFDD424C836CC00728191 /* Webim.swift */; }; + D69EFDE224C836CC00728191 /* MessageStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69EFDD524C836CC00728191 /* MessageStream.swift */; }; + D69EFDE424C841AB00728191 /* RNWebim.h in Headers */ = {isa = PBXBuildFile; fileRef = B3E7B5881CC2AC0600A0062D /* RNWebim.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D69EFDE524C841B000728191 /* RNWebim-Bridging-Header.h in Headers */ = {isa = PBXBuildFile; fileRef = D69EFDC824C836CB00728191 /* RNWebim-Bridging-Header.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -39,21 +41,21 @@ 134814201AA4EA6300B7C361 /* libRNWebim.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNWebim.a; sourceTree = BUILT_PRODUCTS_DIR; }; B3E7B5881CC2AC0600A0062D /* RNWebim.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNWebim.h; sourceTree = ""; }; B3E7B5891CC2AC0600A0062D /* RNWebim.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNWebim.m; sourceTree = ""; }; - D65659AF22A1569F00B76477 /* RNWebim-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RNWebim-Bridging-Header.h"; sourceTree = ""; }; - D65659B822A156A000B76477 /* Department.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Department.swift; path = swift_bridging/Department.swift; sourceTree = ""; }; - D65659B922A156A000B76477 /* WebimLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebimLogger.swift; path = swift_bridging/WebimLogger.swift; sourceTree = ""; }; - D65659BA22A156A000B76477 /* WebimError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebimError.swift; path = swift_bridging/WebimError.swift; sourceTree = ""; }; - D65659BB22A156A100B76477 /* Operator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Operator.swift; path = swift_bridging/Operator.swift; sourceTree = ""; }; - D65659BC22A156A100B76477 /* Webim.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Webim.swift; path = swift_bridging/Webim.swift; sourceTree = ""; }; - D65659BD22A156A100B76477 /* WebimSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebimSession.swift; path = swift_bridging/WebimSession.swift; sourceTree = ""; }; - D65659BE22A156A100B76477 /* MessageTracker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MessageTracker.swift; path = swift_bridging/MessageTracker.swift; sourceTree = ""; }; - D65659BF22A156A100B76477 /* WebimRemoteNotification.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebimRemoteNotification.swift; path = swift_bridging/WebimRemoteNotification.swift; sourceTree = ""; }; - D65659C022A156A100B76477 /* FatalErrorHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FatalErrorHandler.swift; path = swift_bridging/FatalErrorHandler.swift; sourceTree = ""; }; - D65659C122A156A100B76477 /* MessageListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MessageListener.swift; path = swift_bridging/MessageListener.swift; sourceTree = ""; }; - D65659C222A156A100B76477 /* ProvidedAuthorizationTokenStateListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProvidedAuthorizationTokenStateListener.swift; path = swift_bridging/ProvidedAuthorizationTokenStateListener.swift; sourceTree = ""; }; - D65659C322A156A200B76477 /* MessageStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MessageStream.swift; path = swift_bridging/MessageStream.swift; sourceTree = ""; }; - D65659C422A156A200B76477 /* Message.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Message.swift; path = swift_bridging/Message.swift; sourceTree = ""; }; D65659D222A158C400B76477 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + D69EFDC824C836CB00728191 /* RNWebim-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RNWebim-Bridging-Header.h"; sourceTree = ""; }; + D69EFDC924C836CC00728191 /* ProvidedAuthorizationTokenStateListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProvidedAuthorizationTokenStateListener.swift; sourceTree = ""; }; + D69EFDCA24C836CC00728191 /* Operator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operator.swift; sourceTree = ""; }; + D69EFDCB24C836CC00728191 /* Department.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Department.swift; sourceTree = ""; }; + D69EFDCC24C836CC00728191 /* Message.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = ""; }; + D69EFDCD24C836CC00728191 /* WebimSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebimSession.swift; sourceTree = ""; }; + D69EFDCE24C836CC00728191 /* WebimError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebimError.swift; sourceTree = ""; }; + D69EFDCF24C836CC00728191 /* MessageTracker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageTracker.swift; sourceTree = ""; }; + D69EFDD024C836CC00728191 /* WebimLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebimLogger.swift; sourceTree = ""; }; + D69EFDD124C836CC00728191 /* WebimRemoteNotification.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebimRemoteNotification.swift; sourceTree = ""; }; + D69EFDD224C836CC00728191 /* FatalErrorHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FatalErrorHandler.swift; sourceTree = ""; }; + D69EFDD324C836CC00728191 /* MessageListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageListener.swift; sourceTree = ""; }; + D69EFDD424C836CC00728191 /* Webim.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Webim.swift; sourceTree = ""; }; + D69EFDD524C836CC00728191 /* MessageStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageStream.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -80,22 +82,22 @@ children = ( B3E7B5881CC2AC0600A0062D /* RNWebim.h */, B3E7B5891CC2AC0600A0062D /* RNWebim.m */, - D65659B822A156A000B76477 /* Department.swift */, - D65659C022A156A100B76477 /* FatalErrorHandler.swift */, - D65659C422A156A200B76477 /* Message.swift */, - D65659C122A156A100B76477 /* MessageListener.swift */, - D65659C322A156A200B76477 /* MessageStream.swift */, - D65659BE22A156A100B76477 /* MessageTracker.swift */, - D65659BB22A156A100B76477 /* Operator.swift */, - D65659C222A156A100B76477 /* ProvidedAuthorizationTokenStateListener.swift */, - D65659BC22A156A100B76477 /* Webim.swift */, - D65659BA22A156A000B76477 /* WebimError.swift */, - D65659B922A156A000B76477 /* WebimLogger.swift */, - D65659BF22A156A100B76477 /* WebimRemoteNotification.swift */, - D65659BD22A156A100B76477 /* WebimSession.swift */, + D69EFDCB24C836CC00728191 /* Department.swift */, + D69EFDD224C836CC00728191 /* FatalErrorHandler.swift */, + D69EFDCC24C836CC00728191 /* Message.swift */, + D69EFDD324C836CC00728191 /* MessageListener.swift */, + D69EFDD524C836CC00728191 /* MessageStream.swift */, + D69EFDCF24C836CC00728191 /* MessageTracker.swift */, + D69EFDCA24C836CC00728191 /* Operator.swift */, + D69EFDC924C836CC00728191 /* ProvidedAuthorizationTokenStateListener.swift */, + D69EFDD424C836CC00728191 /* Webim.swift */, + D69EFDCE24C836CC00728191 /* WebimError.swift */, + D69EFDD024C836CC00728191 /* WebimLogger.swift */, + D69EFDD124C836CC00728191 /* WebimRemoteNotification.swift */, + D69EFDCD24C836CC00728191 /* WebimSession.swift */, 134814211AA4EA7D00B7C361 /* Products */, D6A45F7F22A1392900B5BB27 /* Frameworks */, - D65659AF22A1569F00B76477 /* RNWebim-Bridging-Header.h */, + D69EFDC824C836CB00728191 /* RNWebim-Bridging-Header.h */, ); sourceTree = ""; }; @@ -109,11 +111,24 @@ }; /* End PBXGroup section */ +/* Begin PBXHeadersBuildPhase section */ + D69EFDE324C841A300728191 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + D69EFDE424C841AB00728191 /* RNWebim.h in Headers */, + D69EFDE524C841B000728191 /* RNWebim-Bridging-Header.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + /* Begin PBXNativeTarget section */ 58B511DA1A9E6C8500147676 /* RNWebim */ = { isa = PBXNativeTarget; buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNWebim" */; buildPhases = ( + D69EFDE324C841A300728191 /* Headers */, 58B511D71A9E6C8500147676 /* Sources */, 58B511D81A9E6C8500147676 /* Frameworks */, 58B511D91A9E6C8500147676 /* CopyFiles */, @@ -138,7 +153,7 @@ TargetAttributes = { 58B511DA1A9E6C8500147676 = { CreatedOnToolsVersion = 6.1.1; - LastSwiftMigration = 1020; + LastSwiftMigration = 1150; }; }; }; @@ -165,20 +180,20 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - D65659CE22A156A200B76477 /* MessageListener.swift in Sources */, - D65659CD22A156A200B76477 /* FatalErrorHandler.swift in Sources */, - D65659CF22A156A200B76477 /* ProvidedAuthorizationTokenStateListener.swift in Sources */, - D65659CB22A156A200B76477 /* MessageTracker.swift in Sources */, + D69EFDDC24C836CC00728191 /* MessageTracker.swift in Sources */, + D69EFDD624C836CC00728191 /* ProvidedAuthorizationTokenStateListener.swift in Sources */, + D69EFDD724C836CC00728191 /* Operator.swift in Sources */, + D69EFDDB24C836CC00728191 /* WebimError.swift in Sources */, + D69EFDD924C836CC00728191 /* Message.swift in Sources */, + D69EFDE224C836CC00728191 /* MessageStream.swift in Sources */, + D69EFDDD24C836CC00728191 /* WebimLogger.swift in Sources */, + D69EFDDF24C836CC00728191 /* FatalErrorHandler.swift in Sources */, + D69EFDE124C836CC00728191 /* Webim.swift in Sources */, + D69EFDE024C836CC00728191 /* MessageListener.swift in Sources */, + D69EFDDE24C836CC00728191 /* WebimRemoteNotification.swift in Sources */, + D69EFDD824C836CC00728191 /* Department.swift in Sources */, + D69EFDDA24C836CC00728191 /* WebimSession.swift in Sources */, B3E7B58A1CC2AC0600A0062D /* RNWebim.m in Sources */, - D65659C722A156A200B76477 /* WebimError.swift in Sources */, - D65659CA22A156A200B76477 /* WebimSession.swift in Sources */, - D65659CC22A156A200B76477 /* WebimRemoteNotification.swift in Sources */, - D65659C922A156A200B76477 /* Webim.swift in Sources */, - D65659C822A156A200B76477 /* Operator.swift in Sources */, - D65659C522A156A200B76477 /* Department.swift in Sources */, - D65659D022A156A200B76477 /* MessageStream.swift in Sources */, - D65659C622A156A200B76477 /* WebimLogger.swift in Sources */, - D65659D122A156A200B76477 /* Message.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/ios/RNWebim.xcodeproj/project.xcworkspace/xcuserdata/nikitasirotkin.xcuserdatad/UserInterfaceState.xcuserstate b/ios/RNWebim.xcodeproj/project.xcworkspace/xcuserdata/nikitasirotkin.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..d887a412d41662fc88569de7932b365a9c81cc5c GIT binary patch literal 18808 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 literal 0 HcmV?d00001 diff --git a/ios/RNWebim.xcodeproj/xcuserdata/nikitasirotkin.xcuserdatad/xcschemes/xcschememanagement.plist b/ios/RNWebim.xcodeproj/xcuserdata/nikitasirotkin.xcuserdatad/xcschemes/xcschememanagement.plist index 317a1a0..7493a26 100644 --- a/ios/RNWebim.xcodeproj/xcuserdata/nikitasirotkin.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/ios/RNWebim.xcodeproj/xcuserdata/nikitasirotkin.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,7 +7,7 @@ RNWebim.xcscheme_^#shared#^_ orderHint - 68 + 0 diff --git a/node_modules/.bin/react-native b/node_modules/.bin/react-native new file mode 120000 index 0000000..7ec0ed3 --- /dev/null +++ b/node_modules/.bin/react-native @@ -0,0 +1 @@ +../../../node_modules/react-native/cli.js \ No newline at end of file diff --git a/package.json b/package.json index 7160400..f97ed0d 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,24 @@ { - "name": "react-native-webim", + "name": "webim-react-native", "version": "0.0.9", - "author": "AlfClausen", + "author": "Nikita Sirotkin", "license": "MIT", "description": "RN Webim implementation", - "main": "index.js", + "main": "build/index.ts", + "scripts": { + "prepublish": "tsc" + }, "repository": { "type": "git", "url": "https://github.com/AlfClausen/react-native-webim" }, "devDependencies": { - "react": "^16.9.0", - "react-native": "^0.61.0" + "@types/react": "*", + "@types/react-native": "*", + "typescript": "^3.8.3" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" } } diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..64f9ede --- /dev/null +++ b/src/index.ts @@ -0,0 +1,7 @@ +import RNWebim from './webim'; + +export * from './types'; +export * from './utils'; +export * from './webim'; + +export default RNWebim; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..11783cb --- /dev/null +++ b/src/types.ts @@ -0,0 +1,54 @@ +export type SessionBuilderParams = { + accountName: string; + location: string; + accountJSON?: string; + providedAuthorizationToken?: string; + appVersion?: string; + clearVisitorData?: boolean; + storeHistoryLocally?: boolean; + title?: string; + pushToken?: string; +}; + +export enum WebimEvents { + NEW_MESSAGE = 'newMessage', + REMOVE_MESSAGE = 'removeMessage', + EDIT_MESSAGE = 'changedMessage', + CLEAR_DIALOG = 'allMessagesRemoved', + TOKEN_UPDATED = 'tokenUpdated', + ERROR = 'error', +} + +export interface WebimAttachment { + contentType: string; + info: string; + name: string; + size: number; + url: string; +} + +export interface WebimMessage { + id: string; + avatar?: string; + time: number; + type: 'OPERATOR' | 'VISITOR' | 'INFO'; + text: string; + name: string; + status: 'SENT'; + read: boolean; + canEdit: boolean; + attachment?: WebimAttachment; +} + +export type NativeError = { + message: string; +}; + +export type NewMessageListener = (data: { msg: WebimMessage }) => void; +export type UpdateMessageListener = (data: { from: WebimMessage, to: WebimMessage }) => void; +export type RemoveMessageListener = (data: { msg: WebimMessage }) => void; +export type DialogClearedListener = () => void; +export type TokenUpdatedListener = (token: string) => void; +export type ErrorListener = (error: NativeError) => void; + +export type WebimEventListener = NewMessageListener | UpdateMessageListener | RemoveMessageListener | DialogClearedListener | TokenUpdatedListener | ErrorListener; diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..9ca6a04 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,17 @@ +import {NativeError} from './types'; + +export function parseNativeResponse(response?: T): T | null { + return response || null; +} + +export function processError(error: NativeError) { + return new Error(error.message); +} + +export class WebimSubscription { + readonly remove: () => void; + + constructor(remove: () => void) { + this.remove = remove; + } +} diff --git a/src/webim.ts b/src/webim.ts new file mode 100644 index 0000000..473d97f --- /dev/null +++ b/src/webim.ts @@ -0,0 +1,163 @@ +import {NativeModules, NativeEventEmitter} from 'react-native'; +import { + DialogClearedListener, ErrorListener, + NativeError, NewMessageListener, RemoveMessageListener, + SessionBuilderParams, TokenUpdatedListener, UpdateMessageListener, WebimEventListener, + WebimEvents, + WebimMessage, +} from './types'; +import {WebimSubscription, processError} from './utils'; + +const {RNWebim: WebimNative} = NativeModules; +const emitter = new NativeEventEmitter(NativeModules.RNWebim); + +const DEFAULT_MESSAGES_LIMIT = 100; + +export class RNWebim { + static resumeSession(params: SessionBuilderParams): Promise { + return new Promise((resolve, reject) => { + WebimNative.resumeSession( + params, + (error: NativeError) => reject(processError(error)), + () => resolve(), + ); + }); + } + + static destroySession(clearData: boolean = false) { + return new Promise((resolve, reject) => { + WebimNative.destroySession( + clearData, + (error: NativeError) => reject(processError(error)), + () => resolve(), + ); + }); + } + + static getLastMessages( + limit: number = DEFAULT_MESSAGES_LIMIT, + ): Promise<{ messages: WebimMessage[] }> { + return new Promise((resolve, reject) => { + WebimNative.getLastMessages( + limit, + (error: NativeError) => reject(processError(error)), + (messages: { messages: WebimMessage[] }) => resolve(messages), + ); + }); + } + + static getNextMessages( + limit: number = DEFAULT_MESSAGES_LIMIT, + ): Promise<{ messages: WebimMessage[] }> { + return new Promise((resolve, reject) => { + WebimNative.getNextMessages( + limit, + (error: NativeError) => reject(processError(error)), + (messages: { messages: WebimMessage[] }) => resolve(messages), + ); + }); + } + + static getAllMessages(): Promise<{ messages: WebimMessage[] }> { + return new Promise((resolve, reject) => { + WebimNative.getAllMessages( + (error: NativeError) => reject(processError(error)), + (messages: { messages: WebimMessage[] }) => resolve(messages), + ); + }); + } + + static send(message: string) { + return new Promise((resolve, reject) => + WebimNative.send( + message, + (error: NativeError) => reject(processError(error)), + (id: string) => resolve(id), + ), + ); + } + + static rateOperator(rate: number) { + return new Promise((resolve, reject) => { + WebimNative.rateOperator( + rate, + (error: NativeError) => reject(processError(error)), + () => resolve(), + ); + }); + } + + static tryAttachFile() { + return new Promise((resolve, reject) => { + WebimNative.tryAttachFile( + (error: NativeError) => reject(processError(error)), + async (file: { + uri: string; + name: string; + mime: string; + extension: string; + }) => { + const {uri, name, mime, extension} = file; + try { + await RNWebim.sendFile(uri, name, mime, extension); + resolve(); + } catch (e) { + reject(processError(e)); + } + }, + ); + }); + } + + static sendFile(uri: string, name: string, mime: string, extension: string) { + return new Promise((resolve, reject) => + WebimNative.sendFile(uri, name, mime, extension, reject, resolve), + ); + } + + public static addNewMessageListener(listener: NewMessageListener): WebimSubscription { + emitter.addListener(WebimEvents.NEW_MESSAGE, listener); + return new WebimSubscription(() => RNWebim.removeListener(WebimEvents.NEW_MESSAGE, listener)); + } + + public static addRemoveMessageListener(listener: RemoveMessageListener): WebimSubscription { + emitter.addListener(WebimEvents.REMOVE_MESSAGE, listener); + return new WebimSubscription(() => RNWebim.removeListener(WebimEvents.REMOVE_MESSAGE, listener)); + } + + public static addEditMessageListener(listener: UpdateMessageListener): WebimSubscription { + emitter.addListener(WebimEvents.EDIT_MESSAGE, listener); + return new WebimSubscription(() => RNWebim.removeListener(WebimEvents.EDIT_MESSAGE, listener)); + } + + public static addDialogClearedListener(listener: DialogClearedListener): WebimSubscription { + emitter.addListener(WebimEvents.CLEAR_DIALOG, listener); + return new WebimSubscription(() => RNWebim.removeListener(WebimEvents.CLEAR_DIALOG, listener)); + } + + public static addTokenUpdatedListener(listener: TokenUpdatedListener): WebimSubscription { + emitter.addListener(WebimEvents.TOKEN_UPDATED, listener); + return new WebimSubscription(() => RNWebim.removeListener(WebimEvents.TOKEN_UPDATED, listener)); + } + + public static addErrorListener(listener: ErrorListener): WebimSubscription { + emitter.addListener(WebimEvents.ERROR, listener); + return new WebimSubscription(() => RNWebim.removeListener(WebimEvents.ERROR, listener)); + } + + public static addListener(event: WebimEvents, listener: WebimEventListener): WebimSubscription { + emitter.addListener(event, listener); + return new WebimSubscription(() => RNWebim.removeListener(event, listener)); + } + + public static removeListener(event: WebimEvents, listener: WebimEventListener): void { + emitter.removeListener(event, listener); + } + + static removeAllListeners(event: WebimEvents) { + emitter.removeAllListeners(event); + } +} + +export default RNWebim; + diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..882cd31 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "declaration": true, + "module": "commonjs", + "strict": true, + "esModuleInterop": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "jsx": "react", + "lib": ["dom", "es5", "es6", "scripthost"], + "target": "es5", + "rootDir": "./src", + "outDir": "build", + "sourceMap": true, + "skipLibCheck": true + }, + "exclude": ["node_modules"] +} From 096891975baeb19fc846da49515be09432d429de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B8=D1=80=D0=BE=D1=82=D0=BA=D0=B8=D0=BD=20=D0=9D?= =?UTF-8?q?=D0=B8=D0=BA=D0=B8=D1=82=D0=B0?= Date: Wed, 22 Jul 2020 17:59:59 +0300 Subject: [PATCH 32/32] revert author and main repo in package.json and podspec --- .gitignore | 3 ++- .npmignore | 6 ++++++ README.md | 2 +- RNWebim.podspec | 2 +- package.json | 8 ++++---- tsconfig.json | 2 +- 6 files changed, 15 insertions(+), 8 deletions(-) create mode 100644 .npmignore diff --git a/.gitignore b/.gitignore index 0a10fe1..4bddbf0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .DS_Store .idea .vscode +/js build *.iml -local.properties \ No newline at end of file +local.properties diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..0a10fe1 --- /dev/null +++ b/.npmignore @@ -0,0 +1,6 @@ +.DS_Store +.idea +.vscode +build +*.iml +local.properties \ No newline at end of file diff --git a/README.md b/README.md index 810399c..8a7151f 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Implementation of [webim sdk](https://webim.ru/) for [react-native](https://gith ## Installation ``` -yarn add react-native-webim +yarn add webim-react-native ``` iOS diff --git a/RNWebim.podspec b/RNWebim.podspec index 9f2e098..d5828a9 100644 --- a/RNWebim.podspec +++ b/RNWebim.podspec @@ -13,7 +13,7 @@ Pod::Spec.new do |s| s.homepage = package['repository']['url'] s.requires_arc = true - s.platform = :ios, '10.0' + s.platform = :ios, '9.0' s.preserve_paths = 'LICENSE', 'README.md', 'package.json', 'index.js' s.source_files = "ios/*.{h,m,swift}" diff --git a/package.json b/package.json index f97ed0d..189962e 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,16 @@ { "name": "webim-react-native", - "version": "0.0.9", + "version": "0.1.0", "author": "Nikita Sirotkin", "license": "MIT", "description": "RN Webim implementation", - "main": "build/index.ts", + "main": "js/index.ts", "scripts": { - "prepublish": "tsc" + "prepare": "rm -rf js && tsc" }, "repository": { "type": "git", - "url": "https://github.com/AlfClausen/react-native-webim" + "url": "https://github.com/volga-volga/react-native-webim" }, "devDependencies": { "@types/react": "*", diff --git a/tsconfig.json b/tsconfig.json index 882cd31..f49a4a7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,7 @@ "lib": ["dom", "es5", "es6", "scripthost"], "target": "es5", "rootDir": "./src", - "outDir": "build", + "outDir": "js", "sourceMap": true, "skipLibCheck": true },