From ee4f6cac1010e87a675553f033a148b5cd9ef8e0 Mon Sep 17 00:00:00 2001 From: Patrick Simpson Date: Wed, 21 Dec 2016 12:53:16 +0100 Subject: [PATCH] Initial import --- .gitignore | 215 + example-header.txt | 23 - src/AcaciaZPushPlugin/AcaciaZPushPlugin.sln | 82 + .../AcaciaOptionAttribute.cs | 53 + .../AcaciaZPushPlugin.csproj | 612 ++ .../AcaciaZPushPlugin/Config.cs | 29 + .../AcaciaZPushPlugin/Constants.cs | 99 + .../AcaciaZPushPlugin/Controls/KAnimator.cs | 96 + .../AcaciaZPushPlugin/Controls/KBusyHider.cs | 189 + .../Controls/KBusyIndicator.Designer.cs | 104 + .../Controls/KBusyIndicator.cs | 62 + .../Controls/KBusyIndicator.resx | 120 + .../Controls/KCheckManager.cs | 271 + .../AcaciaZPushPlugin/Controls/KCopyLabel.cs | 35 + .../Controls/KDialogButtons.Designer.cs | 78 + .../Controls/KDialogButtons.cs | 220 + .../Controls/KDialogButtons.resx | 258 + .../AcaciaZPushPlugin/Controls/KDialogNew.cs | 131 + .../Controls/KDialogNew.resx | 133 + .../Controls/KSelectionManager.cs | 100 + .../AcaciaZPushPlugin/Controls/KTree.cs | 1166 +++ .../AcaciaZPushPlugin/Controls/KTree.resx | 120 + .../AcaciaZPushPlugin/Controls/KTreeNode.cs | 242 + .../Controls/KTreeNodeLoader.cs | 217 + .../Controls/KTreeNodeMeasurements.cs | 157 + .../AcaciaZPushPlugin/Controls/KTreeNodes.cs | 105 + .../Controls/KTreeRenderer.cs | 173 + .../Controls/KTreeRendererDefault.cs | 93 + .../Controls/KTreeRendererVisualStyles.cs | 159 + .../AcaciaZPushPlugin/Controls/KUITask.cs | 570 ++ .../AcaciaZPushPlugin/Controls/KUIUtil.cs | 80 + .../AcaciaZPushPlugin/DebugOptions.cs | 224 + .../DebugSupport/AboutDialog.Designer.cs | 192 + .../Features/DebugSupport/AboutDialog.cs | 59 + .../Features/DebugSupport/AboutDialog.resx | 525 ++ .../DebugSupport/DebugDialog.Designer.cs | 126 + .../Features/DebugSupport/DebugDialog.cs | 117 + .../Features/DebugSupport/DebugDialog.resx | 375 + .../Features/DebugSupport/DebugInfo.cs | 278 + .../DebugSupportSettings.Designer.cs | 89 + .../DebugSupport/DebugSupportSettings.cs | 68 + .../DebugSupport/DebugSupportSettings.resx | 267 + .../DebugSupport/FeatureDebugSupport.cs | 122 + .../DebugSupport/FeatureObjectConverter.cs | 44 + .../Features/DebugSupport/Statistics.cs | 33 + .../AcaciaZPushPlugin/Features/Feature.cs | 259 + .../Features/FeatureDisabled.cs | 41 + .../Features/FeatureWithUI.cs | 32 + .../AcaciaZPushPlugin/Features/Features.cs | 40 + .../Features/FreeBusy/FeatureFreeBusy.cs | 210 + .../Features/FreeBusy/FreeBusyServer.cs | 158 + .../FreeBusy/FreeBusySettings.Designer.cs | 89 + .../Features/FreeBusy/FreeBusySettings.cs | 81 + .../Features/FreeBusy/FreeBusySettings.resx | 279 + .../Features/GAB/ChunkIndex.cs | 52 + .../Features/GAB/FeatureGAB.cs | 626 ++ .../Features/GAB/GABHandler.cs | 693 ++ .../AcaciaZPushPlugin/Features/GAB/GABInfo.cs | 93 + .../Features/GAB/GABSettings.Designer.cs | 58 + .../Features/GAB/GABSettings.cs | 57 + .../Features/GAB/GABSettings.resx | 171 + .../Features/Notes/FeatureNotes.cs | 292 + .../OutOfOffice/FeatureOutOfOffice.cs | 241 + .../OutOfOffice/OutOfOfficeDialog.Designer.cs | 225 + .../Features/OutOfOffice/OutOfOfficeDialog.cs | 192 + .../OutOfOffice/OutOfOfficeDialog.resx | 690 ++ .../Features/ReplyFlags/FeatureReplyFlags.cs | 181 + .../Features/ReplyFlags/ReplyFlags.cs | 229 + .../Features/SendAs/FeatureSendAs.cs | 125 + .../SharedFolders/FeatureSharedFolders.cs | 131 + .../Features/SharedFolders/FolderTreeNode.cs | 95 + .../SharedFoldersDialog.Designer.cs | 232 + .../SharedFolders/SharedFoldersDialog.cs | 495 ++ .../SharedFolders/SharedFoldersDialog.resx | 762 ++ .../Features/SharedFolders/StoreTreeNode.cs | 320 + .../Features/WebApp/FeatureWebApp.cs | 143 + .../Features/packages.config | 4 + .../AcaciaZPushPlugin/GlobalOptions.cs | 178 + .../AcaciaZPushPlugin/Logger.cs | 157 + .../AcaciaZPushPlugin/Logging.cs | 41 + .../AcaciaZPushPlugin/NLogLogger.cs | 101 + .../AcaciaZPushPlugin/Native/User32.cs | 205 + .../AcaciaZPushPlugin/Native/WM.cs | 30 + .../AcaciaZPushPlugin/OutlookConstants.cs | 249 + .../Properties/AssemblyInfo.cs | 25 + .../Properties/Resources.Designer.cs | 1023 +++ .../Properties/Resources.resx | 434 ++ .../Properties/Settings.Designer.cs | 26 + .../Properties/Settings.settings | 7 + .../Properties/TreeLoading.gif | Bin 0 -> 1407 bytes .../Resources/Icons/Ribbon_About.png | Bin 0 -> 700 bytes .../Resources/Icons/Ribbon_About_Small.png | Bin 0 -> 423 bytes .../Icons/Ribbon_AddSharedFolder.png | Bin 0 -> 566 bytes .../Icons/Ribbon_AddSharedFolder_Small.png | Bin 0 -> 355 bytes .../Resources/Icons/Ribbon_Debug.png | Bin 0 -> 773 bytes .../Resources/Icons/Ribbon_Debug_Small.png | Bin 0 -> 391 bytes .../Resources/Icons/Ribbon_Logfile.png | Bin 0 -> 665 bytes .../Resources/Icons/Ribbon_Logfile_Small.png | Bin 0 -> 364 bytes .../Resources/Icons/Ribbon_MDM.png | Bin 0 -> 587 bytes .../Resources/Icons/Ribbon_MDM_Small.png | Bin 0 -> 389 bytes .../Icons/Ribbon_ManageSharedFolders.png | Bin 0 -> 566 bytes .../Icons/Ribbon_ManageSharedFolders1.png | Bin 0 -> 566 bytes .../Ribbon_ManageSharedFolders_Small.png | Bin 0 -> 355 bytes .../Ribbon_ManageSharedFolders_Small1.png | Bin 0 -> 355 bytes .../Ribbon_ManageSharedFolders_Small11.png | Bin 0 -> 355 bytes .../Resources/Icons/Ribbon_OOF.png | Bin 0 -> 535 bytes .../Resources/Icons/Ribbon_OOF_Small.png | Bin 0 -> 333 bytes .../Resources/Icons/Ribbon_Restore.png | Bin 0 -> 924 bytes .../Resources/Icons/Ribbon_Restore_Small.png | Bin 0 -> 434 bytes .../Resources/Icons/Ribbon_Rules.png | Bin 0 -> 653 bytes .../Resources/Icons/Ribbon_Rules_Small.png | Bin 0 -> 383 bytes .../Resources/Icons/Ribbon_Settings.png | Bin 0 -> 700 bytes .../Resources/Icons/Ribbon_Settings_Small.png | Bin 0 -> 423 bytes .../Resources/Icons/Ribbon_SyncGAB.png | Bin 0 -> 749 bytes .../Resources/Icons/Ribbon_SyncGAB_Small.png | Bin 0 -> 417 bytes .../Resources/Icons/Ribbon_WebApp.png | Bin 0 -> 476 bytes .../Resources/Icons/Ribbon_WebApp_Small.png | Bin 0 -> 363 bytes .../Resources/Icons/Ribbon_WebMeetings.png | Bin 0 -> 386 bytes .../Icons/Ribbon_WebMeetings_Small.png | Bin 0 -> 261 bytes .../AcaciaZPushPlugin/Resources/Kopano.ico | Bin 0 -> 105374 bytes .../AcaciaZPushPlugin/Stubs/IAddressBook.cs | 33 + .../Stubs/IAppointmentItem.cs | 34 + .../AcaciaZPushPlugin/Stubs/IBase.cs | 56 + .../AcaciaZPushPlugin/Stubs/IContactItem.cs | 55 + .../Stubs/IDistributionList.cs | 32 + .../AcaciaZPushPlugin/Stubs/IFolder.cs | 105 + .../AcaciaZPushPlugin/Stubs/IItem.cs | 56 + .../AcaciaZPushPlugin/Stubs/IMailItem.cs | 39 + .../AcaciaZPushPlugin/Stubs/INoteItem.cs | 28 + .../AcaciaZPushPlugin/Stubs/ISearch.cs | 62 + .../AcaciaZPushPlugin/Stubs/IStorageItem.cs | 28 + .../AcaciaZPushPlugin/Stubs/IStore.cs | 32 + .../AcaciaZPushPlugin/Stubs/ITaskItem.cs | 28 + .../AcaciaZPushPlugin/Stubs/IUserProperty.cs | 38 + .../AcaciaZPushPlugin/Stubs/IZPushItem.cs | 31 + .../AcaciaZPushPlugin/Stubs/ItemType.cs | 38 + .../OutlookWrappers/AddressBookWrapper.cs | 45 + .../OutlookWrappers/AppointmentItemWrapper.cs | 114 + .../OutlookWrappers/ContactItemWrapper.cs | 245 + .../OutlookWrappers/DisposableWrapper.cs | 74 + .../DistributionListWrapper.cs | 272 + .../Stubs/OutlookWrappers/FolderWrapper.cs | 439 ++ .../Stubs/OutlookWrappers/MailItemWrapper.cs | 167 + .../Stubs/OutlookWrappers/Mapping.cs | 133 + .../Stubs/OutlookWrappers/NoteItemWrapper.cs | 97 + .../Stubs/OutlookWrappers/OutlookWrapper.cs | 173 + .../Stubs/OutlookWrappers/SearchWrapper.cs | 224 + .../OutlookWrappers/StorageItemWrapper.cs | 97 + .../Stubs/OutlookWrappers/StoreWrapper.cs | 69 + .../Stubs/OutlookWrappers/TaskItemWrapper.cs | 97 + .../OutlookWrappers/UserPropertyWrapper.cs | 76 + .../AcaciaZPushPlugin/ThisAddIn.Designer.cs | 286 + .../AcaciaZPushPlugin/ThisAddIn.Designer.xml | 4 + .../AcaciaZPushPlugin/ThisAddIn.cs | 236 + .../AcaciaZPushPlugin/UI/ErrorUtil.cs | 58 + .../AcaciaZPushPlugin/UI/FeatureSettings.cs | 58 + .../UI/GABLookupControl.Designer.cs | 36 + .../AcaciaZPushPlugin/UI/GABLookupControl.cs | 270 + .../AcaciaZPushPlugin/UI/KopanoDialog.cs | 33 + .../UI/Outlook/CommandElement.cs | 139 + .../AcaciaZPushPlugin/UI/Outlook/MenuItem.cs | 102 + .../UI/Outlook/OutlookImageList.cs | 140 + .../AcaciaZPushPlugin/UI/Outlook/OutlookUI.cs | 337 + .../UI/Outlook/RibbonButton.cs | 50 + .../UI/Outlook/RibbonToggleButton.cs | 66 + .../AcaciaZPushPlugin/UI/Outlook/Types.cs | 34 + .../UI/ProgressDialog.Designer.cs | 97 + .../AcaciaZPushPlugin/UI/ProgressDialog.cs | 115 + .../AcaciaZPushPlugin/UI/ProgressDialog.resx | 279 + .../UI/SettingsDialog.Designer.cs | 96 + .../AcaciaZPushPlugin/UI/SettingsDialog.cs | 108 + .../AcaciaZPushPlugin/UI/SettingsDialog.resx | 276 + .../UI/SettingsPage.Designer.cs | 68 + .../AcaciaZPushPlugin/UI/SettingsPage.cs | 146 + .../AcaciaZPushPlugin/UI/SettingsPage.resx | 120 + .../AcaciaZPushPlugin/Utils/ActiveSync.cs | 361 + .../AcaciaZPushPlugin/Utils/CollectionUtil.cs | 82 + .../AcaciaZPushPlugin/Utils/ComRelease.cs | 91 + .../AcaciaZPushPlugin/Utils/DnsUtil.cs | 98 + .../AcaciaZPushPlugin/Utils/FolderUtils.cs | 64 + .../AcaciaZPushPlugin/Utils/JSONUtils.cs | 35 + .../AcaciaZPushPlugin/Utils/LibUtils.cs | 95 + .../AcaciaZPushPlugin/Utils/MailEvents.cs | 294 + .../Utils/OutlookRegistryUtils.cs | 38 + .../Utils/PasswordEncryption.cs | 165 + .../AcaciaZPushPlugin/Utils/ReflectUtil.cs | 99 + .../AcaciaZPushPlugin/Utils/RegistryUtil.cs | 109 + .../AcaciaZPushPlugin/Utils/StringUtil.cs | 109 + .../AcaciaZPushPlugin/Utils/Tasks.cs | 114 + .../Utils/TasksBackground.cs | 54 + .../Utils/TasksMainThread.cs | 117 + .../Utils/TasksSynchronous.cs | 34 + .../AcaciaZPushPlugin/Utils/Util.cs | 48 + .../AcaciaZPushPlugin/Version.cs | 24 + .../WBXML/ActiveSync/ActiveSyncCodeSpace.cs | 68 + .../WBXML/ActiveSync/AirNotifyCodePage.cs | 36 + .../WBXML/ActiveSync/AirSyncBaseCodePage.cs | 58 + .../WBXML/ActiveSync/AirSyncCodePage.cs | 76 + .../WBXML/ActiveSync/CalendarCodePage.cs | 89 + .../WBXML/ActiveSync/ComposeMailCodePage.cs | 53 + .../WBXML/ActiveSync/Contacts2CodePage.cs | 49 + .../WBXML/ActiveSync/ContactsCodePage.cs | 97 + .../ActiveSync/DocumentLibraryCodePage.cs | 47 + .../WBXML/ActiveSync/Email2CodePage.cs | 51 + .../WBXML/ActiveSync/EmailCodePage.cs | 98 + .../ActiveSync/FolderHierarchyCodePage.cs | 59 + .../WBXML/ActiveSync/GALCodePage.cs | 50 + .../WBXML/ActiveSync/ItemEstimateCodePage.cs | 49 + .../ActiveSync/ItemOperationsCodePage.cs | 60 + .../ActiveSync/MeetingResponseCodePage.cs | 48 + .../WBXML/ActiveSync/MoveCodePage.cs | 47 + .../WBXML/ActiveSync/NotesCodePage.cs | 44 + .../WBXML/ActiveSync/PingCodePage.cs | 48 + .../WBXML/ActiveSync/ProvisionCodePage.cs | 94 + .../ActiveSync/ResolveRecipientsCodePage.cs | 64 + .../WBXML/ActiveSync/SearchCodePage.cs | 66 + .../WBXML/ActiveSync/SettingsCodePage.cs | 69 + .../WBXML/ActiveSync/TasksCodePage.cs | 70 + .../WBXML/ActiveSync/ValidateCertCodePage.cs | 45 + .../WBXML/AttributeCodePage.cs | 171 + .../WBXML/AttributeCodeSpace.cs | 45 + .../AcaciaZPushPlugin/WBXML/AttributeStart.cs | 61 + .../AcaciaZPushPlugin/WBXML/AttributeValue.cs | 50 + .../AcaciaZPushPlugin/WBXML/EmptyCodePage.cs | 41 + .../AcaciaZPushPlugin/WBXML/EmptyCodeSpace.cs | 40 + .../AcaciaZPushPlugin/WBXML/GlobalTokens.cs | 83 + .../WBXML/IANACharacterSets.cs | 164 + .../WBXML/OpaqueDataExpression.cs | 41 + .../AcaciaZPushPlugin/WBXML/StringTable.cs | 116 + .../WBXML/StringTableItem.cs | 49 + .../AcaciaZPushPlugin/WBXML/Tag.cs | 49 + .../AcaciaZPushPlugin/WBXML/TagCodePage.cs | 61 + .../AcaciaZPushPlugin/WBXML/TagCodeSpace.cs | 67 + .../AcaciaZPushPlugin/WBXML/WBXMLDocument.cs | 663 ++ .../API/SharedFolders/AvailableFolder.cs | 110 + .../ZPush/API/SharedFolders/SharedFolder.cs | 194 + .../API/SharedFolders/SharedFoldersAPI.cs | 152 + .../ZPush/API/SharedFolders/Types.cs | 45 + .../ZPush/Connect/Soap/ISoapSerializable.cs | 35 + .../ZPush/Connect/Soap/SoapConstants.cs | 32 + .../ZPush/Connect/Soap/SoapException.cs | 29 + .../ZPush/Connect/Soap/SoapParameters.cs | 56 + .../ZPush/Connect/Soap/SoapRequest.cs | 62 + .../ZPush/Connect/Soap/SoapRequestEncoder.cs | 116 + .../ZPush/Connect/Soap/SoapSerializer.cs | 439 ++ .../ZPush/Connect/ZPushConnection.cs | 320 + .../ZPush/Connect/ZPushRequestEncoder.cs | 33 + .../ZPush/Connect/ZPushWebService.cs | 93 + .../AcaciaZPushPlugin/ZPush/Delegates.cs | 31 + .../ZPush/FolderRegistration.cs | 61 + .../AcaciaZPushPlugin/ZPush/GABUser.cs | 100 + .../AcaciaZPushPlugin/ZPush/ItemsWatcher.cs | 46 + .../AcaciaZPushPlugin/ZPush/ZPushAccount.cs | 297 + .../AcaciaZPushPlugin/ZPush/ZPushAccounts.cs | 392 + .../ZPush/ZPushCapabilities.cs | 58 + .../AcaciaZPushPlugin/ZPush/ZPushChannel.cs | 96 + .../AcaciaZPushPlugin/ZPush/ZPushChannels.cs | 43 + .../AcaciaZPushPlugin/ZPush/ZPushFolder.cs | 282 + .../ZPush/ZPushLocalStore.cs | 171 + .../AcaciaZPushPlugin/ZPush/ZPushSync.cs | 225 + .../AcaciaZPushPlugin/ZPush/ZPushTypes.cs | 112 + .../AcaciaZPushPlugin/ZPush/ZPushWatcher.cs | 408 ++ .../AcaciaZPushPlugin/packages.config | 4 + .../PluginDebugger/App.config | 9 + .../PluginDebugger/Kopano.ico | Bin 0 -> 370070 bytes .../PluginDebugger/MainForm.Designer.cs | 180 + .../PluginDebugger/MainForm.cs | 245 + .../PluginDebugger/MainForm.resx | 6293 +++++++++++++++++ .../PluginDebugger/Options.cs | 49 + .../PluginDebugger/OptionsInfra.cs | 384 + .../PluginDebugger/PluginDebugger.csproj | 104 + .../PluginDebugger/Program.cs | 42 + .../PluginDebugger/Properties/AssemblyInfo.cs | 36 + .../Properties/Resources.Designer.cs | 71 + .../PluginDebugger/Properties/Resources.resx | 117 + .../Properties/Settings.Designer.cs | 30 + .../Properties/Settings.settings | 7 + .../PluginDebugger/Spacing.png | Bin 0 -> 161 bytes translations/KOE.pot | 772 ++ translations/de.po | 842 +++ translations/en.po | 774 ++ translations/fr.po | 840 +++ translations/hu.po | 843 +++ translations/it.po | 807 +++ translations/nl.po | 842 +++ 285 files changed, 47027 insertions(+), 23 deletions(-) create mode 100644 .gitignore delete mode 100644 example-header.txt create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin.sln create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaOptionAttribute.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Config.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Constants.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KAnimator.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KBusyHider.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KBusyIndicator.Designer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KBusyIndicator.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KBusyIndicator.resx create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KCheckManager.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KCopyLabel.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogButtons.Designer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogButtons.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogButtons.resx create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogNew.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogNew.resx create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KSelectionManager.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTree.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTree.resx create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeNode.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeNodeLoader.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeNodeMeasurements.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeNodes.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRenderer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRendererDefault.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRendererVisualStyles.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KUITask.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KUIUtil.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/DebugOptions.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/AboutDialog.Designer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/AboutDialog.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/AboutDialog.resx create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.Designer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.resx create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugInfo.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugSupportSettings.Designer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugSupportSettings.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugSupportSettings.resx create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/FeatureDebugSupport.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/FeatureObjectConverter.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/Statistics.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Feature.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FeatureDisabled.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FeatureWithUI.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Features.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FeatureFreeBusy.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FreeBusyServer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FreeBusySettings.Designer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FreeBusySettings.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FreeBusySettings.resx create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/ChunkIndex.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABHandler.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABInfo.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABSettings.Designer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABSettings.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABSettings.resx create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Notes/FeatureNotes.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/FeatureOutOfOffice.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/OutOfOfficeDialog.Designer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/OutOfOfficeDialog.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/OutOfOfficeDialog.resx create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/ReplyFlags/FeatureReplyFlags.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/ReplyFlags/ReplyFlags.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SendAs/FeatureSendAs.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FeatureSharedFolders.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FolderTreeNode.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.Designer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.resx create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/StoreTreeNode.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/WebApp/FeatureWebApp.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/packages.config create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/GlobalOptions.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Logger.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Logging.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/NLogLogger.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/User32.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/WM.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/AssemblyInfo.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Settings.Designer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Settings.settings create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/TreeLoading.gif create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_About.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_About_Small.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_AddSharedFolder.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_AddSharedFolder_Small.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_Debug.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_Debug_Small.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_Logfile.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_Logfile_Small.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_MDM.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_MDM_Small.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_ManageSharedFolders.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_ManageSharedFolders1.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_ManageSharedFolders_Small.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_ManageSharedFolders_Small1.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_ManageSharedFolders_Small11.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_OOF.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_OOF_Small.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_Restore.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_Restore_Small.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_Rules.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_Rules_Small.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_Settings.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_Settings_Small.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_SyncGAB.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_SyncGAB_Small.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_WebApp.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_WebApp_Small.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_WebMeetings.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_WebMeetings_Small.png create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Kopano.ico create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddressBook.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAppointmentItem.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IBase.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IContactItem.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IDistributionList.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolder.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IItem.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IMailItem.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/INoteItem.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ISearch.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IStorageItem.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IStore.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ITaskItem.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IUserProperty.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IZPushItem.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ItemType.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddressBookWrapper.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AppointmentItemWrapper.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/ContactItemWrapper.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/DisposableWrapper.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/DistributionListWrapper.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/MailItemWrapper.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/Mapping.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/NoteItemWrapper.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/OutlookWrapper.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/SearchWrapper.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StorageItemWrapper.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StoreWrapper.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/TaskItemWrapper.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/UserPropertyWrapper.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.Designer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.Designer.xml create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ErrorUtil.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/FeatureSettings.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.Designer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/KopanoDialog.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/CommandElement.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/MenuItem.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookImageList.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookUI.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/RibbonButton.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/RibbonToggleButton.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/Types.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ProgressDialog.Designer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ProgressDialog.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ProgressDialog.resx create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsDialog.Designer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsDialog.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsDialog.resx create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsPage.Designer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsPage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsPage.resx create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ActiveSync.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/CollectionUtil.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ComRelease.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DnsUtil.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/FolderUtils.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/JSONUtils.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/LibUtils.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/MailEvents.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/OutlookRegistryUtils.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/PasswordEncryption.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ReflectUtil.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/RegistryUtil.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/StringUtil.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/Tasks.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksBackground.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksMainThread.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksSynchronous.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/Util.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Version.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ActiveSyncCodeSpace.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/AirNotifyCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/AirSyncBaseCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/AirSyncCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/CalendarCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ComposeMailCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/Contacts2CodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ContactsCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/DocumentLibraryCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/Email2CodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/EmailCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/FolderHierarchyCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/GALCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ItemEstimateCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ItemOperationsCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/MeetingResponseCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/MoveCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/NotesCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/PingCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ProvisionCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ResolveRecipientsCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/SearchCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/SettingsCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/TasksCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ValidateCertCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/AttributeCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/AttributeCodeSpace.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/AttributeStart.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/AttributeValue.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/EmptyCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/EmptyCodeSpace.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/GlobalTokens.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/IANACharacterSets.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/OpaqueDataExpression.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/StringTable.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/StringTableItem.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/Tag.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/TagCodePage.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/TagCodeSpace.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/WBXMLDocument.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/AvailableFolder.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFolder.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFoldersAPI.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/Types.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/ISoapSerializable.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapConstants.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapException.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapParameters.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapRequest.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapRequestEncoder.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapSerializer.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/ZPushConnection.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/ZPushRequestEncoder.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/ZPushWebService.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Delegates.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/FolderRegistration.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/GABUser.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ItemsWatcher.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccounts.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushCapabilities.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushChannel.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushChannels.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushFolder.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushSync.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushTypes.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushWatcher.cs create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/packages.config create mode 100644 src/AcaciaZPushPlugin/PluginDebugger/App.config create mode 100644 src/AcaciaZPushPlugin/PluginDebugger/Kopano.ico create mode 100644 src/AcaciaZPushPlugin/PluginDebugger/MainForm.Designer.cs create mode 100644 src/AcaciaZPushPlugin/PluginDebugger/MainForm.cs create mode 100644 src/AcaciaZPushPlugin/PluginDebugger/MainForm.resx create mode 100644 src/AcaciaZPushPlugin/PluginDebugger/Options.cs create mode 100644 src/AcaciaZPushPlugin/PluginDebugger/OptionsInfra.cs create mode 100644 src/AcaciaZPushPlugin/PluginDebugger/PluginDebugger.csproj create mode 100644 src/AcaciaZPushPlugin/PluginDebugger/Program.cs create mode 100644 src/AcaciaZPushPlugin/PluginDebugger/Properties/AssemblyInfo.cs create mode 100644 src/AcaciaZPushPlugin/PluginDebugger/Properties/Resources.Designer.cs create mode 100644 src/AcaciaZPushPlugin/PluginDebugger/Properties/Resources.resx create mode 100644 src/AcaciaZPushPlugin/PluginDebugger/Properties/Settings.Designer.cs create mode 100644 src/AcaciaZPushPlugin/PluginDebugger/Properties/Settings.settings create mode 100644 src/AcaciaZPushPlugin/PluginDebugger/Spacing.png create mode 100644 translations/KOE.pot create mode 100644 translations/de.po create mode 100644 translations/en.po create mode 100644 translations/fr.po create mode 100644 translations/hu.po create mode 100644 translations/it.po create mode 100644 translations/nl.po diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f58a42f --- /dev/null +++ b/.gitignore @@ -0,0 +1,215 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +tmp/ + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates +*.VC.opendb + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc +*.VC.db + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview + +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml diff --git a/example-header.txt b/example-header.txt deleted file mode 100644 index 4622061..0000000 --- a/example-header.txt +++ /dev/null @@ -1,23 +0,0 @@ -/*********************************************** -* File : filename.source -* Project : Kopano OL Extension -* Descr : Description -* -* Created : 14.12.2016 -* -* Copyright 2016 Kopano b.v. -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License, version 3, -* as published by the Free Software Foundation. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see . -* -* Consult LICENSE file for details -************************************************/ \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin.sln b/src/AcaciaZPushPlugin/AcaciaZPushPlugin.sln new file mode 100644 index 0000000..62867b8 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin.sln @@ -0,0 +1,82 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AcaciaZPushPlugin", "AcaciaZPushPlugin\AcaciaZPushPlugin.csproj", "{1A7427A5-F814-4B07-98B2-C67D758B65D6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{3BAA09C4-9E3C-4088-901C-E03489366468}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginUnitTests", "Test\PluginUnitTests\PluginUnitTests.csproj", "{1862C3CA-3347-4180-B076-D018BAA70F40}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OutlookIntegrationTests", "Test\OutlookIntegrationTests\OutlookIntegrationTests.csproj", "{A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginDebugger", "PluginDebugger\PluginDebugger.csproj", "{9258AD17-0A25-4669-A95C-93EC70882551}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1A7427A5-F814-4B07-98B2-C67D758B65D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1A7427A5-F814-4B07-98B2-C67D758B65D6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1A7427A5-F814-4B07-98B2-C67D758B65D6}.Debug|x64.ActiveCfg = Debug|Any CPU + {1A7427A5-F814-4B07-98B2-C67D758B65D6}.Debug|x64.Build.0 = Debug|Any CPU + {1A7427A5-F814-4B07-98B2-C67D758B65D6}.Debug|x86.ActiveCfg = Debug|Any CPU + {1A7427A5-F814-4B07-98B2-C67D758B65D6}.Debug|x86.Build.0 = Debug|Any CPU + {1A7427A5-F814-4B07-98B2-C67D758B65D6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1A7427A5-F814-4B07-98B2-C67D758B65D6}.Release|Any CPU.Build.0 = Release|Any CPU + {1A7427A5-F814-4B07-98B2-C67D758B65D6}.Release|x64.ActiveCfg = Release|Any CPU + {1A7427A5-F814-4B07-98B2-C67D758B65D6}.Release|x64.Build.0 = Release|Any CPU + {1A7427A5-F814-4B07-98B2-C67D758B65D6}.Release|x86.ActiveCfg = Release|Any CPU + {1A7427A5-F814-4B07-98B2-C67D758B65D6}.Release|x86.Build.0 = Release|Any CPU + {1862C3CA-3347-4180-B076-D018BAA70F40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1862C3CA-3347-4180-B076-D018BAA70F40}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1862C3CA-3347-4180-B076-D018BAA70F40}.Debug|x64.ActiveCfg = Debug|Any CPU + {1862C3CA-3347-4180-B076-D018BAA70F40}.Debug|x64.Build.0 = Debug|Any CPU + {1862C3CA-3347-4180-B076-D018BAA70F40}.Debug|x86.ActiveCfg = Debug|Any CPU + {1862C3CA-3347-4180-B076-D018BAA70F40}.Debug|x86.Build.0 = Debug|Any CPU + {1862C3CA-3347-4180-B076-D018BAA70F40}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1862C3CA-3347-4180-B076-D018BAA70F40}.Release|Any CPU.Build.0 = Release|Any CPU + {1862C3CA-3347-4180-B076-D018BAA70F40}.Release|x64.ActiveCfg = Release|Any CPU + {1862C3CA-3347-4180-B076-D018BAA70F40}.Release|x64.Build.0 = Release|Any CPU + {1862C3CA-3347-4180-B076-D018BAA70F40}.Release|x86.ActiveCfg = Release|Any CPU + {1862C3CA-3347-4180-B076-D018BAA70F40}.Release|x86.Build.0 = Release|Any CPU + {A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Debug|x64.ActiveCfg = Debug|Any CPU + {A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Debug|x64.Build.0 = Debug|Any CPU + {A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Debug|x86.ActiveCfg = Debug|Any CPU + {A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Debug|x86.Build.0 = Debug|Any CPU + {A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Release|Any CPU.Build.0 = Release|Any CPU + {A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Release|x64.ActiveCfg = Release|Any CPU + {A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Release|x64.Build.0 = Release|Any CPU + {A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Release|x86.ActiveCfg = Release|Any CPU + {A1AA144C-ABCE-462D-ADB4-6EC25AC062B7}.Release|x86.Build.0 = Release|Any CPU + {9258AD17-0A25-4669-A95C-93EC70882551}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9258AD17-0A25-4669-A95C-93EC70882551}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9258AD17-0A25-4669-A95C-93EC70882551}.Debug|x64.ActiveCfg = Debug|Any CPU + {9258AD17-0A25-4669-A95C-93EC70882551}.Debug|x64.Build.0 = Debug|Any CPU + {9258AD17-0A25-4669-A95C-93EC70882551}.Debug|x86.ActiveCfg = Debug|Any CPU + {9258AD17-0A25-4669-A95C-93EC70882551}.Debug|x86.Build.0 = Debug|Any CPU + {9258AD17-0A25-4669-A95C-93EC70882551}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9258AD17-0A25-4669-A95C-93EC70882551}.Release|Any CPU.Build.0 = Release|Any CPU + {9258AD17-0A25-4669-A95C-93EC70882551}.Release|x64.ActiveCfg = Release|Any CPU + {9258AD17-0A25-4669-A95C-93EC70882551}.Release|x64.Build.0 = Release|Any CPU + {9258AD17-0A25-4669-A95C-93EC70882551}.Release|x86.ActiveCfg = Release|Any CPU + {9258AD17-0A25-4669-A95C-93EC70882551}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {1862C3CA-3347-4180-B076-D018BAA70F40} = {3BAA09C4-9E3C-4088-901C-E03489366468} + {A1AA144C-ABCE-462D-ADB4-6EC25AC062B7} = {3BAA09C4-9E3C-4088-901C-E03489366468} + EndGlobalSection +EndGlobal diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaOptionAttribute.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaOptionAttribute.cs new file mode 100644 index 0000000..b1575d6 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaOptionAttribute.cs @@ -0,0 +1,53 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia +{ + /// + /// Attached to properties or classes to make them visible in the PluginDebugger. + /// + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Class)] + public class AcaciaOptionAttribute : Attribute + { + private string _description; + + public string Description + { + get { return _description; } + } + + /// + /// If specified, marker interface that controls presence of this option. + /// + public Type Interface + { + get; + set; + } + + public AcaciaOptionAttribute(string description, Type marker = null) + { + this._description = description; + this.Interface = marker; + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj new file mode 100644 index 0000000..01f73c0 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj @@ -0,0 +1,612 @@ + + + + + + {BAA0C2D2-18E2-41B9-852F-F413020CAA33};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Debug + AnyCPU + {1A7427A5-F814-4B07-98B2-C67D758B65D6} + Library + false + Acacia + Kopano + v4.5.2 + VSTO40 + true + publish\ + + en + 1.0.0.0 + true + true + 7 + days + False + Kopano OL Extension + Kopano + + Kopano OL Extension + Kopano OL Extension + 3 + + + + False + Microsoft .NET Framework 4.5.2 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + False + Microsoft Visual Studio 2010 Tools for Office Runtime %28x86 and x64%29 + true + + + False + Windows Installer 4.5 + true + + + + + Outlook + + + + true + full + false + ..\Build\Debug\ + false + $(DefineConstants);DEBUG;TRACE + 4 + false + true + + + + pdbonly + true + ..\Build\Release\ + false + VSTO40 + 4 + false + true + + + + + + ..\packages\NLog.4.2.3\lib\net45\NLog.dll + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + + + True + + + + + False + true + + + False + true + + + False + + + + + + + + + Component + + + Component + + + UserControl + + + KBusyIndicator.cs + + + + Component + + + UserControl + + + KDialogButtons.cs + + + Form + + + + + + + UserControl + + + + + + + + + + Form + + + AboutDialog.cs + + + + UserControl + + + DebugSupportSettings.cs + + + + + + + UserControl + + + FreeBusySettings.cs + + + + UserControl + + + GABSettings.cs + + + + + + + + + + + + + + + + + + + + + Form + + + SharedFoldersDialog.cs + + + + + + + + + + + + + + + + UserControl + + + Component + + + GABLookupControl.cs + + + Form + + + Form + + + SettingsDialog.cs + + + UserControl + + + SettingsPage.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + Form + + + DebugDialog.cs + + + + + + + + + + + + + Form + + + OutOfOfficeDialog.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Form + + + ProgressDialog.cs + + + + + + + + Code + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + KBusyIndicator.cs + + + KDialogButtons.cs + + + KDialogNew.cs + + + KTree.cs + + + AboutDialog.cs + + + DebugDialog.cs + + + DebugSupportSettings.cs + + + FreeBusySettings.cs + + + GABSettings.cs + + + OutOfOfficeDialog.cs + + + SharedFoldersDialog.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + ProgressDialog.cs + + + SettingsDialog.cs + + + SettingsPage.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + + + Code + + + ThisAddIn.cs + + + ThisAddIn.Designer.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + true + + + TemporaryKey.pfx + + + BBFB28C253605E59B6EFA7AAC079FB30F06C8298 + + + false + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Config.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Config.cs new file mode 100644 index 0000000..e0d6e19 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Config.cs @@ -0,0 +1,29 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia +{ + public static class Config + { + public const int ACCOUNT_CHECK_INTERVAL = 5000; + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Constants.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Constants.cs new file mode 100644 index 0000000..d928f6e --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Constants.cs @@ -0,0 +1,99 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Acacia +{ + public static class Constants + { + #region Reply flags + + public const string ZPUSH_REPLY_HEADER = OutlookConstants.NS_TRANSPORT_MESSAGE_HEADERS + "X-Push-Flags"; + + public const string ZPUSH_REPLY_CATEGORY_PREFIX = "Push: Email "; + public const string ZPUSH_REPLY_CATEGORY_REPLIED = "replied"; + public const string ZPUSH_REPLY_CATEGORY_REPLIED_TO_ALL = "replied-to-all"; + public const string ZPUSH_REPLY_CATEGORY_FORWARDED = "forwarded"; + public readonly static Regex ZPUSH_REPLY_CATEGORY_REGEX = new Regex("([a-zA-Z\\-]+) on (.* GMT)$"); + + #endregion + + #region SendAs + + public const string ZPUSH_SEND_AS = OutlookConstants.NS_TRANSPORT_MESSAGE_HEADERS + "X-Push-Sender"; + public const string ZPUSH_SEND_AS_NAME = OutlookConstants.NS_TRANSPORT_MESSAGE_HEADERS + "X-Push-Sender-Name"; + + #endregion + + #region GAB + + public const string ZPUSH_GAB_INDEX = "$PushIndex"; + + public const int ZPUSH_GAB_NEWEST_MAX_CHECK = 5; + + #endregion + + #region Product names + + public const string PRODUCT_PREFIX = "Kopano"; + public const string PRODUCT_NAME = "Kopano OL Extension"; + + #endregion + + #region Local stores + + public const string LOCAL_STORE_DEFAULT_DIRECTORY = "%LocalAppData%\\" + PRODUCT_PREFIX + "\\" + PRODUCT_NAME; + public const string LOCAL_STORE_FILENAME = PRODUCT_PREFIX + "LocalFolders"; + public const string LOCAL_STORE_EXTENSION = "pst"; + + #endregion + + #region ActiveSync headers + + public const string ZPUSH_HEADER_GAB_NAME = "X-Push-GAB-Name"; + public const string ZPUSH_HEADER_CAPABILITIES = "X-Push-Capabilities"; + public const string ZPUSH_HEADER_PLUGIN = "X-Push-Plugin"; + public const string ZPUSH_HEADER_VERSION = "X-Z-Push-Version"; + + + #endregion + + #region Capabilities + + public const string ZPUSH_CAPABILITY_NOTES = "notes"; + public const string ZPUSH_CAPABILITY_OUT_OF_OFFICE = "oof"; + public const string ZPUSH_CAPABILITY_OUT_OF_OFFICE_TIMES = "ooftime"; + + #endregion + + public const string DATE_ISO_8601 = "yyyyMMddTHHmmssZ"; + + public static readonly TimeSpan ZPUSH_SYNC_DEFAULT_PERIOD = new TimeSpan(1, 0, 0); + + #region Registry + + public const string PLUGIN_REGISTRY_BASE = "Software\\" + PRODUCT_PREFIX + "\\" + PRODUCT_NAME; + public const string PLUGIN_REGISTRY_LOGLEVEL = "LogLevel"; + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KAnimator.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KAnimator.cs new file mode 100644 index 0000000..9b4daa2 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KAnimator.cs @@ -0,0 +1,96 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.Controls +{ + public class KAnimator : PictureBox + { + public KAnimator() + { + BackColor = Color.Transparent; + SizeMode = PictureBoxSizeMode.Zoom; + } + + private Image _stillFrame; + private Image _animation; + private bool _animating; + + public Image Animation + { + get { return _animation; } + set + { + if (_animation != value) + { + _animation = value; + _stillFrame = value; + if (_animation != null) + { + int frameCount = _animation.GetFrameCount(FrameDimension.Time); + if (frameCount > 0) + { + _animation.SelectActiveFrame(FrameDimension.Time, 0); + _stillFrame = new Bitmap(_animation); + } + } + SetImage(); + } + } + } + + public bool Animate + { + get { return _animating; } + set + { + if (_animating != value) + { + _animating = value; + SetImage(); + } + } + } + + private void SetImage() + { + if (_animating) + Image = _animation; + else + // TODO: would be awesome to finish the animation + Image = _stillFrame; + } + + public override Size GetPreferredSize(Size proposedSize) + { + Size sz = base.GetPreferredSize(proposedSize); + + // Scale for high resolution screens. + using (Graphics g = CreateGraphics()) + sz = sz.ScaleDpi(g); + + return sz; + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KBusyHider.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KBusyHider.cs new file mode 100644 index 0000000..f23c866 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KBusyHider.cs @@ -0,0 +1,189 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.Controls +{ + + public class KBusyHider : Panel, KUITaskProgress + { + #region UI + + private KBusyIndicator _busyOverlay = null; + private KBusyIndicator _completeOverlay = null; + private string _busyText; + + public bool Busy + { + get + { + return _busyOverlay != null; + } + + set + { + if (value == true) + { + if (_busyOverlay != null) + return; + + _busyOverlay = CreateOverlay(_busyText, true); + } + else if (_busyOverlay != null) + { + // Remove the overlay + RemoveOverlay(_busyOverlay); + _busyOverlay = null; + } + } + } + + private void RemoveOverlay(KBusyIndicator overlay) + { + Controls.Remove(overlay); + + // And enable the controls + foreach (Control control in Controls) + control.Enabled = true; + } + + private KBusyIndicator CreateOverlay(string text, bool showProgress) + { + try + { + SuspendLayout(); + + // Create a new busy indicator and layouyt + KBusyIndicator overlay = new KBusyIndicator(); + overlay.ShowProgress = showProgress; + overlay.Text = text; + + // Remove the existing controls; the overlay must be first to be rendered on top, + // and there's no insert function. + // Also disable the controls on the fly + List existing = new List(); + while (Controls.Count > 0) + { + existing.Add(Controls[0]); + Controls[0].Enabled = false; + Controls.RemoveAt(0); + } + + // Add the busy overlay + Controls.Add(overlay); + + // Re-add the existing controls + Controls.AddRange(existing.ToArray()); + + return overlay; + } + finally + { + ResumeLayout(); + } + } + + public override string Text + { + get + { + return BusyText; + } + + set + { + BusyText = value; + } + } + + public string BusyText + { + get + { + return _busyText; + } + + set + { + _busyText = value; + if (_busyOverlay != null) + _busyOverlay.Text = _busyText; + } + } + + public void ShowCompletion(string text) + { + // Show the overlay + _completeOverlay = CreateOverlay(text, false); + + _completeOverlay.MouseMove += _completeOverlay_MouseMove; + + // Add a timer to hide + var timer = new System.Windows.Forms.Timer(); + timer.Interval = 5000; // TODO: make a property for this + timer.Tick += (o, args) => + { + timer.Stop(); + HideCompleteOverlay(); + }; + timer.Start(); + } + + private void _completeOverlay_MouseMove(object sender, MouseEventArgs e) + { + HideCompleteOverlay(); + } + + private void HideCompleteOverlay() + { + if (_completeOverlay != null) + { + RemoveOverlay(_completeOverlay); + _completeOverlay = null; + } + } + + protected override void OnLayout(LayoutEventArgs levent) + { + base.OnLayout(levent); + + foreach (Control control in Controls) + { + if (control is KBusyIndicator) + { + Size pref = control.GetPreferredSize(ClientSize); + control.Bounds = ClientRectangle.Center(pref); + } + } + } + + public CancellationTokenSource Cancellation + { + get; + set; + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KBusyIndicator.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KBusyIndicator.Designer.cs new file mode 100644 index 0000000..31ddb89 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KBusyIndicator.Designer.cs @@ -0,0 +1,104 @@ +namespace Acacia.Controls +{ + partial class KBusyIndicator + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this._layout = new System.Windows.Forms.TableLayoutPanel(); + this._text = new System.Windows.Forms.Label(); + this._progress = new System.Windows.Forms.ProgressBar(); + this._layout.SuspendLayout(); + this.SuspendLayout(); + // + // _layout + // + this._layout.AutoSize = true; + this._layout.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this._layout.ColumnCount = 1; + this._layout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this._layout.Controls.Add(this._text, 0, 0); + this._layout.Controls.Add(this._progress, 0, 1); + this._layout.Dock = System.Windows.Forms.DockStyle.Fill; + this._layout.Location = new System.Drawing.Point(15, 15); + this._layout.Margin = new System.Windows.Forms.Padding(15, 15, 15, 15); + this._layout.Name = "_layout"; + this._layout.Padding = new System.Windows.Forms.Padding(9, 9, 9, 9); + this._layout.RowCount = 2; + this._layout.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this._layout.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this._layout.Size = new System.Drawing.Size(231, 115); + this._layout.TabIndex = 0; + // + // _text + // + this._text.AutoSize = true; + this._text.Dock = System.Windows.Forms.DockStyle.Fill; + this._text.Location = new System.Drawing.Point(15, 9); + this._text.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this._text.Name = "_text"; + this._text.Size = new System.Drawing.Size(201, 25); + this._text.TabIndex = 0; + this._text.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // _progress + // + this._progress.Dock = System.Windows.Forms.DockStyle.Fill; + this._progress.Location = new System.Drawing.Point(24, 49); + this._progress.Margin = new System.Windows.Forms.Padding(15, 15, 15, 15); + this._progress.MarqueeAnimationSpeed = 50; + this._progress.Name = "_progress"; + this._progress.Size = new System.Drawing.Size(183, 42); + this._progress.Style = System.Windows.Forms.ProgressBarStyle.Marquee; + this._progress.TabIndex = 1; + // + // KBusyIndicator + // + this.AutoScaleDimensions = new System.Drawing.SizeF(11F, 24F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoSize = true; + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.BackColor = System.Drawing.SystemColors.Control; + this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.Controls.Add(this._layout); + this.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); + this.Name = "KBusyIndicator"; + this.Padding = new System.Windows.Forms.Padding(15, 15, 15, 15); + this.Size = new System.Drawing.Size(261, 145); + this._layout.ResumeLayout(false); + this._layout.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel _layout; + private System.Windows.Forms.Label _text; + private System.Windows.Forms.ProgressBar _progress; + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KBusyIndicator.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KBusyIndicator.cs new file mode 100644 index 0000000..f823a7f --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KBusyIndicator.cs @@ -0,0 +1,62 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.Controls +{ + public partial class KBusyIndicator : UserControl + { + public KBusyIndicator() + { + InitializeComponent(); + } + + private bool _showProgress = true; + + public bool ShowProgress + { + get { return _showProgress; } + set + { + _showProgress = value; + _progress.Visible = _showProgress; + _text.Padding = _showProgress ? new Padding(15) : new Padding(15, 30, 15, 30); + } + } + + public override string Text + { + get + { + return _text.Text; + } + + set + { + _text.Text = value; + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KBusyIndicator.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KBusyIndicator.resx new file mode 100644 index 0000000..29dcb1b --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KBusyIndicator.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KCheckManager.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KCheckManager.cs new file mode 100644 index 0000000..86974c7 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KCheckManager.cs @@ -0,0 +1,271 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.Controls +{ + public enum KCheckStyle + { + None, + TwoState, + ThreeState, + Recursive, + RecursiveThreeState + } + + abstract public class KCheckManager + { + abstract public void SetCheck(KTreeNode node, CheckState state); + abstract public void ToggleCheck(KTreeNode node); + abstract public void ToggleCheck(IReadOnlyCollection nodes); + abstract public KCheckStyle CheckStyle { get; } + + public class TwoState : KCheckManager + { + public override KCheckStyle CheckStyle { get { return KCheckStyle.TwoState; } } + + public override void SetCheck(KTreeNode node, CheckState state) + { + node.CheckStateDirect = state == CheckState.Checked ? CheckState.Checked : CheckState.Unchecked; + } + + public override void ToggleCheck(IReadOnlyCollection nodes) + { + // Do a majority vote to determine if we should + bool isChecked = nodes.Sum((x) => x.IsChecked ? 1 : 0) > (double)nodes.Count / 2.0; + foreach (KTreeNode node in nodes) + node.IsChecked = !isChecked; + } + + public override void ToggleCheck(KTreeNode node) + { + node.CheckState = node.CheckState == CheckState.Checked ? CheckState.Unchecked : CheckState.Checked; + } + } + + public class ThreeState : KCheckManager + { + public override KCheckStyle CheckStyle { get { return KCheckStyle.ThreeState; } } + + public override void SetCheck(KTreeNode node, CheckState state) + { + node.CheckStateDirect = state; + } + + public override void ToggleCheck(IReadOnlyCollection nodes) + { + // Count the check states + int[] counts = new int[3]; + foreach (KTreeNode node in nodes) + { + ++counts[(int)node.CheckState]; + } + + // Determine the current check state + CheckState state; + // Use indeterminate only if it has a clear majority + if (counts[(int)CheckState.Indeterminate] > counts[(int)CheckState.Checked] && counts[(int)CheckState.Indeterminate] > counts[(int)CheckState.Unchecked]) + state = CheckState.Indeterminate; + else if (counts[(int)CheckState.Checked] > counts[(int)CheckState.Unchecked]) + state = CheckState.Checked; + else + state = CheckState.Unchecked; + + // Update the state + state = (CheckState)(((int)state + 1) % 3); + foreach (KTreeNode node in nodes) + node.CheckState = state; + } + + public override void ToggleCheck(KTreeNode node) + { + node.CheckState = (CheckState)(((int)node.CheckState + 1) % 3); + } + } + + public class Recursive : KCheckManager + { + public override KCheckStyle CheckStyle { get { return KCheckStyle.Recursive; } } + + public override void SetCheck(KTreeNode node, CheckState state) + { + // TODO + node.CheckStateDirect = state; + } + + public override void ToggleCheck(KTreeNode node) + { + try + { + // Set the check state recursively + node.Owner?.BeginUpdate(); + + SetNodeCheckState(node, NextCheckState(node.CheckState)); + + // Update the parent state + SetParentCheckState(node.Parent, node.CheckState); + } + finally + { + node.Owner?.EndUpdate(); + } + } + + protected virtual CheckState NextCheckState(CheckState checkState) + { + return (checkState == CheckState.Checked) ? CheckState.Unchecked : CheckState.Checked; + } + + protected void SetParentCheckState(KTreeNode parent, CheckState childCheckState) + { + if (parent == null) + return; + + if (childCheckState == CheckState.Indeterminate) + { + // An indeterminate node always leads to an indeterminate parent + parent.CheckState = CheckState.Indeterminate; + } + else + { + // Determine the check state + bool haveChecked = childCheckState == CheckState.Checked; + bool haveUnchecked = childCheckState == CheckState.Unchecked; + bool haveIndeterminate = childCheckState == CheckState.Indeterminate; + foreach (KTreeNode child in parent.Children) + { + if (child.CheckState == CheckState.Checked) + haveChecked = true; + else if (child.CheckState == CheckState.Unchecked) + haveUnchecked = true; + else + haveIndeterminate = true; + } + + if (!haveIndeterminate && (haveChecked ^ haveUnchecked)) + { + parent.CheckState = haveChecked ? CheckState.Checked : CheckState.Unchecked; + } + else + { + parent.CheckState = CheckState.Indeterminate; + } + } + + SetParentCheckState(parent.Parent, parent.CheckState); + } + + private void SetNodeCheckState(KTreeNode node, CheckState checkState) + { + // Apply the children first, otherwise the node's check state will be based on that again + foreach (KTreeNode child in node.Children) + SetNodeCheckState(child, checkState != CheckState.Indeterminate ? checkState : CheckState.Unchecked); + node.CheckState = checkState; + } + + public override void ToggleCheck(IReadOnlyCollection nodes) + { + // Count the check states + int[] counts = new int[3]; + foreach (KTreeNode node in nodes) + { + ++counts[(int)node.CheckState]; + } + + // Sort by depth and remove any nodes whose ancestor is present, they'll get updated recursively + HashSet applyNodes = new HashSet(); + foreach (KTreeNode node in nodes.OrderBy((x) => x.Depth)) + { + bool add = true; + foreach (KTreeNode ancestor in node.Ancestors) + { + if (applyNodes.Contains(ancestor)) + { + add = false; + } + break; + } + + if (add) + applyNodes.Add(node); + } + + // Determine the current check state + bool isChecked; + if (counts[(int)CheckState.Checked] > counts[(int)CheckState.Unchecked]) + isChecked = true; + else + isChecked = false; + + // Update the state for all the nodes + foreach (KTreeNode node in applyNodes) + SetNodeCheckState(node, isChecked ? CheckState.Unchecked : CheckState.Checked); + // Update the parents + foreach (KTreeNode node in applyNodes) + SetParentCheckState(node.Parent, node.CheckState); + } + } + + public class RecursiveThreeState : Recursive + { + public override KCheckStyle CheckStyle { get { return KCheckStyle.RecursiveThreeState; } } + + public override void SetCheck(KTreeNode node, CheckState state) + { + if (state == CheckState.Checked) + { + // Set indeterminate if any of the children is not checked + foreach (KTreeNode child in node.Children) + if (child.CheckState != CheckState.Checked) + { + state = CheckState.Indeterminate; + break; + } + + } + else if (state == CheckState.Indeterminate) + { + if (node.Children.Count == 0) + state = CheckState.Checked; + } + + node.CheckStateDirect = state; + SetParentCheckState(node.Parent, state); + } + + protected override CheckState NextCheckState(CheckState checkState) + { + switch(checkState) + { + case CheckState.Unchecked: + return CheckState.Indeterminate; + case CheckState.Indeterminate: + return CheckState.Checked; + default: + return CheckState.Unchecked; + } + } + + // TODO: special handling for multiple selection? + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KCopyLabel.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KCopyLabel.cs new file mode 100644 index 0000000..3960a16 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KCopyLabel.cs @@ -0,0 +1,35 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.Controls +{ + public class KCopyLabel : TextBox + { + public KCopyLabel() + { + ReadOnly = true; + BorderStyle = BorderStyle.None; + TabStop = false; + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogButtons.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogButtons.Designer.cs new file mode 100644 index 0000000..ee333c7 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogButtons.Designer.cs @@ -0,0 +1,78 @@ +namespace Acacia.Controls +{ + partial class KDialogButtons + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(KDialogButtons)); + this.buttonApply = new System.Windows.Forms.Button(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonClose = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // buttonApply + // + resources.ApplyResources(this.buttonApply, "buttonApply"); + this.buttonApply.Name = "buttonApply"; + this.buttonApply.UseVisualStyleBackColor = true; + this.buttonApply.Click += new System.EventHandler(this.buttonApply_Click); + // + // buttonCancel + // + resources.ApplyResources(this.buttonCancel, "buttonCancel"); + this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // buttonClose + // + resources.ApplyResources(this.buttonClose, "buttonClose"); + this.buttonClose.DialogResult = System.Windows.Forms.DialogResult.OK; + this.buttonClose.Name = "buttonClose"; + this.buttonClose.UseVisualStyleBackColor = true; + this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click); + // + // KDialogButtons + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.buttonApply); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.buttonClose); + this.Name = "KDialogButtons"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private System.Windows.Forms.Button buttonApply; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonClose; + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogButtons.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogButtons.cs new file mode 100644 index 0000000..fea3a5f --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogButtons.cs @@ -0,0 +1,220 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Threading; + +namespace Acacia.Controls +{ + public partial class KDialogButtons : UserControl + { + private static readonly Padding DefaultButtonPadding = new Padding(12, 6, 12, 6); + private static readonly Padding DefaultButtonMargin = new Padding(6, 0, 6, 0); + + public KDialogButtons() + { + InitializeComponent(); + ButtonPadding = DefaultButtonPadding; + ButtonMargin = DefaultButtonMargin; + CheckButtons(); + } + + private bool _isDirty; + /// + /// Dirty flag. Enables the Apply button and prevents closing without confirmation + /// + [Category("Kopano")] + public bool IsDirty + { + get { return _isDirty; } + set { _isDirty = value; CheckButtons(); } + } + + private bool _hasApply = true; + /// + /// Shows or hides the apply button. + /// + [Category("Kopano")] + public bool HasApply + { + get { return _hasApply; } + set { _hasApply = value; CheckButtons(); } + } + + + private void CheckButtons() + { + SuspendLayout(); + + buttonApply.Enabled = IsDirty; + buttonApply.Visible = _hasApply; + buttonClose.Visible = !IsDirty || !_hasApply; + buttonCancel.Visible = IsDirty && !_hasApply; + + KDialogNew dlg = FindForm() as KDialogNew; + if (dlg != null) + { + dlg.AcceptButton = buttonApply; + dlg.CancelButton = IsDirty ? buttonCancel : buttonClose; + } + + ResumeLayout(); + } + + protected override void OnParentVisibleChanged(EventArgs e) + { + base.OnParentVisibleChanged(e); + CheckButtons(); + } + + private Padding _buttonPadding; + [Category("Kopano")] + public Padding ButtonPadding + { + get { return _buttonPadding; } + set + { + _buttonPadding = value; + foreach (Control child in Controls) + child.Padding = _buttonPadding; + } + } + bool ShouldSerializeButtonPadding() { return ButtonPadding != DefaultButtonPadding; } + + private Padding _buttonMargin; + [Category("Kopano")] + public Padding ButtonMargin + { + get { return _buttonMargin; } + set + { + _buttonMargin = value; + foreach (Control child in Controls) + child.Margin = _buttonMargin; + } + } + bool ShouldSerializeButtonMargin() { return ButtonMargin != DefaultButtonMargin; } + + private Size? _buttonSize; + [Category("Kopano")] + public Size? ButtonSize + { + get { return _buttonSize; } + set { _buttonSize = value; } + } + + protected override void OnControlAdded(ControlEventArgs e) + { + base.OnControlAdded(e); + e.Control.Padding = _buttonPadding; + e.Control.Margin = _buttonMargin; + } + + protected override void OnLayout(LayoutEventArgs e) + { + base.OnLayout(e); + + Size buttonSize = CalcButtonSize(); + + int x = ClientSize.Width; + int y = Padding.Top; + foreach (Control child in Controls.Cast().OrderByDescending(ctrl => ctrl.TabIndex)) + { + if (child.Visible) + { + child.SetBounds(x - buttonSize.Width + child.Margin.Left, + y + child.Margin.Top, + buttonSize.Width - child.Margin.Horizontal, + buttonSize.Height - child.Margin.Vertical); + x -= buttonSize.Width; + } + } + } + + private Size CalcButtonSize() + { + Size buttonSize; + if (this._buttonSize.HasValue) + { + buttonSize = new Size(this._buttonSize.Value.Width + ButtonMargin.Horizontal, + this._buttonSize.Value.Height + ButtonMargin.Vertical); + } + else + { + // Make all buttons the size of the largest one + buttonSize = new Size(); + foreach (Control child in Controls) + { + Size childSize = child.GetPreferredSize(ClientSize); + buttonSize = new Size(Math.Max(buttonSize.Width, childSize.Width + child.Margin.Horizontal), + Math.Max(buttonSize.Height, childSize.Height + child.Margin.Vertical)); + } + } + + return buttonSize; + } + + public override Size GetPreferredSize(Size proposedSize) + { + Size buttonSize = CalcButtonSize(); + int count = Controls.Cast().Count(x => x.Visible); + + return new Size(buttonSize.Width * count + Padding.Horizontal, buttonSize.Height + Padding.Vertical); + } + + private void buttonApply_Click(object sender, EventArgs e) + { + if (IsDirty) + OnApply(); + } + + virtual protected void OnApply() + { + if (Apply != null) + Apply(this, new EventArgs()); + } + + [Category("Kopano")] + public event EventHandler Apply; + + public CancellationTokenSource Cancellation + { + get; + set; + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + if (Cancellation != null) + Cancellation.Cancel(); + } + + private void buttonClose_Click(object sender, EventArgs e) + { + if (Cancellation != null) + Cancellation.Cancel(); + + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogButtons.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogButtons.resx new file mode 100644 index 0000000..bd5a466 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogButtons.resx @@ -0,0 +1,258 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + True + + + + GrowAndShrink + + + NoControl + + + + 3, 3 + + + 3, 3, 3, 3 + + + 49, 29 + + + 0 + + + Apply + + + buttonApply + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + GrowAndShrink + + + NoControl + + + 161, 3 + + + 3, 3, 3, 3 + + + 56, 29 + + + 1 + + + Cancel + + + False + + + buttonCancel + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + True + + + GrowAndShrink + + + NoControl + + + 82, 3 + + + 3, 3, 3, 3 + + + 49, 29 + + + 2 + + + Close + + + buttonClose + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + True + + + 6, 13 + + + True + + + GrowAndShrink + + + 2, 2, 2, 2 + + + 220, 35 + + + KDialogButtons + + + System.Windows.Forms.UserControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogNew.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogNew.cs new file mode 100644 index 0000000..da482ee --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogNew.cs @@ -0,0 +1,131 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.Controls +{ + public class KDialogNew : Form, KUITaskProgress + { + public KDialogNew() + { + Icon = Properties.Resources.Kopano; + } + + #region Control links + + [Category("Kopano")] + public KDialogButtons DialogButtons + { + get; + set; + } + + [Category("Kopano")] + public KBusyHider BusyHider + { + get; + set; + } + + #endregion + + #region KUITaskProgress + // TODO: if BusyHider is not set, pop up dialogs + public string BusyText + { + get { return BusyHider?.BusyText; } + set { if (BusyHider != null) BusyHider.BusyText = value; } + } + + public bool Busy + { + get + { + if (BusyHider == null) + return false; + return BusyHider.Busy; + } + + set + { + if (BusyHider != null) + BusyHider.Busy = value; + } + } + + public void ShowCompletion(string text) + { + if (BusyHider != null) + BusyHider.ShowCompletion(text); + } + + public CancellationTokenSource Cancellation + { + get { return DialogButtons?.Cancellation; } + set { if (DialogButtons != null) DialogButtons.Cancellation = value; } + } + + #endregion + + #region Form closing + + protected override void OnFormClosing(FormClosingEventArgs e) + { + base.OnFormClosing(e); + + // If we have dialog buttons, check if the dirty flag is set + if (DialogButtons != null && DialogButtons.IsDirty) + { + OnDirtyFormClosing(e); + } + } + + /// + /// Event that is raised only when trying to close a dirty form + /// + [Category("Kopano")] + public event FormClosingEventHandler DirtyFormClosing; + + virtual protected void OnDirtyFormClosing(FormClosingEventArgs e) + { + if (DirtyFormClosing != null) + DirtyFormClosing(this, e); + } + + #endregion + + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(KDialogNew)); + this.SuspendLayout(); + // + // KDialogNew + // + resources.ApplyResources(this, "$this"); + this.Name = "KDialogNew"; + this.ResumeLayout(false); + + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogNew.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogNew.resx new file mode 100644 index 0000000..e1b8003 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogNew.resx @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + + 284, 261 + + + KDialogNew + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KSelectionManager.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KSelectionManager.cs new file mode 100644 index 0000000..171d427 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KSelectionManager.cs @@ -0,0 +1,100 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Controls +{ + abstract public class KSelectionManager + { + abstract public IReadOnlyCollection CurrentSelection { get; } + + abstract public void Clear(); + abstract public void Add(KTreeNode node); + abstract public void Toggle(KTreeNode node); + + public class Single : KSelectionManager + { + private KTreeNode _selectedNode; + + public override IReadOnlyCollection CurrentSelection + { + get + { + List sel = new List(); + if (_selectedNode != null) + sel.Add(_selectedNode); + return sel; + } + } + + public override void Clear() + { + _selectedNode = null; + } + + public override void Add(KTreeNode node) + { + _selectedNode = node; + } + + public override void Toggle(KTreeNode node) + { + if (node == _selectedNode) + _selectedNode = null; + else + _selectedNode = node; + } + } + + public class Multiple : KSelectionManager + { + // TODO: use some sort of ordered set? + private readonly List _selection = new List(); + + public override IReadOnlyCollection CurrentSelection + { + get + { + return _selection; + } + } + + public override void Clear() + { + _selection.Clear(); + } + + public override void Add(KTreeNode node) + { + if (!_selection.Contains(node)) + _selection.Add(node); + } + + public override void Toggle(KTreeNode node) + { + if (!_selection.Contains(node)) + _selection.Add(node); + else + _selection.Remove(node); + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTree.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTree.cs new file mode 100644 index 0000000..4debde0 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTree.cs @@ -0,0 +1,1166 @@ +/// Project : Kopano OL Extension +/// +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Native; +using Acacia.Utils; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.Controls +{ + //[Designer(typeof(KopanoTreeViewDesigner))] + public class KTree : UserControl + { + #region Checkboxes + + public class CheckStateChangedEventArgs : EventArgs + { + public readonly KTreeNode Node; + + public CheckStateChangedEventArgs(KTreeNode node) + { + this.Node = node; + } + } + + public delegate void CheckStateChangedHandler(object sender, CheckStateChangedEventArgs e); + public event CheckStateChangedHandler CheckStateChanged; + + internal void OnCheckStateChanged(KTreeNode node) + { + if (CheckStateChanged != null) + { + CheckStateChanged(this, new CheckStateChangedEventArgs(node)); + } + } + + private KCheckManager _checkManager; + [Browsable(false)] + public KCheckManager CheckManager + { + get { return _checkManager; } + set { _checkManager = value; Rerender(); } + } + + public KCheckStyle CheckStyle + { + get + { + return _checkManager == null ? KCheckStyle.None : _checkManager.CheckStyle; + } + + set + { + switch(value) + { + case KCheckStyle.TwoState: + _checkManager = new KCheckManager.TwoState(); + break; + case KCheckStyle.ThreeState: + _checkManager = new KCheckManager.ThreeState(); + break; + case KCheckStyle.Recursive: + _checkManager = new KCheckManager.Recursive(); + break; + case KCheckStyle.RecursiveThreeState: + _checkManager = new KCheckManager.RecursiveThreeState(); + break; + default: + _checkManager = null; + break; + } + } + } + + private void ToggleCheck(KTreeNode node) + { + if (_checkManager == null || node == null) + return; + + if (!SelectedNodes.Contains(node) || SelectedNodes.Count == 1) + { + // Update the single node if it's not part of the selection, or it's the only selection + _checkManager.ToggleCheck(node); + } + else + { + // Update all selected nodes + BeginUpdate(); + try + { + _checkManager.ToggleCheck(SelectedNodes); + } + finally + { + EndUpdate(); + } + } + } + + #endregion + + #region Properties + + private Padding _nodePadding = new Padding(2, 4, 2, 4); + public Padding NodePadding + { + get { return _nodePadding; } + set { _nodePadding = value; Rerender(); } + } + + private int _nodeIdent = 8; + public int NodeIndent + { + get { return _nodeIdent; } + set { _nodeIdent = value; Rerender(); } + } + + #endregion + + #region Images + + private ImageList _images; + + public ImageList Images + { + get { return _images; } + set { _images = value; Rerender(); } + } + + #endregion + + #region Nodes + + private readonly KTreeNodes _rootNodes; + + [Browsable(false)] + public KTreeNodes RootNodes + { + get { return _rootNodes; } + } + + #endregion + + #region Creation + + public KTree() + { + SetStyle(ControlStyles.ResizeRedraw, true); + SetStyle(ControlStyles.OptimizedDoubleBuffer, true); + SetStyle(ControlStyles.AllPaintingInWmPaint, true); + SetStyle(ControlStyles.Selectable, true); + BackColor = SystemColors.Window; + + _rootNodes = new KTreeNodes(this); + SetupRenderer(); + InitScrollBars(); + } + + + #endregion + + #region Selection + + private bool _fullRowSelect = true; + public bool FullRowSelect + { + get { return _fullRowSelect; } + set { _fullRowSelect = value; Rerender(); } + } + + internal KTreeNode ActiveNode { get; private set; } + + private int ActiveNodeIndex + { + get { return ActiveNode == null ? -1 : _presentNodes.IndexOf(ActiveNode); } + } + + private KSelectionManager _selectionManager = new KSelectionManager.Multiple(); + public bool MultipleSelection + { + get { return _selectionManager is KSelectionManager.Multiple; } + set + { + _selectionManager = value ? new KSelectionManager.Multiple() : (KSelectionManager)new KSelectionManager.Single(); + } + } + + [Browsable(false)] + public IReadOnlyCollection SelectedNodes + { + get { return _selectionManager.CurrentSelection; } + } + + /// + /// Selects a single node and makes it the active node. + /// + /// The node. Pass null to deselect any nodes + /// Set to a specific mode to scroll the node into view + public void SelectNode(KTreeNode node, ScrollMode scroll = ScrollMode.None) + { + DoSelectNode(node, SelectAction.Set, scroll); + } + + private enum SelectAction + { + Set, + Toggle, + Range, + AddRange, + Activate + } + + private KTreeNode _selectRangeAnchor; + + private void DoSelectNode(KTreeNode node, SelectAction action, ScrollMode scroll) + { + if (action == SelectAction.Set || action == SelectAction.Range) + _selectionManager.Clear(); + + if (node != null) + { + switch(action) + { + + case SelectAction.Range: + case SelectAction.AddRange: + if (_selectRangeAnchor == null) + { + _selectRangeAnchor = node; + _selectionManager.Add(node); + break; + } + + // Select any nodes from the anchor to the current node + int activeIndex = Math.Max(0, _presentNodes.IndexOf(_selectRangeAnchor)); + int nodeIndex = _presentNodes.IndexOf(node); + // Keep to order just in case the selection manager wants it + if (activeIndex > nodeIndex) + { + for (int i = nodeIndex; i <= activeIndex; ++i) + if (_presentNodes[i].IsSelectable) + _selectionManager.Add(_presentNodes[i]); + } + else + { + for (int i = activeIndex; i <= nodeIndex; ++i) + if (_presentNodes[i].IsSelectable) + _selectionManager.Add(_presentNodes[i]); + } + break; + case SelectAction.Set: + _selectRangeAnchor = node; + _selectionManager.Add(node); + break; + case SelectAction.Toggle: + _selectRangeAnchor = node; + _selectionManager.Toggle(node); + break; + } + + if (scroll != ScrollMode.None) + ScrollIntoView(node, scroll); + } + + ActiveNode = node; + + // Must rerender + // TODO: affected nodes only + Rerender(); + + // Raise event if needed + CheckSelectionChanged(); + } + + public class SelectionChangedEventArgs : EventArgs + { + public readonly KTreeNode[] SelectedNodes; + + public SelectionChangedEventArgs(KTreeNode[] selectedNodes) + { + this.SelectedNodes = selectedNodes; + } + } + + public delegate void SelectionChangedDelegate(object sender, SelectionChangedEventArgs e); + + public event SelectionChangedDelegate SelectionChanged; + + private readonly List _previousSelection = new List(); + + private void CheckSelectionChanged() + { + if (_updateCount != 0) + return; + + IReadOnlyCollection selection = _selectionManager.CurrentSelection; + if (!selection.SameElements(_previousSelection)) + { + _previousSelection.Clear(); + _previousSelection.AddRange(selection); + + OnSelectionChanged(new SelectionChangedEventArgs(selection.ToArray())); + } + } + + virtual protected void OnSelectionChanged(SelectionChangedEventArgs e) + { + if (SelectionChanged != null) + SelectionChanged(this, e); + } + + #endregion + + #region Mouse handling + + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + + if ((e.Button & MouseButtons.Left) != 0) + { + HitTestResult? hit = HitTest(e.Location); + if (hit != null && hit.Value.Node.IsSelectable) + { + switch(hit.Value.Part) + { + case KTreeNodeMeasurements.Part.Expander: + hit.Value.Node.ToggleExpanded(); + break; + case KTreeNodeMeasurements.Part.CheckBox: + ToggleCheck(hit.Value.Node); + break; + case KTreeNodeMeasurements.Part.Text: + case KTreeNodeMeasurements.Part.None: + case KTreeNodeMeasurements.Part.Image: + DoSelectNode(hit.Value.Node, ActionFromModifiers(false), ScrollMode.Auto); + break; + } + } + } + } + + private SelectAction ActionFromModifiers(bool isKeyboard) + { + if (ModifierKeys == (Keys.Shift | Keys.Control)) + return SelectAction.AddRange; + else if (ModifierKeys == Keys.Shift) + return SelectAction.Range; + else if (ModifierKeys == Keys.Control) + { + if (isKeyboard) + return SelectAction.Activate; + else + return SelectAction.Toggle; + } + else + return SelectAction.Set; + } + + protected override void OnMouseDoubleClick(MouseEventArgs e) + { + if ((e.Button & MouseButtons.Left) != 0) + { + HitTestResult? hit = HitTest(e.Location, KTreeNodeMeasurements.Part.Text, KTreeNodeMeasurements.Part.Image); + if (hit != null && hit.Value.Node.IsSelectable) + { + hit.Value.Node.ToggleExpanded(); + } + } + } + + private KTreeNode _highlightNode; + private KTreeNodeMeasurements.Part? _highlightPart; + + protected override void OnMouseMove(MouseEventArgs e) + { + CheckMouseHighlight(); + } + + protected override void OnMouseLeave(EventArgs e) + { + // The mouse might be over a control hosted in a node, so check highlighting again + CheckMouseHighlight(); + } + + private void CheckMouseHighlight() + { + HitTestResult? hit = HitTest(PointToClient(MousePosition)); + HighlightNode(hit?.Node, hit?.Part); + } + + private void HighlightNode(KTreeNode newHighlight, KTreeNodeMeasurements.Part? newPart) + { + if (newHighlight != _highlightNode || _highlightPart != newPart) + { + KTreeNode old = _highlightNode; + + if (newHighlight != null && !newHighlight.IsSelectable) + { + _highlightNode = null; + _highlightPart = null; + } + else + { + _highlightNode = newHighlight; + _highlightPart = newPart; + } + + // Render old node without highlight + if (old != null) + Rerender(old); + + // Render new node + if (_highlightNode != null) + Rerender(_highlightNode); + } + } + + protected override void OnMouseWheel(MouseEventArgs e) + { + // Let the scrollbar handle the scrolling + if (HaveVerticalScrollBar) + _verticalScrollBar.ForwardMouseWheel(e); + } + + #endregion + + #region Hit testing + + private struct HitTestResult + { + public KTreeNode Node; + public KTreeNodeMeasurements.Part Part; + } + + private HitTestResult? HitTest(Point location, params KTreeNodeMeasurements.Part[] wanted) + { + if (location.X < 0 || location.X >= ViewRectangle.Width) + return null; + + KTreeNode node = NodeAtY(location.Y); + if (node == null) + return null; + + KTreeNodeMeasurements.Part? part = node.EffectiveDimension.HitTest(location.X + _horizontalScrollBar.Value); + if (part != null) + { + // Check if it's the part we're interested in + if (wanted.Length > 0 && !wanted.Contains(part.Value)) + return null; + + // Part.None is valid only if full row selection is enabled + if (!FullRowSelect && part.Value == KTreeNodeMeasurements.Part.None) + return null; + + // Success + return new HitTestResult() { Node = node, Part = part.Value }; + } + + return null; + } + + private KTreeNode NodeAtY(int y) + { + int index = NodeIndexAtY(y); + if (index < 0 || index >= _presentNodes.Count) + return null; + return _presentNodes[index]; + } + + private int NodeIndexAtY(int y) + { + // TODO: use a secondary index, or assume all rows are the same height? + y += _verticalScrollBar.Value; + if (y < 0) + return -1; + for(int i = 0; i < _presentNodes.Count; ++i) + { + if (_presentNodes[i].EffectiveDimension.NodeRect.ContainsY(y)) + return i; + } + return _presentNodes.Count; + } + + #endregion + + #region Keyboard handling + + protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e) + { + switch (e.KeyCode) + { + case Keys.Up: + KeySelect(-1); + break; + case Keys.Down: + KeySelect(1); + break; + case Keys.PageUp: + KeySelect(-PageSize); + break; + case Keys.PageDown: + KeySelect(PageSize); + break; + case Keys.Home: + KeySelect(-_presentNodes.Count); + break; + case Keys.End: + KeySelect(_presentNodes.Count); + break; + case Keys.Left: + KeyExpand(false); + break; + case Keys.Right: + KeyExpand(true); + break; + case Keys.Space: + if (ModifierKeys == Keys.Control || _checkManager == null) + { + DoSelectNode(ActiveNode, SelectAction.Toggle, ScrollMode.Auto); + } + else if (_checkManager != null) + { + ToggleCheck(ActiveNode); + } + break; + default: + return; + } + e.IsInputKey = true; + } + + private int PageSize + { + get + { + int firstVisible = NodeIndexAtY(0); + int count = 0; + for (int i = 0; i < _presentNodes.Count; ++i) + { + Rectangle nodeRect = _presentNodes[i].EffectiveDimension.NodeRect; + if (nodeRect.Bottom > ViewRectangle.Bottom) + break; + else if (nodeRect.Top >= ViewRectangle.Top) + ++count; + } + return count; + } + } + + private void KeyExpand(bool expand) + { + if (ActiveNode == null) + return; + + if (expand) + { + if (ActiveNode.ChildLoader.NeedsExpander) + { + if (!ActiveNode.IsExpanded) + ActiveNode.IsExpanded = true; + else + DoSelectNode(ActiveNode.Children.First(), ActionFromModifiers(true), ScrollMode.Auto); + } + } + else + { + if (ActiveNode.IsExpanded) + ActiveNode.IsExpanded = false; + else if (ActiveNode.Parent != null) + DoSelectNode(ActiveNode.Parent, ActionFromModifiers(true), ScrollMode.Auto); + } + } + + private void KeySelect(int dir) + { + int currentIndex = ActiveNodeIndex; + for (;;) + { + currentIndex = currentIndex + dir; + currentIndex = Math.Max(Math.Min(currentIndex, _presentNodes.Count - 1), 0); + KTreeNode node = currentIndex < _presentNodes.Count ? _presentNodes[currentIndex] : null; + if (node != null && !node.IsSelectable) + continue; + DoSelectNode(node, ActionFromModifiers(true), dir > 0 ? ScrollMode.Bottom : ScrollMode.Top); + break; + } + } + + #endregion + + #region Columns + // TODO + /* + private readonly TreeViewColumnCollection _columns; + + [Category("Columns")] + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public TreeViewColumnCollection Columns + { + get { return _columns; } + }*/ + + #endregion + + #region Rendering + + private KTreeRenderer _renderer; + + public void SetupRenderer(bool enableVisualStyles = true) + { + if (enableVisualStyles && Application.RenderWithVisualStyles) + _renderer = new KTreeRendererVisualStyles(); + else + _renderer = new KTreeRendererDefault(); + Rerender(); + } + + /// + /// The nodes that are currently present, i.e. their parents are expanded. + /// + private readonly List _presentNodes = new List(); + + internal void OnNodeExpandedChanged(KTreeNode node) + { + BeginUpdate(); + try + { + if (node.IsExpanded) + { + int index = _presentNodes.IndexOf(node); + if (index < 0) + return; + + // Add the child nodes + InsertChildNodes(node, index + 1); + } + else + { + RemoveChildNodes(node); + } + } + finally + { + EndUpdate(); + } + } + + private void RemoveChildNodes(KTreeNode parent) + { + int index = _presentNodes.IndexOf(parent); + if (index < 0) + return; + + // Remove any node that's deeper than the current node + int depth = parent.Depth; + int first = index + 1; + int past = first; + while (past < _presentNodes.Count) + { + if (_presentNodes[past].Depth > depth) + ++past; + else break; + } + if (past > first) + _presentNodes.RemoveRange(first, past - first); + } + + internal void OnNodeChildrenChanged(KTreeNode node) + { + Rerender(node); + } + + internal void OnNodeAdded(KTreeNode parent, KTreeNode node) + { + BeginUpdate(); + try + { + if (parent == null) + { + // TODO: this probably leads to wrong order + _presentNodes.Add(node); + } + else + { + if (!parent.IsExpanded) + return; + + int index = _presentNodes.IndexOf(parent); + if (index < 0) + return; + ++index; + int depth = parent.Depth; + while (index < _presentNodes.Count) + { + if (_presentNodes[index].Depth <= depth) + break; + ++index; + } + _presentNodes.Insert(index, node); + } + + if (node.IsExpanded) + { + OnNodeExpandedChanged(node); + } + } + finally + { + EndUpdate(); + } + } + + internal void OnNodeRemoved(KTreeNode parent, KTreeNode node) + { + throw new NotImplementedException(); + } + + internal void OnNodeCleared(KTreeNode parent) + { + BeginUpdate(); + try + { + if (parent == null) + { + // Root node cleared, means no more nodes + _presentNodes.Clear(); + } + else + { + RemoveChildNodes(parent); + } + } + finally + { + EndUpdate(); + } + } + + private int InsertChildNodes(KTreeNode parent, int index) + { + if (parent.IsExpanded) + { + foreach (KTreeNode node in parent.Children) + { + _presentNodes.Insert(index, node); + index = InsertChildNodes(node, index + 1); + } + } + return index; + } + + private int _updateCount; + + public void BeginUpdate() + { + ++_updateCount; + } + + public void EndUpdate() + { + --_updateCount; + if (_updateCount == 0) + { + Rerender(); + CheckSelectionChanged(); + } + } + + internal void Rerender(KTreeNode node = null) + { + if (_updateCount != 0) + return; + + // TODO: use node + MeasureNodes(); + UpdateScrollBars(); + CheckMouseHighlight(); + Invalidate(); + } + + private void MeasureNodes() + { + _renderer.Init(ViewRectangle, this); + using (Graphics graphics = CreateGraphics()) + { + foreach (KTreeNode node in _presentNodes) + { + _renderer.MeasureNode(graphics, node); + } + } + } + + private readonly List _nodeControls = new List(); + + protected override void OnPaint(PaintEventArgs e) + { + int firstVisibleNode = NodeIndexAtY(0); + List visibleControls = new List(); + + for (int i = firstVisibleNode; i < _presentNodes.Count; ++i) + { + KTreeNode node = _presentNodes[i]; + // Stop rendering when we're out of view + if (node.EffectiveDimension.NodeRect.Y - _verticalScrollBar.Value >= ViewRectangle.Bottom) + break; + + // Render the node + _renderer.RenderNode(e.Graphics, node, new Point(_horizontalScrollBar.Value, _verticalScrollBar.Value), + node == _highlightNode ? _highlightPart : null); + + // May have to add the control + if (node.Control != null) + { + if (node.Control.Parent == null) + { + _nodeControls.Add(node.Control); + node.Control.Parent = this; + } + visibleControls.Add(node.Control); + } + } + + // Check if any controls became invisible + for(int i = 0; i < _nodeControls.Count;) + { + if (!visibleControls.Contains(_nodeControls[i])) + { + _nodeControls[i].Parent = null; + _nodeControls.RemoveAt(i); + } + else + { + ++i; + } + } + + // Fill in a rectangle below the scrollbars, as that may be rendered. If they are not visible, the width or height + // automatically becomes 0 + e.Graphics.FillRectangle(SystemBrushes.Control, + ClientSize.Width - VerticalScrollBarWidth, ClientSize.Height - HorizontalScrollBarHeight, + VerticalScrollBarWidth, HorizontalScrollBarHeight); + } + + #endregion + + #region Scrollbars + + private class VScrollBar2 : VScrollBar + { + public VScrollBar2() + { + } + + internal void ForwardMouseWheel(MouseEventArgs e) + { + OnMouseWheel(e); + } + } + + private class HScrollBar2 : HScrollBar + { + internal void ForwardMouseWheel(MouseEventArgs e) + { + OnMouseWheel(e); + } + } + + private readonly VScrollBar2 _verticalScrollBar = new VScrollBar2(); + private readonly HScrollBar2 _horizontalScrollBar = new HScrollBar2(); + + private void InitScrollBars() + { + _verticalScrollBar.Scroll += _scrollBar_Scroll; + _verticalScrollBar.PreviewKeyDown += _verticalScrollBar_PreviewKeyDown; + Controls.Add(_verticalScrollBar); + _horizontalScrollBar.Scroll += _scrollBar_Scroll; + _horizontalScrollBar.PreviewKeyDown += _verticalScrollBar_PreviewKeyDown; + Controls.Add(_horizontalScrollBar); + } + + private void _verticalScrollBar_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) + { + + } + + private void _scrollBar_Scroll(object sender, ScrollEventArgs e) + { + // Mouse might be over different node now + CheckMouseHighlight(); + + // Repaint + Invalidate(); + } + + protected override void OnSizeChanged(EventArgs e) + { + base.OnSizeChanged(e); + MeasureNodes(); + UpdateScrollBars(); + } + + // TODO: this goes wrong if resizing makes a scrollbar appear/disappear + private void UpdateScrollBars() + { + // May happen during init + if (ViewRectangle.Height < 0) + return; + + // Update scrollbar ranges + _verticalScrollBar.Minimum = 0; + _verticalScrollBar.Maximum = _renderer.TotalRect.Height; + _horizontalScrollBar.Minimum = 0; + _horizontalScrollBar.Maximum = _renderer.TotalRect.Width; + + // Set change sizes + if (_presentNodes.Count > 0) + _verticalScrollBar.SmallChange = _presentNodes.First().EffectiveDimension.NodeRect.Height; + _verticalScrollBar.LargeChange = ViewRectangle.Height; + _horizontalScrollBar.SmallChange = NodeIndent; + _horizontalScrollBar.LargeChange = Math.Max(0, ViewRectangle.Width); // Negative on miminize + if (_verticalScrollBar.LargeChange >= _verticalScrollBar.Maximum) + _verticalScrollBar.Value = 0; + + // Set the positions, make them size 0 if not required + _verticalScrollBar.SetBounds(ClientSize.Width - VerticalScrollBarWidth, 0, VerticalScrollBarWidth, ClientSize.Height - HorizontalScrollBarHeight); + _horizontalScrollBar.SetBounds(0, ClientSize.Height - HorizontalScrollBarHeight, ClientSize.Width - VerticalScrollBarWidth, HorizontalScrollBarHeight); + } + + private bool HaveVerticalScrollBar + { + get { return _verticalScrollBar.LargeChange < _verticalScrollBar.Maximum; } + } + private int VerticalScrollBarWidth + { + get { return HaveVerticalScrollBar ? SystemInformation.VerticalScrollBarWidth : 0; } + } + private bool HaveHorizontalScrollBar + { + get { return _horizontalScrollBar.LargeChange < _horizontalScrollBar.Maximum; } + } + private int HorizontalScrollBarHeight + { + get { return HaveHorizontalScrollBar ? SystemInformation.HorizontalScrollBarHeight : 0; } + } + + private Rectangle ViewRectangle + { + get + { + Rectangle r = ClientRectangle; + r.Width -= VerticalScrollBarWidth; + r.Height -= HorizontalScrollBarHeight; + return r; + } + } + + private Rectangle ScrolledRectangle + { + get + { + Rectangle r = ClientRectangle; + r.Width -= VerticalScrollBarWidth; + r.Height -= HorizontalScrollBarHeight; + r.X += _horizontalScrollBar.Value; + r.Y += _verticalScrollBar.Value; + return r; + } + } + + public enum ScrollMode + { + None, + Auto, + Top, + Middle, + Bottom + } + + public void ScrollIntoView(KTreeNode node, ScrollMode mode) + { + if (mode == ScrollMode.None) + return; + + if (!node.IsVisible) + { + //return; + foreach (KTreeNode parent in node.Ancestors) + { + if (!parent.IsExpanded) + { + parent.IsExpanded = true; + } + else + { + break; + } + } + } + + // Number of pixels from edge to keep node in Y direction. + // TODO: this assumes all nodes are the same height + int scrollBorderY = node.EffectiveDimension.NodeRect.Height; + + // Vertical + // Do nothing if the node is already fully visible + if (!ScrolledRectangle.ContainsY(node.EffectiveDimension.NodeRect.Top - scrollBorderY) || + !ScrolledRectangle.ContainsY(node.EffectiveDimension.NodeRect.Bottom + scrollBorderY)) + { + if (mode == ScrollMode.Auto) + { + if (node.EffectiveDimension.NodeRect.Top + scrollBorderY < ScrolledRectangle.Y) + mode = ScrollMode.Top; + else + mode = ScrollMode.Bottom; + } + + switch (mode) + { + case ScrollMode.Top: + SetVScroll(node.EffectiveDimension.NodeRect.Top - ViewRectangle.Top - scrollBorderY); + break; + case ScrollMode.Middle: + SetVScroll((node.EffectiveDimension.NodeRect.Top + node.EffectiveDimension.NodeRect.Height / 2) - (ViewRectangle.Top + ViewRectangle.Height / 2)); + break; + case ScrollMode.Bottom: + SetVScroll(node.EffectiveDimension.NodeRect.Bottom - ViewRectangle.Bottom + scrollBorderY); + break; + } + } + + // Horizontal + if (!ScrolledRectangle.ContainsX(node.EffectiveDimension.NodeRect.Left) || !ScrolledRectangle.ContainsX(node.EffectiveDimension.NodeRect.Right)) + { + // Align left or right, depending on which is the smallest change + int alignLeft = node.EffectiveDimension.NodeRect.Left - ViewRectangle.Left; + int alignRight = node.EffectiveDimension.NodeRect.Right - ViewRectangle.Right; + if (Math.Abs(alignLeft - _horizontalScrollBar.Value) < Math.Abs(alignRight - _horizontalScrollBar.Value)) + SetHScroll(alignLeft); + else + SetHScroll(alignRight); + } + + // Check current highlight + CheckMouseHighlight(); + } + + private void SetVScroll(int value) + { + _verticalScrollBar.Value = Math.Max(_verticalScrollBar.Minimum, Math.Min(value, _verticalScrollBar.Maximum - _verticalScrollBar.LargeChange + 1)); + } + + private void SetHScroll(int value) + { + _horizontalScrollBar.Value = Math.Max(_horizontalScrollBar.Minimum, Math.Min(value, _horizontalScrollBar.Maximum - _horizontalScrollBar.LargeChange + 1)); + } + + #endregion + + #region Focus + + protected override void OnGotFocus(EventArgs e) + { + base.OnGotFocus(e); + Invalidate(); + } + + protected override void OnLostFocus(EventArgs e) + { + base.OnLostFocus(e); + Invalidate(); + } + + #endregion + + #region Winforms Autogenerated + + private void InitializeComponent() + { + this.SuspendLayout(); + // + // KTree + // + this.Name = "KTree"; + this.ResumeLayout(false); + } + + #endregion + + #region Disabled state + + protected override void OnEnabledChanged(EventArgs e) + { + base.OnEnabledChanged(e); + RedrawBorder(); + } + + protected override void WndProc(ref Message m) + { + if (m.Msg == (int)WM.NCPAINT) + { + WmNcPaint(ref m); + return; + } + base.WndProc(ref m); + } + + private void WmNcPaint(ref Message m) + { + if (BorderStyle == BorderStyle.None) + return; + + IntPtr hDC = User32.GetWindowDC(m.HWnd); + try + { + using (Graphics g = Graphics.FromHdc(hDC)) + { + _renderer.RenderControlBorder(g, new Rectangle(0, 0, Width, Height)); + } + } + finally + { + User32.ReleaseDC(m.HWnd, hDC); + } + } + + protected override void OnResize(EventArgs e) + { + base.OnResize(e); + RedrawBorder(); + } + + private void RedrawBorder() + { + // Force NCPaint update + User32.RedrawWindow(this.Handle, IntPtr.Zero, IntPtr.Zero, + User32.RedrawWindowFlags.Frame | User32.RedrawWindowFlags.Invalidate /*| User32.RedrawWindowFlags.UpdateNow*/); + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTree.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTree.resx new file mode 100644 index 0000000..29dcb1b --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTree.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeNode.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeNode.cs new file mode 100644 index 0000000..0d69747 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeNode.cs @@ -0,0 +1,242 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.Controls +{ + public class KTreeSubNode + { + // TODO: rerender on set + public string Text { get; set; } + + public Control Control { get; set; } + } + + public class KTreeNode : KTreeSubNode + { + #region Children + + private KTreeNodeLoader _childLoader; + + public KTreeNodeLoader ChildLoader + { + get { return _childLoader; } + set + { + if (_childLoader != value) + { + _childLoader = value; + Owner?.OnNodeChildrenChanged(this); + } + } + } + + public KTreeNodes Children + { + get { return _childLoader.Children; } + } + + #endregion + + #region Properties + + public int? ImageIndex { get; set; } + public object Tag { get; set; } + + #endregion + + #region State + + private CheckState _checkState; + internal CheckState CheckStateDirect { get { return _checkState; } set { _checkState = value; } } + public CheckState CheckState + { + get { return _checkState; } + set + { + if (!HasCheckBox) + { + _checkState = value; + return; + } + + if (_checkState != value) + { + KTree owner = Owner; + if (owner != null) + { + owner.CheckManager.SetCheck(this, value); + owner.Rerender(this); + } + else _checkState = value; + + OnCheckStateChanged(); + } + } + } + + public delegate void CheckStateChangedHandler(KTreeNode node); + public event CheckStateChangedHandler CheckStateChanged; + protected virtual void OnCheckStateChanged() + { + if (CheckStateChanged != null) + CheckStateChanged(this); + Owner?.OnCheckStateChanged(this); + } + + public bool IsChecked + { + get { return CheckState == CheckState.Checked; } + set { CheckState = value ? CheckState.Checked : CheckState.Unchecked; } + } + + private bool _hasCheckBox = true; + public bool HasCheckBox + { + get { return _hasCheckBox; } + set + { + if (_hasCheckBox != value) + { + _hasCheckBox = value; + Owner?.Rerender(this); + } + } + } + + private bool _isExpanded; + public bool IsExpanded + { + get { return _isExpanded; } + set + { + if (_isExpanded != value) + { + _isExpanded = value; + if (!_isExpanded) + _childLoader.NodeClosed(); + + if (!_isExpanded || _childLoader.NodeExpanding()) + Owner?.OnNodeExpandedChanged(this); + } + } + } + + public bool ToggleExpanded() + { + IsExpanded = !_isExpanded; + return _isExpanded; + } + + public bool IsSelected + { + get + { + return Owner.SelectedNodes.Contains(this); + } + } + + private bool _isSelectable = true; + + public bool IsSelectable + { + get { return _isSelectable; } + set { _isSelectable = value; } // TODO: update node + } + + public bool IsVisible + { + get + { + for (KTreeNode current = Parent; current != null; current = current.Parent) + { + if (!current.IsExpanded) + return false; + } + return true; + } + } + + + internal KTreeNodes ParentNodes { get; set; } + + public KTreeNode Parent + { + get + { + return ParentNodes?.Parent; + } + } + + public IEnumerable Ancestors + { + get + { + KTreeNode current = Parent; + while (current != null) + { + yield return current; + current = current.Parent; + } + } + } + + public KTree Owner + { + get + { + return ParentNodes?.Owner; + } + } + + public int Depth + { + get + { + int depth = 0; + for (KTreeNode current = Parent; current != null; current = current.Parent) + { + ++depth; + } + return depth; + } + } + + internal KTreeNodeMeasurements EffectiveDimension; + + #endregion + + #region Creation + + public KTreeNode(string text = "", object tag = null) + { + this.Text = text; + this.Tag = tag; + _childLoader = new KTreeNodeLoaderStatic(this); + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeNodeLoader.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeNodeLoader.cs new file mode 100644 index 0000000..6ba4688 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeNodeLoader.cs @@ -0,0 +1,217 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.Controls +{ + public class KTreeNodeLoader + { + public readonly KTreeNodes Children; + + public enum LoadingState + { + NotLoaded, + Loading, + Loaded, + Error + } + + public LoadingState State + { + get; + protected set; + } + + public bool ReloadOnCloseOpen { get; set; } + + public bool NeedsExpander + { + get + { + switch (State) + { + case LoadingState.Loaded: + return Children.Count > 0; + default: + return true; + } + } + } + + public KTreeNodeLoader(KTreeNode parent) + { + Children = new KTreeNodes(parent); + } + + internal void NodeClosed() + { + if (ReloadOnCloseOpen) + State = LoadingState.NotLoaded; + } + + internal bool NodeExpanding() + { + switch (State) + { + case LoadingState.NotLoaded: + case LoadingState.Error: + StartLoadChildren(); + return false; + default: + return true; + } + } + + private void StartLoadChildren() + { + // Set the loading placeholder + State = LoadingState.Loading; + UpdateChildren(null); + + // Load children asynchronously + KTreeNode node = Children.Parent; + OnBeginLoading(node); + KUITask + .New(() => + { + return DoLoadChildren(node); + }) + // Continuation in UI thread + .OnSuccess(result => + { + // Loaded successfully, render + KTreeNodes childrenTemp = new KTreeNodes(node); + DoRenderChildren(node, result, childrenTemp); + State = LoadingState.Loaded; + return childrenTemp; + }, true) + .OnError(error => + { + // On error return an empty node list + State = LoadingState.Error; + return new KTreeNodes(node); + }, true) + .OnCompletion(children => + { + // Update nodes (or plaaceholder) and notify we're done + UpdateChildren(children); + OnEndLoading(node); + }, true) + .Start(); + } + + private KTreeNode _placeholder; + + private void UpdateChildren(KTreeNodes newChildren) + { + Children.Owner?.BeginUpdate(); + try + { + Children.Clear(); + + _placeholder = CreatePlaceholder(State, newChildren); + if (_placeholder != null) + Children.Add(_placeholder); + + if (newChildren != null) + foreach (KTreeNode child in newChildren) + Children.Add(child); + } + finally + { + Children.Owner?.EndUpdate(); + } + } + + protected virtual KTreeNode CreatePlaceholder(LoadingState state, KTreeNodes children) + { + string text = GetPlaceholderText(state, children); + if (string.IsNullOrEmpty(text)) + return null; + + KTreeNode node = new KTreeNode(text); + node.HasCheckBox = false; + node.IsSelectable = false; + return node; + } + + public delegate string PlaceholderTextHandler(KTreeNode node, LoadingState state, KTreeNodes children); + public PlaceholderTextHandler PlaceholderText; + + protected virtual string GetPlaceholderText(LoadingState state, KTreeNodes children) + { + if (PlaceholderText == null) + return null; + return PlaceholderText(Children.Parent, state, children); + } + + public delegate object LoadHandler(KTreeNode node); + public delegate void RenderHandler(KTreeNode node, object loaded, KTreeNodes children); + public LoadHandler LoadChildren; + public RenderHandler RenderChildren; + + virtual protected object DoLoadChildren(KTreeNode node) + { + return LoadChildren(node); + } + + virtual protected void DoRenderChildren(KTreeNode node, object loaded, KTreeNodes children) + { + RenderChildren(node, loaded, children); + } + + public delegate void LoadingHandler(KTreeNode node); + public event LoadingHandler BeginLoading; + public event LoadingHandler EndLoading; + + protected virtual void OnBeginLoading(KTreeNode node) + { + if (BeginLoading != null) + BeginLoading(node); + } + + protected virtual void OnEndLoading(KTreeNode node) + { + if (EndLoading != null) + EndLoading(node); + } + + public void Reload() + { + if (State != LoadingState.Loading) + { + StartLoadChildren(); + } + } + } + + internal class KTreeNodeLoaderStatic : KTreeNodeLoader + { + public KTreeNodeLoaderStatic(KTreeNode owner) + : + base(owner) + { + State = LoadingState.Loaded; + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeNodeMeasurements.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeNodeMeasurements.cs new file mode 100644 index 0000000..b1dabea --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeNodeMeasurements.cs @@ -0,0 +1,157 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.Controls +{ + internal class KTreeNodeMeasurements + { + public enum Part + { + Expander, + CheckBox, + Image, + Text, + Control, + + None + } + + private readonly KTreeNode _node; + private Rectangle _nodeRect; + private readonly KTree _options; + private readonly Padding _paddingOveral; + private readonly Size[] _sizes = new Size[(int)Part.None]; + private readonly Padding[] _paddingInternal = new Padding[(int)Part.None]; + + public KTreeNodeMeasurements(KTreeNode node, KTree options) + { + this._node = node; + this._options = options; + this._nodeRect = new Rectangle(_node.Depth * _options.NodeIndent, 0, 0, 0); + _paddingOveral = options.NodePadding; + } + + private KTreeNodeMeasurements(KTreeNodeMeasurements orig, int x, int y) + { + this._node = orig._node; + this._options = orig._options; + this._paddingOveral = orig._paddingOveral; + this._sizes = (Size[])orig._sizes.Clone(); + + // The node rectangle is the sum of the widths, and the maximum height (plus padding). + // TODO: special handling for control part, make that fit with e.g. a Dock option? + _nodeRect = new Rectangle(orig._nodeRect.X + x, y + orig._nodeRect.Y, + _sizes.Select((i) => i.Width).Sum() + _paddingOveral.Horizontal, + _sizes.Select((i) => i.Height).Max() + _paddingOveral.Vertical); + + for (int i = 0; i < (int)Part.None; ++i) + { + _paddingInternal[i] = new Padding(); + + // Align any parts whose height does not match the total height + if (_sizes[i].Height != InnerRect.Height) + { + _paddingInternal[i].Bottom = (InnerRect.Height - _sizes[i].Height) / 2; + _paddingInternal[i].Top = (InnerRect.Height - _sizes[i].Height) - _paddingInternal[i].Bottom; + + // Quick hack to make sure checkboxes are properly aligned, make the rect square again + // TODO: use padding/dock modes for this + if (i == (int)Part.CheckBox && !_sizes[i].IsEmpty && _sizes[i].IsSquare()) + { + _paddingInternal[i].Left = _paddingInternal[i].Bottom; + _paddingInternal[i].Right = _paddingInternal[i].Top; + } + } + } + } + + public KTreeNodeMeasurements Offset(int x, int y) + { + return new KTreeNodeMeasurements(this, x, y); + } + + public Size this[Part part] + { + get { return _sizes[(int)part]; } + set { _sizes[(int)part] = value; } + } + + public Rectangle NodeRect + { + get + { + return _nodeRect; + } + } + + private Rectangle InnerRect + { + get + { + return _nodeRect.Shrink(_paddingOveral); + } + } + + /// + /// + /// + /// + /// If true, returns the rectangle without padding. Otherwise padding is included. + /// + public Rectangle GetPartRect(Part part, bool inner) + { + Rectangle r = InnerRect; + for (Part i = (Part)0; i < part; ++i) + { + r.Offset(_sizes[(int)i].Width + _paddingInternal[(int)i].Horizontal, 0); + } + r.Width = _sizes[(int)part].Width + _paddingInternal[(int)part].Horizontal; + if (inner) + r = r.Shrink(_paddingInternal[(int)part]); + return r; + } + + public Part? HitTest(int x) + { + // Check the parts + for (Part i = (Part)0; i < Part.None; ++i) + { + // TODO: this could be more efficient, but that requires duplicating the layout logic + if (GetPartRect(i, false).ContainsX(x)) + return i; + } + return Part.None; + } + + public override string ToString() + { + string s = string.Format("Node={0}, Inner={1}", NodeRect, InnerRect); + for(Part part = (Part)0; part < Part.None; ++part) + { + s += string.Format(", {0}={1} ({2}", part, GetPartRect(part, false), _sizes[(int)part]); + } + return s; + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeNodes.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeNodes.cs new file mode 100644 index 0000000..edf0d81 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeNodes.cs @@ -0,0 +1,105 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.Controls +{ + public class KTreeNodes : ICollection + { + private readonly List _items = new List(); + private readonly KTreeNode _parent; + private KTree _owner; + + public KTreeNode Parent { get { return _parent; } } + public KTree Owner + { + get + { + // TODO: this could be cached, but that's tricky with removal of nodes + KTreeNodes current = this; + while (current != null && current._owner == null) + { + current = current._parent.ParentNodes; + } + return current?._owner; + } + } + + internal KTreeNodes(KTreeNode parent) + { + this._parent = parent; + this._owner = null; + } + + internal KTreeNodes(KTree owner) + { + this._parent = null; + this._owner = owner; + } + + public int Count { get{return _items.Count;}} + public bool IsReadOnly { get { return ((ICollection)_items).IsReadOnly; } } + + public void Add(KTreeNode item) + { + _items.Add(item); + item.ParentNodes = this; + Owner?.OnNodeAdded(_parent, item); + } + + public void Clear() + { + Owner?.OnNodeCleared(_parent); + _items.Clear(); + } + + public bool Contains(KTreeNode item) + { + return _items.Contains(item); + } + + public void CopyTo(KTreeNode[] array, int arrayIndex) + { + _items.CopyTo(array, arrayIndex); + } + + public IEnumerator GetEnumerator() + { + return ((ICollection)_items).GetEnumerator(); + } + + public bool Remove(KTreeNode item) + { + if (!_items.Remove(item)) + return false; + Owner?.OnNodeRemoved(_parent, item); + return true; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((ICollection)_items).GetEnumerator(); + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRenderer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRenderer.cs new file mode 100644 index 0000000..ea2a7d3 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRenderer.cs @@ -0,0 +1,173 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Native; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Windows.Forms.VisualStyles; + +namespace Acacia.Controls +{ + internal abstract class KTreeRenderer + { + private Rectangle _clientRect; + private Rectangle _totalRect; + protected KTree _tree; + + public Rectangle TotalRect { get { return _totalRect; } } + + public void Init(Rectangle clientRect, KTree tree) + { + this._clientRect = clientRect; + this._tree = tree; + _totalRect = new Rectangle(0, 0, 0, 0); + } + + #region Measuring + + internal KTreeNodeMeasurements MeasureNode(Graphics graphics, KTreeNode node) + { + // Determine the row rectangle + KTreeNodeMeasurements dims = GetNodeSize(graphics, node).Offset(_totalRect.X, _totalRect.Height); + node.EffectiveDimension = dims; + + // Set up for the next node + _totalRect.Height += dims.NodeRect.Height; + _totalRect.Width = Math.Max(_totalRect.Right, dims.NodeRect.Right) - _totalRect.X; + + return dims; + } + + protected KTreeNodeMeasurements GetNodeSize(Graphics graphics, KTreeNode node) + { + KTreeNodeMeasurements dimension = new KTreeNodeMeasurements(node, _tree); + + // Expander + dimension[KTreeNodeMeasurements.Part.Expander] = GetExpanderSize(graphics, node); + + // Checkbox + if (node.Owner.CheckManager != null && node.HasCheckBox) + { + dimension[KTreeNodeMeasurements.Part.CheckBox] = CheckBoxRenderer.GetGlyphSize(graphics, CheckBoxState.CheckedNormal); + } + + // Image + if (_tree.Images != null) + { + // Image size specified by imagelist + // Scale depending on resolution + dimension[KTreeNodeMeasurements.Part.Image] = _tree.Images.ImageSize.ScaleDpi(graphics); + } + + // Text size + dimension[KTreeNodeMeasurements.Part.Text] = TextRenderer.MeasureText(graphics, node.Text, _tree.Font); + + // Control + if (node.Control != null) + { + dimension[KTreeNodeMeasurements.Part.Control] = node.Control.PreferredSize; + } + + return dimension; + } + + protected abstract Size GetExpanderSize(Graphics graphics, KTreeNode node); + + #endregion + + #region Rendering + + /// + /// + /// + /// The graphics to render into + /// The node + /// The current scrollbar offset + /// If not null, the part of the node that is highlighted. May be Part.None to indicate the row is + /// highlighted, but not a specific part + public void RenderNode(Graphics graphics, KTreeNode node, Point scrollOffset, KTreeNodeMeasurements.Part? highlight) + { + // Make sure the node has been measured + if (node.EffectiveDimension == null) + MeasureNode(graphics, node); + + KTreeNodeMeasurements dims = node.EffectiveDimension.Offset(-scrollOffset.X, -scrollOffset.Y); + + Rectangle containerRect = dims.NodeRect; + containerRect.X = _clientRect.X; + containerRect.Width = Math.Max(_totalRect.Width, _clientRect.Width); + + // Selection background + RenderNodeOutline(graphics, node, _tree.FullRowSelect ? containerRect : dims.NodeRect, highlight); + + // Expander + if (node.ChildLoader.NeedsExpander) + { + RenderNodeExpander(graphics, node, dims.GetPartRect(KTreeNodeMeasurements.Part.Expander, true), highlight); + } + + // Checkbox + if (_tree.CheckManager != null && node.HasCheckBox) + { + RenderCheckBox(graphics, node, dims.GetPartRect(KTreeNodeMeasurements.Part.CheckBox, true), highlight); + } + + // Images + if (_tree.Images != null && node.ImageIndex.HasValue && node.ImageIndex >= 0 && node.ImageIndex < _tree.Images.Images.Count) + { + Rectangle imageRect = dims.GetPartRect(KTreeNodeMeasurements.Part.Image, true); + // TODO: if the rectangle is larger than the image, this probably leads to upscaling. + // if the imagelist stores high-res icons as 16x16, that throws away resolution. + // make a custom image list to handle this? That could also handle scaling automatically + Image image = _tree.Images.Images[node.ImageIndex.Value]; + graphics.DrawImage(image, imageRect.X, imageRect.Y, imageRect.Width, imageRect.Height); + } + + // Text + RenderNodeText(graphics, node, dims.GetPartRect(KTreeNodeMeasurements.Part.Text, true), highlight); + + // Control + if (node.Control != null) + { + node.Control.Bounds = dims.GetPartRect(KTreeNodeMeasurements.Part.Control, true); + } + } + + protected abstract void RenderNodeOutline(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight); + internal protected abstract void RenderNodeExpander(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight); + + protected virtual void RenderCheckBox(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight) + { + int state = (int)node.CheckState * 4 + 1; + if (highlight != null && highlight.Value == KTreeNodeMeasurements.Part.CheckBox) + state += 1; + + CheckBoxRenderer.DrawCheckBox(graphics, rect.Location, (CheckBoxState)state); + } + + protected abstract void RenderNodeText(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight); + + public abstract void RenderControlBorder(Graphics graphics, Rectangle rect); + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRendererDefault.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRendererDefault.cs new file mode 100644 index 0000000..73d5289 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRendererDefault.cs @@ -0,0 +1,93 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Windows.Forms.VisualStyles; + +namespace Acacia.Controls +{ + internal class KTreeRendererDefault : KTreeRenderer + { + private readonly Size _expanderBoxSize = new Size(7, 7); + + protected override Size GetExpanderSize(Graphics graphics, KTreeNode node) + { + return _expanderBoxSize; + } + + internal protected override void RenderNodeExpander(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight) + { + Color color = GetColor(node, highlight); + + using (Pen pen = new Pen(color)) + { + graphics.DrawRectangle(pen, rect.X - 1, rect.Y - 1, _expanderBoxSize.Width + 1, _expanderBoxSize.Height + 1); + int y = rect.Y + rect.Height / 2; + graphics.DrawLine(pen, rect.X + 1, y, rect.Right - 2, y); + + if (!node.IsExpanded) + { + int x = rect.X + rect.Width / 2; + graphics.DrawLine(pen, x, rect.Y + 1, x, rect.Bottom - 2); + } + } + } + + protected override void RenderNodeOutline(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight) + { + + if (highlight != null) + graphics.FillRectangle(SystemBrushes.FromSystemColor(SystemColors.HotTrack), rect); + else if (node.IsSelected) + graphics.FillRectangle(SystemBrushes.FromSystemColor(SystemColors.Highlight), rect); + + if (_tree.ActiveNode == node && !node.IsSelected) + { + graphics.DrawRectangle(SystemPens.FromSystemColor(SystemColors.HotTrack), rect.X, rect.Y, rect.Width - 1, rect.Height - 1); + } + } + + protected override void RenderNodeText(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight) + { + TextRenderer.DrawText(graphics, node.Text, _tree.Font, rect, GetColor(node, highlight), + Color.Transparent, TextFormatFlags.Left | TextFormatFlags.VerticalCenter); + } + + private Color GetColor(KTreeNode node, KTreeNodeMeasurements.Part? highlight) + { + Color color = _tree.ForeColor; + if (node.IsSelected) + color = SystemColors.HighlightText; + else if (highlight != null) + color = Color.White; + return color; + } + + public override void RenderControlBorder(Graphics graphics, Rectangle rect) + { + using (Pen pen = new Pen(_tree.Enabled ? Color.Black : SystemColors.GrayText)) + { + graphics.DrawRectangle(pen, new Rectangle(rect.X, rect.Y, rect.Width - 1, rect.Height - 1)); + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRendererVisualStyles.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRendererVisualStyles.cs new file mode 100644 index 0000000..ca595e3 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRendererVisualStyles.cs @@ -0,0 +1,159 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Native; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Windows.Forms.VisualStyles; + +namespace Acacia.Controls +{ + internal class KTreeRendererVisualStyles : KTreeRenderer + { + // From vsstyle.h + // enum TREEVIEWPARTS + // { + // TVP_TREEITEM = 1, + // TVP_GLYPH = 2, + // TVP_BRANCH = 3, + // TVP_HOTGLYPH = 4, + // }; + // enum TREEITEMSTATES + // { + // TREIS_NORMAL = 1, + // TREIS_HOT = 2, + // TREIS_SELECTED = 3, + // TREIS_DISABLED = 4, + // TREIS_SELECTEDNOTFOCUS = 5, + // TREIS_HOTSELECTED = 6, + // }; + // + // enum GLYPHSTATES + // { + // GLPS_CLOSED = 1, + // GLPS_OPENED = 2, + // }; + private const string TREEVIEW = "Explorer::TreeView"; + + private readonly VisualStyleRenderer _treeViewItemNormal = new VisualStyleRenderer(TREEVIEW, 1, 1); + private readonly VisualStyleRenderer _treeViewItemHot = new VisualStyleRenderer(TREEVIEW, 1, 2); + private readonly VisualStyleRenderer _treeViewItemSelected = new VisualStyleRenderer(TREEVIEW, 1, 3); + private readonly VisualStyleRenderer _treeViewItemDisabled = new VisualStyleRenderer(TREEVIEW, 1, 4); + private readonly VisualStyleRenderer _treeViewItemSelectedNotFocus = new VisualStyleRenderer(TREEVIEW, 1, 5); + private readonly VisualStyleRenderer _treeViewItemHotSelected = new VisualStyleRenderer(TREEVIEW, 1, 6); + private readonly VisualStyleRenderer _treeViewGlyphClosed = new VisualStyleRenderer(TREEVIEW, 2, 1); + private readonly VisualStyleRenderer _treeViewGlyphOpened = new VisualStyleRenderer(TREEVIEW, 2, 2); + private readonly VisualStyleRenderer _treeViewGlyphHotClosed = new VisualStyleRenderer(TREEVIEW, 4, 1); + private readonly VisualStyleRenderer _treeViewGlyphHotOpened = new VisualStyleRenderer(TREEVIEW, 4, 2); + + private Size? _glyphSize; + + protected override Size GetExpanderSize(Graphics graphics, KTreeNode node) + { + // Get glyph size if needed + if (!_glyphSize.HasValue) + _glyphSize = _treeViewGlyphOpened.GetPartSize(graphics, ThemeSizeType.True); + return _glyphSize.Value; + } + + internal protected override void RenderNodeExpander(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight) + { + if (highlight != null && highlight.Value == KTreeNodeMeasurements.Part.Expander) + { + if (node.IsExpanded) + _treeViewGlyphHotOpened.DrawBackground(graphics, rect); + else + _treeViewGlyphHotClosed.DrawBackground(graphics, rect); + } + else + { + if (node.IsExpanded) + _treeViewGlyphOpened.DrawBackground(graphics, rect); + else + _treeViewGlyphClosed.DrawBackground(graphics, rect); + } + } + + private VisualStyleRenderer GetStyle(KTreeNode node, KTreeNodeMeasurements.Part? highlight) + { + if (!_tree.Enabled) + { + return _treeViewItemDisabled; + } + else if (highlight != null) + { + if (node.IsSelected) + return _treeViewItemHotSelected; + else + return _treeViewItemHot; + } + else + { + if (node.IsSelected) + { + if (_tree.Focused) + return _treeViewItemSelected; + else + return _treeViewItemSelectedNotFocus; + } + else + return _treeViewItemNormal; + } + } + + protected override void RenderNodeOutline(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight) + { + // Draw one pixel too far, to overlap top and bottom borders for a continuous selection + + Rectangle highlightRect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height + 1); + if (_tree.ActiveNode == node && _tree.Focused) + { + if (node.IsSelected) + _treeViewItemHotSelected.DrawBackground(graphics, highlightRect); + else + _treeViewItemNormal.DrawBackground(graphics, highlightRect); + } + else if (node.IsSelected || highlight != null) + { + GetStyle(node, highlight).DrawBackground(graphics, highlightRect); + } + } + + protected override void RenderNodeText(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight) + { + Color foreColor = GetStyle(node, highlight).GetColor(ColorProperty.TextColor); + + TextRenderer.DrawText(graphics, node.Text, _tree.Font, rect, foreColor, Color.Transparent, + TextFormatFlags.Left | TextFormatFlags.VerticalCenter); + } + + public override void RenderControlBorder(Graphics graphics, Rectangle rect) + { + Color color = (_tree.Enabled ? _treeViewItemNormal : _treeViewItemDisabled).GetColor(ColorProperty.BorderColor); + using (Pen pen = new Pen(_tree.Enabled ? Color.Black : SystemColors.GrayText)) + { + graphics.DrawRectangle(pen, new Rectangle(rect.X, rect.Y, rect.Width - 1, rect.Height - 1)); + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KUITask.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KUITask.cs new file mode 100644 index 0000000..ee700ea --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KUITask.cs @@ -0,0 +1,570 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.Controls +{ + /// + /// UI progress indicator for tasks. All properties will be accessed in the UI thread. + /// + public interface KUITaskProgress + { + string BusyText { get; set; } + + /// + /// Sets the busy state. + /// + bool Busy { get; set; } + + /// + /// Shows successful completion + /// + void ShowCompletion(string text); + + /// + /// May be set to a cancellation source to allow cancellation. + /// + CancellationTokenSource Cancellation { get; set; } + } + + public interface KUITaskContext + { + CancellationToken CancellationToken { get; } + + /// + /// Adds a number of counts to the busy indicator. Can be invoked from any thread. + /// + /// The number of busy counts to add or subtract + void AddBusy(int count); + + /// + /// Sets the busy text. Can be invoked from any thread. + /// + /// The text + void SetBusyText(string text); + } + + public class KUITaskBase + { + #region Execution state + + internal class ExecutionConfig : KUITaskContext + { + public readonly KUITaskBase Root; + internal readonly ConcurrentDictionary Tasks = new ConcurrentDictionary(); + internal readonly TaskScheduler UIContext; + internal readonly CancellationTokenSource _cancel; + + public ExecutionConfig(KUITaskBase root) + { + this.Root = root; + Tasks.TryAdd(Root, false); + + // Determine the UI context, creating a new one if required + if (SynchronizationContext.Current == null) + SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext()); + UIContext = TaskScheduler.FromCurrentSynchronizationContext(); + + // Create a cancellation source + _cancel = new CancellationTokenSource(); + } + + public CancellationToken CancellationToken { get { return _cancel.Token; } } + + #region Busy indication + + public KUITaskProgress Progress { get; set; } + + private int _busyCount; + public void AddBusy(int count) + { + if (count == 0) + return; + + bool oldBusy = _busyCount != 0; + _busyCount += count; + + bool busy = _busyCount != 0; + if (oldBusy != busy) + { + // TODO: will the synchronisation context always point to the windows forms one, or can someone mess with it? + SynchronizationContext.Current.Send((b) => + { + bool isBusy = (bool)b; + Progress.Busy = isBusy; + if (!isBusy) + Progress.Cancellation = null; + }, busy); + } + } + + public int BusyCount { get { return _busyCount; } } + + public void SetBusyText(string text) + { + SynchronizationContext.Current.Send((t) => + { + Progress.BusyText = (string)t; + }, text); + } + + internal void TaskFinished(KUITaskBase task) + { + Tasks.TryUpdate(task, true, false); + } + + #endregion + } + + internal class ExecutionState + { + public readonly ExecutionConfig Config; + private readonly object _result; + private readonly Exception _exception; + + internal ExecutionState(ExecutionConfig config, object result, Exception exception) + { + this.Config = config; + this._result = result; + this._exception = exception; + } + + internal ExecutionState NewVoid() + { + return new ExecutionState(Config, null, null); + } + + internal ExecutionState NewResult(object result) + { + return new ExecutionState(Config, result, null); + } + + internal ExecutionState NewException(Exception e) + { + return new ExecutionState(Config, null, e); + } + + internal bool HasException + { + get { return _exception != null; } + } + + internal object GetResult(TaskExecutor.Options options) + { + if ((options & TaskExecutor.Options.ErrorOnly) != 0) + return _exception; + else + return _result; + } + } + + #endregion + + #region Executor + + internal protected class TaskExecutor + { + [Flags] + public enum Options + { + None = 0, + UIContext = 1, + ErrorOnly = 2, + SuccessOnly = 4 + } + + private readonly Func _action; + private readonly Options _options; + + internal TaskExecutor(Func action, Options options) + { + this._action = action; + this._options = options; + } + + internal static Options OptionHelper(bool errorOnly, bool successOnly, bool inUI) + { + Options options = Options.None; + if (errorOnly) + options |= Options.ErrorOnly; + if (successOnly) + options |= Options.SuccessOnly; + if (inUI) + options |= Options.UIContext; + return options; + } + + internal Task Execute(KUITaskBase task, ExecutionState state) + { + Func action = () => + { + ExecutionState result = state; + + // TODO: do this outside the task. However, that requires returning some kind of task + bool execute = true; + if ((_options & Options.ErrorOnly) != 0 && !state.HasException) + execute = false; + else if ((_options & Options.SuccessOnly) != 0 && state.HasException) + execute = false; + + // Always clean up one busy count when the task finishes + int busyCountDiff = -1; + if (execute) + { + int busyCountBefore = state.Config.BusyCount; + + try + { + result = _action(state); + } + catch (Exception e) + { + result = state.NewException(e); + + // If there is an exception, restore the busy count + busyCountDiff -= state.Config.BusyCount - busyCountBefore; + } + } + + state.Config.TaskFinished(task); + state.Config.AddBusy(busyCountDiff); + return result; + }; + + return Task.Factory.StartNew(action, state.Config.CancellationToken, TaskCreationOptions.None, GetContext(state)); + } + + private TaskScheduler GetContext(ExecutionState state) + { + return (_options & Options.UIContext) != 0 ? state.Config.UIContext : TaskScheduler.Default; + } + + #region Creators + + // Passes nothing + public static TaskExecutor Void(Action action, Options options) + { + return new TaskExecutor((s) => + { + action(); + return s.NewVoid(); + }, options); + } + public static TaskExecutor Void(Func action, Options options) + { + return new TaskExecutor((s) => + { + ResultType result = action(); + return s.NewResult(result); + }, options); + } + + // Passes the a parameter + public static TaskExecutor Param(Func action, Options options) + { + return new TaskExecutor((s) => + { + ResultType result = action((ParamType)s.GetResult(options)); + return s.NewResult(result); + }, options); + } + public static TaskExecutor Param(Action action, Options options) + { + return new TaskExecutor((s) => + { + action((ParamType)s.GetResult(options)); + return s.NewVoid(); + }, options); + } + + // Passes the task context + public static TaskExecutor TaskContext(Func action, Options options) + { + return new TaskExecutor((s) => + { + ResultType result = action(s.Config); + return s.NewResult(result); + }, options); + } + public static TaskExecutor TaskContext(Action action, Options options) + { + return new TaskExecutor((s) => + { + action(s.Config); + return s.NewVoid(); + }, options); + } + + // Passes the task context and a parameter + public static TaskExecutor TaskContextParam(Func action, Options options) + { + return new TaskExecutor((s) => + { + ResultType result = action(s.Config, (ParamType)s.GetResult(options)); + return s.NewResult(result); + }, options); + } + public static TaskExecutor TaskContextParam(Action action, Options options) + { + return new TaskExecutor((s) => + { + action(s.Config, (ParamType)s.GetResult(options)); + return s.NewVoid(); + }, options); + } + + #endregion + } + + #endregion + + protected readonly TaskExecutor _executor; + private ExecutionConfig _config; + private readonly Mutex _mutexTask = new Mutex(); + private Task _task; + private readonly List _next = new List(); + + protected KUITaskBase(TaskExecutor exec, bool isRoot) + { + this._executor = exec; + this._config = isRoot ? new ExecutionConfig(this) : null; + } + + public void Start(KUITaskProgress progress = null) + { + _config.Progress = progress ?? new DummyTaskProgress(); + _config.Progress.Cancellation = _config._cancel; + _config.AddBusy(_config.Tasks.Count); + + // Execute the root + _config.Root.DoStart(new ExecutionState(_config, null, null)); + } + + private void DoStart(ExecutionState state) + { + // Make sure we're not already started + if (_task != null) + throw new InvalidOperationException("Task chain already started"); + + // Start the task + _mutexTask.WaitOne(); + try + { + _task = _executor.Execute(this, state); + + // TODO: this could probably be outside the mutex + foreach (KUITaskBase next in _next) + AddContinuation(next); + } + finally + { + _mutexTask.ReleaseMutex(); + } + } + + protected TaskType Chain(TaskType next) + where TaskType : KUITaskBase + { + next._config = _config; + _config.Tasks.TryAdd(next, false); + + _mutexTask.WaitOne(); + try + { + // If the task is already started (or finished), add a chainer to that + // Otherwise, add it to the list + if (_task == null) + { + this._next.Add(next); + } + else + { + AddContinuation(next); + } + } + finally + { + _mutexTask.ReleaseMutex(); + } + return next; + } + + private void AddContinuation(KUITaskBase next) + { + // Start a synchronous task, the KUITask will detach if needed + _task.ContinueWith((prevTask) => + { + next.DoStart(prevTask.Result); + }, _config.CancellationToken, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.NotOnCanceled, + TaskScheduler.Current); + } + } + + internal class DummyTaskProgress : KUITaskProgress + { + public bool Busy + { + get; + set; + } + + public string BusyText + { + get; + set; + } + + public CancellationTokenSource Cancellation + { + get; + set; + } + + public void ShowCompletion(string text) + { + } + } + + /// + /// Wrapper class for a chain of tasks with UI feedback + /// + /// + public class KUITask : KUITaskBase + { + internal protected KUITask(TaskExecutor exec, bool isRoot) : base(exec, isRoot) + { + } + + #region Chainers + + /// + /// Invoked on either success or error. + /// + public KUITask OnCompletion(Action func, bool inUI = false) + { + return Chain(new KUITask(TaskExecutor.Param(func, TaskExecutor.OptionHelper(false, false, inUI)), false)); + } + + // OnSuccess - Can either return nothing or a new result type (which could of course happen to be + // the current. + // Can accept Context and the current task result + + public KUITask OnSuccess(Action func, bool inUI = false) + { + return Chain(new KUITask(TaskExecutor.Void(func, TaskExecutor.OptionHelper(false, true, inUI)), false)); + } + + public KUITask OnSuccess(Action func, bool inUI = false) + { + return Chain(new KUITask(TaskExecutor.TaskContext(func, TaskExecutor.OptionHelper(false, true, inUI)), false)); + } + + public KUITask OnSuccess(Action func, bool inUI = false) + { + return Chain(new KUITask(TaskExecutor.TaskContextParam(func, TaskExecutor.OptionHelper(false, true, inUI)), false)); + } + + public KUITask OnSuccess(Func func, bool inUI = false) + { + return Chain(new KUITask(TaskExecutor.Param(func, TaskExecutor.OptionHelper(false, true, inUI)), false)); + } + + // OnError - Can either return nothing, or the already expected return type. This allows an OnCompletion + // handler accepting either a result, or a dummy result returned by the error handler + // TODO: accept Context + + public KUITask OnError(Func func, bool inUI = true) + { + return Chain(new KUITask(TaskExecutor.Param(func, TaskExecutor.OptionHelper(true, false, inUI)), false)); + } + + public KUITask OnError(Action func, bool inUI = true) + { + return Chain(new KUITask(TaskExecutor.Param(func, TaskExecutor.OptionHelper(true, false, inUI)), false)); + } + + #endregion + } + + public class KUITask : KUITaskBase + { + internal protected KUITask(TaskExecutor exec, bool isRoot) : base(exec, isRoot) + { + } + + #region Chainers + + public KUITask OnError(Action func, bool inUI = true) + { + return Chain(new KUITask(TaskExecutor.Param(func, TaskExecutor.OptionHelper(true, false, inUI)), false)); + } + + public KUITask OnSuccess(Action func, bool inUI = false) + { + return Chain(new KUITask(TaskExecutor.Void(func, TaskExecutor.OptionHelper(false, true, inUI)), false)); + } + + public KUITask OnSuccess(Action func, bool inUI = false) + { + return Chain(new KUITask(TaskExecutor.TaskContext(func, TaskExecutor.OptionHelper(false, true, inUI)), false)); + } + + #endregion + + #region Factory methods + + public static KUITask New(Action action) + { + return new KUITask(TaskExecutor.TaskContext(action, TaskExecutor.Options.None), true); + } + + public static KUITask New(Action action) + { + throw new NotImplementedException(); + } + + public static KUITask New(Func action) + { + return new KUITask(TaskExecutor.TaskContext(action, TaskExecutor.Options.None), true); + } + + public static KUITask New(Func action) + { + return new KUITask(TaskExecutor.Void(action, TaskExecutor.Options.None), true); + } + + #endregion + } + + public interface KUITaskExecutor + { + /// + /// Executes a task + /// + /// The text to display while the task is busy + /// The action + /// A task for the action + KUITask Execute(string busyText, Func action); + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KUIUtil.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KUIUtil.cs new file mode 100644 index 0000000..9e9eb86 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KUIUtil.cs @@ -0,0 +1,80 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.Controls +{ + internal static class KUIUtil + { + #region Geometry + + public static Rectangle Center(this Rectangle _this, Size size) + { + int x = _this.X + (_this.Width - size.Width) / 2; + int y = _this.Y + (_this.Height - size.Height) / 2; + return new Rectangle(x, y, size.Width, size.Height); + } + + public static Rectangle Expand(this Rectangle _this, Padding padding) + { + Rectangle r = _this; + r.X -= padding.Left; + r.Y -= padding.Top; + r.Width += padding.Horizontal; + r.Height += padding.Vertical; + return r; + } + + public static Rectangle Shrink(this Rectangle _this, Padding padding) + { + Rectangle r = _this; + r.X += padding.Left; + r.Y += padding.Top; + r.Width -= padding.Horizontal; + r.Height -= padding.Vertical; + return r; + } + + public static bool ContainsX(this Rectangle _this, int x) + { + return (x >= _this.X && x < _this.Right); + } + + public static bool ContainsY(this Rectangle _this, int y) + { + return (y >= _this.Y && y < _this.Bottom); + } + + public static bool IsSquare(this Size _this) + { + return _this.Width == _this.Height; + } + + public static Size ScaleDpi(this Size _this, Graphics graphics) + { + return new Size((int)(_this.Width * graphics.DpiX / 96), (int)(_this.Height * graphics.DpiY / 96)); + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/DebugOptions.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/DebugOptions.cs new file mode 100644 index 0000000..a5b468c --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/DebugOptions.cs @@ -0,0 +1,224 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Utils; +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Acacia +{ + public static class DebugOptions + { + abstract public class Option + { + public readonly string Token; + + public Option(string token) + { + this.Token = token; + } + + abstract public string GetToken(ValueType value); + abstract public ValueType GetValue(string value); + } + + public class BoolOption : Option + { + public readonly bool Inverse; + + public BoolOption(string token, bool inverse) + : + base(inverse ? "-" + token : (token.Length == 0 ? "+" : token)) + { + this.Inverse = inverse; + } + + public override string GetToken(bool value) + { + if (Inverse) + value = !value; + if (value) + return Token; + else + return null; + } + + public override bool GetValue(string value) + { + bool enabled = value == Token; + if (Inverse) + enabled = !enabled; + return enabled; + } + } + + public class EnumOption : Option + { + private EnumType DefaultValue + { + get + { + return (EnumType)typeof(EnumType).GetEnumValues().GetValue(0); + } + } + + public EnumOption(string token) + : + base(token) + { + } + + public override string GetToken(EnumType value) + { + if (value.Equals(DefaultValue)) + return null; + return Token + "=" + value.ToString(); + } + + public override EnumType GetValue(string value) + { + if (string.IsNullOrEmpty(value)) + return DefaultValue; + else + { + if (value.ToLower().StartsWith(Token.ToLower() + "=")) + value = value.Substring(Token.Length + 1); + return (EnumType)Enum.Parse(typeof(EnumType), value, true); + } + } + + } + + public class TimeSpanOption : Option + { + private readonly TimeSpan _defaultValue; + + public TimeSpanOption(string token, TimeSpan defaultValue) + : + base(token) + { + this._defaultValue = defaultValue; + } + + public override string GetToken(TimeSpan value) + { + if (value.Equals(_defaultValue)) + return null; + return Token + "=" + value.ToString(); + } + + public override TimeSpan GetValue(string value) + { + if (string.IsNullOrEmpty(value)) + return _defaultValue; + else + { + if (value.ToLower().StartsWith(Token.ToLower() + "=")) + value = value.Substring(Token.Length + 1); + return TimeSpan.Parse(value); + } + } + + } + + // General + public static readonly BoolOption ENABLED = new BoolOption("", true); + public static readonly BoolOption FEATURE_DISABLED_DEFAULT = new BoolOption("", false); + public static readonly BoolOption OUTLOOK_UI = new BoolOption("UI", true); + public static readonly BoolOption OUTLOOK_UI_RIBBON = new BoolOption("Ribbon", true); + public static readonly BoolOption OUTLOOK_UI_CONTEXT_MENU = new BoolOption("ContextMenu", true); + public static readonly BoolOption WATCHER_ENABLED = new BoolOption("Watcher", true); + + /// + /// Allows all options to return defaults, for testing + /// + public static bool ReturnDefaults + { + get; + set; + } + + /// + /// The threading model + /// + public enum Threading + { + MainThread, + Background, + Synchronous + } + + #region Access methods + + public static string GetOptions(string prefix) + { + if (ReturnDefaults) + return null; + + return RegistryUtil.GetConfigValue(prefix, null, null); + } + + public static ValueType GetOption(string prefix, Option option) + { + // Parse the options + Dictionary tokens = ParseTokens(prefix); + string value; + tokens.TryGetValue(option.Token.ToLower(), out value); + return option.GetValue(value); + } + + private static Dictionary ParseTokens(string prefix) + { + Dictionary tokens = new Dictionary(); + string value = GetOptions(prefix); + if (!string.IsNullOrEmpty(value)) + { + foreach (string token in value.Split(',')) + { + if (!string.IsNullOrEmpty(token)) + { + string[] keyVal = token.Split(new[] { '=' }, 2); + if (!string.IsNullOrEmpty(keyVal[0])) + { + tokens[keyVal[0].ToLower()] = token; + } + } + } + } + return tokens; + } + + public static void SetOption(string prefix, Option option, ValueType value) + { + Dictionary tokens = ParseTokens(prefix); + + // Update the token + string token = option.GetToken(value); + if (token != null) + tokens[option.Token.ToLower()] = token; + else + tokens.Remove(option.Token.ToLower()); + + // Write to registry + string newValue = string.Join(",", tokens.Values); + RegistryUtil.SetConfigValue(prefix, null, newValue, RegistryValueKind.String); + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/AboutDialog.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/AboutDialog.Designer.cs new file mode 100644 index 0000000..27a9e0e --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/AboutDialog.Designer.cs @@ -0,0 +1,192 @@ +namespace Acacia.Features.DebugSupport +{ + partial class AboutDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AboutDialog)); + this._layout = new System.Windows.Forms.TableLayoutPanel(); + this._layoutForm = new System.Windows.Forms.TableLayoutPanel(); + this.labelDateValue = new Acacia.Controls.KCopyLabel(); + this.labelRevisionValue = new Acacia.Controls.KCopyLabel(); + this.icon = new System.Windows.Forms.PictureBox(); + this.labelTitle = new System.Windows.Forms.Label(); + this.labelVersionCaption = new Acacia.Controls.KCopyLabel(); + this.labelRevisionCaption = new Acacia.Controls.KCopyLabel(); + this.richTextBox1 = new System.Windows.Forms.RichTextBox(); + this.labelDateCaption = new Acacia.Controls.KCopyLabel(); + this.linkKopano = new System.Windows.Forms.LinkLabel(); + this.labelVersionValue = new Acacia.Controls.KCopyLabel(); + this._buttons = new Acacia.Controls.KDialogButtons(); + this._layout.SuspendLayout(); + this._layoutForm.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.icon)).BeginInit(); + this.SuspendLayout(); + // + // _layout + // + resources.ApplyResources(this._layout, "_layout"); + this._layout.Controls.Add(this._layoutForm, 0, 0); + this._layout.Controls.Add(this._buttons, 0, 1); + this._layout.Name = "_layout"; + // + // _layoutForm + // + resources.ApplyResources(this._layoutForm, "_layoutForm"); + this._layoutForm.Controls.Add(this.labelDateValue, 1, 4); + this._layoutForm.Controls.Add(this.labelRevisionValue, 1, 3); + this._layoutForm.Controls.Add(this.icon, 0, 0); + this._layoutForm.Controls.Add(this.labelTitle, 1, 0); + this._layoutForm.Controls.Add(this.labelVersionCaption, 0, 2); + this._layoutForm.Controls.Add(this.labelRevisionCaption, 0, 3); + this._layoutForm.Controls.Add(this.richTextBox1, 0, 6); + this._layoutForm.Controls.Add(this.labelDateCaption, 0, 4); + this._layoutForm.Controls.Add(this.linkKopano, 1, 1); + this._layoutForm.Controls.Add(this.labelVersionValue, 1, 2); + this._layoutForm.Name = "_layoutForm"; + // + // labelDateValue + // + this.labelDateValue.BorderStyle = System.Windows.Forms.BorderStyle.None; + resources.ApplyResources(this.labelDateValue, "labelDateValue"); + this.labelDateValue.Name = "labelDateValue"; + this.labelDateValue.ReadOnly = true; + this.labelDateValue.TabStop = false; + // + // labelRevisionValue + // + this.labelRevisionValue.BorderStyle = System.Windows.Forms.BorderStyle.None; + resources.ApplyResources(this.labelRevisionValue, "labelRevisionValue"); + this.labelRevisionValue.Name = "labelRevisionValue"; + this.labelRevisionValue.ReadOnly = true; + this.labelRevisionValue.TabStop = false; + // + // icon + // + resources.ApplyResources(this.icon, "icon"); + this.icon.Name = "icon"; + this.icon.TabStop = false; + // + // labelTitle + // + resources.ApplyResources(this.labelTitle, "labelTitle"); + this.labelTitle.Name = "labelTitle"; + // + // labelVersionCaption + // + this.labelVersionCaption.BorderStyle = System.Windows.Forms.BorderStyle.None; + resources.ApplyResources(this.labelVersionCaption, "labelVersionCaption"); + this.labelVersionCaption.Name = "labelVersionCaption"; + this.labelVersionCaption.ReadOnly = true; + this.labelVersionCaption.TabStop = false; + // + // labelRevisionCaption + // + this.labelRevisionCaption.BorderStyle = System.Windows.Forms.BorderStyle.None; + resources.ApplyResources(this.labelRevisionCaption, "labelRevisionCaption"); + this.labelRevisionCaption.Name = "labelRevisionCaption"; + this.labelRevisionCaption.ReadOnly = true; + this.labelRevisionCaption.TabStop = false; + // + // richTextBox1 + // + this.richTextBox1.BorderStyle = System.Windows.Forms.BorderStyle.None; + this._layoutForm.SetColumnSpan(this.richTextBox1, 2); + resources.ApplyResources(this.richTextBox1, "richTextBox1"); + this.richTextBox1.Name = "richTextBox1"; + this.richTextBox1.ReadOnly = true; + this.richTextBox1.LinkClicked += new System.Windows.Forms.LinkClickedEventHandler(this.richTextBox1_LinkClicked); + // + // labelDateCaption + // + this.labelDateCaption.BorderStyle = System.Windows.Forms.BorderStyle.None; + resources.ApplyResources(this.labelDateCaption, "labelDateCaption"); + this.labelDateCaption.Name = "labelDateCaption"; + this.labelDateCaption.ReadOnly = true; + this.labelDateCaption.TabStop = false; + // + // linkKopano + // + resources.ApplyResources(this.linkKopano, "linkKopano"); + this.linkKopano.Name = "linkKopano"; + this.linkKopano.TabStop = true; + this.linkKopano.VisitedLinkColor = System.Drawing.Color.Blue; + this.linkKopano.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkKopano_LinkClicked); + // + // labelVersionValue + // + this.labelVersionValue.BorderStyle = System.Windows.Forms.BorderStyle.None; + resources.ApplyResources(this.labelVersionValue, "labelVersionValue"); + this.labelVersionValue.Name = "labelVersionValue"; + this.labelVersionValue.ReadOnly = true; + this.labelVersionValue.TabStop = false; + // + // _buttons + // + resources.ApplyResources(this._buttons, "_buttons"); + this._buttons.ButtonSize = null; + this._buttons.Cancellation = null; + this._buttons.HasApply = false; + this._buttons.IsDirty = false; + this._buttons.Name = "_buttons"; + // + // AboutDialog + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this._layout); + this.MinimizeBox = false; + this.Name = "AboutDialog"; + this.ShowInTaskbar = false; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show; + this.TopMost = true; + this._layout.ResumeLayout(false); + this._layout.PerformLayout(); + this._layoutForm.ResumeLayout(false); + this._layoutForm.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.icon)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel _layout; + private System.Windows.Forms.TableLayoutPanel _layoutForm; + private Controls.KDialogButtons _buttons; + private System.Windows.Forms.PictureBox icon; + private System.Windows.Forms.Label labelTitle; + private Controls.KCopyLabel labelVersionCaption; + private Controls.KCopyLabel labelDateValue; + private Controls.KCopyLabel labelRevisionValue; + private Controls.KCopyLabel labelRevisionCaption; + private Controls.KCopyLabel labelDateCaption; + private System.Windows.Forms.LinkLabel linkKopano; + private System.Windows.Forms.RichTextBox richTextBox1; + private Controls.KCopyLabel labelVersionValue; + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/AboutDialog.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/AboutDialog.cs new file mode 100644 index 0000000..81fee1f --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/AboutDialog.cs @@ -0,0 +1,59 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Utils; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Diagnostics; +using System.Drawing; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Collections; +using Acacia.ZPush; +using System.Reflection; +using Acacia.UI; +using Acacia.Controls; + +namespace Acacia.Features.DebugSupport +{ + public partial class AboutDialog : KDialogNew + { + + public AboutDialog() + { + InitializeComponent(); + icon.Image = Properties.Resources.Kopano.ToBitmap(); + labelVersionValue.Text = BuildVersions.VERSION; + labelRevisionValue.Text = BuildVersions.REVISION; + labelDateValue.Text = LibUtils.BuildTime.ToString(); + } + + private void linkKopano_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + System.Diagnostics.Process.Start(linkKopano.Text); + } + + private void richTextBox1_LinkClicked(object sender, LinkClickedEventArgs e) + { + System.Diagnostics.Process.Start(e.LinkText); + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/AboutDialog.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/AboutDialog.resx new file mode 100644 index 0000000..94107b3 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/AboutDialog.resx @@ -0,0 +1,525 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 1 + + + 2 + + + + Fill + + + NoControl + + + + 73, 132 + + + 355, 15 + + + 7 + + + labelDateValue + + + Acacia.Controls.KCopyLabel, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null + + + _layoutForm + + + 0 + + + Fill + + + NoControl + + + 73, 111 + + + 355, 15 + + + 6 + + + labelRevisionValue + + + Acacia.Controls.KCopyLabel, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null + + + _layoutForm + + + 1 + + + Fill + + + 3, 3 + + + 64, 64 + + + AutoSize + + + 0 + + + icon + + + System.Windows.Forms.PictureBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutForm + + + 2 + + + True + + + Fill + + + Microsoft Sans Serif, 16.2pt + + + 73, 0 + + + 355, 70 + + + 1 + + + Kopano OL Extension + + + MiddleLeft + + + labelTitle + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutForm + + + 3 + + + 3, 90 + + + 56, 15 + + + 1 + + + Version + + + labelVersionCaption + + + Acacia.Controls.KCopyLabel, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null + + + _layoutForm + + + 4 + + + NoControl + + + 3, 111 + + + 62, 15 + + + 4 + + + Revision + + + labelRevisionCaption + + + Acacia.Controls.KCopyLabel, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null + + + _layoutForm + + + 5 + + + Fill + + + 3, 173 + + + 425, 272 + + + 9 + + + Copyright 2016 Kopano b.v. + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License, version 3, as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/> + + + richTextBox1 + + + System.Windows.Forms.RichTextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutForm + + + 6 + + + 3, 132 + + + 38, 15 + + + 5 + + + Date + + + labelDateCaption + + + Acacia.Controls.KCopyLabel, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null + + + _layoutForm + + + 7 + + + True + + + 73, 70 + + + 132, 17 + + + 8 + + + https://kopano.com/ + + + linkKopano + + + System.Windows.Forms.LinkLabel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutForm + + + 8 + + + Fill + + + 73, 90 + + + 355, 15 + + + 10 + + + labelVersionValue + + + Acacia.Controls.KCopyLabel, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null + + + _layoutForm + + + 9 + + + Fill + + + 3, 3 + + + 7 + + + 431, 448 + + + 0 + + + _layoutForm + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layout + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelDateValue" Row="4" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="labelRevisionValue" Row="3" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="icon" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="labelTitle" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="labelVersionCaption" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="labelRevisionCaption" Row="3" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="richTextBox1" Row="6" RowSpan="1" Column="0" ColumnSpan="2" /><Control Name="labelDateCaption" Row="4" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="linkKopano" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="labelVersionValue" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,Absolute,20,Percent,100" /></TableLayoutSettings> + + + True + + + GrowAndShrink + + + Fill + + + 3, 456 + + + 3, 2, 3, 2 + + + 431, 39 + + + 1 + + + _buttons + + + Acacia.Controls.KDialogButtons, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null + + + _layout + + + 1 + + + Fill + + + 8, 7 + + + 2 + + + 437, 497 + + + 0 + + + _layout + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_layoutForm" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="_buttons" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,100" /><Rows Styles="Percent,100,AutoSize,0" /></TableLayoutSettings> + + + True + + + 8, 16 + + + True + + + 453, 511 + + + 8, 7, 8, 7 + + + CenterParent + + + About Kopano OL Extenion + + + AboutDialog + + + Acacia.Controls.KDialogNew, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.Designer.cs new file mode 100644 index 0000000..280828f --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.Designer.cs @@ -0,0 +1,126 @@ +namespace Acacia.Features.DebugSupport +{ + partial class DebugDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DebugDialog)); + this.tableMain = new System.Windows.Forms.TableLayoutPanel(); + this.flowButtons = new System.Windows.Forms.FlowLayoutPanel(); + this.buttonGC = new System.Windows.Forms.Button(); + this.buttonRefresh = new System.Windows.Forms.Button(); + this.buttonClose = new System.Windows.Forms.Button(); + this.buttonLog = new System.Windows.Forms.Button(); + this.Properties = new System.Windows.Forms.PropertyGrid(); + this.tableMain.SuspendLayout(); + this.flowButtons.SuspendLayout(); + this.SuspendLayout(); + // + // tableMain + // + resources.ApplyResources(this.tableMain, "tableMain"); + this.tableMain.Controls.Add(this.flowButtons, 0, 1); + this.tableMain.Controls.Add(this.Properties, 0, 0); + this.tableMain.Name = "tableMain"; + // + // flowButtons + // + resources.ApplyResources(this.flowButtons, "flowButtons"); + this.flowButtons.Controls.Add(this.buttonGC); + this.flowButtons.Controls.Add(this.buttonRefresh); + this.flowButtons.Controls.Add(this.buttonClose); + this.flowButtons.Controls.Add(this.buttonLog); + this.flowButtons.Name = "flowButtons"; + // + // buttonGC + // + resources.ApplyResources(this.buttonGC, "buttonGC"); + this.buttonGC.Name = "buttonGC"; + this.buttonGC.UseVisualStyleBackColor = true; + this.buttonGC.Click += new System.EventHandler(this.buttonGC_Click); + // + // buttonRefresh + // + resources.ApplyResources(this.buttonRefresh, "buttonRefresh"); + this.buttonRefresh.Name = "buttonRefresh"; + this.buttonRefresh.UseVisualStyleBackColor = true; + this.buttonRefresh.Click += new System.EventHandler(this.buttonRefresh_Click); + // + // buttonClose + // + resources.ApplyResources(this.buttonClose, "buttonClose"); + this.buttonClose.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonClose.Name = "buttonClose"; + this.buttonClose.UseVisualStyleBackColor = true; + this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click); + // + // buttonLog + // + resources.ApplyResources(this.buttonLog, "buttonLog"); + this.buttonLog.Name = "buttonLog"; + this.buttonLog.UseVisualStyleBackColor = true; + this.buttonLog.Click += new System.EventHandler(this.buttonLog_Click); + // + // Properties + // + resources.ApplyResources(this.Properties, "Properties"); + this.Properties.DisabledItemForeColor = System.Drawing.SystemColors.ControlText; + this.Properties.Name = "Properties"; + this.Properties.PropertySort = System.Windows.Forms.PropertySort.Categorized; + this.Properties.ToolbarVisible = false; + // + // DebugDialog + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.buttonClose; + this.Controls.Add(this.tableMain); + this.MinimizeBox = false; + this.Name = "DebugDialog"; + this.ShowInTaskbar = false; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show; + this.TopMost = true; + this.tableMain.ResumeLayout(false); + this.tableMain.PerformLayout(); + this.flowButtons.ResumeLayout(false); + this.flowButtons.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableMain; + private System.Windows.Forms.FlowLayoutPanel flowButtons; + private System.Windows.Forms.Button buttonGC; + private System.Windows.Forms.PropertyGrid Properties; + private System.Windows.Forms.Button buttonRefresh; + private System.Windows.Forms.Button buttonClose; + private System.Windows.Forms.Button buttonLog; + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.cs new file mode 100644 index 0000000..8b057dc --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.cs @@ -0,0 +1,117 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Utils; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Diagnostics; +using System.Drawing; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Collections; +using Acacia.ZPush; +using System.Reflection; +using Acacia.UI; + +namespace Acacia.Features.DebugSupport +{ + public partial class DebugDialog : KopanoDialog + { + + public DebugDialog() + { + InitializeComponent(); + Properties.SelectedObject = new DebugInfo(); + } + + private void UpdateFields() + { + Properties.Refresh(); + } + + #region Logging + + private const string INDENT = "+"; + + private void ToLog() + { + // Create a new property grid and expand it, to access all items + // This beats implementing the property logic to fetch all of item. + PropertyGrid grid = new PropertyGrid(); + grid.SelectedObject = Properties.SelectedObject; + grid.ExpandAllGridItems(); + object view = grid.GetType().GetField("gridView", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(grid); + + // Log each category recursively + GridItemCollection items = (GridItemCollection)view.GetType().InvokeMember("GetAllGridEntries", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, view, null); + foreach(GridItem item in items) + { + if (item.GridItemType == GridItemType.Category) + { + LogItem(item, string.Empty); + } + } + } + + private void LogItem(GridItem item, string indent) + { + if (item.GridItemType == GridItemType.Category) + Logger.Instance.Info(this, "{0}{1}", indent, item.Label.Trim()); + else + Logger.Instance.Info(this, "{0}{1}={2}", indent, item.Label.Trim(), item.Value); + foreach(GridItem child in item.GridItems) + { + LogItem(child, indent + INDENT); + } + } + + #endregion + + #region Event handlers + + private void buttonGC_Click(object sender, EventArgs e) + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + GC.WaitForPendingFinalizers(); + + UpdateFields(); + } + + private void buttonRefresh_Click(object sender, EventArgs e) + { + UpdateFields(); + } + + private void buttonClose_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void buttonLog_Click(object sender, EventArgs e) + { + ToLog(); + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.resx new file mode 100644 index 0000000..547d1a0 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.resx @@ -0,0 +1,375 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Top, Bottom, Left, Right + + + + True + + + GrowAndShrink + + + 1 + + + Top, Bottom, Left, Right + + + True + + + True + + + + 352, 4 + + + 4, 4, 4, 4 + + + 91, 33 + + + 0 + + + Run GC + + + buttonGC + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + flowButtons + + + 0 + + + True + + + 253, 4 + + + 4, 4, 4, 4 + + + 91, 33 + + + 1 + + + Refresh + + + buttonRefresh + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + flowButtons + + + 1 + + + True + + + 145, 4 + + + 4, 4, 4, 4 + + + 100, 33 + + + 2 + + + Close + + + buttonClose + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + flowButtons + + + 2 + + + True + + + 62, 4 + + + 4, 4, 4, 4 + + + 75, 33 + + + 3 + + + Log + + + buttonLog + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + flowButtons + + + 3 + + + RightToLeft + + + 3, 470 + + + 3, 2, 3, 2 + + + 447, 41 + + + 1 + + + flowButtons + + + System.Windows.Forms.FlowLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableMain + + + 0 + + + Top, Bottom, Left, Right + + + False + + + 3, 2 + + + 3, 2, 3, 2 + + + 447, 464 + + + 2 + + + Properties + + + System.Windows.Forms.PropertyGrid, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableMain + + + 1 + + + 0, 0 + + + 3, 2, 3, 2 + + + 2 + + + 453, 513 + + + 0 + + + tableMain + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="flowButtons" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="Properties" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,100" /><Rows Styles="Percent,100,AutoSize,0" /></TableLayoutSettings> + + + True + + + 8, 16 + + + True + + + 453, 511 + + + 3, 2, 3, 2 + + + CenterParent + + + Debug + + + DebugDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugInfo.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugInfo.cs new file mode 100644 index 0000000..8bbb2c9 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugInfo.cs @@ -0,0 +1,278 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Utils; +using Acacia.ZPush; +using Microsoft.Office.Core; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Features.DebugSupport +{ + public enum DebugCategory + { + Version, + Memory, + Wrappers, + Misc, + System, + Accounts, + Features, + AddIns + } + + public class DebugCategoryAttribute : CategoryAttribute + { + // Add tabs; these are not printed, but are used for the sorting + public DebugCategoryAttribute(DebugCategory order) + : + base(order.ToString().PadLeft(typeof(DebugCategory).GetEnumNames().Length - (int)order + order.ToString().Length, '\t')) + { + + } + } + + public class DebugInfoConverter : ExpandableObjectConverter + { + private class CustomPropertyDescriptor : PropertyDescriptor + { + private readonly TProperty value; + + public CustomPropertyDescriptor(string propertyName, DebugCategory category, TProperty value) + : base(propertyName, new Attribute[] { new DebugCategoryAttribute(category) }) + { + this.value = value; + } + + public override bool CanResetValue(object component) { return false; } + public override Type ComponentType { get { return typeof(TComponent); } } + public override object GetValue(object component) { return value; } + public override bool IsReadOnly { get { return true; } } + public override Type PropertyType { get { return typeof(TProperty); } } + public override void ResetValue(object component) { SetValue(component, null); } + public override void SetValue(object component, object value) { } + public override bool ShouldSerializeValue(object component) { return false; } + } + + + public override bool GetPropertiesSupported(ITypeDescriptorContext context) + { + return true; + } + + public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) + { + PropertyDescriptorCollection properties = new PropertyDescriptorCollection(base.GetProperties(context, value, attributes).Cast().ToArray()); + + DebugInfo info = value as DebugInfo; + if (info != null) + { + // Add accounts + foreach (ZPushAccount account in ThisAddIn.Instance.Watcher.Accounts.GetAccounts()) + { + PropertyDescriptor p = new CustomPropertyDescriptor(account.DisplayName, DebugCategory.Accounts, account); + properties.Add(p); + } + + // Add Features + foreach (Feature feature in ThisAddIn.Instance.Features) + { + PropertyDescriptor p = new CustomPropertyDescriptor(feature.Name, DebugCategory.Features, feature); + properties.Add(p); + } + + // Add Add-ins + foreach (COMAddIn addin in ThisAddIn.Instance.Application.COMAddIns) + { + PropertyDescriptor p = new CustomPropertyDescriptor(addin.ProgId, DebugCategory.AddIns, addin.Description); + properties.Add(p); + } + } + + return properties; + } + } + + [TypeConverter(typeof(DebugInfoConverter))] + class DebugInfo + { + #region Version + + [DebugCategory(DebugCategory.Version)] + public string Version { get { return BuildVersions.VERSION; } } + [DebugCategory(DebugCategory.Version)] + public string Revision { get { return BuildVersions.REVISION; } } + [DebugCategory(DebugCategory.Version)] + public string BuildDate { get { return LibUtils.BuildTime.ToString(); } } + + #endregion + + #region Memory + + [DebugCategory(DebugCategory.Memory)] + public string TotalMemory { get { return MemoryToString(GC.GetTotalMemory(false)); } } + + #endregion + + #region Wrappers + + [DebugCategory(DebugCategory.Wrappers)] + public long ActiveWrappers { get { return Statistics.CreatedWrappers - Statistics.DeletedWrappers; } } + [DebugCategory(DebugCategory.Wrappers)] + public long CreatedWrappers { get { return Statistics.CreatedWrappers; } } + [DebugCategory(DebugCategory.Wrappers)] + public long DeletedWrappers { get { return Statistics.DeletedWrappers; } } + [DebugCategory(DebugCategory.Wrappers)] + public long DisposedWrappers { get { return Statistics.DisposedWrappers; } } + [DebugCategory(DebugCategory.Wrappers)] + public long UndisposedWrappers { get { return Statistics.DeletedWrappers - Statistics.DisposedWrappers; } } + + #endregion + + #region Misc + + [DebugCategory(DebugCategory.Misc)] + public string StartupTime { get { return TimeToString(Statistics.StartupTime); } } + + [DebugCategory(DebugCategory.Misc)] + public LogLevel LogLevel + { + get { return Logger.Instance.MinLevel; } + set + { + Logger.Instance.SetLevel(value); + } + } + + [DebugCategory(DebugCategory.Misc)] + public string Threading + { + get { return Tasks.Executor.Name; } + } + + [DebugCategory(DebugCategory.Misc)] + public bool ZPushSync + { + get { return ThisAddIn.Instance.Watcher.Sync.Enabled; } + } + + [DebugCategory(DebugCategory.Misc)] + public TimeSpan ZPushSyncPeriod + { + get { return ThisAddIn.Instance.Watcher.Sync.Period; } + } + + [DebugCategory(DebugCategory.Misc)] + public string Build + { + get + { +#if DEBUG + return "Debug"; +#else + return "Release"; +#endif + } + } + +#endregion + + #region System + + [DebugCategory(DebugCategory.System)] + public string Locale + { + get + { + return CultureInfo.CurrentUICulture.DisplayName; + } + } + + [DebugCategory(DebugCategory.System)] + public string WindowsVersion + { + get + { + return Environment.OSVersion.Version.ToString(); + } + } + + [DebugCategory(DebugCategory.System)] + public string Architecture + { + get + { + return Environment.Is64BitOperatingSystem ? "64 bit" : "32 bit"; + } + } + + #endregion + +#region Outlook + + [DebugCategory(DebugCategory.System)] + public string OutlookVersion + { + get + { + return ThisAddIn.Instance.Application.Version; + } + } + + [DebugCategory(DebugCategory.System)] + public string OutlookArchitecture + { + get + { + return Environment.Is64BitProcess ? "64 bit" : "32 bit"; + } + } + +#endregion + +#region Helpers + + private string TimeToString(Stopwatch time) + { + return time.ElapsedMilliseconds.ToString("#### ms"); + } + + private static readonly string[] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; + + private string MemoryToString(long value) + { + if (value < 0) { return "-" + MemoryToString(-value); } + + int i = 0; + decimal dValue = (decimal)value; + while (Math.Round(dValue / 1024) >= 1) + { + dValue /= 1024; + i++; + } + + return string.Format("{0:n1} {1}", dValue, SizeSuffixes[i]); + } + +#endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugSupportSettings.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugSupportSettings.Designer.cs new file mode 100644 index 0000000..8bfe434 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugSupportSettings.Designer.cs @@ -0,0 +1,89 @@ +namespace Acacia.Features.DebugSupport +{ + partial class DebugSupportSettings + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DebugSupportSettings)); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.labelLogLevel = new System.Windows.Forms.Label(); + this.comboLogLevel = new System.Windows.Forms.ComboBox(); + this.buttonShowLog = new System.Windows.Forms.Button(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // tableLayoutPanel1 + // + resources.ApplyResources(this.tableLayoutPanel1, "tableLayoutPanel1"); + this.tableLayoutPanel1.BackColor = System.Drawing.SystemColors.Window; + this.tableLayoutPanel1.Controls.Add(this.labelLogLevel, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.comboLogLevel, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.buttonShowLog, 0, 1); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + // + // labelLogLevel + // + resources.ApplyResources(this.labelLogLevel, "labelLogLevel"); + this.labelLogLevel.Name = "labelLogLevel"; + // + // comboLogLevel + // + resources.ApplyResources(this.comboLogLevel, "comboLogLevel"); + this.comboLogLevel.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboLogLevel.FormattingEnabled = true; + this.comboLogLevel.Name = "comboLogLevel"; + this.comboLogLevel.SelectedIndexChanged += new System.EventHandler(this.comboLogLevel_SelectedIndexChanged); + // + // buttonShowLog + // + resources.ApplyResources(this.buttonShowLog, "buttonShowLog"); + this.tableLayoutPanel1.SetColumnSpan(this.buttonShowLog, 2); + this.buttonShowLog.Name = "buttonShowLog"; + this.buttonShowLog.UseVisualStyleBackColor = true; + this.buttonShowLog.Click += new System.EventHandler(this.buttonShowLog_Click); + // + // DebugSupportSettings + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tableLayoutPanel1); + this.Name = "DebugSupportSettings"; + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label labelLogLevel; + private System.Windows.Forms.ComboBox comboLogLevel; + private System.Windows.Forms.Button buttonShowLog; + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugSupportSettings.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugSupportSettings.cs new file mode 100644 index 0000000..c00670e --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugSupportSettings.cs @@ -0,0 +1,68 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using Acacia.UI; + +namespace Acacia.Features.DebugSupport +{ + public partial class DebugSupportSettings : FeatureSettings + { + private readonly FeatureDebugSupport _feature; + public override Feature Feature + { + get + { + return _feature; + } + } + + public DebugSupportSettings(FeatureDebugSupport feature = null) + { + this._feature = feature; + + InitializeComponent(); + + for (int i = 0; i < typeof(LogLevel).GetEnumNames().Length; ++i) + comboLogLevel.Items.Add((LogLevel)i); + comboLogLevel.SelectedItem = Logger.Instance.MinLevel; + } + + private void buttonShowLog_Click(object sender, EventArgs e) + { + if (_feature != null) + _feature.ShowLog(); + } + + private void comboLogLevel_SelectedIndexChanged(object sender, EventArgs e) + { + Dirty = Logger.Instance.MinLevel != (LogLevel)comboLogLevel.SelectedItem; + } + + public override void Apply() + { + Logger.Instance.SetLevel((LogLevel)comboLogLevel.SelectedItem); + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugSupportSettings.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugSupportSettings.resx new file mode 100644 index 0000000..831f1fd --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugSupportSettings.resx @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Top, Left, Right + + + + True + + + 2 + + + True + + + Fill + + + + 3, 0 + + + 53, 27 + + + 0 + + + Log level: + + + MiddleLeft + + + labelLogLevel + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel1 + + + 0 + + + Top, Bottom, Left, Right + + + 62, 3 + + + 281, 21 + + + 1 + + + comboLogLevel + + + System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel1 + + + 1 + + + True + + + 3, 35 + + + 3, 8, 8, 3 + + + 8, 0, 8, 0 + + + 132, 23 + + + 2 + + + Open log file location + + + buttonShowLog + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel1 + + + 2 + + + 0, 0 + + + 2 + + + 346, 63 + + + 0 + + + tableLayoutPanel1 + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelLogLevel" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="comboLogLevel" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="buttonShowLog" Row="1" RowSpan="1" Column="0" ColumnSpan="2" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0" /></TableLayoutSettings> + + + True + + + 6, 13 + + + True + + + 349, 66 + + + DebugSupportSettings + + + Acacia.UI.FeatureSettings, ZPush, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/FeatureDebugSupport.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/FeatureDebugSupport.cs new file mode 100644 index 0000000..8730652 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/FeatureDebugSupport.cs @@ -0,0 +1,122 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using Acacia.Features.ReplyFlags; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Acacia.Utils; +using System.Threading; +using System.Windows.Forms; +using System.Runtime.InteropServices; +using Acacia.UI; +using Acacia.ZPush; +using Acacia.UI.Outlook; + +namespace Acacia.Features.DebugSupport +{ + [AcaciaOption("Contains features to enable support and debugging of the plugin.")] + public class FeatureDebugSupport : Feature, FeatureWithRibbon + { + public FeatureDebugSupport() + { + + } + + public override void Startup() + { + RegisterButton(this, "About", false, ShowAbout); + if (Dialog) + RegisterButton(this, "Debug", false, ShowDialog); + RegisterButton(this, "Settings", false, ShowSettings); + } + + #region About dialog + + public void ShowAbout() + { + new AboutDialog().ShowDialog(); + } + + #endregion + + #region Debug options + + private static readonly DebugOptions.BoolOption OPTION_DIALOG = new DebugOptions.BoolOption("Dialog", false); + + [AcaciaOption("Enables the debug dialog")] + public bool Dialog + { + get { return GetOption(OPTION_DIALOG); } + set { SetOption(OPTION_DIALOG, value); } + } + + #endregion + + #region Settings + + public void ShowSettings() + { + new SettingsDialog().ShowDialog(); + } + + public override FeatureSettings GetSettings() + { + return new DebugSupportSettings(this); + } + + #endregion + + #region Debug dialog + + private void ShowDialog() + { + new DebugDialog().Show(); + } + + #endregion + + #region Log + + public void ShowLog() + { + if (Logger.Instance.Path != null) + { + // This is roughly equivalent to starting explorer with /select, but has + // the benefit of reusing windows if it's done multiple times + IntPtr pidl = ILCreateFromPathW(Logger.Instance.Path); + SHOpenFolderAndSelectItems(pidl, 0, IntPtr.Zero, 0); + ILFree(pidl); + } + } + + + [DllImport("shell32.dll", CharSet = CharSet.Unicode)] + private static extern IntPtr ILCreateFromPathW(string pszPath); + + [DllImport("shell32.dll")] + private static extern int SHOpenFolderAndSelectItems(IntPtr pidlFolder, int cild, IntPtr apidl, int dwFlags); + + [DllImport("shell32.dll")] + private static extern void ILFree(IntPtr pidl); + + #endregion + + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/FeatureObjectConverter.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/FeatureObjectConverter.cs new file mode 100644 index 0000000..4ddca7c --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/FeatureObjectConverter.cs @@ -0,0 +1,44 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Features.DebugSupport +{ + /// + /// Object converter for a feature in the debug dialog. + /// + public class FeatureObjectConverter : ExpandableObjectConverter + { + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(string) && value is Feature) + return ((Feature)value).ToDebugString(); + return base.ConvertTo(context, culture, value, destinationType); + } + + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + return false; + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/Statistics.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/Statistics.cs new file mode 100644 index 0000000..a1fcf69 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/Statistics.cs @@ -0,0 +1,33 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Features.DebugSupport +{ + public static class Statistics + { + public static long CreatedWrappers; + public static long DeletedWrappers; + public static long DisposedWrappers; + public static Stopwatch StartupTime = new Stopwatch(); + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Feature.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Feature.cs new file mode 100644 index 0000000..afc0d80 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Feature.cs @@ -0,0 +1,259 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Acacia.UI; +using Acacia.Utils; +using System.Windows.Forms; +using Acacia.ZPush; +using System.ComponentModel; +using Acacia.Features.DebugSupport; +using Microsoft.Win32; +using Acacia.UI.Outlook; +using Acacia.Stubs; + +namespace Acacia.Features +{ + /// + /// A feature represents a modular piece of functionality that can be enabled in the plugin. + /// As all hooks must be registered from the same callback (Startup in ThisAddIn), the + /// Feature class is used to allow modules to register their hooks. + /// + [TypeConverter(typeof(FeatureObjectConverter))] + abstract public class Feature : LogContext + { + public readonly string Name; + + protected Feature() + { + this.Name = GetFeatureName(GetType()); + } + + [Browsable(false)] + public string DisplayName + { + get { return StringUtil.GetResourceString("Feature_" + Name); } + } + + public virtual FeatureSettings GetSettings() + { + return null; + } + + protected static Microsoft.Office.Interop.Outlook.Application App + { + get { return ThisAddIn.Instance.Application; } + } + + #region Debug options + + public static string GetFeatureName(Type featureType) + { + return featureType.Name.StripPrefix("Feature"); + } + + public static string GetDebugTokens(Type featureType) + { + return DebugOptions.GetOptions(GetFeatureName(featureType)); + } + + public static bool IsEnabled(Type featureType) + { + bool defaultEnabled = !typeof(FeatureDisabled).IsAssignableFrom(featureType); + return DebugOptions.GetOption(GetFeatureName(featureType), + defaultEnabled ? DebugOptions.ENABLED : DebugOptions.FEATURE_DISABLED_DEFAULT); + } + + public ValueType GetOption(DebugOptions.Option option) + { + return DebugOptions.GetOption(Name, option); + } + + public static ValueType GetOption(Type featureType, DebugOptions.Option option) + { + return DebugOptions.GetOption(GetFeatureName(featureType), option); + } + + public void SetOption(DebugOptions.Option option, ValueType value) + { + DebugOptions.SetOption(Name, option, value); + } + + public static void SetOption(Type featureType, DebugOptions.Option option, ValueType value) + { + DebugOptions.SetOption(GetFeatureName(featureType), option, value); + } + + [AcaciaOption("Completely enables or disables the feature. Note that if the feature is enabled, it's components may still be disabled")] + virtual public bool Enabled + { + get { return GetOption(DebugOptions.ENABLED); } + set { SetOption(DebugOptions.ENABLED, value); } + } + + #endregion + + #region Outlook UI + + /// + /// Returns the Outlook UI. May be null if modifications to the UI are disabled. + /// + private OutlookUI OutlookUI + { + get { return ThisAddIn.Instance.OutlookUI; } + } + + /// + /// Helper which registers only if allowed through options + /// + /// + public RibbonButton RegisterButton(FeatureWithRibbon feature, string id, bool large, System.Action callback, + ZPushBehaviour zpushBehaviour = ZPushBehaviour.None) + { + if (OutlookUI == null || !UI_Ribbon || !GlobalOptions.INSTANCE.UI_Ribbon) + return null; + + return OutlookUI.Register(new RibbonButton(feature, id, large, callback, zpushBehaviour)); + } + + public RibbonToggleButton RegisterToggleButton(FeatureWithRibbon feature, string id, bool large, System.Action callback, + ZPushBehaviour zpushBehaviour = ZPushBehaviour.None) + { + if (OutlookUI == null || !UI_Ribbon || !GlobalOptions.INSTANCE.UI_Ribbon) + return null; + + return OutlookUI.Register(new RibbonToggleButton(feature, id, large, callback, zpushBehaviour)); + } + + public MenuItem RegisterMenuItem(FeatureWithContextMenu feature, string id, string menuId, System.Action callback, + ZPushBehaviour zpushBehaviour = ZPushBehaviour.None) + where ItemType : IBase + { + if (OutlookUI == null || !UI_ContextMenu || !GlobalOptions.INSTANCE.UI_ContextMenu) + return null; + + if (menuId == null) + menuId = GetDefaultMenuId(); + return OutlookUI.Register(new MenuItem(feature, id, menuId, callback, zpushBehaviour)); + } + + private string GetDefaultMenuId() + where ItemType : IBase + { + if (typeof(ItemType) == typeof(IFolder)) + return "ContextMenuFolder"; + else + throw new System.Exception("Unknown context menu: " + typeof(ItemType)); + } + + [AcaciaOption("Enables or disables modifications to the Outlook UI for this feature." + + "Note that where applicable, the Ribbon and Context Menu options also control UI modifications.", + Interface = typeof(FeatureWithUI))] + virtual public bool UI + { + get { return GetOption(DebugOptions.OUTLOOK_UI); } + set { SetOption(DebugOptions.OUTLOOK_UI, value); } + } + + [AcaciaOption("Enables or disables modifications to the Outlook Ribbon for this feature." + + "Note that if the UI option is disabled, Ribbon modifications will not be made either.", + Interface = typeof(FeatureWithRibbon))] + virtual public bool UI_Ribbon + { + get { return GetOption(DebugOptions.OUTLOOK_UI_RIBBON); } + set { SetOption(DebugOptions.OUTLOOK_UI_RIBBON, value); } + } + + [AcaciaOption("Enables or disables modifications to the Outlook Context Menus for this feature." + + "Note that if the UI option is disabled, Context Menu modifications will not be made either.", + Interface = typeof(FeatureWithContextMenu))] + virtual public bool UI_ContextMenu + { + get { return GetOption(DebugOptions.OUTLOOK_UI_CONTEXT_MENU); } + set { SetOption(DebugOptions.OUTLOOK_UI_CONTEXT_MENU, value); } + } + + #endregion + + #region Event helpers + + private static MailEvents _mailEvents; + protected static MailEvents MailEvents + { + get + { + if (_mailEvents == null) + _mailEvents = new MailEvents(App); + return _mailEvents; + } + } + + protected ZPushWatcher Watcher + { + get + { + return ThisAddIn.Instance.Watcher; + } + } + + #endregion + + #region Startup + + /// + /// Invoked when the feature is started. The application object is accessible through + /// App + /// + public virtual void Startup() + { + + } + + #endregion + + #region Z-Push channels + + private static ZPushChannels _zPushChannels; + protected static ZPushChannels ZPushChannels + { + get + { + if (_zPushChannels == null) + _zPushChannels = new ZPushChannels(ThisAddIn.Instance.Watcher); + return _zPushChannels; + } + } + + #endregion + + #region Debug support + + [Browsable(false)] + public string LogContextId { get { return Name; } } + + public virtual string ToDebugString() + { + return ""; + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FeatureDisabled.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FeatureDisabled.cs new file mode 100644 index 0000000..13ffb27 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FeatureDisabled.cs @@ -0,0 +1,41 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Features +{ + /// + /// Base class for a feature that is disabled unless specifically enabled + /// + abstract public class FeatureDisabled : Feature + { + #region Debug options + + [AcaciaOption("Completely enables or disables the feature. Note that if the feature is enabled, it's components may still be disabled")] + override public bool Enabled + { + get { return GetOption(DebugOptions.FEATURE_DISABLED_DEFAULT); } + set { SetOption(DebugOptions.FEATURE_DISABLED_DEFAULT, value); } + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FeatureWithUI.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FeatureWithUI.cs new file mode 100644 index 0000000..2908c33 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FeatureWithUI.cs @@ -0,0 +1,32 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Features +{ + /// + /// Marker interfaces for features that display UIs. Implementing these interfaces automatically adds the + /// debug options to control the UI. + /// + public interface FeatureWithUI : LogContext {} + public interface FeatureWithRibbon : FeatureWithUI { }; + public interface FeatureWithContextMenu : FeatureWithUI { }; +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Features.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Features.cs new file mode 100644 index 0000000..a90ee32 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Features.cs @@ -0,0 +1,40 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Features +{ + public static class Features + { + public static readonly Type[] FEATURES = + { + typeof(ReplyFlags.FeatureReplyFlags), + typeof(OutOfOffice.FeatureOutOfOffice), + typeof(SharedFolders.FeatureSharedFolders), + typeof(WebApp.FeatureWebApp), + typeof(FreeBusy.FeatureFreeBusy), + typeof(GAB.FeatureGAB), + typeof(Notes.FeatureNotes), + typeof(SendAs.FeatureSendAs), + typeof(DebugSupport.FeatureDebugSupport) + }; + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FeatureFreeBusy.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FeatureFreeBusy.cs new file mode 100644 index 0000000..f9fb908 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FeatureFreeBusy.cs @@ -0,0 +1,210 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Features.GAB; +using Acacia.Stubs; +using Acacia.UI; +using Acacia.Utils; +using Acacia.ZPush; +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.Features.FreeBusy +{ + [AcaciaOption("Provides free/busy information on users in the Global Adress Book to schedule meetings.")] + public class FeatureFreeBusy : Feature + { + public FeatureFreeBusy() + { + } + + public override void Startup() + { + Thread thread = new Thread(() => + { + try + { + Worker(); + } + catch (System.Exception e) + { + Logger.Instance.Error(this, "Unhandled exception: {0}", e); + } + }); + thread.Name = "FreeBusy"; + thread.Start(); + } + + #region Settings + + public override FeatureSettings GetSettings() + { + return new FreeBusySettings(this); + } + + public ZPushAccounts Accounts + { + get { return Watcher.Accounts; } + } + + private const string REG_DOGABLOOKUP = "GABLookup"; + private const string REG_DEFAULTACCOUNT = "Default"; + + public bool DoGABLookup + { + get + { + return RegistryUtil.GetConfigValue(Name, REG_DOGABLOOKUP, 1) != 0; + } + set + { + RegistryUtil.SetConfigValue(Name, REG_DOGABLOOKUP, value ? 1 : 0, RegistryValueKind.DWord); + } + } + + public ZPushAccount DefaultAccount + { + get + { + string val = RegistryUtil.GetConfigValue(Name, REG_DEFAULTACCOUNT, null); + if (!string.IsNullOrEmpty(val)) + { + ZPushAccount account = Accounts.GetAccount(val); + if (account != null) + return account; + } + + // Fall back to the first one + return Accounts.GetAccounts().FirstOrDefault(); + } + + set + { + RegistryUtil.SetConfigValue(Name, REG_DEFAULTACCOUNT, value == null ? "" : value.SmtpAddress, RegistryValueKind.String); + } + } + + #endregion + + private const string REG_KEY = @"Options\Calendar\Internet Free/Busy"; + private const string REG_VALUE = @"Read URL"; + internal const string URL_IDENTIFIER = "/zpush/"; + private const int DEFAULT_PORT = 18632; + private const string URL_PREFIX = @"http://127.0.0.1:{0}" + URL_IDENTIFIER; + private const string URL = URL_PREFIX + "%NAME%@%SERVER%"; + + private void Worker() + { + Port = DEFAULT_PORT; + + // Register URL + using (RegistryKey key = OutlookRegistryUtils.OpenOutlookKey(REG_KEY, Microsoft.Win32.RegistryKeyPermissionCheck.ReadWriteSubTree)) + { + if (key != null) + { + string oldURL = key.GetValueString(REG_VALUE); + if (string.IsNullOrWhiteSpace(oldURL) || oldURL.Contains(URL_IDENTIFIER)) + key.SetValue(REG_VALUE, string.Format(URL, Port)); + } + } + + FreeBusyServer server = new FreeBusyServer(this); + + // Run + TcpListener listener = new TcpListener(IPAddress.Loopback, Port); + listener.Start(); + for (;;) + { + Interlocked.Increment(ref _iterationCount); + try + { + for (;;) + { + // Wait for a connection + TcpClient client = listener.AcceptTcpClient(); + Interlocked.Increment(ref _requestCount); + // And handle it in the UI thread to allow GAB access + Tasks.Task(this, "FreeBusyHandler", () => server.HandleRequest(client)); + } + } + catch (Exception e) + { + Logger.Instance.Error(this, "Error in FreeBusy server: {0}", e); + } + } + } + + #region Debug + + public int Port { get; private set; } + + private long _requestCount; + public long RequestCount + { + get { return Interlocked.Read(ref _requestCount); } + } + + private long _iterationCount; + public long IterationCount + { + get { return Interlocked.Read(ref _iterationCount); } + } + + #endregion + + + internal ZPushAccount FindZPushAccount(string username) + { + // Search through GABs + if (DoGABLookup) + { + FeatureGAB gab = ThisAddIn.Instance.GetFeature(); + if (gab != null) + { + foreach (GABHandler handler in gab.GABHandlers) + { + ZPushAccount account = handler.ActiveAccount; + if (account != null && handler.Contacts != null) + { + // Look for the email address. If found, use the account associated with the GAB + ISearch search = handler.Contacts.Search(); + search.AddField("urn:schemas:contacts:email1").SetOperation(SearchOperation.Equal, username); + using (IItem result = search.SearchOne()) + { + if (result != null) + return account; + } + } + } + } + } + + // Fall back to default account + return DefaultAccount; + } + + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FreeBusyServer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FreeBusyServer.cs new file mode 100644 index 0000000..e5265c0 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FreeBusyServer.cs @@ -0,0 +1,158 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Features.GAB; +using Acacia.Stubs; +using Acacia.Utils; +using Acacia.ZPush; +using Acacia.ZPush.Connect; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Sockets; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Acacia.Features.FreeBusy +{ + public class FreeBusyServer + { + private readonly FeatureFreeBusy _freeBusy; + private readonly int _port; + private readonly Regex _httpRequest; + + public FreeBusyServer(FeatureFreeBusy freeBusy) + { + this._freeBusy = freeBusy; + this._port = freeBusy.Port; + this._httpRequest = new Regex(@"^GET " + FeatureFreeBusy.URL_IDENTIFIER + @"([^ ]+) HTTP/(\d.\d)$"); + } + + public void HandleRequest(TcpClient client) + { + try + { + using (client) + { + StreamWriter writer = new StreamWriter(client.GetStream()); + StreamReader reader = new StreamReader(client.GetStream()); + try + { + // Read the request + string s = reader.ReadLine(); + Match m = _httpRequest.Match(s); + if (!m.Success) + { + Logger.Instance.Trace(this, "Invalid request: {0}", s); + throw new InvalidOperationException(); + } + string username = m.Groups[1].Value; + Logger.Instance.Trace(this, "REQUEST: {0} -> {1}, {2}", s, m.Groups[1], m.Groups[2]); + + // Headers + for (;;) + { + s = reader.ReadLine(); + if (string.IsNullOrEmpty(s)) + break; + } + + // Write response + FetchData(username, writer); + } + catch (InvalidOperationException) + { + writer.Write("HTTP/1.0 404 Not found\r\nConnection: close\r\n\r\n"); + } + catch (Exception e) + { + Logger.Instance.Error(this, "Error in FreeBusy worker: {0}", e); + writer.Write("HTTP/1.0 404 Not found\r\nConnection: close\r\n\r\n"); + } + writer.Flush(); + } + } + catch(Exception e) + { + Logger.Instance.Error(this, "Error in FreeBusy worker: {0}", e); + } + } + + private void FetchData(string username, StreamWriter output) + { + // Request the data from the ZPush server + ZPushConnection connection = new ZPushConnection(_freeBusy.FindZPushAccount(username), new System.Threading.CancellationToken(false)); + + // Include yesterday in the request, outlook shows it by default + var request = new ActiveSync.ResolveRecipientsRequest(username, + DateTime.Today.AddDays(-1), + DateTime.Today.AddMonths(6)); + var response = connection.Execute(request); + + // If there is no FreeBusy data, return 404 + if (response?.FreeBusy == null) + { + throw new InvalidOperationException(); + } + + Logger.Instance.Trace(this, "Writing response"); + // Encode the response in vcard format + output.WriteLine("HTTP/1.0 200 OK"); + output.WriteLine("Content-Type: text/vcard"); + output.WriteLine("Connection: close"); + output.WriteLine(""); + + + output.WriteLine("BEGIN:VCALENDAR"); + output.WriteLine("PRODID:-//ZPush//EN"); + output.WriteLine("VERSION:2.0"); + output.WriteLine("BEGIN:VFREEBUSY"); + output.WriteLine("ORGANIZER:" + username); + output.WriteLine(string.Format("URL:http://127.0.0.1:{0}{1}{2}", _port, FeatureFreeBusy.URL_IDENTIFIER, username)); + output.WriteLine(string.Format("DTSTAMP:{0:" + Constants.DATE_ISO_8601 + "}", DateTime.Now)); + output.WriteLine(string.Format("DTSTART:{0:" + Constants.DATE_ISO_8601 + "}", response.FreeBusy.StartTime)); + output.WriteLine(string.Format("DTEND:{0:" + Constants.DATE_ISO_8601 + "}", response.FreeBusy.EndTime)); + + foreach(ActiveSync.FreeBusyData data in response.FreeBusy) + { + if (data.Type != ActiveSync.FreeBusyType.Free) + { + string freeBusy = string.Format("FREEBUSY;FBTYPE={2}:{0:" + Constants.DATE_ISO_8601 + "}/{1:" + Constants.DATE_ISO_8601 + "}", + data.Start, data.End, MapType(data.Type)); + output.WriteLine(freeBusy); + } + } + + output.WriteLine("END:VFREEBUSY"); + output.WriteLine("END:VCALENDAR"); + } + + private object MapType(ActiveSync.FreeBusyType type) + { + switch(type) + { + case ActiveSync.FreeBusyType.Free: return "FREE"; + case ActiveSync.FreeBusyType.Busy: return "BUSY"; + case ActiveSync.FreeBusyType.Tentative: return "BUSY-TENTATIVE"; + case ActiveSync.FreeBusyType.OutOfOffice: return "BUSY-UNAVAILABLE"; + default: + return "BUSY"; + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FreeBusySettings.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FreeBusySettings.Designer.cs new file mode 100644 index 0000000..71c6a46 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FreeBusySettings.Designer.cs @@ -0,0 +1,89 @@ +namespace Acacia.Features.FreeBusy +{ + partial class FreeBusySettings + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FreeBusySettings)); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.checkGABLookup = new System.Windows.Forms.CheckBox(); + this.labelUseAccount = new System.Windows.Forms.Label(); + this.comboDefaultAccount = new System.Windows.Forms.ComboBox(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // tableLayoutPanel1 + // + resources.ApplyResources(this.tableLayoutPanel1, "tableLayoutPanel1"); + this.tableLayoutPanel1.Controls.Add(this.checkGABLookup, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.labelUseAccount, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.comboDefaultAccount, 1, 1); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + // + // checkGABLookup + // + resources.ApplyResources(this.checkGABLookup, "checkGABLookup"); + this.tableLayoutPanel1.SetColumnSpan(this.checkGABLookup, 2); + this.checkGABLookup.Name = "checkGABLookup"; + this.checkGABLookup.UseVisualStyleBackColor = true; + this.checkGABLookup.CheckedChanged += new System.EventHandler(this.checkGABLookup_CheckedChanged); + // + // labelUseAccount + // + resources.ApplyResources(this.labelUseAccount, "labelUseAccount"); + this.labelUseAccount.Name = "labelUseAccount"; + // + // comboDefaultAccount + // + resources.ApplyResources(this.comboDefaultAccount, "comboDefaultAccount"); + this.comboDefaultAccount.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboDefaultAccount.FormattingEnabled = true; + this.comboDefaultAccount.Name = "comboDefaultAccount"; + this.comboDefaultAccount.SelectedIndexChanged += new System.EventHandler(this.comboDefaultAccount_SelectedIndexChanged); + // + // FreeBusySettings + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.SystemColors.Window; + this.Controls.Add(this.tableLayoutPanel1); + this.Name = "FreeBusySettings"; + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.CheckBox checkGABLookup; + private System.Windows.Forms.Label labelUseAccount; + private System.Windows.Forms.ComboBox comboDefaultAccount; + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FreeBusySettings.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FreeBusySettings.cs new file mode 100644 index 0000000..d897505 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FreeBusySettings.cs @@ -0,0 +1,81 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using Acacia.ZPush; +using Acacia.UI; + +namespace Acacia.Features.FreeBusy +{ + public partial class FreeBusySettings : FeatureSettings + { + private readonly FeatureFreeBusy _feature; + public override Feature Feature + { + get + { + return _feature; + } + } + + public FreeBusySettings(FeatureFreeBusy feature = null) + { + this._feature = feature; + + InitializeComponent(); + + // Allow null feature for designer + if (feature != null) + { + checkGABLookup.Checked = feature.DoGABLookup; + + foreach (ZPushAccount account in feature.Accounts.GetAccounts()) + comboDefaultAccount.Items.Add(account); + comboDefaultAccount.SelectedItem = feature.DefaultAccount; + } + } + + override public void Apply() + { + _feature.DefaultAccount = (ZPushAccount)comboDefaultAccount.SelectedItem; + _feature.DoGABLookup = checkGABLookup.Checked; + } + + private void CheckDirty() + { + Dirty = checkGABLookup.Checked != _feature.DoGABLookup || + comboDefaultAccount.SelectedItem != _feature.DefaultAccount; + } + + private void checkGABLookup_CheckedChanged(object sender, EventArgs e) + { + CheckDirty(); + } + + private void comboDefaultAccount_SelectedIndexChanged(object sender, EventArgs e) + { + CheckDirty(); + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FreeBusySettings.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FreeBusySettings.resx new file mode 100644 index 0000000..7c1d1b3 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/FreeBusy/FreeBusySettings.resx @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + True + + + + GrowAndShrink + + + 2 + + + True + + + + 2, 2 + + + 2, 2, 2, 2 + + + 222, 17 + + + 0 + + + Look up contacts in Global Address Book + + + checkGABLookup + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel1 + + + 0 + + + Top, Bottom, Left + + + True + + + 2, 30 + + + 2, 0, 2, 0 + + + 74, 30 + + + 1 + + + Use account: + + + MiddleLeft + + + labelUseAccount + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel1 + + + 1 + + + Top, Bottom, Left, Right + + + 80, 32 + + + 2, 2, 2, 2 + + + 172, 21 + + + 2 + + + comboDefaultAccount + + + System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel1 + + + 2 + + + Fill + + + 0, 0 + + + 2, 2, 2, 2 + + + 2 + + + 254, 60 + + + 0 + + + tableLayoutPanel1 + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="checkGABLookup" Row="0" RowSpan="1" Column="0" ColumnSpan="2" /><Control Name="labelUseAccount" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="comboDefaultAccount" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="Percent,50,Percent,50" /></TableLayoutSettings> + + + True + + + 6, 13 + + + True + + + 2, 2, 2, 2 + + + 254, 60 + + + FreeBusySettings + + + Acacia.UI.FeatureSettings, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/ChunkIndex.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/ChunkIndex.cs new file mode 100644 index 0000000..c7cb0bd --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/ChunkIndex.cs @@ -0,0 +1,52 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Acacia.Features.GAB +{ + struct ChunkIndex + { + private static readonly Regex RE = new Regex(@"^account-(\d+)/(\d+)$"); + public int numberOfChunks; + public int chunk; + + public static ChunkIndex? Parse(string s) + { + try + { + Match match = RE.Match(s); + if (!match.Success) + return null; + + return new ChunkIndex() + { + numberOfChunks = int.Parse(match.Groups[1].Value), + chunk = int.Parse(match.Groups[2].Value) + }; + } + catch (Exception) + { + return null; + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs new file mode 100644 index 0000000..c932342 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs @@ -0,0 +1,626 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Acacia.Stubs; +using Acacia.Stubs.OutlookWrappers; +using System.Threading; +using System.Collections.Concurrent; +using Acacia.ZPush; +using Acacia.Utils; +using System.ComponentModel; +using System.Windows.Forms; +using Acacia.UI; +using static Acacia.DebugOptions; + +namespace Acacia.Features.GAB +{ + [AcaciaOption("Provides a Global Address Book for Z-Push accounts.")] + public class FeatureGAB : Feature + { + private readonly Dictionary _gabsByDomainName = new Dictionary(); + private readonly HashSet _gabFolders = new HashSet(); + private readonly HashSet _domains = new HashSet(); + private ZPushLocalStore _store; + private int _processing; + + public FeatureGAB() + { + } + + public static GABHandler FindGABForAccount(ZPushAccount account) + { + FeatureGAB gab = ThisAddIn.Instance.GetFeature(); + if (gab != null) + { + foreach (GABHandler handler in gab.GABHandlers) + { + if (account == handler.ActiveAccount) + { + return handler; + } + } + } + return null; + } + + public override void Startup() + { + MailEvents.BeforeDelete += SuppressEventHandler_Delete; + MailEvents.Write += SuppressEventHandler_Modify; + Watcher.AccountDiscovered += AccountDiscovered; + Watcher.AccountRemoved += AccountRemoved; + Watcher.AccountsScanned += AccountsScanned; + } + + #region Settings + + public override FeatureSettings GetSettings() + { + return new GABSettings(this); + } + + #endregion + + #region Debug options + + [AcaciaOption("Disables the processing of the folder containing the GAB synchronization queue. " + + "This should only be disabled for debug purposes.")] + public bool ProcessFolder + { + get { return GetOption(OPTION_PROCESS_FOLDER); } + set { SetOption(OPTION_PROCESS_FOLDER, value); } + } + private static readonly BoolOption OPTION_PROCESS_FOLDER = new BoolOption("ProcessFolder", true); + + [AcaciaOption("Disables the processing of items in the GAB synchronization queue. " + + "This should only be disabled for debug purposes.")] + public bool ProcessItems + { + get { return GetOption(OPTION_PROCESS_ITEMS); } + set { SetOption(OPTION_PROCESS_ITEMS, value); } + } + private static readonly BoolOption OPTION_PROCESS_ITEMS = new BoolOption("ProcessItems", true); + + [AcaciaOption("Disables the second stage of processing of items in the GAB synchronization queue. " + + "This should only be disabled for debug purposes")] + public bool ProcessItems2 + { + get { return GetOption(OPTION_PROCESS_ITEMS_2); } + set { SetOption(OPTION_PROCESS_ITEMS_2, value); } + } + private static readonly BoolOption OPTION_PROCESS_ITEMS_2 = new BoolOption("ProcessItems2", true); + + [AcaciaOption("Disables the processing of messages containing GAB contacts. " + + "This should only be disabled for debug purposes.")] + public bool ProcessMessage + { + get { return GetOption(OPTION_PROCESS_MESSAGE); } + set { SetOption(OPTION_PROCESS_MESSAGE, value); } + } + private static readonly BoolOption OPTION_PROCESS_MESSAGE = new BoolOption("ProcessMessage", true); + + [AcaciaOption("If disabled, contacts are not created from incoming GAB messages. " + + "This should only be disabled for debug purposes.")] + public bool CreateContacts + { + get { return GetOption(OPTION_CREATE_CONTACTS); } + set { SetOption(OPTION_CREATE_CONTACTS, value); } + } + private static readonly BoolOption OPTION_CREATE_CONTACTS = new BoolOption("CreateContacts", true); + + [AcaciaOption("If disabled, groups are not created from incoming GAB messages. " + + "This should only be disabled for debug purposes.")] + public bool CreateGroups + { + get { return GetOption(OPTION_CREATE_GROUPS); } + set { SetOption(OPTION_CREATE_GROUPS, value); } + } + private static readonly BoolOption OPTION_CREATE_GROUPS = new BoolOption("CreateGroups", true); + + [AcaciaOption("If disabled, group members are not parsed from incoming GAB messages. " + + "This should only be disabled for debug purposes.")] + public bool GroupMembers + { + get { return GetOption(OPTION_GROUP_MEMBERS); } + set { SetOption(OPTION_GROUP_MEMBERS, value); } + } + private static readonly BoolOption OPTION_GROUP_MEMBERS = new BoolOption("GroupMembers", true); + + [AcaciaOption("If disabled, group members are not added to groups created from GAB messages. " + + "This should only be disabled for debug purposes.")] + public bool GroupMembersAdd + { + get { return GetOption(OPTION_GROUP_MEMBERS_ADD); } + set { SetOption(OPTION_GROUP_MEMBERS_ADD, value); } + } + private static readonly BoolOption OPTION_GROUP_MEMBERS_ADD = new BoolOption("GroupMembersAdd", true); + + [AcaciaOption("If disabled, groups that are members of other groups are not added to the parent group. " + + "This should only be disabled for debug purposes.")] + public bool NestedGroups + { + get { return GetOption(OPTION_NESTED_GROUPS); } + set { SetOption(OPTION_NESTED_GROUPS, value); } + } + private static readonly BoolOption OPTION_NESTED_GROUPS = new BoolOption("NestedGroups", true); + + [AcaciaOption("If this option is enabled, the GAB checks for unused local folders and removes them. " + + "If disabled, the unused local folders are left alone. The only reason GAB folders " + + "can become unused is if an account is removed, or if the GAB is removed from the server.")] + public bool CheckUnused + { + get { return GetOption(OPTION_CHECK_UNUSED); } + set { SetOption(OPTION_CHECK_UNUSED, value); } + } + private static readonly BoolOption OPTION_CHECK_UNUSED = new BoolOption("CheckUnused", true); + + #endregion + + #region Modification suppression + + internal void BeginProcessing() + { + ++_processing; + } + + internal void EndProcessing() + { + --_processing; + } + + private void SuppressEventHandler_Delete(IItem item, ref bool cancel) + { + SuppressEventHandler(item, false, ref cancel); + } + + private void SuppressEventHandler_Modify(IItem item, ref bool cancel) + { + SuppressEventHandler(item, true, ref cancel); + } + + private void SuppressEventHandler(IItem item, bool findInspector, ref bool cancel) + { + // Allow events from processing + if (_processing == 0) + { + // Check parent folder is a GAB contacts folder + if (_gabFolders.Contains(item.ParentEntryId) && IsGABItem(item)) + { + DoSuppressEvent(findInspector ? item : null, ref cancel); + } + } + } + + private bool IsGABItem(IItem item) + { + // For some reason, Outlook creates a meeting request in the GAB folder. Modifying that should be allowed + return item is IContactItem || item is IDistributionList; + } + + private void SuppressMoveEventHandler(IFolder src, IItem item, IFolder target, ref bool cancel) + { + // Allow events from processing + if (_processing == 0) + { + // Always disallow moves from out of the folder + DoSuppressEvent(null, ref cancel); + } + } + + /// + /// + /// + /// If specified, the function will attempt to find an inspector for the item and close it. + /// + private void DoSuppressEvent(IItem item, ref bool cancel) + { + if (item != null) + { + foreach (Inspector inspector in App.Inspectors) + { + if (item.EntryId == inspector.CurrentItem.EntryID) + { + break; + } + } + } + MessageBox.Show(StringUtil.GetResourceString("GABEvent_Body"), + StringUtil.GetResourceString("GABEvent_Title"), + MessageBoxButtons.OK, + MessageBoxIcon.Warning + ); + cancel = true; + } + + #endregion + + #region Resync + + internal void FullResync() + { + try + { + Logger.Instance.Trace(this, "FullResync begin: {0}", _processing); + BeginProcessing(); + + // Delete any contacts folders in the local store + using (ZPushLocalStore store = ZPushLocalStore.GetInstance(App)) + { + if (store != null) + { + using (IFolder root = store.RootFolder) + { + foreach (IFolder folder in root.GetSubFolders()) + { + // TODO: let enumerator handle this + using (folder) + { + try + { + if (IsGABContactsFolder(folder)) + { + Logger.Instance.Debug(this, "FullResync: Deleting contacts folder: {0}", folder.Name); + folder.Delete(); + } + } + catch (System.Exception e) + { + Logger.Instance.Error(this, "FullResync: Exception deleting contacts folder: {0}", e); + } + } + } + } + } + } + + // Do the resync + foreach (GABHandler gab in _gabsByDomainName.Values) + { + Logger.Instance.Debug(this, "FullResync: Starting resync: {0}", gab.DisplayName); + Tasks.Task(this, "FullResync", () => gab.FullResync()); + } + } + finally + { + EndProcessing(); + Logger.Instance.Trace(this, "FullResync done: {0}", _processing); + } + } + + #endregion + + #region Contacts folders + + [Browsable(false)] + public IEnumerable GABHandlers + { + get + { + return _gabsByDomainName.Values; + } + } + + private IAddressBook FindGABForDomain(IFolder root, string domain) + { + // Scan all subfolders for the GAB + foreach (IAddressBook subfolder in root.GetSubFolders()) + { + try + { + if (subfolder.DefaultMessageClass == OutlookConstants.MESSAGE_CLASS_CONTACTS) + { + GABInfo gabInfo = GABInfo.Get(subfolder); + if (gabInfo != null && gabInfo.IsForDomain(domain)) + { + Logger.Instance.Debug(this, "Found existing GAB: {0}", gabInfo); + return subfolder; + } + } + } + catch (System.Exception e) + { + Logger.Instance.Warning(this, "Exception scanning GABs: {0}", e); + } + Logger.Instance.Debug(this, "Skipping GAB folder: {0}", subfolder.Name); + subfolder.Dispose(); + } + return null; + } + + private IAddressBook CreateGABContacts(string domainName) + { + if (_store != null) + { + _store.Dispose(); + _store = null; + } + _store = ZPushLocalStore.GetInstance(App); + if (_store == null) + return null; + + // Try to find the existing GAB + using (IFolder root = _store.RootFolder) + { + IAddressBook gab = FindGABForDomain(root, domainName); + if (gab == null) + { + Logger.Instance.Debug(this, "Creating new GAB folder for {0}", domainName); + string name = string.Format(Properties.Resources.GAB_FolderFormat, domainName); + gab = root.CreateFolder(name); + } + else + { + Logger.Instance.Debug(this, "Found existing GAB folder for {0}", domainName); + } + + // The local folders are hidden, unhide tha GAB folder + gab.AttrHidden = false; + + // Update admin + _gabFolders.Add(gab.EntryId); + GABInfo gabInfo = GABInfo.Get(gab, domainName); + gabInfo.Store(gab); + + // Hook BeforeMove event to prevent modifications + // TODO: use ZPushWatcher for this? + gab.BeforeItemMove += SuppressMoveEventHandler; + + return gab; + } + } + + private void DisposeGABContacts(IAddressBook gab) + { + // Unhook the event to prevent the gab lingering in memory + gab.BeforeItemMove -= SuppressMoveEventHandler; + } + + public static GABInfo GetGABContactsFolderInfo(IFolder folder) + { + if (folder.DefaultMessageClass != OutlookConstants.MESSAGE_CLASS_CONTACTS) + return null; + + return GABInfo.Get(folder); + } + + public static bool IsGABContactsFolder(IFolder folder) + { + return GetGABContactsFolderInfo(folder) != null; + } + + private void AccountDiscovered(ZPushAccount zpush) + { + Logger.Instance.Info(this, "Account discovered: {0}", zpush.DisplayName); + _domains.Add(zpush.DomainName); + + zpush.ConfirmedChanged += (z) => + { + if (zpush.Confirmed == ZPushAccount.ConfirmationType.IsZPush && + !string.IsNullOrEmpty(zpush.GABFolder)) + { + // Set up the Z-Push channel listener + ZPushChannel channel = ZPushChannels.Get(this, zpush, zpush.GABFolder); + channel.Available += ZPushChannelAvailable; + channel.Start(); + } + }; + } + + private void AccountRemoved(ZPushAccount account) + { + try + { + foreach (GABHandler gab in _gabsByDomainName.Values) + { + gab.RemoveAccount(account); + } + CheckGABRemoved(); + } + catch (System.Exception e) + { + Logger.Instance.Error(this, "Exception in AccountRemoved: {0}", e); + } + } + + private void AccountsScanned() + { + try + { + Logger.Instance.Debug(this, "Accounts scanned"); + CheckGABUnused(); + CheckGABRemoved(); + } + catch(System.Exception e) + { + Logger.Instance.Error(this, "Exception in AccountsScanned: {0}", e); + } + } + + /// + /// Checks and removes any GAB folders that are not registered to accounts. This + /// happens if an account is removed while Outlook is closed. + /// + private void CheckGABUnused() + { + if (!CheckUnused) + return; + + if (_store != null) + { + _store.Dispose(); + _store = null; + } + _store = ZPushLocalStore.GetInstance(App); + if (_store == null) + return; + + bool deletedSomething = false; + using (IFolder root = _store.RootFolder) + { + foreach (IFolder subfolder in root.GetSubFolders()) + { + using (subfolder) + { + // Remove any contacts folder that is not registered for GAB + GABInfo info = GetGABContactsFolderInfo(subfolder); + if (info != null && !_domains.Contains(info.Domain)) + { + Logger.Instance.Info(this, "Unused GAB folder: {0} - {1}", subfolder.EntryId, subfolder.Name); + try + { + deletedSomething = true; + subfolder.Delete(); + } + catch (System.Exception e) + { + Logger.Instance.Error(this, "Error removing GAB folder: {0}", e); + } + } + } + } + } + + if (deletedSomething) + EmptyDeletedItems(); + } + + private void CheckGABRemoved() + { + Logger.Instance.Debug(this, "CheckGABRemoved"); + + // Find any GABs that no longer have accounts + List> remove = new List>(); + foreach(KeyValuePair entry in _gabsByDomainName) + { + Logger.Instance.Debug(this, "CheckGABRemoved: {0} - {1}", entry.Key, entry.Value.HasAccounts); + if (!entry.Value.HasAccounts) + { + remove.Add(entry); + } + } + + // Remove any + if (remove.Count != 0) + { + foreach (KeyValuePair entry in remove) + { + try + { + Logger.Instance.Info(this, "Removing GAB: {0}", entry.Key); + _gabsByDomainName.Remove(entry.Key); + entry.Value.Remove(); + } + catch (System.Exception e) + { + Logger.Instance.Error(this, "Exception removing GAB: {0}: {1}", entry.Key, e); + } + } + + EmptyDeletedItems(); + } + } + + private void RegisterGABAccount(ZPushAccount account, IFolder folder) + { + // Determine the domain name + string domain = account.DomainName; + + // Could already be registered if there are multiple accounts on the same domain + GABHandler gab; + if (!_gabsByDomainName.TryGetValue(domain, out gab)) + { + // Create the handler + gab = new GABHandler(this, (f) => CreateGABContacts(domain), (f) => DisposeGABContacts(f)); + _gabsByDomainName.Add(domain, gab); + } + else + { + Logger.Instance.Debug(this, "GAB handler already registered: {0} on {1}", folder, folder.StoreDisplayName); + } + + // Register the account with the GAB + gab.AddAccount(account, folder); + + // The folder has become available, check the GAB messages + DoProcess(account, gab, null); + + // And watch for any new messages + Watcher.WatchItems(folder, (item) => DoProcess(account, gab, item), false); + } + + #endregion + + #region Processing + + private void ZPushChannelAvailable(IFolder folder) + { + using (IStore store = folder.Store) + { + Logger.Instance.Debug(this, "Z-Push channel available: {0} on {1}", folder, store.DisplayName); + + ZPushAccount account = Watcher.Accounts.GetAccount(folder); + if (account != null) + { + account.LinkedGABFolder(folder); + RegisterGABAccount(account, folder); + } + else + { + Logger.Instance.Warning(this, "Z-Push channel account not found: {0} on {1}", folder, store.DisplayName); + } + Logger.Instance.Debug(this, "Z-Push channel available done"); + } + } + + private void DoProcess(ZPushAccount account, GABHandler gab, IZPushItem item) + { + // Multiple accounts - and therefore multiple folders - may use the same GAB. + // One process the items from the first associated account + if (account != gab.ActiveAccount) + { + Logger.Instance.Trace(this, "Ignoring GAB message: {0} - {1}", account, item); + return; + } + + ++_processing; + Logger.Instance.Trace(this, "Processing GAB message: {0} - {1}", account, _processing); + try + { + gab.Process(item); + EmptyDeletedItems(); + } + finally + { + Logger.Instance.Trace(this, "Processed GAB message: {0} - {1}", account, _processing); + --_processing; + } + } + + private void EmptyDeletedItems() + { + if (_store != null) + _store.EmptyDeletedItems(); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABHandler.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABHandler.cs new file mode 100644 index 0000000..5e0bbce --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABHandler.cs @@ -0,0 +1,693 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Acacia.Stubs; +using Acacia.ZPush; +using Acacia.Utils; +using System.Collections; +using static Acacia.DebugOptions; + +namespace Acacia.Features.GAB +{ + public class GABHandler : LogContext + { + public string LogContextId { get { return "GAB"; } } + private readonly FeatureGAB _feature; + + #region Contacts + + private readonly Func _contactsProvider; + private readonly Action _contactsDisposer; + + private IAddressBook _contacts; + public IAddressBook Contacts + { + get + { + if (_contacts == null) + { + _contacts = _contactsProvider(Folder); + } + return _contacts; + } + } + + private IStorageItem GetIndexItem() + { + return Contacts?.GetStorageItem(Constants.ZPUSH_GAB_INDEX); + } + + #endregion + + #region Accounts & Folders + + public ZPushAccount ActiveAccount + { + get + { + return ThisAddIn.Instance.Watcher.Accounts.GetAccount(Folder); + } + } + + /// + /// The list of accounts that are associated with this GAB. + /// + private readonly List _accounts = new List(); + private readonly List _accountFolders = new List(); + + private IFolder Folder + { + get + { + if (!HasAccounts) + return null; + return _accountFolders.FirstOrDefault(); + } + } + + public void AddAccount(ZPushAccount account, IFolder folder) + { + _accounts.Add(account); + _accountFolders.Add(folder); + } + + public void RemoveAccount(ZPushAccount account) + { + int i = _accounts.IndexOf(account); + if (i >= 0) + { + _accounts.RemoveAt(i); + _accountFolders.RemoveAt(i); + } + } + + internal bool HasAccounts + { + get + { + return _accounts.Count > 0; + } + } + + #endregion + + public GABHandler(FeatureGAB feature, Func contactsProvider, Action contactsDisposer) + { + this._feature = feature; + this._contactsProvider = contactsProvider; + this._contactsDisposer = contactsDisposer; + } + + public string DisplayName + { + get + { + using(IStore store = Folder.Store) + return store.DisplayName; + } + } + + #region Processing + + public void FullResync() + { + ClearContacts(); + Process(null); + } + + private void ClearContacts() + { + if (Contacts != null) + { + try + { + Contacts.Delete(); + } + catch (Exception e) + { + Logger.Instance.Warning(this, "Error clearing contacts folder for {0}: {1}", DisplayName, e); + // There was an error deleting the contacts folder, try clearing it + using (IStorageItem index = GetIndexItem()) + { + index?.Delete(); + } + Contacts.Clear(); + } + CleanupContactsObject(); + } + } + + /// + /// Processes the GAB message(s). + /// + /// If specified, this item has changed. If null, means a global check should be performed + public void Process(IZPushItem item) + { + try + { + if (item == null) + { + if (Folder != null) + ProcessMessages(); + } + else + { + ProcessMessage(item); + } + } + catch(Exception e) + { + Logger.Instance.Error(this, "Exception in GAB.Process: {0}", e); + } + } + + private void ProcessMessages() + { + if (!_feature.ProcessFolder) + return; + + DetermineSequence(); + if (CurrentSequence == null) + return; // No messages to process + + if (!_feature.ProcessItems) + return; + + // Process the messages + foreach (IItem item in Folder.Items) + { + // TODO: make type-checking iterator? + if (item is IZPushItem) + { + string entryId = item.EntryId; + Logger.Instance.Trace(this, "Checking chunk: {0}", item.Subject); + if (_feature.ProcessItems2) + { + Tasks.Task(_feature, "ProcessChunk", () => + { + using (IItem item2 = Folder.GetItemById(entryId)) + { + if (item2 != null) + ProcessMessage((IZPushItem)item2); + } + }); + } + } + } + } + + public const string PROP_LAST_PROCESSED = "ZPushLastProcessed"; + public const string PROP_SEQUENCE = "ZPushSequence"; + public const string PROP_CHUNK = "ZPushChunk"; + public const string PROP_GAB_ID = "ZPushId"; + public const string PROP_CURRENT_SEQUENCE = "ZPushCurrentSequence"; + + private void ProcessMessage(IZPushItem item) + { + if (!_feature.ProcessMessage) + return; + + // Check if the message is for the current sequence + ChunkIndex? optionalIndex = ChunkIndex.Parse(item.Subject); + if (optionalIndex == null) + { + Logger.Instance.Trace(this, "Not a chunk: {0}", item.Subject); + return; + } + + if (optionalIndex.Value.numberOfChunks != CurrentSequence) + { + // Try to update the current sequence; this message may indicate that it has changed + DetermineSequence(); + + // If it is still not for the current sequence, it's an old message + if (optionalIndex.Value.numberOfChunks != CurrentSequence) + { + Logger.Instance.Trace(this, "Skipping, wrong sequence: {0}", item.Subject); + return; + } + } + ChunkIndex index = optionalIndex.Value; + + // Check if the message is up to date + string lastProcessed = GetChunkStateString(index); + if (lastProcessed == item.Location) + { + Logger.Instance.Trace(this, "Already up to date: {0} - {1}", item.Subject, item.Location); + return; + } + + // Process it + Logger.Instance.Trace(this, "Processing: {0} - {1} - {2}", item.Subject, item.Location, lastProcessed); + _feature?.BeginProcessing(); + try + { + // Delete the old contacts from this chunk + ISearch search = Contacts.Search(); + search.AddField(PROP_SEQUENCE, true).SetOperation(SearchOperation.Equal, index.numberOfChunks); + search.AddField(PROP_CHUNK, true).SetOperation(SearchOperation.Equal, index.chunk); + foreach (IItem oldItem in search.Search()) + { + // TODO: Search should handle this, like folder enumeration + using (oldItem) + { + Logger.Instance.Trace(this, "Deleting GAB entry: {0}", oldItem.Subject); + oldItem.Delete(); + } + } + + // Create the new contacts + ProcessChunkBody(item, index); + + // Update the state + SetChunkStateString(index, item.Location); + } + finally + { + _feature?.EndProcessing(); + } + } + + #endregion + + #region Sequence + + public int? CurrentSequence + { + get + { + using (IStorageItem index = GetIndexItem()) + { + return index?.GetUserProperty(PROP_CURRENT_SEQUENCE)?.Value; + } + } + set + { + using (IStorageItem index = GetIndexItem()) + { + if (value != null) + { + index.GetUserProperty(PROP_CURRENT_SEQUENCE, true).Value = value.Value; + } + else + { + index.Delete(); + } + } + } + } + + private IItem FindNewestChunk() + { + if (Folder == null) + return null; + + // Scan a few of the newest items, in case there is some junk in the ZPush folder + // TODO: this shouldn't happen in production. + int i = 0; + foreach(IItem item in Folder.ItemsSorted("LastModificationTime", true)) + { + if (ChunkIndex.Parse(item.Subject) != null) + return item; + item.Dispose(); + if (i > Constants.ZPUSH_GAB_NEWEST_MAX_CHECK) + return null; + ++i; + } + return null; + } + + public void DetermineSequence() + { + try + { + // Find the newest chunk + using (IItem newest = FindNewestChunk()) + { + if (newest == null) + CurrentSequence = null; + else + { + Logger.Instance.Trace(this, "Newest chunk: {0}", newest.Subject); + ChunkIndex? newestChunkIndex = ChunkIndex.Parse(newest.Subject); + + if (!CurrentSequence.HasValue || CurrentSequence.Value != newestChunkIndex?.numberOfChunks) + { + // Sequence has changed. Delete contacts + Logger.Instance.Trace(this, "Rechunked, deleting contacts"); + ClearContacts(); + + // Determine new sequence + if (newestChunkIndex == null) + { + using (IStorageItem index = GetIndexItem()) + { + if (index != null) + index.Delete(); + } + } + else + { + int numberOfChunks = newestChunkIndex.Value.numberOfChunks; + using (IStorageItem index = GetIndexItem()) + { + index.GetUserProperty(PROP_CURRENT_SEQUENCE, true).Value = numberOfChunks; + index.GetUserProperty(PROP_LAST_PROCESSED, true).Value = CreateChunkStateString(numberOfChunks); + index.Save(); + } + } + } + } + } + } + catch(Exception e) + { + Logger.Instance.Trace(this, "Exception determining sequence: {0}", e); + // Delete the index item + using (IStorageItem index = GetIndexItem()) + index?.Delete(); + return; + } + Logger.Instance.Trace(this, "Current sequence: {0}", CurrentSequence); + } + + private string CreateChunkStateString(int count) + { + string[] defaultValues = new string[count]; + return string.Join(";", defaultValues); + } + + private string GetChunkStateString(ChunkIndex index) + { + using (IStorageItem item = GetIndexItem()) + { + if (item == null) + return null; + string state = item.GetUserProperty(PROP_LAST_PROCESSED)?.Value; + if (string.IsNullOrEmpty(state)) + return null; + + string[] parts = state.Split(';'); + if (parts.Length != index.numberOfChunks) + { + Logger.Instance.Error(this, "Wrong number of chunks, got {0}, expected {1}: {2}", + parts.Length, index.numberOfChunks, state); + } + return parts[index.chunk]; + } + } + + private void SetChunkStateString(ChunkIndex index, string partState) + { + using (IStorageItem item = GetIndexItem()) + { + string state = item.GetUserProperty(PROP_LAST_PROCESSED)?.Value; + string[] parts; + if (string.IsNullOrEmpty(state)) + parts = new string[index.numberOfChunks]; + else + parts = state.Split(';'); + if (parts.Length != index.numberOfChunks) + { + Logger.Instance.Error(this, "Wrong number of chunks, got {0}, expected {1}: {2}", + parts.Length, index.numberOfChunks, state); + } + parts[index.chunk] = partState; + string combined = string.Join(";", parts); + + item.GetUserProperty(PROP_LAST_PROCESSED, true).Value = combined; + item.Save(); + } + } + + #endregion + + #region Message parsing + + + private ValueType Get(Dictionary values, string name) + where ValueType : class + { + object value; + values.TryGetValue(name, out value); + return value as ValueType; + } + + private void ProcessChunkBody(IZPushItem item, ChunkIndex index) + { + // Process the body + foreach (var entry in JSONUtils.Deserialise(item.Body)) + { + string id = entry.Key; + Dictionary value = (Dictionary)entry.Value; + Tasks.Task(_feature, "CreateItem", () => CreateObject(index, id, value)); + } + } + + private void CreateObject(ChunkIndex index, string id, Dictionary value) + { + try + { + _feature?.BeginProcessing(); + + string type = Get(value, "type"); + if (type == "contact") + CreateContact(id, value, index, 0); + else if (type == "group") + CreateGroup(id, value, index); + else if (type == "equipment") + CreateContact(id, value, index, OutlookConstants.DT_EQUIPMENT); + else if (type == "room") + CreateContact(id, value, index, OutlookConstants.DT_ROOM); + else + { + Logger.Instance.Warning(this, "Unknown entry type: {0}", type); + } + } + catch (System.Exception e) + { + Logger.Instance.Error(this, "Error creating entry: {0}: {1}", id, e); + } + finally + { + _feature?.EndProcessing(); + } + } + + private void CreateContact(string id, Dictionary value, ChunkIndex index, int resourceType) + { + if (!_feature.CreateContacts) + return; + + using (IContactItem contact = Contacts.Create()) + { + Logger.Instance.Trace(this, "Creating contact: {0}", id); + contact.CustomerID = id; + + // Create the contact data + if (Get(value, "displayName") != null) contact.FullName = Get(value, "displayName"); + if (Get(value, "givenName") != null) contact.FirstName = Get(value, "givenName"); + if (Get(value, "initials") != null) contact.Initials = Get(value, "initials"); + if (Get(value, "surname") != null) contact.LastName = Get(value, "surname"); + if (Get(value, "title") != null) contact.JobTitle = Get(value, "title"); + + if (Get(value, "smtpAddress") != null) + { + contact.Email1Address = Get(value, "smtpAddress"); + contact.Email1AddressType = "SMTP"; + } + if (Get(value, "companyName") != null) contact.CompanyName = Get(value, "companyName"); + if (Get(value, "officeLocation") != null) contact.OfficeLocation = Get(value, "officeLocation"); + if (Get(value, "businessTelephoneNumber") != null) contact.BusinessTelephoneNumber = Get(value, "businessTelephoneNumber"); + if (Get(value, "mobileTelephoneNumber") != null) contact.MobileTelephoneNumber = Get(value, "mobileTelephoneNumber"); + if (Get(value, "homeTelephoneNumber") != null) contact.HomeTelephoneNumber = Get(value, "homeTelephoneNumber"); + if (Get(value, "beeperTelephoneNumber") != null) contact.PagerNumber = Get(value, "beeperTelephoneNumber"); + if (Get(value, "primaryFaxNumber") != null) contact.BusinessFaxNumber = Get(value, "primaryFaxNumber"); + if (Get(value, "organizationalIdNumber") != null) contact.OrganizationalIDNumber = Get(value, "organizationalIdNumber"); + if (Get(value, "postalAddress") != null) contact.BusinessAddress = Get(value, "postalAddress"); + if (Get(value, "businessAddressCity") != null) contact.BusinessAddressCity = Get(value, "businessAddressCity"); + if (Get(value, "businessAddressPostalCode") != null) contact.BusinessAddressPostalCode = Get(value, "businessAddressPostalCode"); + if (Get(value, "businessAddressPostOfficeBox") != null) contact.BusinessAddressPostOfficeBox = Get(value, "businessAddressPostOfficeBox"); + if (Get(value, "businessAddressStateOrProvince") != null) contact.BusinessAddressState = Get(value, "businessAddressStateOrProvince"); + if (Get(value, "language") != null) contact.Language = Get(value, "language"); + + // Thumbnail + string photoData = Get(value, "thumbnailPhoto"); + if (photoData != null) + { + string path = null; + try + { + byte[] data = Convert.FromBase64String(photoData); + path = System.IO.Path.GetTempFileName(); + Logger.Instance.Trace(this, "Contact image: {0}", path); + System.IO.File.WriteAllBytes(path, data); + contact.SetPicture(path); + } + catch (Exception) { } + finally + { + try + { + if (path != null) + System.IO.File.Delete(path); + } + catch (Exception) { } + } + } + + // Resource flags + if (resourceType != 0) + { + contact.SetProperty(OutlookConstants.PR_DISPLAY_TYPE, 0); + contact.SetProperty(OutlookConstants.PR_DISPLAY_TYPE_EX, resourceType); + } + + // Standard properties + SetItemStandard(contact, id, value, index); + contact.Save(); + + // Update the groups + AddItemToGroups(contact, id, value, index); + } + + } + + private void CreateGroup(string id, Dictionary value, ChunkIndex index) + { + if (!_feature.CreateGroups) + return; + + using (IDistributionList group = Contacts.Create()) + { + Logger.Instance.Debug(this, "Creating group: {0}", id); + group.DLName = Get(value, "displayName"); + if (Get(value, "smtpAddress") != null) + { + group.SMTPAddress = Get(value, "smtpAddress"); + } + + SetItemStandard(group, id, value, index); + group.Save(); + + if (_feature.GroupMembers) + { + ArrayList members = Get(value, "members"); + if (members != null) + { + foreach (string memberId in members) + { + using (IItem item = FindItemById(memberId)) + { + Logger.Instance.Debug(this, "Finding member {0} of {1}: {2}", memberId, id, item?.EntryId); + if (item != null) + AddGroupMember(group, item); + } + } + } + group.Save(); + } + + AddItemToGroups(group, id, value, index); + } + } + + private IItem FindItemById(string id) + { + ISearch search = Contacts.Search(); + search.AddField(PROP_GAB_ID, true).SetOperation(SearchOperation.Equal, id); + return search.SearchOne(); + } + + private void SetItemStandard(IItem item, string id, Dictionary value, ChunkIndex index) + { + // Set the chunk data + item.GetUserProperty(PROP_SEQUENCE, true).Value = index.numberOfChunks; + item.GetUserProperty(PROP_CHUNK, true).Value = index.chunk; + item.GetUserProperty(PROP_GAB_ID, true).Value = id; + } + + private void AddGroupMember(IDistributionList group, IItem item) + { + if (!_feature.GroupMembersAdd) + return; + + if (item is IDistributionList) + { + if (!_feature.NestedGroups) + return; + } + + group.AddMember(item); + } + + private void AddItemToGroups(IItem item, string id, Dictionary value, ChunkIndex index) + { + if (!_feature.GroupMembers) + return; + + // Find the groups + if (Get(value, "memberOf") != null) + { + ArrayList members = Get(value, "memberOf"); + foreach (string memberOf in members) + { + using (IItem groupItem = FindItemById(memberOf)) + { + Logger.Instance.Debug(this, "Finding group {0} for {1}: {2}", memberOf, id, groupItem?.EntryId); + if (groupItem is IDistributionList) + { + AddGroupMember((IDistributionList)groupItem, item); + groupItem.Save(); + } + } + } + } + } + + #endregion + + #region Removal + + public void Remove() + { + if (_contacts != null) + { + _contacts.Delete(); + } + CleanupContactsObject(); + } + + private void CleanupContactsObject() + { + if (_contacts != null) + { + if (_contactsDisposer != null) + _contactsDisposer(_contacts); + _contacts.Dispose(); + _contacts = null; + } + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABInfo.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABInfo.cs new file mode 100644 index 0000000..ae56412 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABInfo.cs @@ -0,0 +1,93 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Stubs; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Features.GAB +{ + public class GABInfo + { + private const string ID = "GAB="; + public readonly string Domain; + + public GABInfo(string domain) + { + this.Domain = domain; + } + + /// + /// Retrieves the GAB info for the folder. + /// + /// The folder + /// The domain name. If this is not null, and a GAB info is not found, it is created + /// + public static GABInfo Get(IFolder folder, string forDomain = null) + { + GABInfo gab = GetExisting(folder); + if (gab == null && forDomain != null) + gab = new GABInfo(forDomain); + return gab; + } + + private static GABInfo GetExisting(IFolder folder) + { + string subject = null; + try + { + subject = (string)folder.GetProperty(OutlookConstants.PR_SUBJECT); + } + catch (System.Exception) { } + if (string.IsNullOrEmpty(subject)) + return null; + + string[] parts = subject.Split(';'); + if (parts.Length < 1 || !parts[0].StartsWith(ID)) + return null; + + string domain = parts[0].Substring(ID.Length); + GABInfo gab = new GABInfo(domain); + + return gab; + } + + public override string ToString() + { + return "GAB(" + Domain + ")"; + } + + public bool IsForDomain(string domain) + { + return this.Domain == domain; + } + + public void Store(IFolder folder) + { + string s = Serialize(); + folder.SetProperty(OutlookConstants.PR_SUBJECT, s); + } + + private string Serialize() + { + return ID + Domain; + } + + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABSettings.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABSettings.Designer.cs new file mode 100644 index 0000000..3512b35 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABSettings.Designer.cs @@ -0,0 +1,58 @@ +namespace Acacia.Features.GAB +{ + partial class GABSettings + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(GABSettings)); + this.buttonGABResync = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // buttonGABResync + // + resources.ApplyResources(this.buttonGABResync, "buttonGABResync"); + this.buttonGABResync.Name = "buttonGABResync"; + this.buttonGABResync.UseVisualStyleBackColor = true; + this.buttonGABResync.Click += new System.EventHandler(this.buttonGABResync_Click); + // + // GABSettings + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.SystemColors.Window; + this.Controls.Add(this.buttonGABResync); + this.Name = "GABSettings"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button buttonGABResync; + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABSettings.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABSettings.cs new file mode 100644 index 0000000..3d2f9cd --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABSettings.cs @@ -0,0 +1,57 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using Acacia.UI; + +namespace Acacia.Features.GAB +{ + public partial class GABSettings : FeatureSettings + { + private readonly FeatureGAB _feature; + public override Feature Feature + { + get + { + return _feature; + } + } + + public GABSettings(FeatureGAB feature = null) + { + this._feature = feature; + + InitializeComponent(); + } + + private void buttonGABResync_Click(object sender, EventArgs e) + { + // Allow null feature for designer + if (_feature != null) + { + _feature.FullResync(); + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABSettings.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABSettings.resx new file mode 100644 index 0000000..c62a953 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/GABSettings.resx @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + True + + + + 3, 3 + + + + 8, 0, 8, 0 + + + 210, 23 + + + 0 + + + Resynchronise Global Address Books + + + buttonGABResync + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 6, 13 + + + True + + + 216, 31 + + + GABSettings + + + Acacia.UI.FeatureSettings, ZPush, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Notes/FeatureNotes.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Notes/FeatureNotes.cs new file mode 100644 index 0000000..38bf5f6 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Notes/FeatureNotes.cs @@ -0,0 +1,292 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Stubs; +using Acacia.Stubs.OutlookWrappers; +using Acacia.Utils; +using Acacia.ZPush; +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using static Acacia.DebugOptions; + +namespace Acacia.Features.Notes +{ + [AcaciaOption("Provides the possibility to synchronise Notes to and from a Z-Push server.")] + public class FeatureNotes : Feature + { + public FeatureNotes() + { + + } + + public override void Startup() + { + Watcher.WatchFolder(new FolderRegistrationTyped(this, ItemType.NoteItem), + OnNotesFolderDiscovered, OnNotesFolderChanged); + } + + #region Debug options + + [AcaciaOption("Disables the patching of Notes folders types. Without this, Outlook will not recognise " + + "these folders as being Notes folders, and contents will not be synchronised.")] + public bool PatchFolders + { + get { return GetOption(OPTION_PATCH_FOLDERS); } + set { SetOption(OPTION_PATCH_FOLDERS, value); } + } + private static readonly BoolOption OPTION_PATCH_FOLDERS = new BoolOption("PatchFolders", true); + + [AcaciaOption("Disables the patching of Note item types. Without this, Outlook will not recognise " + + "these items as being Notes, and they may appear in unusual states.")] + public bool PatchItems + { + get { return GetOption(OPTION_PATCH_ITEMS); } + set { SetOption(OPTION_PATCH_ITEMS, value); } + } + private static readonly BoolOption OPTION_PATCH_ITEMS = new BoolOption("PatchItems", true); + + #endregion + + private void OnNotesFolderDiscovered(IFolder folder) + { + Logger.Instance.Debug(this, "NOTES FOLDER: {0}", folder); + // Always watch the folder. Any notes being synced in indicate the server supports notes, + // and otherwise there's no harm done. + Watcher.WatchItems(folder, PatchNote, true); + + // Patch the folder if needed + PatchIfConfirmed(folder); + } + + private void OnNotesFolderChanged(IFolder folder) + { + Logger.Instance.Debug(this, "NOTES FOLDER CHANGED: {0}, type={1}", folder, folder.GetProperty(OutlookConstants.PR_EAS_SYNCTYPE)); + // Outlook sometimes changes the type back. Patch again if needed. + PatchIfConfirmed(folder); + } + + private bool IsNotesFolder(OutlookConstants.SyncType type) + { + return type == OutlookConstants.SyncType.Note || type == OutlookConstants.SyncType.UserNote; + } + + private void PatchIfConfirmed(IFolder folder) + { + // Only patch if on a ZPush server that supports notes. Store the folder as entryId, there have been some + // issues with the folder object being disposed in the past + string folderId = folder.EntryId; + ZPushAccount zpush = Watcher.Accounts.GetAccount(folder); + if (zpush != null) + { + zpush.ConfirmedChanged += (z) => + { + if (zpush.Confirmed == ZPushAccount.ConfirmationType.IsZPush && + zpush.Capabilities.Has(Constants.ZPUSH_CAPABILITY_NOTES)) + { + PatchFolder(folderId); + } + else if (zpush.Confirmed != ZPushAccount.ConfirmationType.Unknown) + { + // The server is either not a Z-Push server, or it does not support notes + // Restore any patched notes folder + UnpatchFolder(folderId); + } + }; + } + } + + private void PatchFolder(string folderId) + { + if (!PatchFolders) + return; + + Logger.Instance.Trace(this, "PatchFolder: {0}", folderId); + try + { + using (IFolder folder = Mapping.GetFolderFromID(folderId)) + { + if (folder == null) + return; + + // Patch if needed + OutlookConstants.SyncType type = FolderUtils.GetFolderSyncType(folder); + Logger.Instance.Trace(this, "Notes folder type: {0}", type); + if (IsNotesFolder(type)) + { + Logger.Instance.Debug(this, "Patching Notes folder type: {0}", type); + + // Change to task folder + folder.SetProperties(new string[] + { + OutlookConstants.PR_NET_FOLDER_FLAGS, + OutlookConstants.PR_EAS_SYNCTYPE, + OutlookConstants.PR_EAS_SYNC1, + OutlookConstants.PR_EAS_SYNC2 + }, new object[] + { + 0, (int)OutlookConstants.SyncType.UserAppointment, true, true + }); + + if (type == OutlookConstants.SyncType.Note) + { + // Local notes, change name + PatchFolderName(folder); + } + } + } + } + finally + { + Logger.Instance.Trace(this, "PatchFolder done"); + } + } + + private void UnpatchFolder(string folderId) + { + if (!PatchFolders) + return; + + Logger.Instance.Trace(this, "UnpatchFolder: {0}", folderId); + try + { + using (IFolder folder = Mapping.GetFolderFromID(folderId)) + { + if (folder == null) + return; + + // Unpatch if needed + OutlookConstants.SyncType type = FolderUtils.GetFolderSyncType(folder, true); + Logger.Instance.Trace(this, "Notes folder type: {0}", type); + // Unpatch only if the original type is a notes folder, but the current type isn't + if (IsNotesFolder(type) && !IsNotesFolder(FolderUtils.GetFolderSyncType(folder))) + { + Logger.Instance.Debug(this, "Unpatching Notes folder type: {0}", type); + + // Change to original notes folder + folder.SetProperties(new string[] + { + OutlookConstants.PR_EAS_SYNCTYPE, + OutlookConstants.PR_EAS_SYNC1, + OutlookConstants.PR_EAS_SYNC2 + }, new object[] + { + (int)type, + false, + false + }); + + if (type == OutlookConstants.SyncType.Note) + { + // Local notes, change name + UnpatchFolderName(folder); + } + } + } + } + finally + { + Logger.Instance.Trace(this, "PatchFolder done"); + } + } + + private void PatchNote(IItem item) + { + if (!PatchItems) + return; + + Logger.Instance.Trace(this, "NOTE ITEM: Subject='{0}', Class={1}", + item.GetProperty(OutlookConstants.PR_SUBJECT), + item.GetProperty(OutlookConstants.PR_MESSAGE_CLASS)); + try + { + if ((int)item.GetProperty(OutlookConstants.PR_ICON_INDEX) != 771) + { + Logger.Instance.Trace(this, "Patching item: {0}", item.EntryId); + + // Patch standard properties + item.SetProperties( + new string[] { OutlookConstants.PR_MESSAGE_CLASS, OutlookConstants.PR_ICON_INDEX, OutlookConstants.PR_NOTE_COLOR }, + new object[] { OutlookConstants.MESSAGE_CLASS_NOTES, 771, 3 } + ); + + // Set sizes if not set, they get crappy defaults + try + { + // This causes an exception if nothing is set + item.GetProperty(OutlookConstants.PR_NOTE_WIDTH); + } + catch (System.Exception) + { + Logger.Instance.Trace(this, "Setting default sizes"); + item.SetProperty(OutlookConstants.PR_NOTE_WIDTH, 200); + item.SetProperty(OutlookConstants.PR_NOTE_HEIGHT, 166); + item.SetProperty(OutlookConstants.PR_NOTE_X, 80); + item.SetProperty(OutlookConstants.PR_NOTE_Y, 80); + } + item.Save(); + } + } + finally + { + Logger.Instance.Trace(this, "PatchNote done"); + } + } + + private void PatchFolderName(IFolder folder) + { + // Remove parenthesised (this computer only) or localised equivalent + string oldName = folder.Name; + int open = oldName.IndexOf('('); + int close = oldName.IndexOf(')'); + if (open >= 0 && close >= 0) + { + string newName = oldName.Substring(0, Math.Min(open, close)) + oldName.Substring(Math.Max(open, close) + 1); + newName = newName.Trim(); + // Set the new name, and keep the old name in subject in case of a revert + folder.SetProperties(new string[] + { + OutlookConstants.PR_DISPLAY_NAME, OutlookConstants.PR_SUBJECT + }, new object[] + { + newName, oldName + }); + } + } + + private void UnpatchFolderName(IFolder folder) + { + try + { + string oldName = (string)folder.GetProperty(OutlookConstants.PR_SUBJECT); + // Parentheses are not allowed in names (even though they were there originally) + // Replace with square brackets. + oldName = oldName.Replace('(', '['); + oldName = oldName.Replace(')', ']'); + folder.SetProperty(OutlookConstants.PR_DISPLAY_NAME, oldName); + } + catch(System.Exception e) + { + Logger.Instance.Warning(this, "Exception in UnpatchFolderName, leaving name: {0}", e); + } + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/FeatureOutOfOffice.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/FeatureOutOfOffice.cs new file mode 100644 index 0000000..77cbf95 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/FeatureOutOfOffice.cs @@ -0,0 +1,241 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.UI; +using Acacia.UI.Outlook; +using Acacia.Utils; +using Acacia.ZPush; +using Acacia.ZPush.Connect; +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.Features.OutOfOffice +{ + [AcaciaOption("Provides a user interface to modify Out-of-Office settings for ActiveSync accounts.")] + public class FeatureOutOfOffice + : + Feature, FeatureWithRibbon + { + private RibbonToggleButton _button; + + public FeatureOutOfOffice() + { + + } + + public override void Startup() + { + _button = RegisterToggleButton(this, "OOF", true, ShowDialog, ZPushBehaviour.Disable); + Watcher.ZPushAccountChange += Watcher_ZPushAccountChange; + } + + private static bool IsOOFEnabled(ActiveSync.SettingsOOF settings) + { + if (settings == null) + return false; + return settings.State != ActiveSync.OOFState.Disabled; + } + + private void Watcher_ZPushAccountChange(ZPushAccount account) + { + if (_button != null) + { + if (account == null) + _button.IsPressed = false; + else + _button.IsPressed = IsOOFEnabled(account.GetFeatureData(this, "OOF")); + } + } + + private void StoreOOFSettings(ZPushAccount account, ActiveSync.SettingsOOF settings) + { + account.SetFeatureData(this, "OOF", settings); + if (_button != null) + _button.IsPressed = IsOOFEnabled(settings); + } + + private void ShowDialog() + { + ZPushAccount account = Watcher.CurrentZPushAccount(); + if (account != null) + { + try + { + // Fetch the current status + ActiveSync.SettingsOOF settings; + + try + { + settings = ProgressDialog.Execute("OOFGet", + (ct) => + { + using (ZPushConnection con = new ZPushConnection(account, ct)) + return con.Execute(new ActiveSync.SettingsOOFGet()); + } + ); + } + catch (System.Exception e) + { + Logger.Instance.Warning(this, "Exception getting OOF state: {0}", e); + if (MessageBox.Show( + Properties.Resources.OOFGet_Failed, + Properties.Resources.OOFGet_Title, + MessageBoxButtons.OKCancel, + MessageBoxIcon.Error + ) != DialogResult.OK) + { + return; + } + else + { + // Initialise default settings + settings = new ActiveSync.SettingsOOF(); + settings.Message = new ActiveSync.OOFMessage[3]; + } + } + + // Store them for later use + StoreOOFSettings(account, settings); + + // Show the dialog + ShowOOFDialog(account, settings); + } + catch(System.Exception e) + { + Logger.Instance.Warning(this, "Exception: {0}", e); + } + } + } + + private void ShowOOFDialog(ZPushAccount account, ActiveSync.SettingsOOF settings) + { + + // Show dialog + if (new OutOfOfficeDialog(account, settings).ShowDialog() != DialogResult.OK) + return; + + try + { + // Store settings + ActiveSync.SettingsOOF actualSettings = ProgressDialog.Execute("OOFSet", + (ct) => + { + using (ZPushConnection connection = new ZPushConnection(account, ct)) + { + // Set the OOF state. This always seems to return ok, so we fetch the settings + // again, to see what happend + connection.Execute(new ActiveSync.SettingsOOFSet(settings)); + + // Fetch the OOF state + return connection.Execute(new ActiveSync.SettingsOOFGet()); + } + } + ); + + // Store them for later use + StoreOOFSettings(account, actualSettings); + + // Check what happened + string message; + MessageBoxIcon messageIcon; + if (settings.State == ActiveSync.OOFState.Disabled) + { + // Tried to disable. + if (actualSettings.State != ActiveSync.OOFState.Disabled) + { + // It's an error if its not actually disabled + message = Properties.Resources.OOFSet_DisableFailed; + messageIcon = MessageBoxIcon.Error; + } + else + { + // All good + message = Properties.Resources.OOFSet_Disabled; + messageIcon = MessageBoxIcon.Information; + } + } + else if (actualSettings.State == ActiveSync.OOFState.Disabled) + { + // It's an error if the state is set to disabled when we tried to enable + message = Properties.Resources.OOFSet_EnableFailed; + messageIcon = MessageBoxIcon.Error; + } + else + { + // All good + if (actualSettings.State == ActiveSync.OOFState.EnabledTimeBased) + { + message = string.Format(Properties.Resources.OOFSet_EnabledTimeBased, + actualSettings.From, actualSettings.Till); + } + else + { + message = Properties.Resources.OOFSet_Enabled; + } + messageIcon = MessageBoxIcon.Information; + + // It's okay if the state is not the same, but it deserves a message + if (actualSettings.State != settings.State) + { + message = Properties.Resources.OOFSet_DifferentState + message; + messageIcon = MessageBoxIcon.Warning; + } + } + + Logger.Instance.Debug(this, "OOF state updated: {0}, {1}", message, messageIcon); + MessageBox.Show(message, + Properties.Resources.OOFSet_Title, + MessageBoxButtons.OK, + messageIcon + ); + } + catch (System.Exception e) + { + ErrorUtil.HandleErrorNew(this, "Exception in OOFSet", e, + Properties.Resources.OOFSet_Title, Properties.Resources.OOFSet_Failed); + } + } + + /// + /// Invoked by AccountWatcher on start-up to notify of the oof status. + /// + public void OnOOFSettings(ZPushAccount account, ActiveSync.SettingsOOF oof) + { + // Store them for later use + StoreOOFSettings(account, oof); + + // Show a message if OOF is enabled + if (oof.State != ActiveSync.OOFState.Disabled) + { + if (MessageBox.Show( + string.Format(Properties.Resources.OOFStartup_Message, account.SmtpAddress), + Properties.Resources.OOFStartup_Title, + MessageBoxButtons.YesNo, + MessageBoxIcon.Question + ) == DialogResult.Yes) + { + ShowOOFDialog(account, oof); + } + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/OutOfOfficeDialog.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/OutOfOfficeDialog.Designer.cs new file mode 100644 index 0000000..f2ac927 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/OutOfOfficeDialog.Designer.cs @@ -0,0 +1,225 @@ +namespace Acacia.Features.OutOfOffice +{ + partial class OutOfOfficeDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(OutOfOfficeDialog)); + this.tableGlobal = new System.Windows.Forms.TableLayoutPanel(); + this.chkEnable = new System.Windows.Forms.CheckBox(); + this.tableDates = new System.Windows.Forms.TableLayoutPanel(); + this.radioNoTime = new System.Windows.Forms.RadioButton(); + this.radioTime = new System.Windows.Forms.RadioButton(); + this.dateFrom = new System.Windows.Forms.DateTimePicker(); + this.timeFrom = new System.Windows.Forms.DateTimePicker(); + this.labelTill = new System.Windows.Forms.Label(); + this.dateTill = new System.Windows.Forms.DateTimePicker(); + this.timeTill = new System.Windows.Forms.DateTimePicker(); + this.groupTextEntry = new System.Windows.Forms.GroupBox(); + this.tableTextEntry = new System.Windows.Forms.TableLayoutPanel(); + this.labelBody = new System.Windows.Forms.Label(); + this.textBody = new System.Windows.Forms.TextBox(); + this.flowButtons = new System.Windows.Forms.FlowLayoutPanel(); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnSave = new System.Windows.Forms.Button(); + this.tableGlobal.SuspendLayout(); + this.tableDates.SuspendLayout(); + this.groupTextEntry.SuspendLayout(); + this.tableTextEntry.SuspendLayout(); + this.flowButtons.SuspendLayout(); + this.SuspendLayout(); + // + // tableGlobal + // + resources.ApplyResources(this.tableGlobal, "tableGlobal"); + this.tableGlobal.Controls.Add(this.chkEnable, 0, 0); + this.tableGlobal.Controls.Add(this.tableDates, 0, 1); + this.tableGlobal.Controls.Add(this.groupTextEntry, 0, 2); + this.tableGlobal.Controls.Add(this.flowButtons, 0, 3); + this.tableGlobal.Name = "tableGlobal"; + // + // chkEnable + // + resources.ApplyResources(this.chkEnable, "chkEnable"); + this.chkEnable.Name = "chkEnable"; + this.chkEnable.UseVisualStyleBackColor = true; + this.chkEnable.CheckedChanged += new System.EventHandler(this.chkEnable_CheckedChanged); + // + // tableDates + // + resources.ApplyResources(this.tableDates, "tableDates"); + this.tableDates.Controls.Add(this.radioNoTime, 0, 0); + this.tableDates.Controls.Add(this.radioTime, 0, 1); + this.tableDates.Controls.Add(this.dateFrom, 1, 1); + this.tableDates.Controls.Add(this.timeFrom, 2, 1); + this.tableDates.Controls.Add(this.labelTill, 0, 2); + this.tableDates.Controls.Add(this.dateTill, 1, 2); + this.tableDates.Controls.Add(this.timeTill, 2, 2); + this.tableDates.Name = "tableDates"; + // + // radioNoTime + // + resources.ApplyResources(this.radioNoTime, "radioNoTime"); + this.radioNoTime.Checked = true; + this.tableDates.SetColumnSpan(this.radioNoTime, 3); + this.radioNoTime.Name = "radioNoTime"; + this.radioNoTime.TabStop = true; + this.radioNoTime.UseVisualStyleBackColor = true; + // + // radioTime + // + resources.ApplyResources(this.radioTime, "radioTime"); + this.radioTime.Name = "radioTime"; + this.radioTime.UseVisualStyleBackColor = true; + this.radioTime.CheckedChanged += new System.EventHandler(this.radioTime_CheckedChanged); + // + // dateFrom + // + resources.ApplyResources(this.dateFrom, "dateFrom"); + this.dateFrom.Name = "dateFrom"; + this.dateFrom.ValueChanged += new System.EventHandler(this.dateFrom_ValueChanged); + // + // timeFrom + // + resources.ApplyResources(this.timeFrom, "timeFrom"); + this.timeFrom.Format = System.Windows.Forms.DateTimePickerFormat.Custom; + this.timeFrom.Name = "timeFrom"; + this.timeFrom.ShowUpDown = true; + this.timeFrom.ValueChanged += new System.EventHandler(this.timeFrom_ValueChanged); + // + // labelTill + // + resources.ApplyResources(this.labelTill, "labelTill"); + this.labelTill.Name = "labelTill"; + // + // dateTill + // + resources.ApplyResources(this.dateTill, "dateTill"); + this.dateTill.Name = "dateTill"; + this.dateTill.ValueChanged += new System.EventHandler(this.dateTill_ValueChanged); + // + // timeTill + // + resources.ApplyResources(this.timeTill, "timeTill"); + this.timeTill.Format = System.Windows.Forms.DateTimePickerFormat.Custom; + this.timeTill.Name = "timeTill"; + this.timeTill.ShowUpDown = true; + // + // groupTextEntry + // + resources.ApplyResources(this.groupTextEntry, "groupTextEntry"); + this.groupTextEntry.Controls.Add(this.tableTextEntry); + this.groupTextEntry.Name = "groupTextEntry"; + this.groupTextEntry.TabStop = false; + // + // tableTextEntry + // + resources.ApplyResources(this.tableTextEntry, "tableTextEntry"); + this.tableTextEntry.Controls.Add(this.labelBody, 0, 0); + this.tableTextEntry.Controls.Add(this.textBody, 0, 1); + this.tableTextEntry.Name = "tableTextEntry"; + // + // labelBody + // + resources.ApplyResources(this.labelBody, "labelBody"); + this.labelBody.Name = "labelBody"; + // + // textBody + // + this.textBody.AcceptsReturn = true; + resources.ApplyResources(this.textBody, "textBody"); + this.textBody.Name = "textBody"; + // + // flowButtons + // + resources.ApplyResources(this.flowButtons, "flowButtons"); + this.flowButtons.Controls.Add(this.btnCancel); + this.flowButtons.Controls.Add(this.btnSave); + this.flowButtons.Name = "flowButtons"; + // + // btnCancel + // + resources.ApplyResources(this.btnCancel, "btnCancel"); + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Name = "btnCancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnSave + // + resources.ApplyResources(this.btnSave, "btnSave"); + this.btnSave.DialogResult = System.Windows.Forms.DialogResult.OK; + this.btnSave.Name = "btnSave"; + this.btnSave.UseVisualStyleBackColor = true; + // + // OutOfOfficeDialog + // + this.AcceptButton = this.btnSave; + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.Controls.Add(this.tableGlobal); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "OutOfOfficeDialog"; + this.ShowInTaskbar = false; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show; + this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.OutOfOfficeDialog_FormClosed); + this.tableGlobal.ResumeLayout(false); + this.tableGlobal.PerformLayout(); + this.tableDates.ResumeLayout(false); + this.tableDates.PerformLayout(); + this.groupTextEntry.ResumeLayout(false); + this.groupTextEntry.PerformLayout(); + this.tableTextEntry.ResumeLayout(false); + this.tableTextEntry.PerformLayout(); + this.flowButtons.ResumeLayout(false); + this.flowButtons.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableGlobal; + private System.Windows.Forms.CheckBox chkEnable; + private System.Windows.Forms.RadioButton radioNoTime; + private System.Windows.Forms.GroupBox groupTextEntry; + private System.Windows.Forms.FlowLayoutPanel flowButtons; + private System.Windows.Forms.Button btnCancel; + private System.Windows.Forms.Button btnSave; + private System.Windows.Forms.TableLayoutPanel tableDates; + private System.Windows.Forms.RadioButton radioTime; + private System.Windows.Forms.DateTimePicker dateFrom; + private System.Windows.Forms.DateTimePicker dateTill; + private System.Windows.Forms.TableLayoutPanel tableTextEntry; + private System.Windows.Forms.Label labelBody; + private System.Windows.Forms.TextBox textBody; + private System.Windows.Forms.DateTimePicker timeFrom; + private System.Windows.Forms.DateTimePicker timeTill; + private System.Windows.Forms.Label labelTill; + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/OutOfOfficeDialog.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/OutOfOfficeDialog.cs new file mode 100644 index 0000000..44a3805 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/OutOfOfficeDialog.cs @@ -0,0 +1,192 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.UI; +using Acacia.Utils; +using Acacia.ZPush; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.Features.OutOfOffice +{ + public partial class OutOfOfficeDialog : KopanoDialog + { + private ActiveSync.SettingsOOF _settings; + private readonly bool haveTimes; + + public OutOfOfficeDialog(ZPushAccount account, ActiveSync.SettingsOOF settings) + { + this._settings = settings; + + InitializeComponent(); + + // Add the email address to the title + Text = string.Format(Text, account.SmtpAddress); + + // Set the time formats + timeFrom.CustomFormat = CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern; + timeTill.CustomFormat = CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern; + + // Patch the position of the until label, to align + // with the from text + using (Graphics graphics = radioTime.CreateGraphics()) + { + Size size = RadioButtonRenderer.GetGlyphSize(graphics, System.Windows.Forms.VisualStyles.RadioButtonState.CheckedNormal); + Padding padding = labelTill.Margin; + padding.Left = radioTime.Margin.Left + size.Width + 2; + labelTill.Margin = padding; + } + + // Enable controls + chkEnable_CheckedChanged(chkEnable, null); + radioTime_CheckedChanged(radioTime, null); + + // Hide time options, only if it is known that these are not supported + haveTimes = _settings.SupportsTimes != false; + if (!haveTimes) + { + tableDates.Visible = false; + } + + // Load settings + switch(settings.State) + { + case ActiveSync.OOFState.Disabled: + chkEnable.Checked = false; + break; + case ActiveSync.OOFState.Enabled: + chkEnable.Checked = true; + radioNoTime.Checked = true; + break; + case ActiveSync.OOFState.EnabledTimeBased: + chkEnable.Checked = true; + radioTime.Checked = true; + dateFrom.Value = settings.From.Value; + timeFrom.Value = settings.From.Value; + dateTill.Value = settings.Till.Value; + timeTill.Value = settings.Till.Value; + break; + } + + textBody.Text = settings.Message[(int)ActiveSync.OOFTarget.Internal]?.Message; + + // Set up limits + SetTillTimeLimit(); + } + + private void chkEnable_CheckedChanged(object sender, EventArgs e) + { + tableDates.Enabled = chkEnable.Checked; + groupTextEntry.Enabled = chkEnable.Checked; + } + + private void radioTime_CheckedChanged(object sender, EventArgs e) + { + dateFrom.Enabled = timeFrom.Enabled = radioTime.Checked; + dateTill.Enabled = timeTill.Enabled = radioTime.Checked; + } + + private void OutOfOfficeDialog_FormClosed(object sender, FormClosedEventArgs e) + { + // Save the settings + _settings.From = null; + _settings.Till = null; + + if (chkEnable.Checked) + { + if (radioNoTime.Checked || !haveTimes) + { + _settings.State = ActiveSync.OOFState.Enabled; + } + else + { + _settings.State = ActiveSync.OOFState.EnabledTimeBased; + _settings.From = GetDateTime(dateFrom, timeFrom); + _settings.Till = GetDateTime(dateTill, timeTill); + } + } + else + { + _settings.State = ActiveSync.OOFState.Disabled; + } + + // Always set the message, so it's stored + string message = textBody.Text; + for (int i = 0; i < 3; ++i) + { + _settings.Message[i] = new ActiveSync.OOFMessage(); + _settings.Message[i].Message = message; + } + } + + private DateTime GetDateTime(DateTimePicker dateControl, DateTimePicker timeControl) + { + DateTime date = dateControl.Value; + DateTime time = timeControl.Value; + DateTime combined = new DateTime(date.Year, date.Month, date.Day); + combined = combined.Add(time.TimeOfDay); + return combined; + } + + #region Date/Time checking + + private void dateFrom_ValueChanged(object sender, EventArgs e) + { + SetTillTimeLimit(); + } + + private void timeFrom_ValueChanged(object sender, EventArgs e) + { + SetTillTimeLimit(); + } + + private void dateTill_ValueChanged(object sender, EventArgs e) + { + SetTillTimeLimit(); + } + + private void timeTill_ValueChanged(object sender, EventArgs e) + { + SetTillTimeLimit(); + } + + private void SetTillTimeLimit() + { + // Don't allow setting till to before from, or before now + dateTill.MinDate = new DateTime(Math.Max(dateFrom.Value.Ticks, DateTime.Today.Ticks)); + + if (dateTill.Value.Date == dateFrom.Value.Date) + { + timeTill.MinDate = timeFrom.Value; + } + else + { + timeTill.MinDate = DateTimePicker.MinimumDateTime; + } + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/OutOfOfficeDialog.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/OutOfOfficeDialog.resx new file mode 100644 index 0000000..ef516dd --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/OutOfOffice/OutOfOfficeDialog.resx @@ -0,0 +1,690 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Top, Bottom, Left, Right + + + + 1 + + + True + + + + 3, 2 + + + 3, 2, 3, 2 + + + 262, 21 + + + 0 + + + Enable out-of-office auto-responding + + + chkEnable + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableGlobal + + + 0 + + + Top, Bottom, Left, Right + + + True + + + GrowAndShrink + + + 3 + + + Top, Bottom, Left + + + True + + + 24, 2 + + + 24, 2, 3, 2 + + + 143, 21 + + + 1 + + + until further notice + + + radioNoTime + + + System.Windows.Forms.RadioButton, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableDates + + + 0 + + + Top, Bottom, Left + + + True + + + 24, 27 + + + 24, 2, 3, 2 + + + 57, 22 + + + 2 + + + from + + + radioTime + + + System.Windows.Forms.RadioButton, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableDates + + + 1 + + + 87, 27 + + + 3, 2, 3, 2 + + + 169, 22 + + + 3 + + + dateFrom + + + System.Windows.Forms.DateTimePicker, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableDates + + + 2 + + + HH:mm + + + 262, 27 + + + 3, 2, 3, 2 + + + 87, 22 + + + 4 + + + timeFrom + + + System.Windows.Forms.DateTimePicker, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableDates + + + 3 + + + Top, Bottom, Left, Right + + + True + + + 44, 51 + + + 44, 0, 3, 0 + + + 37, 26 + + + 7 + + + until + + + MiddleLeft + + + labelTill + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableDates + + + 4 + + + 87, 53 + + + 3, 2, 3, 2 + + + 169, 22 + + + 5 + + + dateTill + + + System.Windows.Forms.DateTimePicker, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableDates + + + 5 + + + HH:mm + + + 262, 53 + + + 3, 2, 3, 2 + + + 87, 22 + + + 6 + + + timeTill + + + System.Windows.Forms.DateTimePicker, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableDates + + + 6 + + + 0, 25 + + + 0, 0, 0, 0 + + + 3 + + + 431, 77 + + + 1 + + + tableDates + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableGlobal + + + 1 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="radioNoTime" Row="0" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="radioTime" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="dateFrom" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="timeFrom" Row="1" RowSpan="1" Column="2" ColumnSpan="1" /><Control Name="labelTill" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="dateTill" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="timeTill" Row="2" RowSpan="1" Column="2" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,AutoSize,0,AutoSize,0,Absolute,20" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0" /></TableLayoutSettings> + + + Top, Bottom, Left, Right + + + True + + + Top, Bottom, Left, Right + + + True + + + GrowAndShrink + + + 1 + + + True + + + 3, 6 + + + 3, 6, 3, 0 + + + 377, 17 + + + 2 + + + AutoReply only once to each sender with the following text: + + + labelBody + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableTextEntry + + + 0 + + + Top, Bottom, Left, Right + + + 3, 25 + + + 3, 2, 3, 2 + + + True + + + 411, 168 + + + 8 + + + textBody + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableTextEntry + + + 1 + + + 4, 14 + + + 3, 2, 3, 2 + + + 2 + + + 417, 195 + + + 0 + + + tableTextEntry + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupTextEntry + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelBody" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="textBody" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,100" /><Rows Styles="AutoSize,0,Percent,100,Absolute,25,Absolute,25" /></TableLayoutSettings> + + + 3, 104 + + + 3, 2, 3, 2 + + + 3, 2, 3, 2 + + + 425, 216 + + + 2 + + + groupTextEntry + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableGlobal + + + 2 + + + Top, Bottom, Left, Right + + + True + + + 341, 2 + + + 3, 2, 3, 2 + + + 81, 33 + + + 10 + + + Cancel + + + btnCancel + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + flowButtons + + + 0 + + + True + + + 254, 2 + + + 3, 2, 3, 2 + + + 81, 33 + + + 9 + + + Save + + + btnSave + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + flowButtons + + + 1 + + + RightToLeft + + + 3, 324 + + + 3, 2, 3, 2 + + + 425, 38 + + + 3 + + + flowButtons + + + System.Windows.Forms.FlowLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableGlobal + + + 3 + + + 5, 5 + + + 3, 2, 3, 2 + + + 4 + + + 431, 364 + + + 0 + + + tableGlobal + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="chkEnable" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="tableDates" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="groupTextEntry" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="flowButtons" Row="3" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0,Percent,100,AutoSize,0,Absolute,20" /></TableLayoutSettings> + + + True + + + 8, 16 + + + 444, 382 + + + 3, 2, 3, 2 + + + 458, 415 + + + 5, 5, 5, 5 + + + CenterParent + + + Out of Office Assistant for {0} + + + OutOfOfficeDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/ReplyFlags/FeatureReplyFlags.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/ReplyFlags/FeatureReplyFlags.cs new file mode 100644 index 0000000..4d77a6f --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/ReplyFlags/FeatureReplyFlags.cs @@ -0,0 +1,181 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Acacia.Stubs; +using Acacia.Utils; +using Acacia.ZPush; +using Microsoft.Office.Interop.Outlook; +using static Acacia.DebugOptions; + +namespace Acacia.Features.ReplyFlags +{ + [AcaciaOption("Synchronises reply flags between Outlook and Z-Push servers.")] + public class FeatureReplyFlags : Feature + { + public FeatureReplyFlags() + { + + } + + public override void Startup() + { + if (UpdateEvents) + { + // Watch all mail folders and all items in them + Watcher.WatchFolder(new FolderRegistrationTyped(this, ItemType.MailItem), + (folder) => Watcher.WatchItems(folder, UpdateReplyStatus, false) + ); + } + + if (ReadEvent) + { + // As a fallback, add an event handler to update the message when displaying it + MailEvents.Read += UpdateReplyStatus; + } + + if (SendEvents) + { + // Hook reply and send events to update local state to server + MailEvents.Reply += OnReply; + MailEvents.ReplyAll += OnReplyAll; + MailEvents.Forward += OnForwarded; + } + } + + [AcaciaOption("Enables or disables the handling of update events to mail items. When a mail item is " + + "updated, it is checked to see if the reply flags are up to date. This is the main " + + "mechanism for updating reply flags that change on the server")] + public bool UpdateEvents + { + get { return GetOption(OPTION_UPDATE_EVENTS); } + set { SetOption(OPTION_UPDATE_EVENTS, value); } + } + private static readonly BoolOption OPTION_UPDATE_EVENTS = new BoolOption("FolderEvents", true); + + [AcaciaOption("Enables or disables the handling of read events on mail items. If this is enabled, " + + "the reply flag is checked. This is almost guaranteed to work, but has the downside " + + "of only updating the reply flag when an email is opened")] + public bool ReadEvent + { + get { return GetOption(OPTION_READ_EVENT); } + set { SetOption(OPTION_READ_EVENT, value); } + } + private static readonly BoolOption OPTION_READ_EVENT = new BoolOption("ReadEvents", true); + + [AcaciaOption("Enables or disables the handling of send events on mail items. If this is enabled, " + + "the reply flag is included in emails sent to the Z-Push server, which will update " + + "the flag on the server")] + public bool SendEvents + { + get { return GetOption(OPTION_SEND_EVENTS); } + set { SetOption(OPTION_SEND_EVENTS, value); } + } + private static readonly BoolOption OPTION_SEND_EVENTS = new BoolOption("SendEvents", true); + + [AcaciaOption("Disables the parsing of reply flags on incoming mail items." + + "When this flag is disabled, reply flags coming from the server will be completely ignored.")] + public bool ParseIncoming + { + get { return GetOption(OPTION_INCOMING_PARSE); } + set { SetOption(OPTION_INCOMING_PARSE, value); } + } + private static readonly BoolOption OPTION_INCOMING_PARSE = new BoolOption("IncomingParse", true); + + [AcaciaOption("Disables the updating of reply flags on incoming mail items." + + "When this flag is disabled, reply flags coming from the server will be examined, " + + "but not action will be taken on them.")] + public bool UpdateIncoming + { + get { return GetOption(OPTION_INCOMING_UPDATE); } + set { SetOption(OPTION_INCOMING_UPDATE, value); } + } + private static readonly BoolOption OPTION_INCOMING_UPDATE = new BoolOption("IncomingUpdate", true); + + [AcaciaOption("Disables the updating of reply flags in outgoing emails." + + "If this option is enabled, reply flags will not be sent to the Z-Push server")] + public bool UpdateOutgoing + { + get { return GetOption(OPTION_OUTGOING_UPDATE); } + set { SetOption(OPTION_OUTGOING_UPDATE, value); } + } + private static readonly BoolOption OPTION_OUTGOING_UPDATE = new BoolOption("OutgoingUpdate", true); + + #region Server to outlook + + private void UpdateReplyStatus(IMailItem mail) + { + if (!ParseIncoming) + return; + bool update = UpdateIncoming; + + // See if the categories contain a reply flag + ReplyFlags flags = ReplyFlags.FromCategory(mail, update); + if (flags != null) + { + if (update) + { + Logger.Instance.Debug(this, "Updating flags: {0}", mail.Subject); + + // Update the mail item. This will also save the changed category list + flags.UpdateLocal(); + } + } + } + + #endregion + + #region Outlook to server + + private readonly Queue lastItems = new Queue(); + + private void OnReply(IMailItem mail, IMailItem response) + { + SetReplyFlag(mail, response, Verb.REPLIED); + } + + private void OnReplyAll(IMailItem mail, IMailItem response) + { + SetReplyFlag(mail, response, Verb.REPLIED_TO_ALL); + } + + private void OnForwarded(IMailItem mail, IMailItem response) + { + SetReplyFlag(mail, response, Verb.FORWARDED); + } + + private void SetReplyFlag(IMailItem mail, IMailItem response, Verb verb) + { + if (!UpdateOutgoing) + return; + + string id = (string)mail.GetProperty(OutlookConstants.PR_ZPUSH_MESSAGE_ID); + using (IFolder folder = mail.Parent) + { + string folderId = (string)folder.GetProperty(OutlookConstants.PR_ZPUSH_FOLDER_ID); + string value = ReplyFlags.VerbToExchange(verb) + "/" + id + "/" + folderId; + Logger.Instance.Trace(this, "Reply header: {0}", value); + response.SetProperty(Constants.ZPUSH_REPLY_HEADER, value); + } + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/ReplyFlags/ReplyFlags.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/ReplyFlags/ReplyFlags.cs new file mode 100644 index 0000000..e50f83c --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/ReplyFlags/ReplyFlags.cs @@ -0,0 +1,229 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Acacia.Stubs; +using Acacia.Utils; + +namespace Acacia.Features.ReplyFlags +{ + public enum Verb + { + NONE, + REPLIED, + REPLIED_TO_ALL, + FORWARDED + } + + // TODO: unit tests for parsing + public class ReplyFlags + { + private readonly IMailItem _item; + + public Verb Verb + { + get; + private set; + } + + public DateTime? Date + { + get; + private set; + } + + /// + /// Constructor. Reads the reply state from the mail item's reply properties + /// + public ReplyFlags(IMailItem item) + { + this._item = item; + ReadFromProperties(); + } + + /// + /// Fully initializing constructor. + /// + private ReplyFlags(IMailItem item, Verb verb, DateTime date) + { + this._item = item; + this.Verb = verb; + this.Date = date; + } + + /// + /// Constructs the ReplyFlags object from the mail's categories, if present. + /// If the category is present, it is removed. Changes are not saved, so this will have to be done explicitly. + /// If no category is present, null is returned. + /// + /// + /// + public static ReplyFlags FromCategory(IMailItem item, bool updateCategories = true) + { + string[] categories = item.AttrCategories; + if (categories == null || categories.Length == 0) + return null; + + // See if we have the z-push reply header + for (int i = 0; i < categories.Length; ++i) + { + string category = categories[i]; + + // This test will be invoked on every change, so do a quick test first + if (category.StartsWith(Constants.ZPUSH_REPLY_CATEGORY_PREFIX)) + { + string suffix = category.Substring(Constants.ZPUSH_REPLY_CATEGORY_PREFIX.Length); + Match match = Constants.ZPUSH_REPLY_CATEGORY_REGEX.Match(suffix); + if (match.Success) + { + try + { + string dateString = match.Groups[2].Value; + + // Parse the state + Verb verb = VerbFromString(match.Groups[1].Value); + + // Parse the date + DateTime date = DateTime.Parse(dateString); + + // Remove the category + if (updateCategories) + { + var categoriesList = new List(categories); + categoriesList.RemoveAt(i); + item.AttrCategories = categoriesList.ToArray(); + } + + // Return the flags + return new ReplyFlags(item, verb, date); + } + catch (System.Exception e) + { + // Ignore any exception + Logger.Instance.Error(typeof(ReplyFlags), "Exception while parsing reply category: {0}", e); + } + } + } + } + + return null; + } + + private void ReadFromProperties() + { + // Read the date + Date = _item.AttrLastVerbExecutionTime; + + // And the state + int state = _item.AttrLastVerbExecuted; + switch (state) + { + case OutlookConstants.EXCHIVERB_FORWARD: + Verb = Verb.FORWARDED; + break; + case OutlookConstants.EXCHIVERB_REPLYTOALL: + case OutlookConstants.EXCHIVERB_REPLYTOSENDER: + case OutlookConstants.EXCHIVERB_REPLYTOFOLDER: + Verb = Verb.REPLIED; + break; + default: + Verb = Verb.NONE; + break; + } + } + + /// + /// Updates the local mail item from the current state + /// + public void UpdateLocal() + { + // Determine icon and verb + int icon = OutlookConstants.PR_ICON_INDEX_NONE; + int verb = OutlookConstants.EXCHIVERB_OPEN; + switch (Verb) + { + case Verb.REPLIED: + icon = OutlookConstants.PR_ICON_INDEX_REPLIED; + verb = OutlookConstants.EXCHIVERB_REPLYTOSENDER; + break; + case Verb.REPLIED_TO_ALL: + icon = OutlookConstants.PR_ICON_INDEX_REPLIED; + verb = OutlookConstants.EXCHIVERB_REPLYTOALL; + break; + case Verb.FORWARDED: + icon = OutlookConstants.PR_ICON_INDEX_FORWARDED; + verb = OutlookConstants.EXCHIVERB_FORWARD; + break; + } + + // Set the properties + _item.SetProperties( + new string[] + { + OutlookConstants.PR_ICON_INDEX, + OutlookConstants.PR_LAST_VERB_EXECUTED, + OutlookConstants.PR_LAST_VERB_EXECUTION_TIME + }, + new object[] + { + icon, + verb, + Date + } + ); + + // And save + _item.Save(); + } + + override public string ToString() + { + return Verb + "=" + Date; + } + + public static Verb VerbFromString(string verb) + { + if (verb == Constants.ZPUSH_REPLY_CATEGORY_REPLIED) + return Verb.REPLIED; + else if (verb == Constants.ZPUSH_REPLY_CATEGORY_REPLIED_TO_ALL) + return Verb.REPLIED_TO_ALL; + else if (verb == Constants.ZPUSH_REPLY_CATEGORY_FORWARDED) + return Verb.FORWARDED; + else + throw new System.Exception("Invalid verb: " + verb); + } + + public static int VerbToExchange(Verb verb) + { + switch(verb) + { + case Verb.REPLIED: + return OutlookConstants.EXCHIVERB_REPLYTOSENDER; + case Verb.REPLIED_TO_ALL: + return OutlookConstants.EXCHIVERB_REPLYTOALL; + case Verb.FORWARDED: + return OutlookConstants.EXCHIVERB_FORWARD; + default: + throw new System.Exception("Invalid verb: " + verb); + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SendAs/FeatureSendAs.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SendAs/FeatureSendAs.cs new file mode 100644 index 0000000..2ad949e --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SendAs/FeatureSendAs.cs @@ -0,0 +1,125 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Acacia.Stubs; +using Acacia.Utils; +using Acacia.ZPush; +using Microsoft.Office.Interop.Outlook; +using Acacia.Features.SharedFolders; +using Acacia.ZPush.API.SharedFolders; +using static Acacia.DebugOptions; + +namespace Acacia.Features.SendAs +{ + [AcaciaOption("Provides the ability to select different senders for Z-Push accounts.")] + public class FeatureSendAs : FeatureDisabled + { + private FeatureSharedFolders _sharedFolders; + + public FeatureSendAs() + { + } + + [AcaciaOption("Disables the \"Send As Owner\" feature. This feature allows sending as the owner of a shared folder, " + + "when responding to messages in that folder. Note that this feature requires SharedFolders to be " + + "enabled")] + public bool SendAsOwner + { + get { return GetOption(OPTION_SEND_AS_OWNER); } + set { SetOption(OPTION_SEND_AS_OWNER, value); } + } + private static readonly BoolOption OPTION_SEND_AS_OWNER = new BoolOption("SendAsOwner", true); + + public override void Startup() + { + MailEvents.ItemSend += MailEvents_ItemSend; + + if (SendAsOwner) + { + // Need shared folders for automatic sender selection + _sharedFolders = ThisAddIn.Instance.GetFeature(); + if (_sharedFolders != null) + { + MailEvents.Respond += MailEvents_Respond; + } + } + } + + private void MailEvents_Respond(IMailItem mail, IMailItem response) + { + Logger.Instance.Trace(this, "Responding to mail, checking"); + using (IStore store = mail.Store) + { + ZPushAccount zpush = Watcher.Accounts.GetAccount(store); + Logger.Instance.Trace(this, "Checking ZPush: {0}", zpush); + if (zpush != null) + { + // Check if the containing folder is a shared folder + using (IFolder parent = mail.Parent) + { + Logger.Instance.Trace(this, "Checking, Parent folder: {0}", parent.Name); + SharedFolder shared = _sharedFolders.GetSharedFolder(parent); + if (shared != null) + Logger.Instance.Trace(this, "Checking, Shared folder: {0}, flags={1}", shared, shared?.Flags); + else + Logger.Instance.Trace(this, "Not a shared folder"); + if (shared != null && shared.FlagSendAsOwner) + { + Logger.Instance.Trace(this, "Checking, Shared folder owner: {0}", shared.Store.UserName); + // It's a shared folder, use the owner as the sender if possible + // TODO: make a wrapper for this + var recip = ThisAddIn.Instance.Application.Session.CreateRecipient(shared.Store.UserName); + Logger.Instance.Trace(this, "Checking, Shared folder owner recipient: {0}", recip.Name); + if (recip != null && recip.Resolve()) + { + Logger.Instance.Trace(this, "Sending as: {0}", recip.AddressEntry.Address); + response.SetSender(recip.AddressEntry); + } + else + { + Logger.Instance.Trace(this, "Unable to resolve sender"); + } + } + } + } + } + } + + private void MailEvents_ItemSend(IMailItem item, ref bool cancel) + { + using (IStore store = item.Store) + { + ZPushAccount zpush = Watcher.Accounts.GetAccount(store); + if (zpush != null) + { + string address = item.SenderEmailAddress; + if (address != null && address != zpush.SmtpAddress) + { + Logger.Instance.Trace(this, "SendAs: {0}: {1}", address, item.SenderName); + item.SetProperty(Constants.ZPUSH_SEND_AS, address); + if (item.SenderName != null) + item.SetProperty(Constants.ZPUSH_SEND_AS_NAME, item.SenderName); + } + } + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FeatureSharedFolders.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FeatureSharedFolders.cs new file mode 100644 index 0000000..38e1617 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FeatureSharedFolders.cs @@ -0,0 +1,131 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Stubs; +using Acacia.UI; +using Acacia.UI.Outlook; +using Acacia.ZPush; +using Acacia.ZPush.API.SharedFolders; +using Acacia.ZPush.Connect; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Features.SharedFolders +{ + [AcaciaOption("Provides the ability to open shared folders from other users in Outlook.")] + public class FeatureSharedFolders + : + Feature, FeatureWithRibbon, FeatureWithContextMenu + { + public override void Startup() + { + RegisterButton(this, "SharedFolders", true, ManageFolders, ZPushBehaviour.Disable); + + MenuItem menuItem = RegisterMenuItem(this, "SharedFolders_Context", null, ManageFolder, ZPushBehaviour.Hide); + if (menuItem != null) + menuItem.CheckEnabled = CanManageFolder; + + // Sync state + Watcher.Sync.AddTask(this, Name, AdditionalFolders_Sync); + } + + #region UI + + private bool CanManageFolder(MenuItem b, IFolder folder) + { + return folder.SyncId?.IsShared == true; + } + + private void ManageFolder(IFolder folder) + { + ZPushAccount account = Watcher.Accounts.GetAccount(folder); + if (account != null) + { + new SharedFoldersDialog(account, folder.SyncId).ShowDialog(); + } + } + + private void ManageFolders() + { + ZPushAccount account = Watcher.CurrentZPushAccount(); + if (account != null) + { + new SharedFoldersDialog(account).ShowDialog(); + } + } + + #endregion + + #region Shared folders sync + + private const string KEY_SHARES = "Shares"; + + private void AdditionalFolders_Sync(ZPushConnection connection) + { + Logger.Instance.Debug(this, "Starting sync for account {0}", connection.Account); + using (SharedFoldersAPI api = new SharedFoldersAPI(connection)) + { + // Fetch the current shares + ICollection shares = api.GetCurrentShares(); + Logger.Instance.Trace(this, "AdditionalFolders_Sync: {0}", shares.Count); + + // Convert to dictionary + Dictionary dict = shares.ToDictionary(x => x.SyncId); + Logger.Instance.Trace(this, "AdditionalFolders_Sync2: {0}", shares.Count); + + // Store with the account + connection.Account.SetFeatureData(this, KEY_SHARES, dict); + } + } + + public SharedFolder GetSharedFolder(IFolder folder) + { + if (folder == null) + return null; + + // Check that we can get the id + SyncId folderId = folder.SyncId; + Logger.Instance.Trace(this, "GetSharedFolder1: {0}", folderId); + if (folderId == null || !folderId.IsShared) + return null; + + // Get the ZPush account + ZPushAccount account = Watcher.Accounts.GetAccount(folder); + Logger.Instance.Trace(this, "GetSharedFolder2: {0}", account); + if (account == null) + return null; + + // Get the shared folders + Dictionary shared = account.GetFeatureData>(this, KEY_SHARES); + Logger.Instance.Trace(this, "GetSharedFolder3: {0}", shared?.Count); + if (shared == null) + return null; + + SharedFolder share = null; + shared.TryGetValue(folderId, out share); + Logger.Instance.Trace(this, "GetSharedFolder4: {0}", share); + + return share; + } + + #endregion + + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FolderTreeNode.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FolderTreeNode.cs new file mode 100644 index 0000000..a20a1fa --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FolderTreeNode.cs @@ -0,0 +1,95 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Controls; +using Acacia.ZPush; +using Acacia.ZPush.API.SharedFolders; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Features.SharedFolders +{ + public class FolderTreeNode : KTreeNode + { + private readonly StoreTreeNode _store; + private readonly AvailableFolder _folder; + private SharedFolder _share; + + public FolderTreeNode(StoreTreeNode store, AvailableFolder folder, SharedFolder share) + { + this._store = store; + this._folder = folder; + this._share = share; + + this.Text = folder.Name; + + // Image + // TODO: clean this up + int index = ((int)OutlookConstants.BASIC_SYNC_TYPES[(int)folder.Type]) - 1; + if (index < 0 || index >= store.Owner.Images.Images.Count - 1) + index = 0; + ImageIndex = index; + } + + protected override void OnCheckStateChanged() + { + // Update share state + if (CheckState == System.Windows.Forms.CheckState.Unchecked) + _store.RemoveShare(_folder); + else + _share = _store.AddShare(_folder, _share); + + base.OnCheckStateChanged(); + } + + public AvailableFolder AvailableFolder { get { return _folder; } } + + public bool IsShared { get { return CheckState != System.Windows.Forms.CheckState.Unchecked; } } + + /// + /// Returns the current share state. Note that this may return a state, even if IsShared is false, as the state is retained, + /// in case the user reselects it. However, if IsShared is true, a valid object is guaranteed. + /// + public SharedFolder SharedFolder + { + get { return _share; } + set + { + if (value == null) + throw new InvalidOperationException("Cannot unset share"); + if (_share != value) + { + _share = value; + _store.AddShare(_folder, _share); + } + } + } + + // TODO: this is generally useful, move to KTreeNode + public IEnumerable Descendants() + { + foreach(KTreeNode child in Children) + { + yield return (FolderTreeNode)child; + foreach (FolderTreeNode desc in ((FolderTreeNode)child).Descendants()) + yield return desc; + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.Designer.cs new file mode 100644 index 0000000..7645b31 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.Designer.cs @@ -0,0 +1,232 @@ +namespace Acacia.Features.SharedFolders +{ + partial class SharedFoldersDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SharedFoldersDialog)); + Acacia.Controls.KCheckManager.RecursiveThreeState recursiveThreeState1 = new Acacia.Controls.KCheckManager.RecursiveThreeState(); + this._layout = new System.Windows.Forms.TableLayoutPanel(); + this._mainBusyHider = new Acacia.Controls.KBusyHider(); + this._layoutMain = new System.Windows.Forms.TableLayoutPanel(); + this._layoutSelectUser = new System.Windows.Forms.TableLayoutPanel(); + this.labelSelectUser = new System.Windows.Forms.Label(); + this.buttonOpenUser = new System.Windows.Forms.Button(); + this._layoutCenterGABLookup = new System.Windows.Forms.TableLayoutPanel(); + this.gabLookup = new Acacia.UI.GABLookupControl(); + this.kTreeFolders = new Acacia.Controls.KTree(); + this._layoutOptions = new System.Windows.Forms.TableLayoutPanel(); + this._labelName = new System.Windows.Forms.Label(); + this.textName = new System.Windows.Forms.TextBox(); + this._labelSendAs = new System.Windows.Forms.Label(); + this.checkSendAs = new System.Windows.Forms.CheckBox(); + this._labelPermissions = new System.Windows.Forms.Label(); + this.labelPermissionsValue = new System.Windows.Forms.Label(); + this.dialogButtons = new Acacia.Controls.KDialogButtons(); + this._layout.SuspendLayout(); + this._mainBusyHider.SuspendLayout(); + this._layoutMain.SuspendLayout(); + this._layoutSelectUser.SuspendLayout(); + this._layoutCenterGABLookup.SuspendLayout(); + this._layoutOptions.SuspendLayout(); + this.SuspendLayout(); + // + // _layout + // + resources.ApplyResources(this._layout, "_layout"); + this._layout.Controls.Add(this._mainBusyHider, 0, 0); + this._layout.Controls.Add(this.dialogButtons, 0, 1); + this._layout.Name = "_layout"; + // + // _mainBusyHider + // + this._mainBusyHider.Busy = false; + this._mainBusyHider.BusyText = null; + this._mainBusyHider.Cancellation = null; + this._mainBusyHider.Controls.Add(this._layoutMain); + resources.ApplyResources(this._mainBusyHider, "_mainBusyHider"); + this._mainBusyHider.Name = "_mainBusyHider"; + // + // _layoutMain + // + resources.ApplyResources(this._layoutMain, "_layoutMain"); + this._layoutMain.Controls.Add(this._layoutSelectUser, 0, 0); + this._layoutMain.Controls.Add(this.kTreeFolders, 0, 1); + this._layoutMain.Controls.Add(this._layoutOptions, 0, 2); + this._layoutMain.Name = "_layoutMain"; + // + // _layoutSelectUser + // + resources.ApplyResources(this._layoutSelectUser, "_layoutSelectUser"); + this._layoutSelectUser.Controls.Add(this.labelSelectUser, 0, 0); + this._layoutSelectUser.Controls.Add(this.buttonOpenUser, 2, 0); + this._layoutSelectUser.Controls.Add(this._layoutCenterGABLookup, 1, 0); + this._layoutSelectUser.Name = "_layoutSelectUser"; + // + // labelSelectUser + // + resources.ApplyResources(this.labelSelectUser, "labelSelectUser"); + this.labelSelectUser.Name = "labelSelectUser"; + // + // buttonOpenUser + // + resources.ApplyResources(this.buttonOpenUser, "buttonOpenUser"); + this.buttonOpenUser.Name = "buttonOpenUser"; + this.buttonOpenUser.UseVisualStyleBackColor = true; + this.buttonOpenUser.Click += new System.EventHandler(this.buttonOpenUser_Click); + // + // _layoutCenterGABLookup + // + resources.ApplyResources(this._layoutCenterGABLookup, "_layoutCenterGABLookup"); + this._layoutCenterGABLookup.Controls.Add(this.gabLookup, 0, 1); + this._layoutCenterGABLookup.Name = "_layoutCenterGABLookup"; + // + // gabLookup + // + this.gabLookup.DisplayMember = "DisplayName"; + resources.ApplyResources(this.gabLookup, "gabLookup"); + this.gabLookup.FormattingEnabled = true; + this.gabLookup.GAB = null; + this.gabLookup.Name = "gabLookup"; + this.gabLookup.SelectedUserChanged += new Acacia.UI.GABLookupControl.SelectedUserEventHandler(this.gabLookup_SelectedUserChanged); + // + // kTreeFolders + // + this.kTreeFolders.BackColor = System.Drawing.SystemColors.Window; + this.kTreeFolders.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.kTreeFolders.CheckManager = recursiveThreeState1; + this.kTreeFolders.CheckStyle = Acacia.Controls.KCheckStyle.RecursiveThreeState; + resources.ApplyResources(this.kTreeFolders, "kTreeFolders"); + this.kTreeFolders.FullRowSelect = true; + this.kTreeFolders.Images = null; + this.kTreeFolders.MultipleSelection = true; + this.kTreeFolders.Name = "kTreeFolders"; + this.kTreeFolders.NodeIndent = 8; + this.kTreeFolders.NodePadding = new System.Windows.Forms.Padding(2, 4, 2, 4); + this.kTreeFolders.CheckStateChanged += new Acacia.Controls.KTree.CheckStateChangedHandler(this.kTreeFolders_CheckStateChanged); + this.kTreeFolders.SelectionChanged += new Acacia.Controls.KTree.SelectionChangedDelegate(this.kTreeFolders_SelectionChanged); + // + // _layoutOptions + // + resources.ApplyResources(this._layoutOptions, "_layoutOptions"); + this._layoutOptions.Controls.Add(this._labelName, 0, 0); + this._layoutOptions.Controls.Add(this.textName, 1, 0); + this._layoutOptions.Controls.Add(this._labelSendAs, 0, 1); + this._layoutOptions.Controls.Add(this.checkSendAs, 1, 1); + this._layoutOptions.Controls.Add(this._labelPermissions, 0, 2); + this._layoutOptions.Controls.Add(this.labelPermissionsValue, 1, 2); + this._layoutOptions.Name = "_layoutOptions"; + // + // _labelName + // + resources.ApplyResources(this._labelName, "_labelName"); + this._labelName.Name = "_labelName"; + // + // textName + // + resources.ApplyResources(this.textName, "textName"); + this.textName.Name = "textName"; + this.textName.TextChanged += new System.EventHandler(this.textName_TextChanged); + // + // _labelSendAs + // + resources.ApplyResources(this._labelSendAs, "_labelSendAs"); + this._labelSendAs.Name = "_labelSendAs"; + // + // checkSendAs + // + resources.ApplyResources(this.checkSendAs, "checkSendAs"); + this.checkSendAs.Name = "checkSendAs"; + this.checkSendAs.ThreeState = true; + this.checkSendAs.UseVisualStyleBackColor = true; + this.checkSendAs.CheckedChanged += new System.EventHandler(this.checkSendAs_CheckedChanged); + // + // _labelPermissions + // + resources.ApplyResources(this._labelPermissions, "_labelPermissions"); + this._labelPermissions.Name = "_labelPermissions"; + // + // labelPermissionsValue + // + resources.ApplyResources(this.labelPermissionsValue, "labelPermissionsValue"); + this.labelPermissionsValue.Name = "labelPermissionsValue"; + // + // dialogButtons + // + resources.ApplyResources(this.dialogButtons, "dialogButtons"); + this.dialogButtons.ButtonSize = null; + this.dialogButtons.Cancellation = null; + this.dialogButtons.HasApply = true; + this.dialogButtons.IsDirty = false; + this.dialogButtons.Name = "dialogButtons"; + this.dialogButtons.Apply += new System.EventHandler(this.dialogButtons_Apply); + // + // SharedFoldersDialog + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BusyHider = this._mainBusyHider; + this.Controls.Add(this._layout); + this.DialogButtons = this.dialogButtons; + this.Name = "SharedFoldersDialog"; + this.DirtyFormClosing += new System.Windows.Forms.FormClosingEventHandler(this.SharedFoldersDialog_DirtyFormClosing); + this.Shown += new System.EventHandler(this.AddSharedFolderDialog_Shown); + this._layout.ResumeLayout(false); + this._layout.PerformLayout(); + this._mainBusyHider.ResumeLayout(false); + this._layoutMain.ResumeLayout(false); + this._layoutMain.PerformLayout(); + this._layoutSelectUser.ResumeLayout(false); + this._layoutSelectUser.PerformLayout(); + this._layoutCenterGABLookup.ResumeLayout(false); + this._layoutOptions.ResumeLayout(false); + this._layoutOptions.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel _layout; + private Controls.KTree kTreeFolders; + private System.Windows.Forms.TableLayoutPanel _layoutSelectUser; + private System.Windows.Forms.Label labelSelectUser; + private System.Windows.Forms.Button buttonOpenUser; + private System.Windows.Forms.TableLayoutPanel _layoutMain; + private System.Windows.Forms.TableLayoutPanel _layoutOptions; + private System.Windows.Forms.Label _labelName; + private System.Windows.Forms.TextBox textName; + private System.Windows.Forms.Label _labelSendAs; + private System.Windows.Forms.CheckBox checkSendAs; + private System.Windows.Forms.Label _labelPermissions; + private System.Windows.Forms.Label labelPermissionsValue; + private Controls.KBusyHider _mainBusyHider; + private Controls.KDialogButtons dialogButtons; + private System.Windows.Forms.TableLayoutPanel _layoutCenterGABLookup; + private UI.GABLookupControl gabLookup; + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs new file mode 100644 index 0000000..364470b --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs @@ -0,0 +1,495 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Controls; +using Acacia.Features.GAB; +using Acacia.Stubs; +using Acacia.UI; +using Acacia.UI.Outlook; +using Acacia.Utils; +using Acacia.ZPush; +using Acacia.ZPush.API.SharedFolders; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Xml; +using System.Xml.Serialization; +using static Acacia.ZPush.API.SharedFolders.SharedFoldersAPI; + +namespace Acacia.Features.SharedFolders +{ + public partial class SharedFoldersDialog : KDialogNew + { + private readonly ZPushAccount _account; + private SyncId _initialSyncId; + private SharedFolder _initialFolder; + + public SharedFoldersDialog(ZPushAccount account, SyncId initial = null) + { + this._account = account; + this._initialSyncId = initial; + + InitializeComponent(); + + // TODO: make a specialised class out of this + this.kTreeFolders.Images = new OutlookImageList( + "NewFolder", // Other + "JunkEmailMarkAsNotJunk", // Inbox + "GoDrafts", // Drafts + "RecycleBin", // WasteBasket + "ReceiveMenu", // SentMail + "NewFolder", // Outbox + "ShowTaskPage", // Task + "ShowAppointmentPage", // Appointment + "ShowContactPage", // Contact + "NewNote", // Note + "ShowJournalPage", // Journal + "LastModifiedBy" // Store + + ).Images; + + // Add the email address to the title + Text = string.Format(Text, account.SmtpAddress); + + // Set up options + ShowOptions(new KTreeNode[0]); + + // Set up user selector + gabLookup.GAB = FeatureGAB.FindGABForAccount(_account); + } + + #region Load and store + + private void AddSharedFolderDialog_Shown(object sender, EventArgs args) + { + BusyText = Properties.Resources.SharedFolders_Fetching_Label; + KUITask + .New((ctx) => + { + using (SharedFoldersAPI api = new SharedFoldersAPI(_account)) + { + // TODO: bind cancellation token to Cancel button + // Fetch current shares + ICollection folders = api.GetCurrentShares(ctx.CancellationToken); + + // Find the initial folder if required + if (_initialSyncId != null) + _initialFolder = folders.FirstOrDefault(f => f.SyncId == _initialSyncId); + + // Group by store and folder id + return folders.GroupBy(f => f.Store) + .ToDictionary(group => group.Key, + group => group.ToDictionary(folder => folder.BackendId)); + } + }) + .OnSuccess(InitialiseTree, true) + .OnError((e) => + { + UI.ErrorUtil.HandleErrorNew(typeof(FeatureSharedFolders), "Exception fetching shared folders for account {0}", e, + Properties.Resources.SharedFolders_Fetching_Title, + Properties.Resources.SharedFolders_Fetching_Failure, + _account.DisplayName); + DialogResult = DialogResult.Cancel; + }) + .Start(this) + ; + } + + private void InitialiseTree(KUITaskContext context, Dictionary> shares) + { + kTreeFolders.BeginUpdate(); + try + { + // Add public folders + Dictionary publicShares; + shares.TryGetValue(GABUser.USER_PUBLIC, out publicShares); + AddUserFolders(GABUser.USER_PUBLIC, publicShares, false); + + // Add any users for which we have shared folders + foreach (KeyValuePair> entry in shares.OrderBy(x => x.Key.DisplayName)) + if (GABUser.USER_PUBLIC != entry.Key) + AddUserFolders(entry.Key, entry.Value, false); + } + finally + { + kTreeFolders.EndUpdate(); + } + + // Try to select initial node + if (_initialFolder != null) + { + StoreTreeNode node; + if (_userFolders.TryGetValue(_initialFolder.Store, out node)) + { + // Keep indicating busy until it's done + context.AddBusy(1); + node.NodesLoaded += (_) => + { + KTreeNode folderNode = node.FindNode(_initialFolder); + if (folderNode != null) + FocusNode(folderNode); + context.AddBusy(-1); + }; + FocusNode(node); + } + } + kTreeFolders.Focus(); + } + + private void dialogButtons_Apply(object sender, EventArgs e) + { + BusyText = Properties.Resources.SharedFolders_Applying_Label; + KUITask.New((ctx) => + { + using (SharedFoldersAPI folders = new SharedFoldersAPI(_account)) + { + // We reuse the same busy indicationg for all calls. A count is kept to ensure it's removed. + int count = 0; + + foreach (StoreTreeNode storeNode in _userFolders.Values) + { + if (storeNode.IsDirty) + { + ctx.AddBusy(1); + ++count; + + folders.SetCurrentShares(storeNode.User, storeNode.CurrentShares, ctx.CancellationToken); + } + } + + return count; + } + }) + .OnSuccess((ctx, count) => + { + foreach (StoreTreeNode storeNode in _userFolders.Values) + if (storeNode.IsDirty) + storeNode.ChangesApplied(); + + ctx.AddBusy(-count); + + // Sync account + _account.SendReceive(); + + // Show success + ShowCompletion(Properties.Resources.SharedFolders_Applying_Success); + }, true) + .OnError((x) => + { + ErrorUtil.HandleErrorNew(typeof(FeatureSharedFolders), "Exception applying shared folders for account {0}", x, + Properties.Resources.SharedFolders_Applying_Title, + Properties.Resources.SharedFolders_Applying_Failure, + _account.DisplayName); + }) + .Start(this); + } + + #endregion + + #region Event handlers + + private void buttonOpenUser_Click(object sender, EventArgs e) + { + AddUserFolders(gabLookup.SelectedUser, null, true); + } + + private void gabLookup_SelectedUserChanged(object source, GABLookupControl.SelectedUserEventArgs e) + { + buttonOpenUser.Enabled = (e.SelectedUser != null); + + if (e.IsChosen) + { + AddUserFolders(e.SelectedUser, null, true); + } + } + + private void SharedFoldersDialog_DirtyFormClosing(object sender, FormClosingEventArgs e) + { + // Require confirmation before closing a dirty form + e.Cancel = MessageBox.Show(Properties.Resources.SharedFolders_Unsaved_Changes, + Text, + MessageBoxButtons.YesNo, + MessageBoxIcon.Question + ) != DialogResult.Yes; + } + + #endregion + + private readonly Dictionary _userFolders = new Dictionary(); + + private void AddUserFolders(GABUser user, Dictionary currentShares, bool select) + { + if (user == null) + return; + + // If the user is already fetched, reuse the node + StoreTreeNode node; + if (!_userFolders.TryGetValue(user, out node)) + { + if (!user.HasFullName) + { + // Try to fill in the full name + user = gabLookup.LookupExact(user.UserName); + } + + // Add the node + node = new StoreTreeNode(_account, user, user.DisplayName, currentShares ?? new Dictionary()); + node.DirtyChanged += UserSharesChanged; + _userFolders.Add(user, node); + kTreeFolders.RootNodes.Add(node); + } + + if (select) + { + FocusNode(node); + } + } + + private void FocusNode(KTreeNode node) + { + // Scroll it to the top of the window + kTreeFolders.SelectNode(node, KTree.ScrollMode.Top); + + // Start loading folders + node.IsExpanded = true; + + // Clear any selected user + gabLookup.SelectedUser = null; + + // And focus the tree + kTreeFolders.Focus(); + } + + private readonly Dictionary _dirtyUsers = new Dictionary(); + + private void UserSharesChanged(StoreTreeNode node) + { + _dirtyUsers[node.User.UserName] = node.IsDirty; + dialogButtons.IsDirty = _dirtyUsers.Values.Any((x) => x); + } + + #region Advanced options + + private string OptionName + { + get { return textName.Visible ? textName.Text : null; } + set + { + _labelName.Visible = textName.Visible = value != null; + textName.Text = value ?? ""; + } + } + private FolderTreeNode _optionNameNode; + + private CheckState? OptionSendAs + { + get + { + if (checkSendAs.Visible) + return checkSendAs.CheckState; + return null; + } + + set + { + _labelSendAs.Visible = checkSendAs.Visible = value != null; + if (value != null) + checkSendAs.CheckState = value.Value; + } + } + private readonly List _optionSendAsNodes = new List(); + private readonly List _optionSendAsInitial = new List(); + + private Permission? _optionPermissions; + private Permission? OptionPermissions + { + get { return _optionPermissions; } + set + { + _optionPermissions = value; + _labelPermissions.Visible = labelPermissionsValue.Visible = value != null; + + if (value == null) + labelPermissionsValue.Text = ""; + else + { + // Look up permission string + switch (value) + { + case Permission.None: + labelPermissionsValue.Text = Properties.Resources.SharedFolders_Permission_None; + break; + case Permission.Read: + labelPermissionsValue.Text = Properties.Resources.SharedFolders_Permission_Read; + break; + case Permission.Write: + labelPermissionsValue.Text = Properties.Resources.SharedFolders_Permission_Write; + break; + case Permission.ReadWrite: + labelPermissionsValue.Text = Properties.Resources.SharedFolders_Permission_Read + " / " + Properties.Resources.SharedFolders_Permission_Write; + break; + } + } + } + } + private readonly List _optionPermissionNodes = new List(); + + private void ShowOptions(KTreeNode[] nodes) + { + try + { + _layoutOptions.SuspendLayout(); + + _optionNameNode = null; + _optionSendAsNodes.Clear(); + _optionSendAsInitial.Clear(); + _optionPermissionNodes.Clear(); + OptionName = null; + OptionSendAs = null; + OptionPermissions = null; + + foreach (KTreeNode node in nodes) + { + // Ignore the root nodes + if (node is StoreTreeNode) + continue; + + FolderTreeNode folderNode = (FolderTreeNode)node; + // Can only set options for shared folders + if (!folderNode.IsShared) + continue; + + SharedFolder share = folderNode.SharedFolder; + AvailableFolder folder = folderNode.AvailableFolder; + + // Assume we will edit the name for this node; cleared below if there are multiple + _optionNameNode = folderNode; + + // Show send as if there are any mail folders + if (folder.IsMailFolder) + { + _optionSendAsNodes.Add(folderNode); + _optionSendAsInitial.Add(folderNode.SharedFolder.FlagSendAsOwner); + } + + // Show permissions for all shared nodes + _optionPermissionNodes.Add(folderNode); + } + + // Now check consistency of the options + + // Only show the name if there is a single node. + // We do that here so there doesn't have to be duplication if testing if it's sharedd, + // ect + if (_optionNameNode != null && nodes.Length == 1) + { + OptionName = _optionNameNode.SharedFolder.Name; + } + else + { + _optionNameNode = null; + } + + // Permissions shown if all are the same + if (_optionPermissionNodes.Count > 0) + { + Permission permissions = _optionPermissionNodes.First().SharedFolder.Permissions; + if (_optionPermissionNodes.All(x => x.SharedFolder.Permissions == permissions)) + OptionPermissions = permissions; + } + + // Send as shown if any node supports it + if (_optionSendAsNodes.Count > 0) + { + bool sendAs = _optionSendAsNodes.First().SharedFolder.FlagSendAsOwner; + if (_optionSendAsNodes.All(x => x.SharedFolder.FlagSendAsOwner == sendAs)) + { + OptionSendAs = sendAs ? CheckState.Checked : CheckState.Unchecked; + checkSendAs.ThreeState = false; + } + else + { + OptionSendAs = CheckState.Indeterminate; + checkSendAs.ThreeState = true; + } + } + } + finally + { + _layoutOptions.ResumeLayout(); + } + } + + private void kTreeFolders_CheckStateChanged(object sender, KTree.CheckStateChangedEventArgs e) + { + // If the node is selected, may have to change option display + if (e.Node.IsSelected) + { + ShowOptions(kTreeFolders.SelectedNodes.ToArray()); + } + } + + private void kTreeFolders_SelectionChanged(object sender, KTree.SelectionChangedEventArgs e) + { + ShowOptions(e.SelectedNodes); + } + + private void textName_TextChanged(object sender, EventArgs e) + { + if (_optionNameNode != null) + { + _optionNameNode.SharedFolder = _optionNameNode.SharedFolder.WithName(textName.Text); + } + } + + private void checkSendAs_CheckedChanged(object sender, EventArgs e) + { + for (int i = 0; i < _optionSendAsNodes.Count; ++i) + { + FolderTreeNode node = _optionSendAsNodes[i]; + bool sendAs = false; + switch(checkSendAs.CheckState) + { + case CheckState.Checked: sendAs = true; break; + case CheckState.Indeterminate: sendAs = _optionSendAsInitial[i]; break; + case CheckState.Unchecked: sendAs = false; break; + } + + if (node.SharedFolder.FlagSendAsOwner != sendAs) + { + node.SharedFolder = node.SharedFolder.WithFlagSendAsOwner(sendAs); + + // Send-as is applied recursively + foreach (FolderTreeNode desc in node.Descendants()) + { + desc.SharedFolder = desc.SharedFolder.WithFlagSendAsOwner(sendAs); + } + } + } + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.resx new file mode 100644 index 0000000..ffdef70 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.resx @@ -0,0 +1,762 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 1 + + + 1 + + + True + + + + GrowAndShrink + + + 3 + + + True + + + Fill + + + NoControl + + + + 4, 0 + + + 4, 0, 4, 0 + + + 143, 36 + + + 0 + + + Open folders for user + + + MiddleLeft + + + labelSelectUser + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutSelectUser + + + 0 + + + True + + + GrowAndShrink + + + Fill + + + False + + + NoControl + + + 510, 4 + + + 4, 4, 4, 4 + + + 11, 0, 11, 0 + + + 75, 28 + + + 1 + + + Open + + + buttonOpenUser + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutSelectUser + + + 1 + + + True + + + 1 + + + Fill + + + Popup + + + 4, 4 + + + 4, 4, 4, 4 + + + 265, 0 + + + 343, 24 + + + 1 + + + gabLookup + + + Acacia.UI.GABLookupControl, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null + + + _layoutCenterGABLookup + + + 0 + + + Fill + + + 153, 2 + + + 2, 2, 2, 2 + + + 3 + + + 351, 32 + + + 2 + + + _layoutCenterGABLookup + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutSelectUser + + + 2 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="gabLookup" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,100" /><Rows Styles="Percent,50,AutoSize,0,Percent,50" /></TableLayoutSettings> + + + Fill + + + 4, 4 + + + 4, 4, 4, 4 + + + 1 + + + 589, 36 + + + 0 + + + _layoutSelectUser + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutMain + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelSelectUser" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="buttonOpenUser" Row="0" RowSpan="1" Column="2" ColumnSpan="1" /><Control Name="_layoutCenterGABLookup" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100,AutoSize,0" /><Rows Styles="Percent,100,Absolute,37" /></TableLayoutSettings> + + + Fill + + + 4, 48 + + + 4, 4, 4, 4 + + + 589, 377 + + + 1 + + + kTreeFolders + + + Acacia.Controls.KTree, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null + + + _layoutMain + + + 1 + + + True + + + GrowAndShrink + + + 2 + + + True + + + Fill + + + 4, 0 + + + 4, 0, 4, 0 + + + 102, 30 + + + 0 + + + Share as + + + MiddleLeft + + + _labelName + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutOptions + + + 0 + + + Fill + + + 118, 4 + + + 8, 4, 4, 4 + + + 475, 22 + + + 1 + + + textName + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutOptions + + + 1 + + + True + + + Fill + + + 4, 30 + + + 4, 0, 4, 0 + + + 102, 34 + + + 2 + + + Send as owner + + + MiddleLeft + + + _labelSendAs + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutOptions + + + 2 + + + True + + + Left + + + 118, 35 + + + 8, 5, 4, 4 + + + 0, 4, 0, 4 + + + 18, 25 + + + 3 + + + checkSendAs + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutOptions + + + 3 + + + True + + + Fill + + + 4, 64 + + + 4, 0, 4, 0 + + + 0, 5, 0, 4 + + + 102, 26 + + + 4 + + + Permissions + + + MiddleLeft + + + _labelPermissions + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutOptions + + + 4 + + + True + + + Fill + + + MiddleLeft + + + 114, 64 + + + 4, 0, 4, 0 + + + 0, 5, 0, 4 + + + 479, 26 + + + 5 + + + Permissions + + + MiddleLeft + + + labelPermissionsValue + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutOptions + + + 5 + + + Fill + + + 0, 429 + + + 0, 0, 0, 0 + + + 3 + + + 597, 90 + + + 2 + + + _layoutOptions + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutMain + + + 2 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_labelName" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="textName" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelSendAs" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="checkSendAs" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelPermissions" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="labelPermissionsValue" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0" /></TableLayoutSettings> + + + Fill + + + 0, 0 + + + 4, 4, 4, 4 + + + 3 + + + 597, 519 + + + 3 + + + _layoutMain + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _mainBusyHider + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_layoutSelectUser" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="kTreeFolders" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="_layoutOptions" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,100" /><Rows Styles="AutoSize,0,Percent,100,AutoSize,0" /></TableLayoutSettings> + + + Fill + + + 4, 4 + + + 4, 4, 4, 4 + + + 597, 519 + + + 4 + + + + + + _mainBusyHider + + + Acacia.Controls.KBusyHider, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null + + + _layout + + + 0 + + + True + + + GrowAndShrink + + + Fill + + + 2, 528 + + + 2, 1, 2, 1 + + + 601, 39 + + + 5 + + + dialogButtons + + + Acacia.Controls.KDialogButtons, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null + + + _layout + + + 1 + + + Fill + + + 8, 7 + + + 0, 0, 0, 0 + + + 2 + + + 605, 568 + + + 0 + + + _layout + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_mainBusyHider" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="dialogButtons" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,100" /><Rows Styles="Percent,100,AutoSize,0,Absolute,25" /></TableLayoutSettings> + + + True + + + 8, 16 + + + 621, 582 + + + 8, 7, 8, 7 + + + CenterParent + + + Shared Folders - {0} + + + SharedFoldersDialog + + + Acacia.Controls.KDialogNew, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/StoreTreeNode.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/StoreTreeNode.cs new file mode 100644 index 0000000..b841161 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/StoreTreeNode.cs @@ -0,0 +1,320 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Controls; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Acacia.ZPush; +using Acacia.Utils; +using System.Threading; +using Acacia.ZPush.API.SharedFolders; +using Acacia.ZPush.Connect; +using Acacia.Native; + +namespace Acacia.Features.SharedFolders +{ + /// + /// A tree node representing the root node for a store. Responsible for loading the store contents and managing the + /// shares for that store. + /// + public class StoreTreeNode : KTreeNode + { + private KAnimator _reloader; + + // The initial and current shares states. The initial state is kept to check for modifications + private readonly Dictionary _initialShares; + private readonly Dictionary _currentShares; + + public StoreTreeNode(ZPushAccount account, GABUser user, string text, Dictionary currentFolders) + : + base(text) + { + this._initialShares = currentFolders; + + // Create an empty current state. When loading the nodes, the shares will be added. This has the benefit of + // cleaning up automatically any obsolote shares. + this._currentShares = new Dictionary(); + + ChildLoader = new UserFolderLoader(this, account, user); + ChildLoader.ReloadOnCloseOpen = true; + HasCheckBox = false; + + // TODO: better icons, better way of handling this + ImageIndex = user == GABUser.USER_PUBLIC ? 0 : 11; + + // Reloader + _reloader = new KAnimator(); + _reloader.Animation = Properties.Resources.TreeLoading; + _reloader.Visible = false; + _reloader.Click += (s, e) => + { + ChildLoader.Reload(); + }; + Control = _reloader; + } + + public GABUser User + { + get { return ((UserFolderLoader)ChildLoader).User; } + } + + #region Share management + + /// + /// Adds a share. + /// + /// The folder to share. + /// The share state. This may be null to add a default share + /// The share information + internal SharedFolder AddShare(AvailableFolder folder, SharedFolder state) + { + state = state ?? CreateDefaultShare(folder); + _currentShares[folder.BackendId] = state; + CheckDirty(); + return state; + } + + private SharedFolder CreateDefaultShare(AvailableFolder folder) + { + SharedFolder share = new SharedFolder(folder); + + // Default send as for mail folders + if (folder.IsMailFolder) + share = share.WithFlagSendAsOwner(true); + + // Default include the store name in root folders + if (folder.ParentId.IsNone) + share = share.WithName(folder.Store.UserName + " - " + folder.Name); + + return share; + } + + internal void RemoveShare(AvailableFolder folder) + { + if (_currentShares.Remove(folder.BackendId)) + { + CheckDirty(); + } + } + + private SharedFolder GetInitialShareState(AvailableFolder folder) + { + SharedFolder state; + if (_initialShares.TryGetValue(folder.BackendId, out state)) + { + return state; + } + return null; + } + + public ICollection CurrentShares + { + get { return _currentShares.Values; } + } + + #endregion + + #region Dirty tracking + + public delegate void DirtyChangedHandler(StoreTreeNode node); + + public event DirtyChangedHandler DirtyChanged; + + public bool IsDirty { get; private set; } + private void CheckDirty() + { + bool newDirty = !_initialShares.SameElements(_currentShares); + if (newDirty != IsDirty) + { + IsDirty = newDirty; + if (DirtyChanged != null) + DirtyChanged(this); + } + } + + public void ChangesApplied() + { + // Save a copy of current folders to initial folders + _initialShares.Clear(); + foreach (var entry in _currentShares) + { + _initialShares.Add(entry.Key, entry.Value); + } + CheckDirty(); + } + + #endregion + + #region Node loading + + public class UserFolderLoader : KTreeNodeLoader + { + private readonly ZPushAccount _account; + public GABUser User { get; private set; } + + public UserFolderLoader(StoreTreeNode parent, ZPushAccount account, GABUser user) : base(parent) + { + this._account = account; + this.User = user; + } + + protected override object DoLoadChildren(KTreeNode node) + { + using (SharedFoldersAPI folders = new SharedFoldersAPI(_account)) + { + return folders.GetUserFolders(User); + } + } + + private class FolderComparer : IComparer + { + private bool _isRoot; + + public FolderComparer(bool isRoot) + { + this._isRoot = isRoot; + } + + public int Compare(AvailableFolder x, AvailableFolder y) + { + if (_isRoot) + { + int i = (int)x.Type - (int)y.Type; + if (i != 0) + return i; + } + + return x.Name.CompareTo(y.Name); + } + } + + protected override void DoRenderChildren(KTreeNode node, object loaded, KTreeNodes children) + { + List folders = (List)loaded; + foreach (AvailableFolder folder in folders.OrderBy(f => f, new FolderComparer(true))) + { + AddFolderNode(node, children, folder); + } + } + + private void AddFolderNode(KTreeNode node, KTreeNodes children, AvailableFolder folder) + { + StoreTreeNode rootNode = (StoreTreeNode)this.Children.Parent; + + // Create the tree node + SharedFolder share = rootNode.GetInitialShareState(folder); + FolderTreeNode child = new FolderTreeNode(rootNode, folder, share); + + // Add + children.Add(child); + + // Add the children + foreach (AvailableFolder childFolder in folder.Children.OrderBy(f => f, new FolderComparer(false))) + { + AddFolderNode(child, child.Children, childFolder); + } + + // Set the initial share state + if (share != null) + { + child.IsChecked = true; + } + + // Add the share; it might have become checked by any of the child nodes + if (child.IsShared) + rootNode.AddShare(folder, share); + } + + protected override void OnBeginLoading(KTreeNode node) + { + base.OnBeginLoading(node); + ((StoreTreeNode)node)._reloader.Visible = true; + ((StoreTreeNode)node)._reloader.Animate = true; + } + + protected override void OnEndLoading(KTreeNode node) + { + ((StoreTreeNode)node)._reloader.Animate = false; + ((StoreTreeNode)node)._reloader.Visible = false; + base.OnEndLoading(node); + ((StoreTreeNode)node).OnNodesLoaded(); + } + + protected override string GetPlaceholderText(LoadingState state, KTreeNodes children) + { + switch (state) + { + case KTreeNodeLoader.LoadingState.Error: + return Properties.Resources.SharedFolders_Loading_Error; + case KTreeNodeLoader.LoadingState.Loading: + return Properties.Resources.SharedFolders_Loading; + case KTreeNodeLoader.LoadingState.Loaded: + if (children.Count == 0) + return Properties.Resources.SharedFolders_None; + return null; + } + return null; + } + } + + + /// + /// Event handler for the first time nodes are loaded; not invoked on reload. + /// + public delegate void NodesLoadedHandler(StoreTreeNode node); + public event NodesLoadedHandler NodesLoaded; + + virtual protected void OnNodesLoaded() + { + if (NodesLoaded != null) + { + NodesLoaded(this); + NodesLoaded = null; + } + } + + #endregion + + #region Node finding + + public KTreeNode FindNode(SharedFolder folder) + { + return FindNode(this, folder); + } + + private KTreeNode FindNode(KTreeNode node, SharedFolder folder) + { + // TODO: use an index for this? For now it's used only to select the initial node. It might also be useful in KTree + // in a more general way + foreach(FolderTreeNode child in node.Children) + { + if (child.AvailableFolder.BackendId == folder.BackendId) + return child; + + KTreeNode found = FindNode(child, folder); + if (found != null) + return found; + } + + return null; + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/WebApp/FeatureWebApp.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/WebApp/FeatureWebApp.cs new file mode 100644 index 0000000..34ad026 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/WebApp/FeatureWebApp.cs @@ -0,0 +1,143 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.UI; +using Acacia.UI.Outlook; +using Acacia.Utils; +using Acacia.ZPush; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Features.WebApp +{ + [AcaciaOption("Provides the ability to open Kopano WebApp from within Outlook.")] + public class FeatureWebApp : Feature, FeatureWithRibbon + { + private RibbonButton _button; + + public override void Startup() + { + _button = RegisterButton(this, "WebApp", true, OpenWebApp, ZPushBehaviour.None); + // Start autodiscover + Watcher.AccountDiscovered += Watcher_AccountDiscovered; + Watcher.ZPushAccountChange += AccountChange; + } + + private void Watcher_AccountDiscovered(ZPushAccount account) + { + // Start an autodiscover for each account + AutoDiscover(account); + } + + private void AccountChange(ZPushAccount account) + { + if (_button != null) + { + bool enabled = account != null; + if (enabled) + { + // Hide the button if the url could not be fetched + enabled = AutoDiscover(account) != null; + } + _button.IsEnabled = enabled; + } + } + + private const string TXT_KDISCOVER = "kdiscover"; + + private class URLCached + { + public readonly string Url; + public readonly DateTime Date; + + public URLCached(string url) + { + this.Url = url; + this.Date = DateTime.Now; + } + } + + private void Check_AutoDiscover(ZPushAccount account) + { + AutoDiscover(account); + + // Update button state + AccountChange(account); + } + + private void OpenWebApp() + { + ZPushAccount account = Watcher.CurrentZPushAccount(); + if (account == null) + return; + + // Get the url + string url = AutoDiscover(account); + if (url == null) + return; + + // Open the browser + System.Diagnostics.Process.Start(url); + } + + private string AutoDiscover(ZPushAccount account) + { + // Check for a cached entry + URLCached cached = account.GetFeatureData(this, TXT_KDISCOVER); + // Only cache actual URLs, not missing urls + if (cached != null) + return cached.Url; + + // Perform a cached auto discover + try + { + Logger.Instance.Debug(this, "Starting kdiscover: {0}", account.DomainName); + string url = PerformAutoDiscover(account); + Logger.Instance.Debug(this, "Finished kdiscover: {0}: {1}", account.DomainName, url); + account.SetFeatureData(this, TXT_KDISCOVER, new URLCached(url)); + return url; + } + catch (Exception e) + { + Logger.Instance.Warning(this, "Exception during kdiscover: {0}: {1}", account.DomainName, e); + account.SetFeatureData(this, TXT_KDISCOVER, null); + return null; + } + } + + private string PerformAutoDiscover(ZPushAccount account) + { + // Fetch the txt record + List txt = DnsUtil.GetTxtRecord(account.DomainName); + if (txt == null) + return null; + + // Find kdiscover + string kdiscover = txt.FirstOrDefault((record) => record.StartsWith(TXT_KDISCOVER)); + if (string.IsNullOrEmpty(kdiscover)) + return null; + + string url = kdiscover.Substring(TXT_KDISCOVER.Length + 1).Trim(); + if (string.IsNullOrWhiteSpace(url)) + return null; + + return url; + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/packages.config b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/packages.config new file mode 100644 index 0000000..fccc652 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/GlobalOptions.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/GlobalOptions.cs new file mode 100644 index 0000000..ceca0c8 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/GlobalOptions.cs @@ -0,0 +1,178 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Utils; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static Acacia.DebugOptions; + +namespace Acacia +{ + public class GlobalOptions + { + /// + /// A singleton is used so the property debugger can access the fields. + /// + public static readonly GlobalOptions INSTANCE = new GlobalOptions(); + + [AcaciaOption("Completely enables or disables the Outlook plugin. Note that if the plugin is enabled, individual " + + "features may still have to be enabled.")] + virtual public bool Enabled + { + get { return GetOption(null, ENABLED); } + set { SetOption(null, ENABLED, value); } + } + + [AcaciaOption("Sets the threading model for long running tasks. MainThread means all tasks are executed " + + "in Outlook's main thread. This is the standard option, but has the effect of locking the UI " + + "for short periods of time. The Background threading model prevents this, but is currently " + + "experimental. The Synchronous option means all tasks are executed synchronously, which " + + "locks up the UI quite frequently, but is the safest option.")] + public Threading Threading + { + get { return GetOption(null, THREADING); } + set { SetOption(null, THREADING, value); } + } + private static readonly EnumOption THREADING = new EnumOption("Threading"); + + [AcaciaOption("Enables or disables ZPush account checking. To enable advanced features, it must be known " + + "which accounts use ZPush servers. This option checks responses from ActiveSync servers to " + + "identify the ZPush ones.")] + public bool ZPushCheck + { + get { return GetOption(null, ZPUSH_CHECK); } + set { SetOption(null, ZPUSH_CHECK, value); } + } + private static readonly BoolOption ZPUSH_CHECK = new BoolOption("ZPushCheck", true); + + [AcaciaOption("Enables or disables the account timer. Outlook doesn't notify the plugin of new or removed " + + "accounts. The timer is used to periodically check for modified accounts. This is needed to " + + "accurately detect ZPush accounts.")] + public bool AccountTimer + { + get { return GetOption(null, ACCOUNT_TIMER); } + set { SetOption(null, ACCOUNT_TIMER, value); } + } + private static readonly BoolOption ACCOUNT_TIMER = new BoolOption("AccountTimer", true); + + [AcaciaOption("Enables or disables ZPush synchronization tasks. These are used to ensure Oulook " + + "has the latest data from the server.")] + public bool ZPushSync + { + get { return GetOption(null, ZPUSH_SYNC); } + set { SetOption(null, ZPUSH_SYNC, value); } + } + private static readonly BoolOption ZPUSH_SYNC = new BoolOption("ZPushSync", true); + + [AcaciaOption("Sets the interval at which ZPush synchronization tasks will be executed.")] + public TimeSpan ZPushSync_Period + { + get { return GetOption(null, ZPUSH_SYNC_PERIOD); } + set { SetOption(null, ZPUSH_SYNC_PERIOD, value); } + } + private static readonly TimeSpanOption ZPUSH_SYNC_PERIOD = new TimeSpanOption("ZPushSyncPeriod", Constants.ZPUSH_SYNC_DEFAULT_PERIOD); + + [AcaciaOption("Disables the release of COM objects. This generally leads to resource leaks and should " + + "only be disabled for debug purposes.")] + public bool COMRelease + { + get { return GetOption(null, COM_RELEASE); } + set { SetOption(null, COM_RELEASE, value); } + } + private static readonly BoolOption COM_RELEASE = new BoolOption("COMRelease", true); + + [AcaciaOption("Enables or disables logging completely.")] + public bool Logging + { + get { return GetOption(null, LOGGING); } + set { SetOption(null, LOGGING, value); } + } + private static readonly BoolOption LOGGING = new BoolOption("Logging", true); + + [AcaciaOption("Sets the level of messages that will be logged. For production use, Info should be enough. " + + "The log level may be set higher if there are issues that need to be debugged.")] + public LogLevel Logging_Level + { + get { return Logger.Instance.MinLevel; } + set + { + Logger.Instance.SetLevel(value); + } + } + + #region UI Options + + [AcaciaOption("Completely enables or disables modifications to the Outlook UI." + + "Note that where applicable, the Ribbon and Context Menu options also control UI modifications, " + + "as do individual features.")] + virtual public bool UI + { + get { return GetOption(null, OUTLOOK_UI); } + set { SetOption(null, OUTLOOK_UI, value); } + } + + [AcaciaOption("Completely enables or disables modifications to the Outlook Ribbon." + + "Note that if the UI option is disabled, Ribbon modifications will not be made either.")] + virtual public bool UI_Ribbon + { + get { return GetOption(null, OUTLOOK_UI_RIBBON); } + set { SetOption(null, OUTLOOK_UI_RIBBON, value); } + } + + [AcaciaOption("Completely enables or disables modifications to the Outlook Context Menus." + + "Note that if the UI option is disabled, Context Menu modifications will not be made either.")] + virtual public bool UI_ContextMenu + { + get { return GetOption(null, OUTLOOK_UI_CONTEXT_MENU); } + set { SetOption(null, OUTLOOK_UI_CONTEXT_MENU, value); } + } + + #endregion + + #region Local folders + + [AcaciaOption("If this option is enabled, any local folders created in the local store are hidden. " + + "This prevents them from showing up in the Outlook folder list. " + + "Note that this applies only to folders created automatically by Outlook, relevant " + + "folders will still be visible.")] + public bool LocalFolders_Hide + { + get { return GetOption(null, OPTION_HIDE_LOCAL_FOLDERS); } + set { SetOption(null, OPTION_HIDE_LOCAL_FOLDERS, value); } + } + private static readonly BoolOption OPTION_HIDE_LOCAL_FOLDERS = new BoolOption("HideLocalFolders", true); + + [AcaciaOption("Specifies the location in which to store local folders. Note that changing this option " + + "does not migrate any existing stores. Setting an invalid path will most likely lead to " + + "errors when starting Outlook. Environment variables such as %APPDATA% can be used to " + + "specify the path.")] + public string LocalFolders_Path + { + get { return RegistryUtil.GetConfigValue(null, "LocalStorePath", (string)null); } + set + { + RegistryUtil.SetConfigValue(null, "LocalStorePath", value, Microsoft.Win32.RegistryValueKind.String); + } + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Logger.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Logger.cs new file mode 100644 index 0000000..cfb8433 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Logger.cs @@ -0,0 +1,157 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Features; +using Acacia.Utils; +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia +{ + public interface LogContext + { + string LogContextId { get; } + } + + public abstract class Logger + { + public static readonly Logger Instance = GlobalOptions.INSTANCE.Logging + ? (Logger)new NLogLogger(LibUtils.AssemblyName) + : (Logger)new NullLogger(); + + virtual public string Path + { + get { return null; } + } + + private LogLevel _minLevel = LogLevel.Trace; + public LogLevel MinLevel + { + get { return _minLevel; } + } + + public void Initialize() + { + try + { + _minLevel = (LogLevel)RegistryUtil.GetConfigValue(null, Constants.PLUGIN_REGISTRY_LOGLEVEL, (int)_minLevel); + OnLogLevelChanged(); + } + catch (Exception) { } + DoLog(_minLevel, this, "Level initialized", null); + } + + public void SetLevel(LogLevel level) + { + if (level != _minLevel) + { + _minLevel = level; + RegistryUtil.SetConfigValue(null, Constants.PLUGIN_REGISTRY_LOGLEVEL, (int)level, RegistryValueKind.DWord); + OnLogLevelChanged(); + } + } + + virtual protected void OnLogLevelChanged() { } + + #region Loggers + + public void TraceExtra(object context, string format, params object[] args) + { + DoLog(LogLevel.TraceExtra, context, format, args); + } + + public void Trace(object context, string format, params object[] args) + { + DoLog(LogLevel.Trace, context, format, args); + } + + public void Debug(object context, string format, params object[] args) + { + DoLog(LogLevel.Debug, context, format, args); + } + + public void Info(object context, string format, params object[] args) + { + DoLog(LogLevel.Info, context, format, args); + } + + public void Warning(object context, string format, params object[] args) + { + DoLog(LogLevel.Warning, context, format, args); + } + + public void Error(object context, string format, params object[] args) + { + DoLog(LogLevel.Error, context, format, args); + } + + public void Fatal(object context, string format, params object[] args) + { + DoLog(LogLevel.Fatal, context, format, args); + } + + #endregion + + #region Implementation + + protected abstract void DoLogMessage(LogLevel level, string message); + + private void DoLog(LogLevel level, object context, string format, object[] args) + { + if (!IsLevelEnabled(level)) + return; + + // Message + string msg = args == null || args.Length == 0 ? format : String.Format(format, args); + + // Include context + if (context is LogContext) + msg = ((LogContext)context).LogContextId + ": " + msg; + else if (context is Type) + msg = ((Type)context).Name + ": " + msg; + else if (context is string) + msg = ((string)context) + ": " + msg; + else if (context != null) + msg = context.GetType().Name + ": " + msg; + + // Include level + msg = level.ToString() + ": " + msg; + + // Report + DoLogMessage(level, msg); + } + + public bool IsLevelEnabled(LogLevel level) + { + return level <= MinLevel; + } + + #endregion + } + + public class NullLogger + : + Logger + { + protected override void DoLogMessage(LogLevel level, string message) + { + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Logging.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Logging.cs new file mode 100644 index 0000000..ffca5be --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Logging.cs @@ -0,0 +1,41 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Acacia +{ + public enum LogLevel + { + Fatal, + Error, + Warning, + Info, + Debug, + Trace, + TraceExtra + } + + public static class LoggerHelpers + { + public static string LoggerPath(string name) + { + return System.IO.Path.Combine(System.IO.Path.GetTempPath(), name + ".log"); + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/NLogLogger.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/NLogLogger.cs new file mode 100644 index 0000000..9d058d8 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/NLogLogger.cs @@ -0,0 +1,101 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using NLog.Config; +using NLog.Targets; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NLog; + +namespace Acacia +{ + class NLogLogger : Logger + { + private readonly NLog.Logger _impl; + private readonly string _path; + + internal NLogLogger(string name) + { + _path = LoggerHelpers.LoggerPath(name); + + FileTarget file = new FileTarget(); + file.MaxArchiveFiles = 10; + file.ArchiveAboveSize = 1 * 1024 * 1024; + file.CreateDirs = true; + file.FileName = _path; + file.Layout = "${date} (${threadid},${threadname}): ${message}"; + + LoggingConfiguration config = new LoggingConfiguration(); + config.AddTarget("file", file); + config.LoggingRules.Add(new LoggingRule("*", file)); + + DebuggerTarget debug = new DebuggerTarget(); + debug.Layout = file.Layout; + config.AddTarget("debug", debug); + config.LoggingRules.Add(new LoggingRule("*", debug)); + + NLog.LogManager.Configuration = config; + OnLogLevelChanged(); + + _impl = NLog.LogManager.GetLogger("main"); + } + + protected override void OnLogLevelChanged() + { + foreach(LoggingRule rule in NLog.LogManager.Configuration.LoggingRules) + { + for (int i = 0; i <= (int)LogLevel.Trace; ++i) + { + LogLevel level = (LogLevel)i; + if (IsLevelEnabled(level)) + rule.EnableLoggingForLevel(MapLevel(level)); + else + rule.DisableLoggingForLevel(MapLevel(level)); + } + } + NLog.LogManager.ReconfigExistingLoggers(); + } + + protected override void DoLogMessage(LogLevel level, string message) + { + _impl.Log(MapLevel(level), message); + } + + private NLog.LogLevel MapLevel(LogLevel level) + { + switch(level) + { + case LogLevel.Trace: return NLog.LogLevel.Trace; + case LogLevel.Debug: return NLog.LogLevel.Debug; + case LogLevel.Info: return NLog.LogLevel.Info; + case LogLevel.Warning: return NLog.LogLevel.Warn; + case LogLevel.Error: return NLog.LogLevel.Error; + case LogLevel.Fatal: return NLog.LogLevel.Fatal; + default: return NLog.LogLevel.Trace; + } + } + + override public string Path + { + get { return _path; } + } + + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/User32.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/User32.cs new file mode 100644 index 0000000..4eb05ee --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/User32.cs @@ -0,0 +1,205 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace Acacia.Native +{ + public static class User32 + { + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern int RegisterClipboardFormat(string format); + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + public static extern IntPtr SetParent(IntPtr window, IntPtr parent); + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + public static extern IntPtr GetParent(IntPtr window); + + public static int WS_CHILD = 0x40000000; + + public enum GWL : int + { + MSGRESULT = 0, + STYLE = -16 + } + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + public static extern int SetWindowLong(IntPtr hWnd, GWL gwl, int value); + + [DllImport("user32.dll")] + public static extern int GetWindowLong(IntPtr hWnd, GWL gwl); + + #region Messages + + [DllImport("user32.dll")] + public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam); + + [DllImport("user32.dll")] + public static extern int PostMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam); + + #endregion + + #region DCs + + [DllImport("user32.dll")] + public static extern IntPtr GetWindowDC(IntPtr hWnd); + + [DllImport("user32.dll")] + public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); + + #endregion + + #region RedrawWindow + + [Flags()] + public enum RedrawWindowFlags : uint + { + Invalidate = 0X1, + InternalPaint = 0X2, + Erase = 0X4, + Validate = 0X8, + NoInternalPaint = 0X10, + NoErase = 0X20, + NoChildren = 0X40, + AllChildren = 0X80, + UpdateNow = 0X100, + EraseNow = 0X200, + Frame = 0X400, + NoFrame = 0X800 + } + + [DllImport("user32.dll")] + public static extern bool RedrawWindow(IntPtr hWnd, IntPtr lprcUpdate, IntPtr hrgnUpdate, RedrawWindowFlags flags); + + #endregion + + #region System metrics + + public enum SystemMetric : int + { + CXSCREEN = 0, + CYSCREEN = 1, + CXVSCROLL = 2, + CYHSCROLL = 3, + CYCAPTION = 4, + CXBORDER = 5, + CYBORDER = 6, + CXDLGFRAME = 7, + CYDLGFRAME = 8, + CYVTHUMB = 9, + CXHTHUMB = 10, + CXICON = 11, + CYICON = 12, + CXCURSOR = 13, + CYCURSOR = 14, + CYMENU = 15, + CXFULLSCREEN = 16, + CYFULLSCREEN = 17, + CYKANJIWINDOW = 18, + MOUSEPRESENT = 19, + CYVSCROLL = 20, + CXHSCROLL = 21, + DEBUG = 22, + SWAPBUTTON = 23, + RESERVED1 = 24, + RESERVED2 = 25, + RESERVED3 = 26, + RESERVED4 = 27, + CXMIN = 28, + CYMIN = 29, + CXSIZE = 30, + CYSIZE = 31, + CXFRAME = 32, + CYFRAME = 33, + CXMINTRACK = 34, + CYMINTRACK = 35, + CXDOUBLECLK = 36, + CYDOUBLECLK = 37, + CXICONSPACING = 38, + CYICONSPACING = 39, + MENUDROPALIGNMENT = 40, + PENWINDOWS = 41, + DBCSENABLED = 42, + CMOUSEBUTTONS = 43, + CXFIXEDFRAME = CXDLGFRAME, /* ;win40 name change */ + CYFIXEDFRAME = CYDLGFRAME, /* ;win40 name change */ + CXSIZEFRAME = CXFRAME, /* ;win40 name change */ + CYSIZEFRAME = CYFRAME, /* ;win40 name change */ + SECURE = 44, + CXEDGE = 45, + CYEDGE = 46, + CXMINSPACING = 47, + CYMINSPACING = 48, + CXSMICON = 49, + CYSMICON = 50, + CYSMCAPTION = 51, + CXSMSIZE = 52, + CYSMSIZE = 53, + CXMENUSIZE = 54, + CYMENUSIZE = 55, + ARRANGE = 56, + CXMINIMIZED = 57, + CYMINIMIZED = 58, + CXMAXTRACK = 59, + CYMAXTRACK = 60, + CXMAXIMIZED = 61, + CYMAXIMIZED = 62, + NETWORK = 63, + CLEANBOOT = 67, + CXDRAG = 68, + CYDRAG = 69, + SHOWSOUNDS = 70, + CXMENUCHECK = 71, /* Use instead of GetMenuCheckMarkDimensions()! */ + CYMENUCHECK = 72, + SLOWMACHINE = 73, + MIDEASTENABLED = 74, + MOUSEWHEELPRESENT = 75, + XVIRTUALSCREEN = 76, + YVIRTUALSCREEN = 77, + CXVIRTUALSCREEN = 78, + CYVIRTUALSCREEN = 79, + CMONITORS = 80, + SAMEDISPLAYFORMAT = 81, + IMMENABLED = 82, + CXFOCUSBORDER = 83, + CYFOCUSBORDER = 84, + TABLETPC = 86, + MEDIACENTER = 87, + STARTER = 88, + SERVERR2 = 89, + MOUSEHORIZONTALWHEELPRESENT = 91, + CXPADDEDBORDER = 92, + DIGITIZER = 94, + MAXIMUMTOUCHES = 95, + REMOTESESSION = 0x1000, + SHUTTINGDOWN = 0x2000, + REMOTECONTROL = 0x2001, + CARETBLINKINGENABLED = 0x2002, + CONVERTIBLESLATEMODE = 0x2003, + SYSTEMDOCKED = 0x2004, + } + + [DllImport("user32.dll")] + public static extern int GetSystemMetrics(SystemMetric nIndex); + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/WM.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/WM.cs new file mode 100644 index 0000000..4c63978 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/WM.cs @@ -0,0 +1,30 @@ +/// Project : Kopano OL Extension +/// +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Acacia.Native +{ + public enum WM : int + { + NCPAINT = 0x0085, + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs new file mode 100644 index 0000000..4b6ff6d --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs @@ -0,0 +1,249 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia +{ + public static class OutlookConstants + { + #region Registry + + public const string REG_KEY_BASE = @"SOFTWARE\Microsoft\Office\{0}\Outlook\"; + public const string REG_SUBKEY_ACCOUNTS = @"Profiles\{0}\9375CFF0413111d3B88A00104B2A6676\"; + + public const string REG_VAL_ACCOUNTNAME = "Account Name"; + public const string REG_VAL_DISPLAYNAME = "Display Name"; + public const string REG_VAL_EMAIL = "Email"; + public const string REG_VAL_EAS_SERVER = "EAS Server URL"; + public const string REG_VAL_EAS_DEVICEID = "EAS DeviceId"; + public const string REG_VAL_EAS_USERNAME = "EAS User"; + public const string REG_VAL_EAS_PASSWORD = "EAS Password"; + public const string REG_VAL_EAS_STOREID = "EAS Store EID"; + public const string REG_VAL_IS_ACTIVESYNC = REG_VAL_EAS_USERNAME; + public const string REG_VAL_DELIVERY_STORE = "Delivery Store EntryID"; + public const string REG_VAL_DELIVERY_FOLDER = "Delivery Folder EntryID"; + + public const string REG_VAL_NEXT_ACCOUNT_ID = "NextAccountID"; + + #endregion + + #region PREFIXES + + private const string PROP = "http://schemas.microsoft.com/mapi/proptag/0x"; + private const string NAMED = "http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/"; + private const string GUID = "http://schemas.microsoft.com/mapi/id/"; + + #endregion + + #region Property types + + public const string PT_BOOLEAN = "000B"; + public const string PT_BINARY = "0102"; + public const string PT_MV_BINARY = "1102"; + public const string PT_DOUBLE = "0005"; + public const string PT_LONG = "0003"; + public const string PT_OBJECT = "000D"; + public const string PT_STRING8 = "001E"; + public const string PT_MV_STRING8 = "101E"; + public const string PT_SYSTIME = "0040"; + public const string PT_UNICODE = "001F"; + public const string PT_MV_UNICODE = "101F"; + #endregion + + #region General properties + + public const string PR_ICON_INDEX = PROP + "1080" + PT_LONG; + public const int PR_ICON_INDEX_NONE = -1; + public const int PR_ICON_INDEX_REPLIED = 261; + public const int PR_ICON_INDEX_FORWARDED = 262; + + public const string PR_CATEGORIES = NAMED + "Keywords"; + + public const string PR_ATTR_HIDDEN = PROP + "10F4" + PT_BOOLEAN; + + public const string PR_DISPLAY_NAME = PROP + "3001" + PT_STRING8; + + public const string PR_SUBJECT = PROP + "0037" + PT_UNICODE; + + #endregion + + #region Email specific + + public const string PR_LAST_VERB_EXECUTED = PROP + "1081" + PT_LONG; + public const string PR_LAST_VERB_EXECUTION_TIME = PROP + "1082" + PT_SYSTIME; + public const int EXCHIVERB_OPEN = 0; + public const int EXCHIVERB_RESERVED_COMPOSE = 100; + public const int EXCHIVERB_RESERVED_OPEN = 101; + public const int EXCHIVERB_REPLYTOSENDER = 102; + public const int EXCHIVERB_REPLYTOALL = 103; + public const int EXCHIVERB_FORWARD = 104; + public const int EXCHIVERB_PRINT = 105; + public const int EXCHIVERB_SAVEAS = 106; + public const int EXCHIVERB_RESERVED_DELIVERY = 107; + public const int EXCHIVERB_REPLYTOFOLDER = 108; + + public const string NS_TRANSPORT_MESSAGE_HEADERS = "http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/"; + public const string PR_TRANSPORT_MESSAGE_HEADERS = PROP + "007D" + PT_STRING8; + + public const string PR_IN_REPLY_TO_ID = PROP + "1042" + PT_UNICODE; + public const string PR_INTERNET_MESSAGE_ID = PROP + "1035" + PT_UNICODE; + + #endregion + + #region EAS / ZPush + + public const string PR_ZPUSH_MESSAGE_ID = PROP + "6B20" + PT_STRING8; + public const string PR_ZPUSH_FOLDER_ID = PROP + "6A19" + PT_STRING8; + + // TODO: names for these, use MFCMAPI + public const string PR_EAS_SYNC1 = PROP + "6A17" + PT_BOOLEAN; + // TODO: this is property zpush_folder_id, that cannot be right? + public const string PR_EAS_SYNCTYPE_ORIG = PROP + "6A19" + PT_UNICODE; + public const string PR_EAS_SYNCTYPE = PROP + "6A1A" + PT_LONG; + public const string PR_EAS_SYNC2 = PROP + "6A1D" + PT_BOOLEAN; + public const string PR_NET_FOLDER_FLAGS = PROP + "36DE" + PT_LONG; + + public enum SyncType + { + Other = 1, + Inbox = 2, + Drafts = 3, + WasteBasket = 4, + SentMail = 5, + Outbox = 6, + Task = 7, + Appointment = 8, + Contact = 9, + Note = 10, + Journal = 11, + UserMail = 12, + UserAppointment = 13, + UserContact = 14, + UserTask = 15, + UserJournal = 16, + UserNote = 17, + Unknown = 18, + RecipientCache = 19 + } + + public static readonly SyncType[] USER_SYNC_TYPES = + { + SyncType.Unknown, + SyncType.Other, // Other = 1, + SyncType.UserMail, // Inbox = 2, + SyncType.UserMail, // Drafts = 3, + SyncType.UserMail, // WasteBasket = 4, + SyncType.UserMail, // SentMail = 5, + SyncType.UserMail, // Outbox = 6, + SyncType.UserTask, // Task = 7, + SyncType.UserAppointment, // Appointment = 8, + SyncType.UserContact, // Contact = 9, + SyncType.UserNote, // Note = 10, + SyncType.UserJournal, // Journal = 11, + SyncType.UserMail,// = 12, + SyncType.UserAppointment,// = 13, + SyncType.UserContact,// = 14, + SyncType.UserTask,// = 15, + SyncType.UserJournal,// = 16, + SyncType.UserNote,// = 17, + SyncType.Unknown, // Unknown = 18, + SyncType.RecipientCache, // RecipientCache = 19 + }; + + public static readonly SyncType[] BASIC_SYNC_TYPES = + { + SyncType.Unknown, + SyncType.Other, // Other = 1, + SyncType.Inbox, // Inbox = 2, + SyncType.Drafts, // Drafts = 3, + SyncType.WasteBasket, // WasteBasket = 4, + SyncType.SentMail, // SentMail = 5, + SyncType.Outbox, // Outbox = 6, + SyncType.Task, // Task = 7, + SyncType.Appointment, // Appointment = 8, + SyncType.Contact, // Contact = 9, + SyncType.Note, // Note = 10, + SyncType.Journal, // Journal = 11, + SyncType.Other,// = 12, + SyncType.Appointment,// = 13, + SyncType.Contact,// = 14, + SyncType.Task,// = 15, + SyncType.Journal,// = 16, + SyncType.Note,// = 17, + SyncType.Unknown, // Unknown = 18, + SyncType.RecipientCache, // RecipientCache = 19 + }; + + public static bool IsMailType(SyncType type) + { + return USER_SYNC_TYPES[(int)type] == SyncType.UserMail; + } + + #endregion + + #region Contacts & Distribution lists + + public const string PREFIX_DISTLIST = GUID + "{00062004-0000-0000-C000-000000000046}/"; + public const string PR_DISTLIST_ONEOFFMEMBERS = PREFIX_DISTLIST + "8054" + PT_MV_BINARY; + public const string PR_DISTLIST_MEMBERS = PREFIX_DISTLIST + "8055" + PT_MV_BINARY; + + public const string PR_DISPLAY_TYPE = PROP + "3900" + PT_LONG; + public const string PR_DISPLAY_TYPE_EX = PROP + "3905" + PT_LONG; + public const int DT_ROOM = 7; + public const int DT_EQUIPMENT = 8; + + public const string PREFIX_CONTACTS = GUID + "{00062004-0000-0000-C000-000000000046}/"; + public const string PR_EMAIL1DISPLAYNAME = PREFIX_CONTACTS + "8080" + PT_UNICODE; + public const string PR_EMAIL1ADDRESSTYPE = PREFIX_CONTACTS + "8082" + PT_UNICODE; + public const string PR_EMAIL1EMAILADDRESS = PREFIX_CONTACTS + "8083" + PT_UNICODE; + public const string PR_EMAIL1ORIGINALDISPLAYNAME = PREFIX_CONTACTS + "8084" + PT_UNICODE; + public const string PR_EMAIL1ORIGINALENTRYID = PREFIX_CONTACTS + "8085" + PT_BINARY; + + #endregion + + #region Notes + + + public const string PREFIX_NOTES = GUID + "{0006200E-0000-0000-C000-000000000046}/"; + public const string PR_NOTE_COLOR = PREFIX_NOTES + "8B00" + PT_LONG; + public const string PR_NOTE_WIDTH = PREFIX_NOTES + "8B02" + PT_LONG; + public const string PR_NOTE_HEIGHT = PREFIX_NOTES + "8B03" + PT_LONG; + public const string PR_NOTE_X = PREFIX_NOTES + "8B04" + PT_LONG; + public const string PR_NOTE_Y = PREFIX_NOTES + "8B05" + PT_LONG; + + #endregion + + #region Tasks + + public const string PREFIX_TASKS = GUID + "{00062008-0000-0000-C000-000000000046}/"; + + #endregion + + + #region Message classes + + public const string PR_MESSAGE_CLASS = PROP + "001A" + PT_UNICODE; + public const string MESSAGE_CLASS_CONTACTS = "IPM.Contact"; + public const string MESSAGE_CLASS_NOTES = "IPM.StickyNote"; + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/AssemblyInfo.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b9b6a8f --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/AssemblyInfo.cs @@ -0,0 +1,25 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Kopano OL Extension")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Kopano OL Extension")] +[assembly: AssemblyCopyright("Copyright © Kopano b.v. 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c60a4b51-30f1-433f-99ff-bffc89e5675f")] + diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs new file mode 100644 index 0000000..22a01c6 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs @@ -0,0 +1,1023 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Acacia.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Acacia.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Support. + /// + internal static string Feature_DebugSupport { + get { + return ResourceManager.GetString("Feature_DebugSupport", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Free/Busy. + /// + internal static string Feature_FreeBusy { + get { + return ResourceManager.GetString("Feature_FreeBusy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Global Address Book. + /// + internal static string Feature_GAB { + get { + return ResourceManager.GetString("Feature_GAB", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Notes. + /// + internal static string Feature_Notes { + get { + return ResourceManager.GetString("Feature_Notes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Out of office. + /// + internal static string Feature_OutOfOffice { + get { + return ResourceManager.GetString("Feature_OutOfOffice", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reply flags. + /// + internal static string Feature_ReplyFlags { + get { + return ResourceManager.GetString("Feature_ReplyFlags", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Address Book for {0}. + /// + internal static string GAB_FolderFormat { + get { + return ResourceManager.GetString("GAB_FolderFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Modifications to the Global Address Book are not allowed. Please contact your administrator if you think changes are required.. + /// + internal static string GABEvent_Body { + get { + return ResourceManager.GetString("GABEvent_Body", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Global Address Book. + /// + internal static string GABEvent_Title { + get { + return ResourceManager.GetString("GABEvent_Title", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + internal static System.Drawing.Icon Kopano { + get { + object obj = ResourceManager.GetObject("Kopano", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Looks up a localized string similar to Kopano Folders. + /// + internal static string LocalStore_DisplayName { + get { + return ResourceManager.GetString("LocalStore_DisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to retrieve Out of Office settings. You can still enable or disable Out of Office, but applying the settings might fail.. + /// + internal static string OOFGet_Failed { + get { + return ResourceManager.GetString("OOFGet_Failed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Retrieving current Out of Office settings. + /// + internal static string OOFGet_Label { + get { + return ResourceManager.GetString("OOFGet_Label", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Out of Office Assistant. + /// + internal static string OOFGet_Title { + get { + return ResourceManager.GetString("OOFGet_Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Out of office has been enabled, but the server could not handle your full request. + /// + ///. + /// + internal static string OOFSet_DifferentState { + get { + return ResourceManager.GetString("OOFSet_DifferentState", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Out of Office has been disabled.. + /// + internal static string OOFSet_Disabled { + get { + return ResourceManager.GetString("OOFSet_Disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to disable Out of Office.. + /// + internal static string OOFSet_DisableFailed { + get { + return ResourceManager.GetString("OOFSet_DisableFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Out of Office has been enabled until further notice.. + /// + internal static string OOFSet_Enabled { + get { + return ResourceManager.GetString("OOFSet_Enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Out of Office has been enabled from {0} till {1}.. + /// + internal static string OOFSet_EnabledTimeBased { + get { + return ResourceManager.GetString("OOFSet_EnabledTimeBased", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to enable Out of Office.. + /// + internal static string OOFSet_EnableFailed { + get { + return ResourceManager.GetString("OOFSet_EnableFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to apply Out of Office settings. + /// + internal static string OOFSet_Failed { + get { + return ResourceManager.GetString("OOFSet_Failed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Applying Out of Office settings. + /// + internal static string OOFSet_Label { + get { + return ResourceManager.GetString("OOFSet_Label", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Out of Office Assistant. + /// + internal static string OOFSet_Title { + get { + return ResourceManager.GetString("OOFSet_Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Out of Office is currently enabled on account '{0}'. Would you like to change the settings?. + /// + internal static string OOFStartup_Message { + get { + return ResourceManager.GetString("OOFStartup_Message", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Out of Office Assistant. + /// + internal static string OOFStartup_Title { + get { + return ResourceManager.GetString("OOFStartup_Title", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_About { + get { + object obj = ResourceManager.GetObject("Ribbon_About", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to About. + /// + internal static string Ribbon_About_Label { + get { + return ResourceManager.GetString("Ribbon_About_Label", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to About dialog. + /// + internal static string Ribbon_About_Screentip { + get { + return ResourceManager.GetString("Ribbon_About_Screentip", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_About_Small { + get { + object obj = ResourceManager.GetObject("Ribbon_About_Small", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Shows the about dialog, which contains licensing and version information.. + /// + internal static string Ribbon_About_Supertip { + get { + return ResourceManager.GetString("Ribbon_About_Supertip", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_AddSharedFolder { + get { + object obj = ResourceManager.GetObject("Ribbon_AddSharedFolder", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_AddSharedFolder_Small { + get { + object obj = ResourceManager.GetObject("Ribbon_AddSharedFolder_Small", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_Debug { + get { + object obj = ResourceManager.GetObject("Ribbon_Debug", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Debug. + /// + internal static string Ribbon_Debug_Label { + get { + return ResourceManager.GetString("Ribbon_Debug_Label", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Debug dialog. + /// + internal static string Ribbon_Debug_Screentip { + get { + return ResourceManager.GetString("Ribbon_Debug_Screentip", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_Debug_Small { + get { + object obj = ResourceManager.GetObject("Ribbon_Debug_Small", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Opens the debug dialog, which shows information on the Kopano Outlook Extension.. + /// + internal static string Ribbon_Debug_Supertip { + get { + return ResourceManager.GetString("Ribbon_Debug_Supertip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kopano. + /// + internal static string Ribbon_GroupMain_Label { + get { + return ResourceManager.GetString("Ribbon_GroupMain_Label", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_Logfile { + get { + object obj = ResourceManager.GetObject("Ribbon_Logfile", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_Logfile_Small { + get { + object obj = ResourceManager.GetObject("Ribbon_Logfile_Small", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_ManageSharedFolders { + get { + object obj = ResourceManager.GetObject("Ribbon_ManageSharedFolders", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_ManageSharedFolders_Small { + get { + object obj = ResourceManager.GetObject("Ribbon_ManageSharedFolders_Small", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_MDM { + get { + object obj = ResourceManager.GetObject("Ribbon_MDM", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_MDM_Small { + get { + object obj = ResourceManager.GetObject("Ribbon_MDM_Small", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_OOF { + get { + object obj = ResourceManager.GetObject("Ribbon_OOF", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Out-of-Office. + /// + internal static string Ribbon_OOF_Label { + get { + return ResourceManager.GetString("Ribbon_OOF_Label", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Change Out-of-Office settings. + /// + internal static string Ribbon_OOF_Screentip { + get { + return ResourceManager.GetString("Ribbon_OOF_Screentip", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_OOF_Small { + get { + object obj = ResourceManager.GetObject("Ribbon_OOF_Small", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Opens a dialog which allows Out-of-Office settings to be viewed or modified.. + /// + internal static string Ribbon_OOF_Supertip { + get { + return ResourceManager.GetString("Ribbon_OOF_Supertip", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_Restore { + get { + object obj = ResourceManager.GetObject("Ribbon_Restore", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_Restore_Small { + get { + object obj = ResourceManager.GetObject("Ribbon_Restore_Small", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_Rules { + get { + object obj = ResourceManager.GetObject("Ribbon_Rules", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_Rules_Small { + get { + object obj = ResourceManager.GetObject("Ribbon_Rules_Small", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_Settings { + get { + object obj = ResourceManager.GetObject("Ribbon_Settings", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Settings. + /// + internal static string Ribbon_Settings_Label { + get { + return ResourceManager.GetString("Ribbon_Settings_Label", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Settings dialog. + /// + internal static string Ribbon_Settings_Screentip { + get { + return ResourceManager.GetString("Ribbon_Settings_Screentip", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_Settings_Small { + get { + object obj = ResourceManager.GetObject("Ribbon_Settings_Small", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Opens the settings dialog, which allows configuration of the plugin and access to support functions.. + /// + internal static string Ribbon_Settings_Supertip { + get { + return ResourceManager.GetString("Ribbon_Settings_Supertip", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_SharedFolders { + get { + object obj = ResourceManager.GetObject("Ribbon_SharedFolders", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_SharedFolders_Context { + get { + object obj = ResourceManager.GetObject("Ribbon_SharedFolders_Context", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Manage shared folder. + /// + internal static string Ribbon_SharedFolders_Context_Label { + get { + return ResourceManager.GetString("Ribbon_SharedFolders_Context_Label", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Manage this folder in the Shared Folders dialog. + /// + internal static string Ribbon_SharedFolders_Context_Screentip { + get { + return ResourceManager.GetString("Ribbon_SharedFolders_Context_Screentip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Open the "Shared Folders" dialog for the currently selected folder.. + /// + internal static string Ribbon_SharedFolders_Context_Supertip { + get { + return ResourceManager.GetString("Ribbon_SharedFolders_Context_Supertip", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shared folders. + /// + internal static string Ribbon_SharedFolders_Label { + get { + return ResourceManager.GetString("Ribbon_SharedFolders_Label", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Manage shared folders. + /// + internal static string Ribbon_SharedFolders_Screentip { + get { + return ResourceManager.GetString("Ribbon_SharedFolders_Screentip", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_SharedFolders_Small { + get { + object obj = ResourceManager.GetObject("Ribbon_SharedFolders_Small", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Open the "Shared Folders" dialog, which can be used to add or remove shared folders.. + /// + internal static string Ribbon_SharedFolders_Supertip { + get { + return ResourceManager.GetString("Ribbon_SharedFolders_Supertip", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_SyncGAB { + get { + object obj = ResourceManager.GetObject("Ribbon_SyncGAB", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_SyncGAB_Small { + get { + object obj = ResourceManager.GetObject("Ribbon_SyncGAB_Small", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Kopano. + /// + internal static string Ribbon_Title { + get { + return ResourceManager.GetString("Ribbon_Title", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_WebApp { + get { + object obj = ResourceManager.GetObject("Ribbon_WebApp", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Open WebApp. + /// + internal static string Ribbon_WebApp_Label { + get { + return ResourceManager.GetString("Ribbon_WebApp_Label", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Open WebApp. + /// + internal static string Ribbon_WebApp_Screentip { + get { + return ResourceManager.GetString("Ribbon_WebApp_Screentip", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_WebApp_Small { + get { + object obj = ResourceManager.GetObject("Ribbon_WebApp_Small", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Open WebApp in the system default browser. + /// + internal static string Ribbon_WebApp_Supertip { + get { + return ResourceManager.GetString("Ribbon_WebApp_Supertip", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_WebMeetings { + get { + object obj = ResourceManager.GetObject("Ribbon_WebMeetings", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ribbon_WebMeetings_Small { + get { + object obj = ResourceManager.GetObject("Ribbon_WebMeetings_Small", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to Unable to open the shared folder. Please ensure you have permission to open the shared folder.. + /// + internal static string SharedFolders_Adding_Failure { + get { + return ResourceManager.GetString("SharedFolders_Adding_Failure", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Opening shared folder. + /// + internal static string SharedFolders_Adding_Label { + get { + return ResourceManager.GetString("SharedFolders_Adding_Label", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shared folders. + /// + internal static string SharedFolders_Adding_Title { + get { + return ResourceManager.GetString("SharedFolders_Adding_Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to apply the changes to the shared folders. Please try again later.. + /// + internal static string SharedFolders_Applying_Failure { + get { + return ResourceManager.GetString("SharedFolders_Applying_Failure", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Applying changes to shared folders. + /// + internal static string SharedFolders_Applying_Label { + get { + return ResourceManager.GetString("SharedFolders_Applying_Label", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The changes to the shared folders have been applied successfully.. + /// + internal static string SharedFolders_Applying_Success { + get { + return ResourceManager.GetString("SharedFolders_Applying_Success", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shared folders. + /// + internal static string SharedFolders_Applying_Title { + get { + return ResourceManager.GetString("SharedFolders_Applying_Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Close shared folder {0}?. + /// + internal static string SharedFolders_Closing_Confirm { + get { + return ResourceManager.GetString("SharedFolders_Closing_Confirm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to close the shared folder.. + /// + internal static string SharedFolders_Closing_Failure { + get { + return ResourceManager.GetString("SharedFolders_Closing_Failure", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Closing shared folder. + /// + internal static string SharedFolders_Closing_Label { + get { + return ResourceManager.GetString("SharedFolders_Closing_Label", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shared folders. + /// + internal static string SharedFolders_Closing_Title { + get { + return ResourceManager.GetString("SharedFolders_Closing_Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to retrieve shared folders. Please try again later.. + /// + internal static string SharedFolders_Fetching_Failure { + get { + return ResourceManager.GetString("SharedFolders_Fetching_Failure", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Retrieving shared folders. + /// + internal static string SharedFolders_Fetching_Label { + get { + return ResourceManager.GetString("SharedFolders_Fetching_Label", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shared folders. + /// + internal static string SharedFolders_Fetching_Title { + get { + return ResourceManager.GetString("SharedFolders_Fetching_Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Retrieving shared folders. + /// + internal static string SharedFolders_Loading { + get { + return ResourceManager.GetString("SharedFolders_Loading", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There was an error retrieving shared folders. + /// + internal static string SharedFolders_Loading_Error { + get { + return ResourceManager.GetString("SharedFolders_Loading_Error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No shared folders are available. + /// + internal static string SharedFolders_None { + get { + return ResourceManager.GetString("SharedFolders_None", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to None. + /// + internal static string SharedFolders_Permission_None { + get { + return ResourceManager.GetString("SharedFolders_Permission_None", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Read. + /// + internal static string SharedFolders_Permission_Read { + get { + return ResourceManager.GetString("SharedFolders_Permission_Read", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Write. + /// + internal static string SharedFolders_Permission_Write { + get { + return ResourceManager.GetString("SharedFolders_Permission_Write", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Public folders. + /// + internal static string SharedFolders_PublicFolders { + get { + return ResourceManager.GetString("SharedFolders_PublicFolders", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There are unsaved changes. Do you really want to to discard these?. + /// + internal static string SharedFolders_Unsaved_Changes { + get { + return ResourceManager.GetString("SharedFolders_Unsaved_Changes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There is an error with the security certificate for server {0}. Do you want to allow the connection anyway?. + /// + internal static string SSLFailed_Body { + get { + return ResourceManager.GetString("SSLFailed_Body", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Certificate error. + /// + internal static string SSLFailed_Title { + get { + return ResourceManager.GetString("SSLFailed_Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Kopano. + /// + internal static string ThisAddIn_Title { + get { + return ResourceManager.GetString("ThisAddIn_Title", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap TreeLoading { + get { + object obj = ResourceManager.GetObject("TreeLoading", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx new file mode 100644 index 0000000..ccf7cde --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx @@ -0,0 +1,434 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Unable to retrieve Out of Office settings. You can still enable or disable Out of Office, but applying the settings might fail. + + + Retrieving current Out of Office settings + + + Out of Office Assistant + + + Out of office has been enabled, but the server could not handle your full request. + + + + + Out of Office has been disabled. + + + Unable to disable Out of Office. + + + Out of Office has been enabled until further notice. + + + Out of Office has been enabled from {0} till {1}. + + + Unable to enable Out of Office. + + + Unable to apply Out of Office settings + + + Applying Out of Office settings + + + Out of Office Assistant + + + Debug + + + Debug dialog + + + Opens the debug dialog, which shows information on the Kopano Outlook Extension. + + + Kopano + The group label for the ribbon + + + Out-of-Office + + + Change Out-of-Office settings + + + Opens a dialog which allows Out-of-Office settings to be viewed or modified. + + + Settings + + + Settings dialog + + + Opens the settings dialog, which allows configuration of the plugin and access to support functions. + + + Out of Office is currently enabled on account '{0}'. Would you like to change the settings? + + + Out of Office Assistant + + + Modifications to the Global Address Book are not allowed. Please contact your administrator if you think changes are required. + + + Global Address Book + + + Address Book for {0} + + + Kopano Folders + + + Support + + + Free/Busy + + + Global Address Book + + + Notes + + + Out of office + + + Reply flags + + + Kopano + + + There is an error with the security certificate for server {0}. Do you want to allow the connection anyway? + + + Certificate error + + + Kopano + + + Opening shared folder + + + Shared folders + + + Close shared folder {0}? + {0} will be replaced with the folder name + + + Closing shared folder + + + Shared folders + + + Unable to open the shared folder. Please ensure you have permission to open the shared folder. + + + Unable to close the shared folder. + + + + ..\Resources\Kopano.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Open WebApp + + + Open WebApp + + + Open WebApp in the system default browser + + + ..\Resources\Icons\Ribbon_AddSharedFolder.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_AddSharedFolder_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_Debug.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_Debug_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_Logfile.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_Logfile_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_ManageSharedFolders.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_ManageSharedFolders_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_MDM.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_MDM_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_OOF.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_OOF_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_Restore.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_Restore_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_Rules.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_Rules_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_Settings.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_Settings_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_SyncGAB.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_SyncGAB_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_WebApp.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_WebApp_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_WebMeetings.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_WebMeetings_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\Ribbon_ManageSharedFolders1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Shared folders + + + Manage shared folders + + + ..\Resources\Icons\Ribbon_ManageSharedFolders_Small1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Open the "Shared Folders" dialog, which can be used to add or remove shared folders. + + + Public folders + + + Retrieving shared folders + + + There was an error retrieving shared folders + + + No shared folders are available + + + TreeLoading.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Unable to retrieve shared folders. Please try again later. + + + Retrieving shared folders + + + Shared folders + + + There are unsaved changes. Do you really want to to discard these? + + + ..\Resources\Icons\Ribbon_ManageSharedFolders_Small11.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Manage shared folder + + + Manage this folder in the Shared Folders dialog + + + Open the "Shared Folders" dialog for the currently selected folder. + + + Applying changes to shared folders + + + Unable to apply the changes to the shared folders. Please try again later. + + + Shared folders + + + None + + + Read + + + Write + + + The changes to the shared folders have been applied successfully. + + + ..\Resources\Icons\Ribbon_About.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + About + + + About dialog + + + ..\Resources\Icons\Ribbon_About_Small.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Shows the about dialog, which contains licensing and version information. + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Settings.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Settings.Designer.cs new file mode 100644 index 0000000..1499d61 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Acacia.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Settings.settings b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Settings.settings new file mode 100644 index 0000000..abf36c5 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/TreeLoading.gif b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/TreeLoading.gif new file mode 100644 index 0000000000000000000000000000000000000000..1ea23fe894c21b6726ecadb9764f77d1c1b605d6 GIT binary patch literal 1407 zcmZ?wbhEHb6krfwXklRB$-C0C>&=l{UtId`JbCwL&8asftDf9>_2ZTzIDTtVLFE4B9S7E){G=4!_e}Y0h|ZN)4gsqaTAY~EtGc9E zHFeUCdgc0wE;JO?W$IQ}bd=B)VQ{S~DUguK^tOvt(>InHgkcY`%EI)@b)yQBSW^=2MO>@S0kX`jkg{#G-T^$?siQuNY~gG$y-sy z%f(dh!IYOQDTpn=@?Zg`dyr|S+82ctJ2V+i~a5~-AQj*}|+xc1D>ke-rFE5L`nx_B@Uj+*< zD=V+7x^h8LZ+~cjR!?&XRl+N6!^uhkD`WFO7iWeBleQ!uriEM!GE_d?6wwL{xz3>8 zJZ0U?=?aRsOH7tD`Ur4TOjr_;u#v+-diRknRjs@;&%N%}kmRV6YA!NL5RvG5kauzg z_pw*9yJEvrj;9E5F%?F7x@H=BU=6KeU}!NN=1Are`1Lb!%?kGkzX8a zj@2piv!vEHwNwjm%)tg+8eA?lTt2!X;ex`fQO0to-dzdc5RsbXndG4|;p8#KMhlC%7ulE?9AboT z=5C*9kg_~<*`YOtJU4iYES1x>g__iF*79E4Un-oJ7GIbjS?!56#6TI+<+1=UL!MwZ zb-n1|($sZ+q5TFQ3AW?B3#}Erma|-#a6mM6$%2R5vQ}o8sWVoI8b~xfdZ?Aeb1uo~ zh)u#1zL=@vJ)2jFH6DH8cw?y;7Xw$7fQyx`HDeP4qn~wBLsLtrUagft#bmAgLM5t% zRth3Ro>kzv5?;%ESfp#og5`>9dK5wrO+C1*8t<3VsoDq L7yY6ze|IwgR38r; literal 0 HcmV?d00001 diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_About.png b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_About.png new file mode 100644 index 0000000000000000000000000000000000000000..d94a001112f51f85428b894c4ede9e004de137cf GIT binary patch literal 700 zcmV;t0z>_YP)X)}r&DalyKxd-7Ygo)@HX8-m8Z=q#kSN?CSXxTf;TuA$&0vx<5-82 zn45`Th(|?3*)}|!34V_iCFDii#B#jK_>ZK9wt&f)DJ}l7)7opKyk{?LJSX_gA9xh~j=Y>Z0K5~|J!lRksDR_t-736(* zj9D4~vD8pD3!YaHOcz$-uF(I}VU%0;HlEcHFfvXO=!w5hF(M4C-)JTO&th$Z#C5S2 z=Zd^V0bTNg=x?GwC*ZqqVEotURk%N-yI>Ui6WeVp6$-3sz_f8XKD#W&7I8pw@XcM# zHsS;x2#uBO(YxQ34k&YUPJ$l^ZLlMU>K}ASep! z6SVK;wsIk)Xu2viTbwz0?!&zUhiB$LFXzmE=ILrQ8al{LEQCITrFKDw3VjgMg?%2! z;+!k+X&lc+ExyC}fI2Q>A6JW{DI7%)#xWm7o4LT*NQQ|HEnO@0Q#gZWZebBGD+wET z7H6a4Tf*bAg+1&R0q^6+t+4yC?0}0u_?rvNVFcI1xvrHo_$8706DOnzZR1M~4=TZL zbe7i=q2l6}F=lCpW$CU0HOyiZcLKW{_->onD}{X@Uu$?6z)9S|09GUt*TOd>kvI_c zQ{2r}NegnMs6K}8cpLTw^cDWz{L1cny$-i=ukz%>(sV{bFJ%;~_?!uQhaaIYPx#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^Ag1Z(U700E{+L_t(oN5$7YF9cB(#_{!9s1z!lL^ML9 zvz0`pv7bO8@db!PvGD-}6@^5Ch)!q}5>Zl-Xf(uIG}cCzXNk zlg-Jw_dYv!W_BkN1VO6IVv@{ak}}zBwgJ;PM*$C26tRI8Xq*>1Od*J26V0fYtR6aC z!dmDz>u5#AgmLMhQ)?|!%L(>z5Yr*Fl|v{6(7sy>{I?I}(hMMHX$L5#9iZSdzz!C1 zQ&y|RTYzO~F6o9ITvngUOMo}@A`BpVuzFp83h<5<^q~vk;_bMGHO3VyfF2;*Q2!dV z@Bp^(ggH#$2-bK@HH& zQeFWX^#OXkKEiz=@l9*!RbUoP=Ic_D%wm$vVse7aHx=PI*Sm&+(f|Me07*qoM6N<$ Ef^IJ8tpET3 literal 0 HcmV?d00001 diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_AddSharedFolder_Small.png b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_AddSharedFolder_Small.png new file mode 100644 index 0000000000000000000000000000000000000000..64aaa1aed10095bf1cd6b8d4870bf62ca0c2ed69 GIT binary patch literal 355 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85o30K$!7fntTONP_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCf(Pd8;#}EturI+{f9So2;`f*>2_(rpj5^CIHWsVr|6bF%dydML zP6_l}xu|6h*O!#&#_pM1O(8$JXL}#ybM+C9)H$IQ;rM>l&ZsG>k=$k%)J!iP7b?E- z?NpRO%O@tez;B&fAM|k^dy&+@CgyR@^O>B@#kOZ({$76lzG+SIf=PngI(5WWJ-F;y vQW)yU?tbKd6ZhFy^X7f!|J`a@lDgTe~DWM4fT`7x3 literal 0 HcmV?d00001 diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_Debug.png b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_Debug.png new file mode 100644 index 0000000000000000000000000000000000000000..3ff3ce13a924193aa4850b1c6533de60619f63e1 GIT binary patch literal 773 zcmV+g1N!`lP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E;(#7eog=Y0(MD6K~z{r#n(@$O;Hrb@mv1?DSsv}#Q-V) zBD{(2g#4LF24)hHG9=1`3H5pd6Au#-DU47C1|}#26edcE{234f5hLaJuGikTwfFg* zov7V1tiP z#gs3Y0F@^pgTgkbLTz?J_E(a5jJ1@4xB?gsf%S;l*Rt#ECw}w z@#rva;1W~<&-R7ISuFPz7hpN8FDQUpWMN-dR)?lA=6Kb(i z+Q2pVTEo_WIdxElUKF@a&Hhlu$I&owiaG3f>pr6MuKQ# zDg_l0MFa&wQrMYdXK~N0;r{0BoBjWJGyj`csnu#q@B{BLf(QJ>KIWeiE6*h8#R<-1 zUqxTU8jzH!u~-mR3swDt1f6(Ohz($(ggcJG!u~C~5_IDdb7;jKzT!))mBRNeUf^4_ z*PTXR(^$r5wBsyJS&H>jtg~^zhe&vo#*Y=$ae#Nx1{`AxV};VUqKb#ygB<-KF5<4l zi;vN^JVAmsER>MT&?38$HY6!_Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^Ag1Z(U700Id~L_t(oNA1_YYg1tq#_Px#?oAqy3?I^S?z!)IQbM@t%d*TUl}b~1jqky?7HB@hL+GpqeqTd_p$+JeqV6MC zfK4p>wW>dO6hl7GMc+;Y#Q&#Gc>R&|s)&fGdarILXzfX{xPDTJY3fKCSZ;`fY73wLcDer@jl5FK)s2io(;V7=%GUWBPfU7Xz0lR^zPNygJ|pzhu61=XVv^ZQ;3F= z8{|3eLJydaLQiht2K2Cz&aYw-`dy&UiJp++wOj$(sp|p0`hBJlhPoa=pX_Egw?p0U zGleiz^ta*P?D&1A5Qa|U9e%W#zBkU0#LT=By}Z;C1rt33 zJwqdBmh3k`MRz=1978Ppw_ZBW#TY1Zyzu-(%_Bu(Yiyd9<}6Xs%wMqP&6_8pdl*jk zZQ8Ig@YJPCXJ)k8YhM3uuvjzQs8`3X^wqr2ySG>8pOW~T5_yf~IEUG}6V6rliytz4 zcIB5AS;)5I0vq$C$!*OslN$7vtZ$5+#87xpEbdZ6!|&{dztb6Z#;%QA%yy!Er?QO6 zv8(H+NBrKpn3d(Q@BWpKuh;Sf9%9(EY+sYkiRot(TAAE36uZr|ZZuCk&rq3c=_W^IR%%QQpzn|WnQUf^-kQPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^Ag1Z(U700Fy6L_t(oNA1_oE2U8!$MKtFMVcf{Y?Yyz zW`EWE4TLR!1IkLFDPs!7EGB<~*eKnIWT9Az6|!W(G%n@G)y(bj{?vKube@NMo_pEo zS-k3=@Ao<9`P_5w;+#wn1et6$TgoiXa8;o^F0q6Udbdx2Q3P)w=Nn)TaSK%H&Nsj= zG+_Z_7_WflPvIU9z5!050CBx?ZGl(&1qin+u2-%Ncn283uv4qlvpdj)W=Gfy#~-a) zxgr7d;%z+QzvG`_kN435cVSYLqq+U&^Sl}NnsF%wJHU$56opbx4ouCantJPI zyog5VSm!<)XVVT)k7Zoouc52-Z~U}s@&~%v=(qd=ZN0AEMI1rF-D`PBYiho}aAObz ZnJ3+kk-(*u;Ryf$002ovPDHLkV1j?!`cD7= literal 0 HcmV?d00001 diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_MDM_Small.png b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_MDM_Small.png new file mode 100644 index 0000000000000000000000000000000000000000..3753eaee704b9f58773d9c271852c6cff4a705cc GIT binary patch literal 389 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucLCF%=h?3y^w370~qEv>0#LT=By}Z;C1rt33 zJwqdBmh3k`MPEH#978Pp?_Rd|b_$d@{?WTz*D|D=BX4ihvF=7^C5vA|HSB#CAKVG+ zR`}w6tBRR(kz@C+$OR8BJmN0MUvc?6qyN8}MHyv34(vT&JYW8K!8zYcCZVi40{mw1~bzBty(9R%Tlsr;Vq5bQCkEH^m$8rgTuSG=|1q2I>qF*ZrLtF z2mi$Qd2c0hSu16d{ht{0G0M+)C@E@_)MajxD88DnK6qyQ`U70^S0wJN+J8VY?qbAM ek^RLU`xpw(s{Z6VlA#O?00vK2KbLh*2~7Zh;Fh5P literal 0 HcmV?d00001 diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_ManageSharedFolders.png b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_ManageSharedFolders.png new file mode 100644 index 0000000000000000000000000000000000000000..2b6d5d1cde6e93c83fb3618486d18934781b88ac GIT binary patch literal 566 zcmV-60?GY}P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^Ag1Z(U700E{+L_t(oN5$7YF9cB(#_{!9s1z!lL^ML9 zvz0`pv7bO8@db!PvGD-}6@^5Ch)!q}5>Zl-Xf(uIG}cCzXNk zlg-Jw_dYv!W_BkN1VO6IVv@{ak}}zBwgJ;PM*$C26tRI8Xq*>1Od*J26V0fYtR6aC z!dmDz>u5#AgmLMhQ)?|!%L(>z5Yr*Fl|v{6(7sy>{I?I}(hMMHX$L5#9iZSdzz!C1 zQ&y|RTYzO~F6o9ITvngUOMo}@A`BpVuzFp83h<5<^q~vk;_bMGHO3VyfF2;*Q2!dV z@Bp^(ggH#$2-bK@HH& zQeFWX^#OXkKEiz=@l9*!RbUoP=Ic_D%wm$vVse7aHx=PI*Sm&+(f|Me07*qoM6N<$ Ef^IJ8tpET3 literal 0 HcmV?d00001 diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_ManageSharedFolders1.png b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_ManageSharedFolders1.png new file mode 100644 index 0000000000000000000000000000000000000000..2b6d5d1cde6e93c83fb3618486d18934781b88ac GIT binary patch literal 566 zcmV-60?GY}P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^Ag1Z(U700E{+L_t(oN5$7YF9cB(#_{!9s1z!lL^ML9 zvz0`pv7bO8@db!PvGD-}6@^5Ch)!q}5>Zl-Xf(uIG}cCzXNk zlg-Jw_dYv!W_BkN1VO6IVv@{ak}}zBwgJ;PM*$C26tRI8Xq*>1Od*J26V0fYtR6aC z!dmDz>u5#AgmLMhQ)?|!%L(>z5Yr*Fl|v{6(7sy>{I?I}(hMMHX$L5#9iZSdzz!C1 zQ&y|RTYzO~F6o9ITvngUOMo}@A`BpVuzFp83h<5<^q~vk;_bMGHO3VyfF2;*Q2!dV z@Bp^(ggH#$2-bK@HH& zQeFWX^#OXkKEiz=@l9*!RbUoP=Ic_D%wm$vVse7aHx=PI*Sm&+(f|Me07*qoM6N<$ Ef^IJ8tpET3 literal 0 HcmV?d00001 diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_ManageSharedFolders_Small.png b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_ManageSharedFolders_Small.png new file mode 100644 index 0000000000000000000000000000000000000000..64aaa1aed10095bf1cd6b8d4870bf62ca0c2ed69 GIT binary patch literal 355 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85o30K$!7fntTONP_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCf(Pd8;#}EturI+{f9So2;`f*>2_(rpj5^CIHWsVr|6bF%dydML zP6_l}xu|6h*O!#&#_pM1O(8$JXL}#ybM+C9)H$IQ;rM>l&ZsG>k=$k%)J!iP7b?E- z?NpRO%O@tez;B&fAM|k^dy&+@CgyR@^O>B@#kOZ({$76lzG+SIf=PngI(5WWJ-F;y vQW)yU?tbKd6ZhFy^X7f!|J`a@lDgTe~DWM4fT`7x3 literal 0 HcmV?d00001 diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_ManageSharedFolders_Small1.png b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_ManageSharedFolders_Small1.png new file mode 100644 index 0000000000000000000000000000000000000000..64aaa1aed10095bf1cd6b8d4870bf62ca0c2ed69 GIT binary patch literal 355 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85o30K$!7fntTONP_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCf(Pd8;#}EturI+{f9So2;`f*>2_(rpj5^CIHWsVr|6bF%dydML zP6_l}xu|6h*O!#&#_pM1O(8$JXL}#ybM+C9)H$IQ;rM>l&ZsG>k=$k%)J!iP7b?E- z?NpRO%O@tez;B&fAM|k^dy&+@CgyR@^O>B@#kOZ({$76lzG+SIf=PngI(5WWJ-F;y vQW)yU?tbKd6ZhFy^X7f!|J`a@lDgTe~DWM4fT`7x3 literal 0 HcmV?d00001 diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_ManageSharedFolders_Small11.png b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_ManageSharedFolders_Small11.png new file mode 100644 index 0000000000000000000000000000000000000000..64aaa1aed10095bf1cd6b8d4870bf62ca0c2ed69 GIT binary patch literal 355 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85o30K$!7fntTONP_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCf(Pd8;#}EturI+{f9So2;`f*>2_(rpj5^CIHWsVr|6bF%dydML zP6_l}xu|6h*O!#&#_pM1O(8$JXL}#ybM+C9)H$IQ;rM>l&ZsG>k=$k%)J!iP7b?E- z?NpRO%O@tez;B&fAM|k^dy&+@CgyR@^O>B@#kOZ({$76lzG+SIf=PngI(5WWJ-F;y vQW)yU?tbKd6ZhFy^X7f!|J`a@lDgTe~DWM4fT`7x3 literal 0 HcmV?d00001 diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_OOF.png b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_OOF.png new file mode 100644 index 0000000000000000000000000000000000000000..a6507a79898103857f1dbdbd9e81edff135050f4 GIT binary patch literal 535 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=BdgAk26#O}+vsC{f}XQ4*Y=R#Ki=l*&+$n3-3imzP?iV4`QB zXPIMM=La;j!_&nvB*Ojb^u2zE4MbYGnOwRfc7K%cspL$X$9(WaafxdZi;94BthVUX zyaU_^4)nLMaQi&84vmSGcCMdvCFuv-^LulORjfDOJ@L85XIg3!ci%(7dk+_@T$(V= zWa-<=D(0@-isn6POYUx)m)OvkY1hPjL%-8x$IcHzkG%u9(2E$(Uc?r@E(M@vA3*t*0$7HfgV zNN{i9(iiAD*R?ET3rv8CUx4e}>3LuOh%-*|cl_k4F{!TYa?tDk455?tM|BI1d73Hb z9yed0Yk9IvM?~q{oxs&q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&oalj&JU<&pQnpsh=u>w%Z6Ns3`CB7)amLD7o1bf6uY-+_9IoRl47wvjo$@iMPufO zzFZTl`ft8Uv!UVD2OpZZo&25gNhq}^FzU6Po&oP2g9%m-nY88@W+m{RiepyU*8cv}wA)ZI{g1BI@Rb*W5U7DBL_2(V$(@#O_&V_*x@9ewqCG&4K)n X)SI^)IegPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^Ag1Z(U700Rt3L_t(oN5$7ksEuJ9$MI_(7On*rBB97a zGOJ6n5G7McVZlPN5s64-%$SXhLQ0g4+=W7!A|$0u5gC%P%yWj0@9%bgxBq>5&wGb+ z%c)O2=Xaj>|2*&foQkTds)p)^#W;Z%n1QT*jglD_wZSl~#T671r;u*b8Iv$EWVtd! z%*P$X0dHd`Cg3H$qZ_(o4vyeC)b|fYBCB>CnIVotg*1s(7=-wHHT3&Uyf3y>I}o=S ziz!J~assoVA_qe@92;;IUy%+Ny}?4nn$w{pvmj(8C(s_+vv=5wd&n9ndV~YeKsq(C zUI)yB`))?fZ?Ti~z+4={H^c!_e{lobF%BIOYxTu4=&pH;FNoV~j7oLvgQYl$4~U&o zI`n6-0)x>KaZu5zI*j^uK&rLD{Ul7i#xdyJ^+r0N4Zu;vZFQ6+W_A}NwBh9t+C%Ka zRCGZ)SgI#-$kyldxj zL+|-m;5?M;4sqta()o2Zt(ct)nJkBE=W-)Hr{w~a&kC6@EFB4FdhRRJgq_JExOOf# zv?sAZxf9S1xppo$#v>LecLF{&^>Ra>SfJbqXop-omm7L+#{%U}Kp)r6l zZs=9~6fSZW$~Azqt;K9x$n=U;rUizxSLg)S&gDic#HE@3gy@~VBxG7ds-OOVIMX9s z{nX!?7NA-a)ETIh_~jN{MD(X5UKhWhKEFfu30m9vyJ$zU7OR=!m(z%ano2LGST|Sv yqI>rm-a>y!8cW-0T{#r7Zmx<#q3|CSD*ge{AG-DC-5G-b00000>^5(ra@B4o9W~Y*-se&EFRgB;)ZsRQuqYvM( zQ9Mv7Z*bM zK&XHvJi=>yz)9T1ee|P-?gX=O5I*A_W-y1fSiglE=)o#BBh{4z&+rn@L)Nac&EhF` zVm^gWcv4Bz^bGExj&8JYFve;~-NhH&#d48c#W9THV#pi8ItFE>YhhSc*7|;FRs0Hn z0TZ%HOky5y@G$mQWTh!@3v+;K(63bK(5G|YDiXvBRG#m c`?@fPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^Ag1Z(U700I3;L_t(oNA1?VYZOr!#o-V`Kru!wEUbip zkSdi?Sw#GZ7FG&M2m}Q|5YsDat%V?xB2B8a{s9`WPz1%wLPH7*NfT@|h!BE;jK8z) z9d_rQot=+OBNh)VbMO1U2j=7MK$0X)jYh-SgVVT!r}&5;NV?G43bgkw&SDf%?=ZJp zfU9^5H)I{}@eF}@=7A9DfZa@(drVP0bq_i-JUa2}^x&fy}ob`RRCns3PVn?X7^8$fgm zvPJ!(V9hys0ptT*gF04`&gd230Di$Ws^T{eBAwAIfao5(W>s83NB<%L29uP&I(e!VMRl1+FGiC%^>Ua5(~36R8v6DBN(-+u~{> zbpjlR8!ji|Y9jvw{Idb3;A$e<72p_LO=LR)EMW&+O{AXzexmRfFsKti$7~q>3S)5l na@7eijx{`NyH?uYxyisEbgM1FYNHee00000NkvXXu0mjfJFN|3 literal 0 HcmV?d00001 diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_Rules_Small.png b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_Rules_Small.png new file mode 100644 index 0000000000000000000000000000000000000000..57b297c357b055aa29e6314df7b11f37e7a901e6 GIT binary patch literal 383 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucLCF%=h?3y^w370~qEv>0#LT=By}Z;C1rt33 zJwqdBmh3k`MejXb978Ppr(QJlb8-}EeRzEXqgAy$LJ&!Md8KU}XSEt%QOddc>J<)OR)3p5b?46iTu-D6 ze;zkd51+8_(LEq#;HEPp;@J}}IYI7uy2XB#2Un;1t$V;56}K>T=49=PL%-vm0Uc?7 Y>yFR29KTXypw}5ZUHx3vIVCg!0NW>-R{#J2 literal 0 HcmV?d00001 diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_Settings.png b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_Settings.png new file mode 100644 index 0000000000000000000000000000000000000000..d94a001112f51f85428b894c4ede9e004de137cf GIT binary patch literal 700 zcmV;t0z>_YP)X)}r&DalyKxd-7Ygo)@HX8-m8Z=q#kSN?CSXxTf;TuA$&0vx<5-82 zn45`Th(|?3*)}|!34V_iCFDii#B#jK_>ZK9wt&f)DJ}l7)7opKyk{?LJSX_gA9xh~j=Y>Z0K5~|J!lRksDR_t-736(* zj9D4~vD8pD3!YaHOcz$-uF(I}VU%0;HlEcHFfvXO=!w5hF(M4C-)JTO&th$Z#C5S2 z=Zd^V0bTNg=x?GwC*ZqqVEotURk%N-yI>Ui6WeVp6$-3sz_f8XKD#W&7I8pw@XcM# zHsS;x2#uBO(YxQ34k&YUPJ$l^ZLlMU>K}ASep! z6SVK;wsIk)Xu2viTbwz0?!&zUhiB$LFXzmE=ILrQ8al{LEQCITrFKDw3VjgMg?%2! z;+!k+X&lc+ExyC}fI2Q>A6JW{DI7%)#xWm7o4LT*NQQ|HEnO@0Q#gZWZebBGD+wET z7H6a4Tf*bAg+1&R0q^6+t+4yC?0}0u_?rvNVFcI1xvrHo_$8706DOnzZR1M~4=TZL zbe7i=q2l6}F=lCpW$CU0HOyiZcLKW{_->onD}{X@Uu$?6z)9S|09GUt*TOd>kvI_c zQ{2r}NegnMs6K}8cpLTw^cDWz{L1cny$-i=ukz%>(sV{bFJ%;~_?!uQhaaIYPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^Ag1Z(U700Lb}L_t(oN7dKMt4&cH!0|&epa>y(=2=W! zp*S(Z&_qc}7bQt1!d2u^45a)41|}v3CNlGkFf$N}Ofc|%lu(G{`#tTY)n5DDbKJ9T za_Y11*=zsSZ~g9G>zut#tzNHh!c)A*QcS^1yv@Lz_pt8$ftqOsIRlp@AgUiEzSHN}bz-nxVx3?-TmaTwW7>aVDo2ZHp zvK7#WBnkGQDn7_oz!oG)(2J`0AX@>4ktD%ERK*9`3b=tJ39g_jKFC&p_99NQ3srHk zECoEqQOrS{WFC&;3Cewft_!$;u}Bg`#=*F_U(i(n=P?9H=N8T(^bNWyU=@;%{aArt z2>mtS0{lA*NymQ7#CL?8x{RvWjtW=?=ifPQ$2fD8@4z)AgUds^DfkFu-gUsZZ-q11 zj5Sz*WN>+CSHR!8gO!K}YPpC#TA;@mH+`N&?tahPu;9>KllMhu7TW3U@P;a!=8W&tj;kYu0*e8y}v|0^uSqUb!f z4)!_WxeX7C2Dx}N2bZe?^J zG%heMF)~90YwQ330Uk+2K~y+TrP9Ak12GuJ@rXrt(aFI@L{P+~pxmZ*QQVbE=|3O{ zRy&Kup@S$$p>z{>H$nU{wVhlXMd<3Ff{X2>@%tQ?nz#29B_g zcf7=S!#M__y+)sJoS_7pz!QcM27KZa2XIASxWoxs!JPAmA;bpU!!N)Z)MZ}*S8xGK z!CYSfub6_?%fVdYfF>5;E@~V_v=JNNUSSgc;x9F5{m)l8gbMOl#d?Is*LX%1VQ@4c zdI#O?Vh$TvL>SOPuYeuQ;0`*9Ug;Pq1?X}r(C^%B^9RN-k7;O63OCr+UN2bZe?^J zG%heMF)~90YwQ330a-~zK~z{r)tBK7f-n$;8Nm@4!4cF+7{v`7!6p3f2#nwe#tHB} zy{1_1N-0S7C0|0Iy?3-nTdKd+et+2Yk=x%BOloifE$9qxfNi$YZN3-`T!Ch2(Mb1s zLZD+1IEBT`&q3f6bo0w&T8$u3iaF<-Q$u)dnKz&VXSov>0>y^?4*0y5=5cv*$5Ec> zLSPo0W=uFL8)-VOp}E8ULSSH3dpz?{wmG>?H>FBoYnT>8+bo0C?0c`4>3x7x?)3r5^fLi3wEjw{FfjbEH#rX`?PYhNrTJ$MSg zpTK%kKq(23b&8OJS@F-X_(H@ZSC{};G3`+5gn&86@@a26CIrm+F&Td6bA_N~e$6bwePklX*Js(Jz_zOeF{ SQycIA0000!lvI6;>1s;*b z3=Bd=Aj}w-8vPh3C|TkfQ4*Y=R#Ki=l*&+$n3-3imzP?iV4`QBXK3WilKlp#=!K_? zV~BG1V$Phz8LuxPQ4jPpgQu&X%Q~lo FCIGjiiah`T literal 0 HcmV?d00001 diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_WebMeetings.png b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_WebMeetings.png new file mode 100644 index 0000000000000000000000000000000000000000..a9df944e9b04e3ddd92bd452f38a673f95cd87f8 GIT binary patch literal 386 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=BdgAk26#O}+vsC|TkfQ4*Y=R#Ki=l*&+$n3-3imzP?iV4`QB zXK3WilKlp#=#!_5V@QPi+iQDy4;cusJ_vAhW!F|n^Kd*U5n{l^yU5w+08fYIkDE+w z4oj9E+|$kAx=*~Nr8Y09Ch$v%-@G7;b90J4FJ2Jh)ddr&mGk@`u<1=;f3uML)1UQE zf*7hV?0>c(?!{#8XqiK7SGcv0ZI~jx&7x%&Q|%2$OZCS61|s_%xYG(+&(8^MRGi~* z_Nd;4M$&fhVpL=~OkTU=P literal 0 HcmV?d00001 diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_WebMeetings_Small.png b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Icons/Ribbon_WebMeetings_Small.png new file mode 100644 index 0000000000000000000000000000000000000000..2b046449b9fc13a6d26d045bae79fca06d10bbe3 GIT binary patch literal 261 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85o30K$!7fntTONP_o1|q9iy!t)x7$D3zfgF*C13FE6!3!9>qM z&(O%3CHoCfQK_ekV~B-+@{j-j?Oi2SD`?I*c*d6UFEQ+M}~Pu;|_+7{f$RFOcyY9_$zcz%wk}Zt72<7^uS`1#7ee?q(;t;lYOjD xN)|93@pj-j6{NK7i!awPEe{a3`FEayL57dP>BIi`Q$PnWc)I$ztaD0e0st=+QxE_E literal 0 HcmV?d00001 diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Kopano.ico b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Resources/Kopano.ico new file mode 100644 index 0000000000000000000000000000000000000000..107a670448a45c056e200a8700149092f5247cd6 GIT binary patch literal 105374 zcmeHQ2V7HE7k>$1qadQ-s6@rRu(pm*gt);;U04-GZ5_2LP81b_BB<3u>i{RX>a2(p zMNLH1wk}-Nx&lrVWeCU$dEYr9FD8(LBxDKP-|uqYeed3T{^$J99q+#P0zuFS69NN` zU=q%C31SKyv)Lv2mS!|!6P#nQMEPC>aiI~7aCR=q?{7vBuYI5IfIdGzTyV$q`y+k5;x-mBi# zjICZ~w7PQ>pVt^`H|lwfR=rMMOInvW<2Uzn^9MhnHD5Kjg@dgh`&)C{pGV#qVAXfm z!j-K%GB1yJ$oE{E7+!P#cjoOT3|YM6!5gOs5ArVLr7d;2)s2kGdA;mI*H5u8$c!Cf zZ?<)B#UA5YoO8FY|5=}B<6gM!a9vjTqyL!B8Dm}i(x0ppL=|+)DX5wHHg<9LDp%fw z8)?h3mpX4A)F@Ao$YQL2ScCZBnba-uT234*i0?ng_Wj9+A6obR@Mzz@tM`ud_MbAn z;cpH#C!MyuZc4W?3EkdkMox0{1cxQYVe8)Z^zD!m-l!;id0Qs?FW-l6r>|T7ao34M zXFJ55X7SRN{&1C#x6E2qUHOD0*j#?It)*Z zn0&hb*E#e4w`*U~litjFPr{z=xEDmYOzahSpsRWDr1zhu1qTG2JInogk>%H!MvP>e z^k;WFd^kzp={Ll~WVTOaa!oTIr*n0Oh8@a@3rSz*uqcvc>r?AV&l(9`ne3pzHOWri)_*TNt;zq>keiSUpY5B z{b2FZu-NlIFFL}0W1jk|eTeA?7BMe6xx-eE^M}kXw7F}j+kVP#7tS@GGWGeWBllPSXU>ieDMK2B9kXG7|8M+ue?Q)xZ~1lIlfRiV`sn6M$0mNH zN0ZmnoY)PzjmzD9A>}lSzAxn&VeS(eFni(T)0bQPZNXieoAGMy{iz`#Ji7U|%Q+^U zhiz}*K8)zLF1Ov}OS6L*H-G>5gf)!**Ypt1+C!ORnL+-;#Tu73dG-5%f%~!1DJNoV_uH|Kyja$JJ}AcOwB?QQJ#%iuD~mgv&T_5Y24&Ri)ZysP z55B`j(v$y;&zawSVfRTk-SNW4!Gp)Hy>G@&;CMUv4;$KGSOVZ4lQJgg!^3r{%PnXP z9UXZ$bC&aUqQIeD3Mt6rc%9>aycWB)aiimd;@ZcKVr?UA0)pN8?im0_`yX>6 zCNFSYk-4wNKz4}Hq1eaY_1i!=zwVzuy#J$ZYzGiv7TDhXcea`EXqNkLtogL)1nZPr zk*Rf7d}qvl6cFr~__VvtVB*}NupOT!Eh~;>@}m>{4|@lH$ME@-oiTA>%s3l?Z{(ke zX&rCYHfv7|Pt9h&iqGmCl)0k$^`~pRdfQtV+p~_WbTxCEwj#`a>yUkEjX6_1Y01RU zV8`n%a(eE*$l&((yL~Tb<@N7^(_|FX3a_~ zHgn5dd8?4n_k42MzGfJ>t+PlZQc4wp0&kD}nG-lQC?!5QH_w$Qu1=!F# z*(DE4X&Mpr;0!VMU13u`)5$f2KEycu?qLwsBxU|c?q*`{mfZgNJ=>0pvFKWx)!x|6 z%x%@WYxKq~=*eRO{rzon_t_G`j%JhYUmj0uLH}#wb3p&Q@3)P+jv=}=e7`!=Xy;m2 z&-ojOxm}-GrbPT*Y%TC=8#rs&xcukeEF8Wo<+(#_Ed617Ti3geaCJMU`1C^;{+`kN z>w6v+U3qhS6RYFLXY>`u;f2Q>6FSsx5HK*^)*-%a*M7v~zPr2vgC{h9@`0CMe0A!x zsCdSjTIbn4>F#HqVN)0TU%gzI;o80tnRoXQCzP>fW8)%*i8=HB*2PWuUr)E>G@EK} zb^gC;vuT<4qjog9A_(zbk$Ek+H>dD%VBP*vE+2BTx($qWNU}_A$F>_7P%Ge!Z~ht6 zq|kBAocHvJiy($=E9js9D&cssOPX77!)DGu^o@=oPW=)*MF2%dL==UD?`Evo(T0AW z!Fozs4?hFeotx6$&9B%yd@Cc)o^^?x?d^8qI5F%XwsXhtPK@OlkLc9c{?W&Y)OV!w z$}ON>=W(f*jNOj>?Lj}+pY2a;e&6AMl? zyEuwAjq|r@LI+2lH~GK0;jD|(XQ4*QREw}cq$1776U2Rx#uIhfqDU|l=lX2x;dGokp}9;cu` z?k?ZLU|z^KO?j|7aPj33D`dEY+-~)UwYrc-zC+fxyKau&(Cc# z{VAtIEBEMGv$=5U!u>7@G4`!S22M_DA9Qx?ng=y#2^s&S5(zO|JGS5t=oQb{?-$rQ zd*8Eg|Bu!QF%6!*^%FcGS3R|w+A@NBVEyug;LO2a6|Kum3-v3?I>OoD**0kS)sQG# z_K7UFgea5V>FK*^>umSmG#aslm~@3S3#^~H#Vw|I-sdK{ns2PXHE+z%#+!SqyNNQn@8MkPSg^7b9-E2cas{nM{5TicbhbXXu_ZV`0~%IZh}` z-rU?C-|$_Vru?_-f6C?AI1NaCdv{+R4D2CwSV^|YUK5tpNg2BB?-M<(}r*pWDQ;8_iS;CPkCTo@S^M+ zT_y+e=Jm|Ky8cCBpjWU*GT-T5JtBic24t;p|tU! z@qoUl4*TAZZoxdq?tz7VvBg&dug(e?&}$&qg8R4|u{8J1c(#*G0LRCg+qKsK_ATSc z{DbrjT?;}pi%bWyUzoR|&8EjK$$OI%msZ>$)gr;s#Ee^Gr&BV_JC8Gxlapq=h+m!= zYDD)n9hiKv3&*oMnzjB^>{p?=;t{v4n^gDJagVGIWzOl(3#KCiCN&^>w+AXLCljZJS?kG02}uxE&>yUN?4X$M)kD4}RbL z2UA9J==s@8caARly{Hb&jOc1ihZUqVVMR+YqUF~Rt)kwA6KsVYKZTIl2g9C$N>$M!pB)aV9Sp|RKE~eAgwn$y* z)6k4QZh7sXE4BD6n}+5lkEM?*`{*uVOOK8 z%kx^ii%q^T+p5VKdoGJUE2Tbh#F%)xDqynBlloS+zBSeaoo)Q;U!NJqvuawHcV!F= z`e0_}R{M22*J_sa4(qrs+@-<6QJc+uejC5k;rSsC@49V`%-5QpHl5MWGkMgcAllXiLFD;=Jcqh?f6#a$*$%;muk{ZS>75LG?E!~qNhiu zx$ULd4|meIr|J+BiZfQuqB(`P-*0C3Rlt-L3}2oF+t0{#)olxRruW?TX10w2rfg*R zX1))Z+}MkLkVT)Kuyy&Od7iUcngvd@Cw7=~-<%=5*^E0)ulf@;Qr^rX{7do>h=0^=CZjO&2o6Ps{Z4l0? zzvq8eNe%&H=|A(1e1ch#TPJ8Hi(crFwT-ndrOWl!#D@kWX@~33ZknW8Iz>lq^oz2C zDRDGn^WV;2uiH^C%U>5yy)YPM7$IG&v!*LjBV1`;f?V^lBIhqe#n0`=6$~*TU@vJ(;SC&@aeelP&{Ft+RMKK z^JM1T`(#J&;#&`jpSsZc@EScab!XWRTS7aqGOE>V^3OXhiNTi$(B5?Q0$QsOp6BD@ zsm-$m8~>QdHnvS#vF9v%#3i?wqFX1-S@)f}bn{g9X$zQ$R|oh`JD4){^#XG98G4eZ z9e7=|(S_A5d4s;G+bWdj`$zu1>w7*-n9CrC z_g6Fi%=LkrhS0;ojuV))|MDAIytECtbYOkpmQ*LAU-l0^_1syVFN`vtYY`anx7)y} zG|vvnt$RHEwfM#v!Zv(e+VJ3c7MzLej|lwEF7=s8bFSaUXe*oXGGS#;7dziMtESCL znSF?V=*~dGHmruDkrUH?hjns|-jfe9=2>!5?#1$E=G5UfsrPzf>+^((ZTPjw$7^0W z1Y9T_-r4KXCc!^Bw#4pNC!$?h^tmbKJ$E>~@BM2^mz=YOoz5Gx&a;2?_jf4jzMzH^ zGr~3Aq*G0|OJ3w|S2FrE5ou?!;vJjuLqay;;+QnbX~Vqy__~4-^_+-w<0Si~;djOX z8Q~sV8FOoLcIMrWf(y-0)(QGLoIPmECevC1!Q{Ye4m79JO*{dV$AZPqd70Lm3p#Wf zO$_=+2z2#EV*R}Q8Y^N1*GJRZZaKq#_0Y|D0*n52>^xex(5M-LR!a``hKns}&aFPw znnt%Jdc7T&%}bm{bN+pHt8@!@!hKizC|+;hCa~%X{Y0}RmPammIMr*L8QUYaPh3rR zBJq#6{i1rq#C$Kp7}#Rgog7houxo8%chE;A){+Yk8+MF|E@7&4l@l)oH9JjjN zSahzv>sdkF*>E>H68w>P5Vs>Y=J{Y^(2zs)y6!~RD{l`6)`4(l$ec}E^i^Jjd2^!qRbdHl^N#5qYL5VMdlPsV-jbrao-afRjUK~ zdJ9@`plkhvTl;N@6>EBSvt{LvT|GYKL7i{uK1cnS7Z^5zQM>;Al-GA7;qa{Qv{7b9 zH+FS43+yyyU`D^g-phJ_*MhjRt%Yy*t7C#jL*1<%uPxo$@l$qK-@QcSwi(8~1`;W= zL&CDY_6nFYgYWIxhOn$zKer7nn6o*_bWtJeJmKIv_lcGHu`TwQ?ci*qPS1E&3+A65 z`nwIWKJ6U4gE^C*JFQX1gWuK?4xKvqHa*=qXa=71jfe_3z3{}Zd1>wgh)oSc8AqJh znNiL5wh!FsWXydTH^6xm-HiPH#I28~e>+UH&2e0`{RiKs5zn}uPA=i}w;*AnZ zc4J!Gt&J~^d4DQ6ItDbp8+pjpuOMvF>C0WdH{{- zyIzMJ^8Qq!(-NAqOWWvuX*mPuw7XwGYZKHz%=NGT@uzGfP0l~L@n`%5Q-)`g1+|Vc z@?%e&u#0aM`>>S_e>jWyHuA?y4bJT79a(>=Yt-9x$IG*R`G(2v=1^d@dIf2+oM**I3c43+(kiH9fE$y&T*9=aa7F`JMdg zN-Ja7k8^QJ9#89WWT%&n$%RM5lNbLSX!?{theg!vcz>nK^hNdN8PDpt-aqfgp7EPT zE^%eUc3WjvCTnelI$W!Tl@w^7B3>pl{Q9>Cfz2>z=yd@xBg?XM#Fu8TFC8z~ohc9qe35TB zHi&>&5EFo5e(Cl#MEq!15$CrIf^Y>Oz!z>+`+{b?2+ZsW_KZ@pB@(vN#aav!)sX(1Zi;8r^bz`+3h@1dz0a2&C z$Hm2w81)sZ{h)+=us_c4JYDjDy!YzaQyBH>1E{k|_bRtO0M(hGI|ovo21)J>#Rt#; zB3m$J&5M=o9H@))pU#6U?hVWbaNWbMYrS1A zYVON7xriI4w#ETyUoUfhHTUInPn7_UINIPJ+BdlOcBuPxRZ|1r*Q02xXv)^44*(cu zMFFW(zq;S6V>NLdrlx!V#}sj^Iy$K4zG8;f)I0zvJS&Do_1e|kt8OznH9RXa20)uS z-{Y%H+!uf1$)QCzr(q000BY|ILS3D%`6?6lg)gGWtP=!@sh$H{oiP9~W8c@=y?$ln z9{Ja|4~RHac?5ogHtvg3W0dAzpFV)xmgfWDCo$;H+6tA8dmQ%_&G{7HvQk~I36Wbx`~&AqZSjun zRyOWYr`&6vD))U!U(mG=0A!{-AJFEyuQGBk?_N)mUuBMU=>v+^fiOO3<@tVP-JsI1&0U&?Z;Y&l)|0B~Gp4$#KfUs<`wK9YT&sd4^w zH4ey{17KX>pkA5^m6>~W?)Q`(19ag7$aU#CKvTS9JC&Jx)GzlcODla}(nqvC7fA9C zDzQ*6O@zwMJwDTy9_>@`EKIL+ zzbwD0s1G3bs`9@xI=aenkNoTUzF!vKvd&e+2SofUeeZ{TU*6oU&Ur&0^O1Kd7{c05 z7XNroT^|7cmF6DpaQN_Hjq(2_agVwiGXE9v0n|;|FlWvjjqv}aagX+q*Y^zRyt?Cn zviz$v#+R=1C363z@Q=QT&!)8z-n@BJ;l7Xe4PR<7q<*dl3%-l2jgXX-RAK%%ZrGp= zXgXbdB>9w3X`RetbcKt|O>p$eb z`us=WWB$!|R>%CoHc>T<8j9$@wUuVME8if~{3{0C>Y@ z`_Cn+pZ^-p7@%&yr`Qxd{|lq?%BI!tf9T%_D#|@_4g4ebYQ6te)!zL>d&ydN>EoOx zxJP{;AoutVpjx4-`G6tZ189(Y4EMSXq5QlVgCcxJQm9IhQ=v#vDM67?sfnH1#`hy5b(WkTv#G zJ^+`sG6z&J!TUH9=Lkz{2Hqy#A4pij#;B?JBax05-$#cMY_5XiR z(ec&!Z2(x)!7~ul51T5-O!^MO>9xx4e2Fg$eEBUXsp3wGWhUauGMo@_4MsbwJ@$J`(MesP=(! z?dnqzZk4SIeil|P5-k;|_5s<3MNX9EPZQ-po?g}hsC~5$Nc#YCp$Se^X#)`Gd~Z-v z>uMh;u?BF@LoQU|PE%z;t~1Ej%X$#Cuj)P^vc0pW_*AEzY9ByP)O|1n?kRr(?VWXR zfzJ}F=s2L)eot{vrND;X?hDZqs+bS>PjC_&GeZf6H0I0myUOGPIHnj% z_!79Md_v>{Jbl?t6LW!qagVk%sQI4aT3!lxaev^8+#@nD?$L&Nxxbgktt#ii2f_fq zUV=K~fPrzZ(>+~PcvYn=knba!zjW>gs`!ARa4)izk194c^s+!aK0DUSe4vaE7!dbp zBc`GAsV+Xy&EVc6G8FF7HtO2-OR6Ut3pkMKG{_nU41s$X7dc=E=9k2wCa{9eo}fDq zQk?}!AJ8}VBHcYTVaqSI4Im!>VI>=Ek)bOmK;HGqy+~J_2fx_+I!*hVKKwve{zl2E z=DmEcK|jE6)kR|?Wx6jq73osl-^-_8ssxaZ>w}mtm3$HQDm}kT5vpbe_-Bg71ikDZ zsN#RX`7OkXnAKFbx|#wDNcaLr6<)Mi7C7frbFP3iEnWg%SrGC5fdf(N_Yf!pWuZ)n zEG?>5-Lx7O08W_53-SXzg&|j>sI+fDc_GK5dSTd>s7)g+Ip$6>Fd7;41S)o9&Hh4aeBqhWX zgj?CX1RNnC2{=MP$&&2@pwfA+ObGc7OAl`e0jYMw1!pQdVFx_Wg^*A`HfuhQkY(tuU=pJeI!rsd^J`+Mnp zdHtvK_0s*ZbiQudVLahV=3%@^mdwi-pQIFoNk&Qm$Fk$0lmakb zN&$xPR0=R;B?ma+cq{=>I9^Kt6prT-fP{0N1RzIjPXd4&<|PCQv!4YD#YtF1C{AKR z5lyLL0gfg0#To^c!MeJ{stH+u z*$g7?Z|wnnGARAjO|cDZ3)_TfrU{JNXalg}dmw88Z<@NgmRAqkMj0qe8#<`dCitln z;E4uoWqewZJ|8}OATg>FM6#k$wmO(KQ3r6F0T;o5B~MiyP;Z|J6NFJ+8=y>-jTjJ% zCUjD^4X}Gxkj+C3ss>8;UOjt~7|{+Du>r~lEch{li?aADQVw)q3i4F)b;?Gib=R;B ziV#~xbW>Cpbg%+ni=lK;HI=8kCT)P2L>R3U>7wd2Xx0iizoe?pRQd9Bm$bpBPoJo2 zYNsNs8nFR@K;0jx3r1Pp(FPkgY*1HBnR+736|#XycdhfTY27JfRMZc&+21Lj*Ou;- z4NwPF`#YA$v6N~<)l^?TFAt}x^8&Qv0=}csIZl#q>R6NgU7qfE9(4g5bXCR=ptu>7 z=V3ingQ4**iC?5sx$8veFSwpmIT*6;lrpHBA|C)BaRNK3y`HE1T2WdNpU21BRc%yPycecK2><^;Hn(MkY=An-(jU$`|K z|AmU!K%^tHv<;wd;J$*=L07s93ew1r@eX3$ssBMy5gVYclKO+vIOZ$8Z=);Sk&I6_ zMwHRLqBaoeDxM2K4DPKd6?CaPAN~FWp)gj!4?HO!0Dr*!#d3o#bw@DD{y%ngY=Amb z`h!1|yHBfY-Id{9(l=DK0qTtUgPEPnBVO0KBOXQlUQ%z#V^wW{y2E+^pEJk}`p{j# z&n7>fGE>;^CH0m(R>cOWJM@D{dCKcUcf?YZdQ>glDLW`@1JoV*fz164+=rU-wsK58P zamqHORyj@SE!j@~gGEYXsp|SyCI2rdC@{S7?_5KjjDM(m_53G){WE#eB!%N3wJy^1 zT%gPKk0Gvq3t#Q8kpC;1^Cc$%)ZHNOe+o0C_WLB~vGR_U)gA31(%m5Me{-*Us_X-* z=q~aD;rn$k1{&P{N738kD(SDP?x-`h{{#J?O7DMxFBs(hr!qdED(@n{$3(pU3C9Mz z|DF4{yWD=DuI}Lbcrzs4|Hgg*eZVlEf8@O&Kc2BEV*_<{N8(Xes_#=N%mw)Dv&>o; z%gYP8+8-<34=SR&NJl26w`2->8tn7Wf~UU-eV`(`i+GHd)LHUa9VcF;Z7!A|+3mRHTba??=N}P-WkLLm$8Z zV}aJ*cc%6ZwDJ5z(kD=d5^Yrf3+?FSy=QIN0Q?@GZE4~i;41n4GvzV5@&o)9#L(V< zm$ZR4#{*4#2ZQ}ygt0a?9b+Rx^m{KX15C-b^I*iyQdFuCD%A_Ti_4l_teB2UfVttZJ@}^W;+8&gh zD7#U1q*Bq3N_@6E7aIf~gbi7L=857>{2LKa5Q+&4LNN$JdRszmXNW!!so#lUH-n4@ z1IVJmm{k{27f5Hq8tn+g6o~lt>nPsgrPB01@@y13GkvXj%b?a;rkS^&tj;9P|MJC0|xrR8&MBJa9nxp61P)H)R!( zc}}E97+h=uktP?63KyUqIz$&}I{_jejui$W_Jaq>fddARZmzE6IC!V*)-7}sSo-CH|9TAqBn@|Vj0oqcg8DSZa`2ot$fs92N zU`m{Tde}#?ex|U&a{kD|PVGe@4>M=ZB-7K=%V|aWGU$N6L$MNY)KCJlxCpd@cK3z4 z+0re_&MCr<_8&2PIC=5nMV0JNNdgQw?uI~KDITC4j_Ko|j#9=_277{<*d=tp=Noe& z&k!3~&H;{sD!=;}Pi77|uObR8iB| z`B^ssw-cFl9KOSYn0=v{(mDXv_kg)G#Q_}8f^%}$2Aak$D9R>tufcm{h@JY5P<0(v zg1vEVgTH@sR-WxOjUD9({pPgQXY6X|0GM$sY6!6n9H+>_uMO;iqAd81rI)nrDg2l! z&qF3)?+dtn0DqYu$I%9Mv=RTqCFrxY%GzE<9RPDN;K%WPcWK*e3p>imyFX99?N!&| zJmCLF5Y;Nd}1YhY>}Nv*}yUC-e6e>qp&l*6xtF9G&<5T$(oc2W}gou_9R z?5GQ_Bh|%@HWK8$B(piql*eC=4uHJ~Vg_Y@I3`0wLxuNEl+7{K1a_2Boc*uNZ|=oo zsHFc$9*g@lhk`0j0dp>u$<56rfByOBGWb!4ef#!N#nevuS+}6?)>hniC2>n0gAO@~ zT}VN}J1O~qKZiPj&nWRe3GbIA?T^R1cJ3^9FM(=DURq)NS6l)Ad#UCDzxX}{{Rh8q z#C|G?AN^-V`HxQ#rD~3K2d-SMQbjbU6zH(MK}(uRij9ND1tS5in-}cHG0ZgyU0^xFwIZp+n*8L*&QP zHOl&tlGsJ~Zvggscn<^VRM4SN61U{Brggx6{OS5|X%1Atj@SV6GDw7bym0&#;8*xA zlcsgxXWjlhma2#yu)YP%9jW_A)C10iLR7d3plKb1estCj#>loXH%SfSXkxhma7MvJ zsqYLxpQdpBq1;NM3mVlyPz3uY`(@6n@^An~w0#%K_L3=_p99y+Ji990mPU0b-ME50 zU_<{{1ySa60XT01Wlkt)LVQUdIsi6Y05y`ddFf-|paYaE*N;#UUFras-T=1VrSZzj zL%Hvu{9CcH6&&b72f%{QA*Mj2%fegw9G1iKP*1$JhP>RMj1Kt!d$F9V0Wjo(J^dk; z*|RN;TQU!F@L4J9P+=bMerWcrSt|dYH^|NsVOQ(fFyN;{{bA6~f6CZR77utYgx`DL zzkgquCd6ex=1Y+M1Dr6Cw5vMD&;~xUJ_)fvEI`hIqz-6z#E$nw$_9{u&*l>WyBpL| z%HNgI3EHX!ZO((XA3;?3P#twR3il7Q;9go;yF-)s-1j-e6(Gw&8BD5{fp+m3jT6XN z0}=I*yXM0^yv)qZa-TUu8))xji1^KUdyt{^_c>4o$Z~`@1LU58i0_0R2^lW5;Rmrf9GClSQB`{@Qy%16f&A7GCjzFu5N{whh#w&$PK?O*5AWSjk;(v^T6qSHK!uON{38LinBZ3gV&*VrD zC9fxaPN6z9KoDF^!4s&Ijd?&SmEt))2ewGQFqOc^#q)qaSuzE^D1C+cTYt6#Wf#g$ z!v8u1c0)TFVG0ci?Ftozc7}6kcYIHa36TX+{GOH#WYh@Y3k>iLd>0AFsXrh-fhZnx z;TZR8u&*A1vWuXcM&9=k$#sQxH$i*>Q9M3^4BkEq)R9*l_Y|(d^`4Y&ic%=o8_LVQ=cQy*d!dNI-`}6i$q{e&%ESR} zCPUlhy{FI>%E?_&l$MS2`1EPh$p0QHwX8=wAO@NL)e6qnhwB$)f|sy4rMFo2e@ZQ( z#La??e?V4qNeMd6``hr4#*a!v0>o35A{`N|iaFt~X_+;Vp?PSrL zKjmToS-5`fhc_^>RMgy%r!4miMf!J5Ny8Glzt zb}{_+06q($p8bD}uP+w^$V>&c~c=@}GoC@7=-vkvt3_6GRK2vr0Wc zQdf4#^Xs0{dvExhNHK;Oz>z2<1peUrj5w~T)5nDS$8lwU_d&RyEC&O~#yLgk_gPt4 zr0?w6;%8L&Y)3e@$n9ek>XNh|B~seN{m}=0{NV?s@6ifUHkWJv?DLNBTd~K)DuHZVx8O@s!f@x#9de?Nj~D}v@ycT0 zr(c0_N521+mW={IHr`+CEs6Z z9_{5tCMJF!&n3&@F*JeqV>scs$dV=R9ALGFdO;9{^F!%&ac=TkxUf9gcpvyHwDpxd zIf~AMOx)M{2HFUR_%B4MbsD~x1J|XXK^dIWA4A*>*LuK3xZAH-5aDow_HeDZAL12= z_>KYYP2sl$Zz28-5yx}fcWR}qT#`)_Zq>j(1AcRd-`n9gcBWj|USPx40Y*ZN0QGQB zhQ=+4M#<17wv94SmT-FrWaB;sZc8vBQu`DvsgVILlnS7qDa3)G?_r3kuyzo@cS-1H z_}*G9T>B29%)N0qUk}QxhbVkM48LVsv3xoC=bwL~uL`+@6!*xsL0Kukfr}1s{;04J z{CW589qGS#vG6{8^{Q1Qej6njpzK-5H$wQ38beT23VF>w;mW$`!k8w4{Z9v^LhjeuIkcdSp2!G@ z2=6bJEnP~crAhzBcmCsG3H&xBt|>|217u_Wib8oP7u!JIO1FW}?mxnB5esz})x|nc z_Xu!+`zpeh(Vq`i`{!Y=Zj2Jupb? zKsyIZw}E>&AuCss`T5e1sG;0(s8e6E`(Ya*96|yR2l_s~n+4|)GN$Pe*F#z1dmxha wslEW$&>lM>@?ac=u2WC|$M~G$54h$5QHYtUn+!QFjHGN8Mk6eXb+GRL0aSITt^fc4 literal 0 HcmV?d00001 diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddressBook.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddressBook.cs new file mode 100644 index 0000000..661f326 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddressBook.cs @@ -0,0 +1,33 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs +{ + public interface IAddressBook : IFolder + { + /// + /// Removes all contacts + /// + void Clear(); + + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAppointmentItem.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAppointmentItem.cs new file mode 100644 index 0000000..dde7298 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAppointmentItem.cs @@ -0,0 +1,34 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs +{ + /// + /// Specialisation for appointments + /// + public interface IAppointmentItem : IItem + { + DateTime Start { get; set; } + DateTime End { get; set; } + string Location { get; set; } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IBase.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IBase.cs new file mode 100644 index 0000000..8cfa0a9 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IBase.cs @@ -0,0 +1,56 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs +{ + public interface IBase : IDisposable + { + #region MAPI properties + + bool AttrHidden { get; set; } + + object GetProperty(string property); + void SetProperty(string property, object value); + void SetProperties(string[] properties, object[] values); + + #endregion + + string EntryId { get; } + IFolder Parent { get; } + string ParentEntryId { get; } + + IStore Store { get; } + /// + /// Quick accessor to Store.Id, to prevent allocation a wrapper for it. + /// + string StoreId { get; } + /// + /// Quick accessor to Store.DisplayName, to prevent allocation a wrapper for it. + /// + string StoreDisplayName { get; } + void Delete(); + + bool MustRelease { get; set; } + + string ToString(); + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IContactItem.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IContactItem.cs new file mode 100644 index 0000000..311ee6c --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IContactItem.cs @@ -0,0 +1,55 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs +{ + public interface IContactItem : IItem + { + string CustomerID { get; set; } + + string FullName { get; set; } + string FirstName { get; set; } + string LastName { get; set; } + string Initials { get; set; } + string Title { get; set; } + + string Email1Address { get; set; } + string Email1AddressType { get; set; } + string CompanyName { get; set; } + string JobTitle { get; set; } + string OfficeLocation { get; set; } + string BusinessTelephoneNumber { get; set; } + string MobileTelephoneNumber { get; set; } + string HomeTelephoneNumber { get; set; } + string PagerNumber { get; set; } + string BusinessFaxNumber { get; set; } + string OrganizationalIDNumber { get; set; } + string BusinessAddress { get; set; } + string BusinessAddressCity { get; set; } + string BusinessAddressPostalCode { get; set; } + string BusinessAddressPostOfficeBox { get; set; } + string BusinessAddressState { get; set; } + string Language { get; set; } + + void SetPicture(string path); + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IDistributionList.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IDistributionList.cs new file mode 100644 index 0000000..184f5a6 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IDistributionList.cs @@ -0,0 +1,32 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs +{ + public interface IDistributionList : IItem + { + string DLName { get; set; } + string SMTPAddress { get; set; } + + void AddMember(IItem item); + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolder.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolder.cs new file mode 100644 index 0000000..9130f06 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolder.cs @@ -0,0 +1,105 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.ZPush; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs +{ + public delegate void IFolder_BeforeItemMove(IFolder src, IItem item, IFolder target, ref bool cancel); + + public interface IFolder : IBase + { + #region Properties + + string Name { get; set; } + string Description { get; set; } + string DefaultMessageClass { get; } + + bool ShowAsOutlookAB { get; set; } + + IEnumerable Items { get; } + + IEnumerable ItemsSorted(string field, bool descending); + + IItem GetItemById(string id); + + #endregion + + #region Searching + + ISearch Search() + where ItemType : IItem; + + #endregion + + #region Subfolders + + IEnumerable GetSubFolders() + where FolderType : IFolder; + + FolderType GetSubFolder(string name) + where FolderType : IFolder; + + FolderType CreateFolder(string name) + where FolderType : IFolder; + + #endregion + + #region Item creation + + /// + /// Creates a new item + /// + ItemType Create() + where ItemType: IItem; + + #endregion + + #region Storage items + + /// + /// Provides access to storage items. These are hidden items that can be used to store folder + /// information. If the item does not exist, it is created. + /// + /// The name, for identifcation. + /// The storage item, or null if an error occurred + IStorageItem GetStorageItem(string name); + + #endregion + + #region Events + + event IFolder_BeforeItemMove BeforeItemMove; + + #endregion + + ItemType ItemType { get; } + + SyncId SyncId { get; } + + /// + /// Checks if the folder is at the specified depth. The root folder is at depth 0, its children at depth 1, etc. + /// This function exists because sometimes it's need to determine if a folder is at a specific depth; using this + /// function prevents creating lots of wrappers. + /// + bool IsAtDepth(int depth); + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IItem.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IItem.cs new file mode 100644 index 0000000..fea2a9a --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IItem.cs @@ -0,0 +1,56 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs +{ + /// + /// The base interface for Outlook items (messages, appointments, etc). These interfaces exist so + /// that features can be tested with mocked implementations. + /// + public interface IItem : IBase + { + #region Properties + + string[] AttrCategories { get; set; } + string Body { get; set; } + string Subject { get; set; } + + #endregion + + #region User properties + + /// + /// Retrieves the user property with the specified name. + /// + /// If true, the property is created if it does not exist. + /// If false, null is returned in this case + IUserProperty GetUserProperty(string name, bool create = false); + + #endregion + + #region Methods + + void Save(); + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IMailItem.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IMailItem.cs new file mode 100644 index 0000000..355ea10 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IMailItem.cs @@ -0,0 +1,39 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Office.Interop.Outlook; + +namespace Acacia.Stubs +{ + /// + /// Specialisation for mail messages + /// + public interface IMailItem : IItem + { + DateTime? AttrLastVerbExecutionTime { get; set; } + int AttrLastVerbExecuted { get; set; } + + string SenderEmailAddress { get; } + string SenderName { get; } + + void SetSender(AddressEntry addressEntry); + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/INoteItem.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/INoteItem.cs new file mode 100644 index 0000000..38d86d8 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/INoteItem.cs @@ -0,0 +1,28 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs +{ + public interface INoteItem : IItem + { + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ISearch.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ISearch.cs new file mode 100644 index 0000000..13335ac --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ISearch.cs @@ -0,0 +1,62 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs +{ + public enum SearchOperation + { + Equal, + NotEqual, + SmallerEqual, + Smaller, + GreaterEqual, + Greater, + Like + } + + public interface ISearchField + { + void SetOperation(SearchOperation operation, object param); + } + + public enum SearchOperator + { + Or, + And + } + + public interface ISearchOperator + { + ISearchField AddField(string name, bool isUserField = false); + } + + public interface ISearch + : ISearchOperator + where ItemType : IItem + { + ISearchOperator AddOperator(SearchOperator oper); + + IEnumerable Search(int maxResults = int.MaxValue); + + ItemType SearchOne(); + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IStorageItem.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IStorageItem.cs new file mode 100644 index 0000000..30f5db9 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IStorageItem.cs @@ -0,0 +1,28 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs +{ + public interface IStorageItem : IItem + { + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IStore.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IStore.cs new file mode 100644 index 0000000..51c0523 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IStore.cs @@ -0,0 +1,32 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs +{ + public interface IStore : IDisposable + { + IFolder GetRootFolder(); + IItem GetItemFromID(string id); + string DisplayName { get; } + string StoreID { get; } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ITaskItem.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ITaskItem.cs new file mode 100644 index 0000000..3d9ce64 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ITaskItem.cs @@ -0,0 +1,28 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs +{ + public interface ITaskItem : IItem + { + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IUserProperty.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IUserProperty.cs new file mode 100644 index 0000000..44db833 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IUserProperty.cs @@ -0,0 +1,38 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs +{ + public interface IUserProperty + { + #region Properties + + Type Value + { + get; + set; + } + + #endregion + } + +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IZPushItem.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IZPushItem.cs new file mode 100644 index 0000000..cd709ab --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IZPushItem.cs @@ -0,0 +1,31 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs +{ + /// + /// Interface for hidden items used to communicate with Z-Push + /// + public interface IZPushItem : IAppointmentItem + { + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ItemType.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ItemType.cs new file mode 100644 index 0000000..2c7857a --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ItemType.cs @@ -0,0 +1,38 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs +{ + public enum ItemType + { + MailItem = 0, + AppointmentItem = 1, + ContactItem = 2, + TaskItem = 3, + JournalItem = 4, + NoteItem = 5, + PostItem = 6, + DistributionListItem = 7, + MobileItemSMS = 11, + MobileItemMMS = 12 + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddressBookWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddressBookWrapper.cs new file mode 100644 index 0000000..47a9f3a --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddressBookWrapper.cs @@ -0,0 +1,45 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Utils; +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs.OutlookWrappers +{ + class AddressBookWrapper : FolderWrapper, IAddressBook + { + public AddressBookWrapper(Folder folder) + : + base(folder) + { + + } + + public void Clear() + { + foreach(dynamic item in _item.Items) + { + item.Delete(); + ComRelease.Release(item); + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AppointmentItemWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AppointmentItemWrapper.cs new file mode 100644 index 0000000..c50382f --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AppointmentItemWrapper.cs @@ -0,0 +1,114 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Office.Interop.Outlook; +using Acacia.Utils; + +namespace Acacia.Stubs.OutlookWrappers +{ + class AppointmentItemWrapper : OutlookWrapper, IAppointmentItem, IZPushItem + { + + internal AppointmentItemWrapper(AppointmentItem item) + : + base(item) + { + } + public override string ToString() { return "Appointment: " + Subject; } + + protected override PropertyAccessor GetPropertyAccessor() + { + return _item.PropertyAccessor; + } + + #region Properties + + public DateTime Start + { + get { return _item.Start; } + set { _item.Start = value; } + } + public DateTime End + { + get { return _item.End; } + set { _item.End = value; } + } + + public string Location + { + get { return _item.Location; } + set { _item.Location = value; } + } + + public string Body + { + get { return _item.Body; } + set { _item.Body = value; } + } + + public string Subject + { + get { return _item.Subject; } + set { _item.Subject = value; } + } + + public IStore Store { get { return StoreWrapper.Wrap(_item.Parent?.Store); } } + // TODO: release needed + public string StoreId { get { return _item.Parent?.Store?.StoreID; } } + public string StoreDisplayName { get { return _item.Parent?.Store?.DisplayName; } } + + #endregion + + #region Methods + + public IUserProperty GetUserProperty(string name, bool create = false) + { + return UserPropertyWrapper.Get(_item.UserProperties, name, create); + } + + public void Delete() { _item.Delete(); } + public void Save() { _item.Save(); } + + #endregion + + public IFolder Parent + { + get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); } + } + public string ParentEntryId + { + get + { + Folder parent = _item.Parent; + try + { + return parent?.EntryID; + } + finally + { + ComRelease.Release(parent); + } + } + } + + public string EntryId { get { return _item.EntryID; } } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/ContactItemWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/ContactItemWrapper.cs new file mode 100644 index 0000000..8b888ee --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/ContactItemWrapper.cs @@ -0,0 +1,245 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Utils; +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs.OutlookWrappers +{ + class ContactItemWrapper : OutlookWrapper, IContactItem + { + internal ContactItemWrapper(ContactItem item) + : + base(item) + { + } + + protected override PropertyAccessor GetPropertyAccessor() + { + return _item.PropertyAccessor; + } + + public override string ToString() { return "Contact: " + Subject; } + + #region IContactItem implementation + + public string CustomerID + { + get { return _item.CustomerID; } + set { _item.CustomerID = value; } + } + + public string FullName + { + get { return _item.FullName; } + set { _item.FullName = value; } + } + + public string FirstName + { + get { return _item.FirstName; } + set { _item.FirstName = value; } + } + + public string LastName + { + get { return _item.LastName; } + set { _item.LastName = value; } + } + + public string Initials + { + get { return _item.Initials; } + set { _item.Initials = value; } + } + + public string Title + { + get { return _item.Title; } + set { _item.Title = value; } + } + + public string Email1Address + { + get { return _item.Email1Address; } + set { _item.Email1Address = value; } + } + + public string Email1AddressType + { + get { return _item.Email1AddressType; } + set { _item.Email1AddressType = value; } + } + + public string CompanyName + { + get { return _item.CompanyName; } + set { _item.CompanyName = value; } + } + + public string JobTitle + { + get { return _item.JobTitle; } + set { _item.JobTitle = value; } + } + + public string OfficeLocation + { + get { return _item.OfficeLocation; } + set { _item.OfficeLocation = value; } + } + + public string BusinessTelephoneNumber + { + get { return _item.BusinessTelephoneNumber; } + set { _item.BusinessTelephoneNumber = value; } + } + + public string MobileTelephoneNumber + { + get { return _item.MobileTelephoneNumber; } + set { _item.MobileTelephoneNumber = value; } + } + + public string HomeTelephoneNumber + { + get { return _item.HomeTelephoneNumber; } + set { _item.HomeTelephoneNumber = value; } + } + + public string PagerNumber + { + get { return _item.PagerNumber; } + set { _item.PagerNumber = value; } + } + + public string BusinessFaxNumber + { + get { return _item.BusinessFaxNumber; } + set { _item.BusinessFaxNumber = value; } + } + + public string OrganizationalIDNumber + { + get { return _item.OrganizationalIDNumber; } + set { _item.OrganizationalIDNumber = value; } + } + + public string BusinessAddress + { + get { return _item.BusinessAddress; } + set { _item.BusinessAddress = value; } + } + + public string BusinessAddressCity + { + get { return _item.BusinessAddressCity; } + set { _item.BusinessAddressCity = value; } + } + + public string BusinessAddressPostalCode + { + get { return _item.BusinessAddressPostalCode; } + set { _item.BusinessAddressPostalCode = value; } + } + + public string BusinessAddressPostOfficeBox + { + get { return _item.BusinessAddressPostOfficeBox; } + set { _item.BusinessAddressPostOfficeBox = value; } + } + + public string BusinessAddressState + { + get { return _item.BusinessAddressState; } + set { _item.BusinessAddressState = value; } + } + + public string Language + { + get { return _item.Language; } + set { _item.Language = value; } + } + + #endregion + + #region IItem implementation + + public string Body + { + get { return _item.Body; } + set { _item.Body = value; } + } + + public string Subject + { + get { return _item.Subject; } + set { _item.Subject = value; } + } + + public IStore Store { get { return StoreWrapper.Wrap(_item.Parent?.Store); } } + // TODO: release needed + public string StoreId { get { return _item.Parent?.Store?.StoreID; } } + public string StoreDisplayName { get { return _item.Parent?.Store?.DisplayName; } } + + public IUserProperty GetUserProperty(string name, bool create = false) + { + return UserPropertyWrapper.Get(_item.UserProperties, name, create); + } + + public void Delete() { _item.Delete(); } + public void Save() { _item.Save(); } + + public void SetPicture(string path) + { + _item.AddPicture(path); + } + + #endregion + + #region IBase implementation + + public IFolder Parent + { + get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); } + } + public string ParentEntryId + { + get + { + Folder parent = _item.Parent; + try + { + return parent?.EntryID; + } + finally + { + ComRelease.Release(parent); + } + } + } + + public string EntryId { get { return _item.EntryID; } } + + #endregion + + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/DisposableWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/DisposableWrapper.cs new file mode 100644 index 0000000..ee2bded --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/DisposableWrapper.cs @@ -0,0 +1,74 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Features.DebugSupport; +using Acacia.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Acacia.Stubs.OutlookWrappers +{ + public abstract class DisposableWrapper : IDisposable + { + + /// + /// Creates a wrapper. + /// + internal DisposableWrapper() + { + Interlocked.Increment(ref Statistics.CreatedWrappers); + this._createdTrace = new System.Diagnostics.StackTrace(); + } + + ~DisposableWrapper() + { + Interlocked.Increment(ref Statistics.DeletedWrappers); + if (!_isDisposed) + { + Logger.Instance.Warning(this, "Undisposed wrapper: {0}", _createdTrace); + Dispose(); + // Don't count auto disposals + Interlocked.Decrement(ref Statistics.DisposedWrappers); + } + } + + private bool _isDisposed; + private readonly System.Diagnostics.StackTrace _createdTrace; + + virtual public void Dispose() + { + if (!_isDisposed) + { + Logger.Instance.TraceExtra(this, "Disposing wrapper: {0}", new System.Diagnostics.StackTrace()); + _isDisposed = true; + Interlocked.Increment(ref Statistics.DisposedWrappers); + DoRelease(); + } + } + + public bool MustRelease + { + get; + set; + } + + abstract protected void DoRelease(); + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/DistributionListWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/DistributionListWrapper.cs new file mode 100644 index 0000000..b5b06cc --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/DistributionListWrapper.cs @@ -0,0 +1,272 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Office.Interop.Outlook; +using Acacia.Utils; + +namespace Acacia.Stubs.OutlookWrappers +{ + class DistributionListWrapper : OutlookWrapper, IDistributionList + { + internal DistributionListWrapper(DistListItem item) + : + base(item) + { + } + + protected override PropertyAccessor GetPropertyAccessor() + { + return _item.PropertyAccessor; + } + + #region Properties + + public string SMTPAddress + { + get + { + PropertyAccessor props = _item.PropertyAccessor; + try + { + return (string)props.GetProperty(OutlookConstants.PR_EMAIL1EMAILADDRESS); + } + finally + { + ComRelease.Release(props); + } + } + set + { + string displayName = DLName + " (" + value + ")"; + byte[] oneOffId = CreateOneOffMemberId(DLName, "SMTP", value); + PropertyAccessor props = _item.PropertyAccessor; + try + { + props.SetProperties( + new string[] + { + OutlookConstants.PR_EMAIL1DISPLAYNAME, + OutlookConstants.PR_EMAIL1EMAILADDRESS, + OutlookConstants.PR_EMAIL1ADDRESSTYPE, + OutlookConstants.PR_EMAIL1ORIGINALDISPLAYNAME, + OutlookConstants.PR_EMAIL1ORIGINALENTRYID + }, + new object[] + { + DLName, + value, + "SMTP", + value, + oneOffId + } + ); + } + finally + { + ComRelease.Release(props); + } + } + } + + #endregion + + #region Methods + + public IUserProperty GetUserProperty(string name, bool create = false) + { + return UserPropertyWrapper.Get(_item.UserProperties, name, create); + } + + public void Delete() { _item.Delete(); } + public void Save() { _item.Save(); } + + public void AddMember(IItem item) + { + if (item is IContactItem) + { + string email = ((IContactItem)item).Email1Address; + Recipient recipient = ThisAddIn.Instance.Application.Session.CreateRecipient(email); + if (recipient.Resolve()) + _item.AddMember(recipient); + else + Logger.Instance.Warning(this, "Unable to resolve recipient: {0}", email); + } + else if (item is IDistributionList) + { + AddDistributionListMember((IDistributionList)item); + } + else + { + Logger.Instance.Warning(this, "Unknown item type when adding to distlist: {0}", item); + } + } + + private void AddDistributionListMember(IDistributionList member) + { + // Resolving a distribution list can only be done by name. This fails if the name is in multiple + // groups (e.g. 'Germany' and 'Sales Germany' fails to find Germany). Patch the member + // tables explicitly. + PropertyAccessor props = _item.PropertyAccessor; + object[] members = props.GetProperty(OutlookConstants.PR_DISTLIST_MEMBERS); + object[] oneOffMembers = props.GetProperty(OutlookConstants.PR_DISTLIST_ONEOFFMEMBERS); + + // Create the new member ids + byte[] memberId = CreateMemberId(member); + byte[] oneOffMemberId = CreateOneOffMemberId(member); + + // See if it is already a member + // Compare on one-off member id, as memberId changes + int existingIndex = -1; + for (int i = 0; i < oneOffMembers.Length; ++i) + { + byte[] existing = (byte[])oneOffMembers[i]; + if (existing.SequenceEqual(oneOffMemberId)) + { + existingIndex = i; + break; + } + } + + // Copy the existing members + int newElements = existingIndex < 0 ? 1 : 0; + object[] newMembers = new object[members.Length + newElements]; + object[] newOneOffMembers = new object[members.Length + newElements]; + for (int i = 0; i < members.Length; ++i) + { + newMembers[i] = members[i]; + newOneOffMembers[i] = oneOffMembers[i]; + } + + // Create the new entry + // If it was already a member, overwrite. Otherwise append. + if (existingIndex < 0) + existingIndex = members.Length; + newMembers[existingIndex] = memberId; + newOneOffMembers[existingIndex] = oneOffMemberId; + + // Write back + props.SetProperties( + new string[] { OutlookConstants.PR_DISTLIST_MEMBERS, OutlookConstants.PR_DISTLIST_ONEOFFMEMBERS }, + new object[] { newMembers, newOneOffMembers } + ); + } + + private static readonly byte[] PREFIX_MEMBER_ID = + { + 0x00, 0x00, 0x00, 0x00, 0xC0, 0x91, 0xAD, 0xD3, 0x51, 0x9D, 0xCF, 0x11, 0xA4, 0xA9, 0x00, 0xAA, 0x00, 0x47, 0xFA, 0xA4, 0xB4 + }; + + private byte[] CreateMemberId(IDistributionList member) + { + List id = new List(); + id.AddRange(PREFIX_MEMBER_ID); + id.AddRange(StringUtil.HexToBytes(member.EntryId)); + return id.ToArray(); + } + + private static readonly byte[] PREFIX_ONEOFFMEMBER_ID = + { + 0x00, 0x00, 0x00, 0x00, 0x81, 0x2B, 0x1F, 0xA4, 0xBE, 0xA3, 0x10, 0x19, 0x9D, 0x6E, 0x00, 0xDD, 0x01, 0x0F, 0x54, 0x02, 0x00, 0x00, 0x01, 0x80 + }; + + private byte[] CreateOneOffMemberId(IDistributionList member) + { + return CreateOneOffMemberId(member.DLName, "UNKNOWN", "UNKNOWN"); + } + + private byte[] CreateOneOffMemberId(string displayName, string addressType, string address) + { + byte[] zeroes = { 0, 0 }; + List id = new List(); + id.AddRange(PREFIX_ONEOFFMEMBER_ID); + + id.AddRange(Encoding.Unicode.GetBytes(displayName)); + id.AddRange(zeroes); + + id.AddRange(Encoding.Unicode.GetBytes(addressType)); + id.AddRange(zeroes); + + id.AddRange(Encoding.Unicode.GetBytes(address)); + id.AddRange(zeroes); + + id.AddRange(zeroes); + return id.ToArray(); + } + + #endregion + + public override string ToString() { return "DistributionList: " + DLName; } + + public string DLName + { + get { return _item.DLName; } + set { _item.DLName = value; } + } + + public string Body + { + get { return _item.Body; } + set { _item.Body = value; } + } + + public string Subject + { + get { return _item.Subject; } + set { _item.Subject = value; } + } + + public IFolder Parent { get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); } } + public string ParentEntryId + { + get + { + Folder parent = _item.Parent; + try + { + return parent?.EntryID; + } + finally + { + ComRelease.Release(parent); + } + } + } + public IStore Store { get { return StoreWrapper.Wrap(_item.Parent?.Store); } } + public string StoreId + { + get + { + // TODO: release needed + return _item.Parent?.Store?.StoreID; + } + } + public string StoreDisplayName + { + get + { + // TODO: release needed + return _item.Parent?.Store?.DisplayName; + } + } + + public string EntryId { get { return _item.EntryID; } } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs new file mode 100644 index 0000000..a89df4d --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs @@ -0,0 +1,439 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Collections; +using Acacia.Utils; +using Acacia.ZPush; + +namespace Acacia.Stubs.OutlookWrappers +{ + public class FolderWrapper : OutlookWrapper, IFolder + { + public FolderWrapper(Folder folder) + : + base(folder) + { + } + + protected override PropertyAccessor GetPropertyAccessor() + { + return _item.PropertyAccessor; + } + + public IFolder Parent + { + get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); } + } + public string ParentEntryId + { + get + { + Folder parent = _item.Parent; + try + { + return parent?.EntryID; + } + finally + { + ComRelease.Release(parent); + } + } + } + + /// + /// Checks if the folder is at the specified depth. The root folder is at depth 0, its children at depth 1, etc. + /// This function exists because sometimes it's need to determine if a folder is at a specific depth; using this + /// function prevents creating lots of wrappers. + /// + public bool IsAtDepth(int depth) + { + using (ComRelease com = new ComRelease()) + { + // The parent of the root item is a session, not null. Hence the explicit type checks. + Folder current = _item; + for (int i = 0; i < depth; ++i) + { + object parent = current.Parent; + com.Add(parent); + if (!(parent is Folder)) + return false; + current = (Folder)parent; + } + + return !(com.Add(current.Parent) is Folder); + } + } + + public SyncId SyncId + { + get + { + string folderId = (string)GetProperty(OutlookConstants.PR_ZPUSH_FOLDER_ID); + return folderId == null ? null : new SyncId(folderId); + } + } + + public string EntryId { get { return _item.EntryID; } } + + public IStore Store { get { return StoreWrapper.Wrap(_item.Store); } } + public string StoreId + { + get + { + using (IStore store = Store) + { + return store.StoreID; + } + } + } + public string StoreDisplayName + { + get + { + using (IStore store = Store) + { + return store.DisplayName; + } + } + } + + public ItemType ItemType { get { return (ItemType)(int)_item.DefaultItemType; } } + + public class IItemsEnumerator : IEnumerator + where ItemType : IItem + { + private Items _items; + private IEnumerator _enum; + private ItemType _last; + + public IItemsEnumerator(Folder _folder, string field, bool descending) + { + this._items = _folder.Items; + if (field != null) + { + this._items.Sort("[" + field + "]", descending); + } + this._enum = _items.GetEnumerator(); + } + + public ItemType Current + { + get + { + if (_last != null) + { + _last.Dispose(); + _last = default(ItemType); + } + _last = Mapping.Wrap(_enum.Current); + return _last; + } + } + + object IEnumerator.Current + { + get + { + return Current; + } + } + + public void Dispose() + { + if (_enum != null) + { + if (_enum is IDisposable) + ((IDisposable)_enum).Dispose(); + _enum = null; + } + if (_items != null) + { + ComRelease.Release(_items); + _items = null; + } + } + + public bool MoveNext() + { + if (_last != null) + { + _last.Dispose(); + _last = default(ItemType); + } + return _enum.MoveNext(); + } + + public void Reset() + { + _enum.Reset(); + } + } + + public class IItemsEnumerable : IEnumerable + where ItemType : IItem + { + private readonly Folder _folder; + private readonly string _field; + private readonly bool _descending; + + public IItemsEnumerable(Folder folder, string field, bool descending) + { + this._folder = folder; + this._field = field; + this._descending = descending; + } + + public IEnumerator GetEnumerator() + { + return new IItemsEnumerator(_folder, _field, _descending); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + + public IEnumerable Items + { + get + { + return new IItemsEnumerable(_item, null, false); + } + } + + public IEnumerable ItemsSorted(string field, bool descending) + { + return new IItemsEnumerable(_item, field, descending); + } + + public IItem GetItemById(string entryId) + { + try + { + using (IStore store = Store) + { + return store.GetItemFromID(entryId); + } + } + catch(System.Exception) + { + return null; + } + } + + public string Name + { + get { return _item.Name; } + set { _item.Name = value; } + } + + public string Description + { + get { return _item.Description; } + set { _item.Description = value; } + } + + public string DefaultMessageClass + { + get { return _item.DefaultMessageClass; } + } + + public bool ShowAsOutlookAB + { + get { return _item.ShowAsOutlookAB; } + set { _item.ShowAsOutlookAB = value; } + } + + public ISearch Search() + where ItemType: IItem + { + return new SearchWrapper(_item.Items); + } + + public IEnumerable GetSubFolders() + where FolderType : IFolder + { + foreach (MAPIFolder folder in _item.Folders) + { + yield return WrapFolder(folder); + }; + } + + public FolderType GetSubFolder(string name) + where FolderType : IFolder + { + // Fetching the folder by name throws an exception if not found, loop and find + // to prevent exceptions in the log + MAPIFolder sub = null; + foreach(MAPIFolder folder in _item.Folders) + { + if (folder.Name == name) + { + sub = folder; + break; + } + } + if (sub == null) + return default(FolderType); + return WrapFolder(sub); + } + + public FolderType CreateFolder(string name) + where FolderType : IFolder + { + Folders folders = _item.Folders; + try + { + if (typeof(FolderType) == typeof(IFolder)) + { + return WrapFolder(folders.Add(name)); + } + else if (typeof(FolderType) == typeof(IAddressBook)) + { + MAPIFolder newFolder = folders.Add(name, OlDefaultFolders.olFolderContacts); + newFolder.ShowAsOutlookAB = true; + return WrapFolder(newFolder); + } + else + throw new NotSupportedException(); + } + finally + { + ComRelease.Release(folders); + } + } + + private FolderType WrapFolder(MAPIFolder folder) + where FolderType : IFolder + { + if (typeof(FolderType) == typeof(IFolder)) + { + return (FolderType)(IFolder)new FolderWrapper((Folder)folder); + } + else if (typeof(FolderType) == typeof(IAddressBook)) + { + return (FolderType)(IFolder)new AddressBookWrapper((Folder)folder); + } + else + throw new NotSupportedException(); + } + + public IStorageItem GetStorageItem(string name) + { + StorageItem item = _item.GetStorage(name, OlStorageIdentifierType.olIdentifyBySubject); + if (item == null) + return null; + return new StorageItemWrapper(item); + } + + + #region Item creation + + /// + /// Creates a new item + /// + public ItemType Create() + where ItemType : IItem + { + Items items = _item.Items; + try + { + object item = items.Add(Mapping.OutlookItemType()); + return Mapping.Wrap(item); + } + finally + { + ComRelease.Release(items); + } + } + + #endregion + + public void Delete() + { + _item.Delete(); + } + + #region Misc + + public override string ToString() + { + return "Folder: " + _item.Name; + } + + #endregion + + #region Events + + // Hook the BeforeItemMove event handler only if someone is actually listening on it + private IFolder_BeforeItemMove _beforeItemMove; + public event IFolder_BeforeItemMove BeforeItemMove + { + add + { + if (_beforeItemMove == null) + HookBeforeItemMove(true); + _beforeItemMove += value; + } + remove + { + _beforeItemMove -= value; + if (_beforeItemMove == null) + HookBeforeItemMove(false); + } + } + + private void HookBeforeItemMove(bool hook) + { + if (hook) + _item.BeforeItemMove += HandleBeforeItemMove; + else + _item.BeforeItemMove -= HandleBeforeItemMove; + } + + private void HandleBeforeItemMove(object item, MAPIFolder target, ref bool cancel) + { + try + { + if (_beforeItemMove != null) + { + using (IItem itemWrapped = Mapping.Wrap(item)) + using (IFolder targetWrapped = Mapping.Wrap(target)) + { + if (itemWrapped != null && targetWrapped != null) + { + _beforeItemMove(this, itemWrapped, targetWrapped, ref cancel); + } + } + } + } + catch(System.Exception e) + { + Logger.Instance.Error(this, "Exception in HandleBeforeItemMove: {0}", e); + } + } + + #endregion + + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/MailItemWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/MailItemWrapper.cs new file mode 100644 index 0000000..9af5487 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/MailItemWrapper.cs @@ -0,0 +1,167 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Office.Interop.Outlook; +using Acacia.Utils; + +namespace Acacia.Stubs.OutlookWrappers +{ + class MailItemWrapper : OutlookWrapper, IMailItem + { + internal MailItemWrapper(MailItem item) + : + base(item) + { + } + + protected override PropertyAccessor GetPropertyAccessor() + { + return _item.PropertyAccessor; + } + + public override string ToString() { return "Mail: " + Subject; } + + #region Properties + + public string Body + { + get { return _item.Body; } + set { _item.Body = value; } + } + + public string Subject + { + get { return _item.Subject; } + set { _item.Subject = value; } + } + + public IStore Store + { + get + { + Folder parent = (Folder)_item.Parent; + try + { + return StoreWrapper.Wrap(parent?.Store); + } + finally + { + ComRelease.Release(parent); + } + } + } + + public string StoreId + { + get + { + Folder parent = (Folder)_item.Parent; + Store store = null; + try + { + store = parent?.Store; + return store?.StoreID; + } + finally + { + ComRelease.Release(parent); + ComRelease.Release(store); + } + } + } + + public string StoreDisplayName + { + get + { + Folder parent = (Folder)_item.Parent; + Store store = null; + try + { + store = parent?.Store; + return store?.DisplayName; + } + finally + { + ComRelease.Release(parent); + ComRelease.Release(store); + } + } + } + + public string SenderEmailAddress + { + get + { + // TODO: should Sender be released? + return _item.Sender?.Address; + } + } + + public string SenderName + { + get { return _item.Sender?.Name; } + } + + + public void SetSender(AddressEntry addressEntry) + { + _item.Sender = addressEntry; + } + + + #endregion + + #region Methods + + public IUserProperty GetUserProperty(string name, bool create = false) + { + return UserPropertyWrapper.Get(_item.UserProperties, name, create); + } + + public void Delete() { _item.Delete(); } + public void Save() { _item.Save(); } + + #endregion + + public IFolder Parent + { + get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); } + } + public string ParentEntryId + { + get + { + Folder parent = _item.Parent; + try + { + return parent?.EntryID; + } + finally + { + ComRelease.Release(parent); + } + } + } + + public string EntryId { get { return _item.EntryID; } } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/Mapping.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/Mapping.cs new file mode 100644 index 0000000..93bcf10 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/Mapping.cs @@ -0,0 +1,133 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Utils; +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs.OutlookWrappers +{ + public static class Mapping + { + + /// + /// Wraps the specified Outlook object in an IItem; + /// + /// The Outlook object. + /// The IItem wrapper, or null if the object could not be wrapped + public static IBase Wrap(object o, bool mustRelease = true) + { + if (o == null) + return null; + + IBase wrapper = CreateWrapper(o); + if (wrapper != null) + wrapper.MustRelease = mustRelease; + ComRelease.LogWrapper(o, wrapper); + return wrapper; + } + + private static IBase CreateWrapper(object o) + { + // TODO: switch on o.Class + if (o is MailItem) + return new MailItemWrapper((MailItem)o); + if (o is AppointmentItem) + return new AppointmentItemWrapper((AppointmentItem)o); + if (o is Folder) + return new FolderWrapper((Folder)o); + if (o is ContactItem) + return new ContactItemWrapper((ContactItem)o); + if (o is DistListItem) + return new DistributionListWrapper((DistListItem)o); + if (o is NoteItem) + return new NoteItemWrapper((NoteItem)o); + if (o is TaskItem) + return new TaskItemWrapper((TaskItem)o); + + // TODO: support this? + if (o is ReportItem) + return null; + + return null; + } + + public static Type Wrap(object o, bool mustRelease = true) + where Type : IBase + { + return (Type)Wrap(o, mustRelease); + } + + public static Type WrapOrDefault(object o, bool mustRelease = true) + where Type : IBase + { + IBase wrapped = Wrap(o, mustRelease); + if (wrapped is Type) + return (Type)wrapped; + if (wrapped != null) + wrapped.Dispose(); + return default(Type); + } + + public static OlItemType OutlookItemType() + where ItemType: IItem + { + Type type = typeof(ItemType); + if (type == typeof(IContactItem)) + return OlItemType.olContactItem; + if (type == typeof(IDistributionList)) + return OlItemType.olDistributionListItem; + throw new NotImplementedException(); // TODO + } + + public static OlUserPropertyType OutlookPropertyType() + { + Type type = typeof(PropType); + if (type == typeof(string)) + return OlUserPropertyType.olText; + if (type == typeof(DateTime)) + return OlUserPropertyType.olDateTime; + if (type == typeof(int)) + return OlUserPropertyType.olInteger; + if (type.IsEnum) + return OlUserPropertyType.olInteger; + if (type == typeof(string[])) + return OlUserPropertyType.olKeywords; + throw new NotImplementedException(); // TODO + } + + + // TODO: this needs to go elsewhere + public static IFolder GetFolderFromID(string folderId) + { + NameSpace nmspace = ThisAddIn.Instance.Application.Session; + try + { + Folder f = (Folder)nmspace.GetFolderFromID(folderId); + return Wrap(f); + } + finally + { + ComRelease.Release(nmspace); + } + } + + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/NoteItemWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/NoteItemWrapper.cs new file mode 100644 index 0000000..a18f307 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/NoteItemWrapper.cs @@ -0,0 +1,97 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.Linq; +using Acacia.Utils; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs.OutlookWrappers +{ + public class NoteItemWrapper : OutlookWrapper, INoteItem + { + internal NoteItemWrapper(NoteItem item) + : + base(item) + { + } + + protected override PropertyAccessor GetPropertyAccessor() + { + return _item.PropertyAccessor; + } + + public override string ToString() { return "Note: " + Subject; } + + #region Properties + + public string Body + { + get { return _item.Body; } + set { _item.Body = value; } + } + + public string Subject + { + get { return _item.Subject; } + set { throw new NotSupportedException(); } + } + + public IStore Store { get { return StoreWrapper.Wrap(_item.Parent?.Store); } } + // TODO: release needed + public string StoreId { get { return _item.Parent?.Store?.StoreID; } } + public string StoreDisplayName { get { return _item.Parent?.Store?.DisplayName; } } + + #endregion + + #region Methods + + public IUserProperty GetUserProperty(string name, bool create = false) + { + throw new NotSupportedException(); + } + + public void Delete() { _item.Delete(); } + public void Save() { _item.Save(); } + + #endregion + + public IFolder Parent + { + get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); } + } + public string ParentEntryId + { + get + { + Folder parent = _item.Parent; + try + { + return parent?.EntryID; + } + finally + { + ComRelease.Release(parent); + } + } + } + + public string EntryId { get { return _item.EntryID; } } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/OutlookWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/OutlookWrapper.cs new file mode 100644 index 0000000..2bb4efe --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/OutlookWrapper.cs @@ -0,0 +1,173 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Features.DebugSupport; +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.Linq; +using Acacia.Utils; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Acacia.Stubs.OutlookWrappers +{ + /// + /// Helper for Outlook wrapper implementations + /// + abstract public class OutlookWrapper : DisposableWrapper + { + + #region Construction / Destruction + + protected ItemType _item; + + /// + /// Creates a wrapper. + /// + internal OutlookWrapper(ItemType item) + { + this._item = item; + } + + ~OutlookWrapper() + { + } + + protected override void DoRelease() + { + if (_props != null) + { + ComRelease.Release(_props); + _props = null; + } + + if (MustRelease) + { + if (_item != null) + { + ComRelease.Release(_item); + _item = default(ItemType); + } + } + } + + #endregion + + #region Properties implementation + + private PropertyAccessor _props; + + private PropertyAccessor Props + { + get + { + if (_props == null) + { + _props = GetPropertyAccessor(); + } + return _props; + } + } + + /// + /// Returns the wrapped item's property accessor. + /// + /// The property accessor. The caller is responsible for disposing this. + abstract protected PropertyAccessor GetPropertyAccessor(); + + #endregion + + #region Properties + + public string[] AttrCategories + { + // Get the categories using the MAPI property. If using the C# property, they get concatenated + // into a string which must be parsed again. + get + { + return Props.GetProperty(OutlookConstants.PR_CATEGORIES); + } + set + { + Props.SetProperty(OutlookConstants.PR_CATEGORIES, value); + } + } + + public bool AttrHidden + { + get + { + return Props.GetProperty(OutlookConstants.PR_ATTR_HIDDEN); + } + set + { + Props.SetProperty(OutlookConstants.PR_ATTR_HIDDEN, value); + } + } + + public DateTime? AttrLastVerbExecutionTime + { + get + { + return Props.GetProperty(OutlookConstants.PR_LAST_VERB_EXECUTION_TIME) as DateTime?; + } + set + { + Props.SetProperty(OutlookConstants.PR_LAST_VERB_EXECUTION_TIME, value); + } + } + + public int AttrLastVerbExecuted + { + get + { + return Props.GetProperty(OutlookConstants.PR_LAST_VERB_EXECUTED); + } + set + { + Props.SetProperty(OutlookConstants.PR_LAST_VERB_EXECUTED, value); + } + } + + public object GetProperty(string property) + { + try + { + object val = Props.GetProperty(property); + if (val is DBNull) + return null; + return val; + } + catch(System.Exception) { return null; } // TODO: is this fine everywhere? + } + + public void SetProperty(string property, object value) + { + Props.SetProperty(property, value); + } + + public void SetProperties(string[] properties, object[] values) + { + Props.SetProperties(properties, values); + } + + #endregion + + public override abstract string ToString(); + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/SearchWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/SearchWrapper.cs new file mode 100644 index 0000000..440aa03 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/SearchWrapper.cs @@ -0,0 +1,224 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Office.Interop.Outlook; +using Acacia.Utils; + +namespace Acacia.Stubs.OutlookWrappers +{ + class SearchWrapper : ISearch + where ItemType : IItem + { + private interface SearchTerm + { + string MakeFilter(); + } + + private class SearchOperatorImpl : ISearchOperator, SearchTerm + { + private readonly SearchOperator oper; + private readonly List terms = new List(); + + public SearchOperatorImpl(SearchOperator oper) + { + this.oper = oper; + } + + public string MakeFilter() + { + string oper; + switch (this.oper) + { + case SearchOperator.Or: + oper = "OR"; + break; + case SearchOperator.And: + oper = "AND"; + break; + default: + throw new NotImplementedException(); + } + + string query = ""; + + foreach(SearchTerm term in terms) + { + if (query.Length > 0) + query += oper; + query += "(" + term.MakeFilter() + ")"; + } + return query; + } + + public ISearchField AddField(string name, bool isUserField = false) + { + SearchField field = new SearchField(name, isUserField); + terms.Add(field); + return field; + } + } + + private class SearchField : ISearchField, SearchTerm + { + public string Name { get; set; } + public bool IsUserField { get; set; } + public SearchOperation Operation { get; set; } + public object Parameter { get; set; } + + public SearchField(string name, bool isUserField) + { + this.Name = name; + this.IsUserField = isUserField; + } + + public void SetOperation(SearchOperation operation, object param) + { + this.Operation = operation; + this.Parameter = param; + } + + public string MakeFilter() + { + string oper; + switch(Operation) + { + case SearchOperation.Equal: + oper = "="; + break; + case SearchOperation.NotEqual: + oper = "<>"; + break; + case SearchOperation.SmallerEqual: + oper = "<="; + break; + case SearchOperation.Smaller: + oper = "<"; + break; + case SearchOperation.GreaterEqual: + oper = ">="; + break; + case SearchOperation.Greater: + oper = ">"; + break; + case SearchOperation.Like: + oper = "like"; + break; + default: + throw new NotImplementedException(); + } + return NameQuery + " " + oper + " " + ParameterQuery; + } + + private string NameQuery + { + get + { + return "\"" + Name + "\""; + } + } + private string ParameterQuery + { + get + { + if (Parameter is string) + return "'" + ((string)Parameter).Replace("'", "''") + "'"; + if (Parameter.GetType().IsEnum) + { + throw new NotImplementedException(); + } + return Parameter.ToString(); + } + + } + } + + private readonly List terms = new List(); + private readonly Items _items; + + public SearchWrapper(Items items) + { + this._items = items; + } + + public ISearchOperator AddOperator(SearchOperator oper) + { + SearchOperatorImpl so = new SearchOperatorImpl(oper); + terms.Add(so); + return so; + } + + public ISearchField AddField(string name, bool isUserField = false) + { + SearchField field = new SearchField(name, isUserField); + terms.Add(field); + return field; + } + + public IEnumerable Search(int maxResults) + { + List values = new List(); + string filter = MakeFilter(); + object value = _items.Find(filter); + while(value != null) + { + if (values.Count < maxResults) + { + ItemType wrapped = Mapping.WrapOrDefault(value); + if (wrapped != null) + { + values.Add(wrapped); + } + } + else + { + ComRelease.Release(value); + } + value = _items.FindNext(); + } + return values; + } + + public ItemType SearchOne() + { + object value = _items.Find(MakeFilter()); + if (value == null) + return default(ItemType); + return Mapping.Wrap(value); + } + + private string MakeFilter() + { + string filter = "@SQL="; + + bool first = true; + foreach(SearchTerm term in terms) + { + if (first) + first = false; + else + filter += " AND "; + filter += term.MakeFilter(); + } + Logger.Instance.Trace(this, "Filter: {0}", filter); + return filter; + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StorageItemWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StorageItemWrapper.cs new file mode 100644 index 0000000..adea510 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StorageItemWrapper.cs @@ -0,0 +1,97 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Utils; +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs.OutlookWrappers +{ + public class StorageItemWrapper : OutlookWrapper, IStorageItem + { + public StorageItemWrapper(StorageItem item) + : + base(item) + { + } + + protected override PropertyAccessor GetPropertyAccessor() + { + return _item.PropertyAccessor; + } + + public override string ToString() { return "StorageItem"; } + + #region Properties + + public string Body + { + get { return _item.Body; } + set { _item.Body = value; } + } + + public string Subject + { + get { return _item.Subject; } + set { _item.Subject = value; } + } + + public IStore Store { get { return StoreWrapper.Wrap(_item.Parent?.Store); } } + // TODO: release needed + public string StoreId { get { return _item.Parent?.Store?.StoreID; } } + public string StoreDisplayName { get { return _item.Parent?.Store?.DisplayName; } } + + #endregion + + #region Methods + + public IUserProperty GetUserProperty(string name, bool create = false) + { + return UserPropertyWrapper.Get(_item.UserProperties, name, create); + } + + public void Delete() { _item.Delete(); } + public void Save() { _item.Save(); } + + #endregion + + public IFolder Parent + { + get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); } + } + public string ParentEntryId + { + get + { + Folder parent = _item.Parent; + try + { + return parent?.EntryID; + } + finally + { + ComRelease.Release(parent); + } + } + } + + public string EntryId { get { return _item.EntryID; } } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StoreWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StoreWrapper.cs new file mode 100644 index 0000000..a4270f8 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StoreWrapper.cs @@ -0,0 +1,69 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Office.Interop.Outlook; +using Acacia.Utils; + +namespace Acacia.Stubs.OutlookWrappers +{ + public class StoreWrapper : DisposableWrapper, IStore + { + public static IStore Wrap(Store store) + { + return store == null ? null : new StoreWrapper(store); + } + + private Store _store; + + private StoreWrapper(Store store) + { + this._store = store; + } + + protected override void DoRelease() + { + ComRelease.Release(_store); + _store = null; + } + + public IFolder GetRootFolder() + { + return new FolderWrapper((Folder)_store.GetRootFolder()); + } + + public IItem GetItemFromID(string id) + { + NameSpace nmspace = _store.Session; + try + { + object o = nmspace.GetItemFromID(id); + return Mapping.Wrap(o); + } + finally + { + ComRelease.Release(nmspace); + } + } + + public string DisplayName { get { return _store.DisplayName; } } + public string StoreID { get { return _store.StoreID; } } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/TaskItemWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/TaskItemWrapper.cs new file mode 100644 index 0000000..bb16a93 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/TaskItemWrapper.cs @@ -0,0 +1,97 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Utils; +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Stubs.OutlookWrappers +{ + public class TaskItemWrapper : OutlookWrapper, ITaskItem + { + internal TaskItemWrapper(TaskItem item) + : + base(item) + { + } + + protected override PropertyAccessor GetPropertyAccessor() + { + return _item.PropertyAccessor; + } + + public override string ToString() { return "Task: " + Subject; } + + #region Properties + + public string Body + { + get { return _item.Body; } + set { _item.Body = value; } + } + + public string Subject + { + get { return _item.Subject; } + set { throw new NotSupportedException(); } + } + + public IStore Store { get { return StoreWrapper.Wrap(_item.Parent?.Store); } } + // TODO: release needed + public string StoreId { get { return _item.Parent?.Store?.StoreID; } } + public string StoreDisplayName { get { return _item.Parent?.Store?.DisplayName; } } + + #endregion + + #region Methods + + public IUserProperty GetUserProperty(string name, bool create = false) + { + throw new NotSupportedException(); + } + + public void Delete() { _item.Delete(); } + public void Save() { _item.Save(); } + + #endregion + + public IFolder Parent + { + get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); } + } + public string ParentEntryId + { + get + { + Folder parent = _item.Parent; + try + { + return parent?.EntryID; + } + finally + { + ComRelease.Release(parent); + } + } + } + + public string EntryId { get { return _item.EntryID; } } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/UserPropertyWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/UserPropertyWrapper.cs new file mode 100644 index 0000000..ed23ba2 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/UserPropertyWrapper.cs @@ -0,0 +1,76 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Office.Interop.Outlook; + +namespace Acacia.Stubs.OutlookWrappers +{ + class UserPropertyWrapper : IUserProperty + { + private readonly UserProperty _prop; + + private UserPropertyWrapper(UserProperty prop) + { + this._prop = prop; + } + + #region IUserProperty implementation + + public PropType Value + { + get + { + if (typeof(PropType).IsEnum) + return typeof(PropType).GetEnumValues().GetValue(_prop.Value); + return _prop.Value; + } + set + { + if (typeof(PropType).IsEnum) + { + int i = Array.FindIndex(typeof(PropType).GetEnumNames(), n => n.Equals(value.ToString())); + _prop.Value = typeof(PropType).GetEnumValues().GetValue(i); + } + else + _prop.Value = value; + } + } + + #endregion + + #region Helpers + + internal static IUserProperty Get(UserProperties userProperties, string name, bool create) + { + UserProperty prop = userProperties.Find(name, true); + if (prop == null) + { + if (!create) + return null; + prop = userProperties.Add(name, Mapping.OutlookPropertyType()); + } + + return new UserPropertyWrapper(prop); + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.Designer.cs new file mode 100644 index 0000000..189d58e --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.Designer.cs @@ -0,0 +1,286 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#pragma warning disable 414 +namespace Acacia { + + + /// + [Microsoft.VisualStudio.Tools.Applications.Runtime.StartupObjectAttribute(0)] + [global::System.Security.Permissions.PermissionSetAttribute(global::System.Security.Permissions.SecurityAction.Demand, Name="FullTrust")] + public sealed partial class ThisAddIn : Microsoft.Office.Tools.Outlook.OutlookAddInBase { + + internal Microsoft.Office.Tools.CustomTaskPaneCollection CustomTaskPanes; + + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "14.0.0.0")] + private global::System.Object missing = global::System.Type.Missing; + + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "14.0.0.0")] + internal Microsoft.Office.Interop.Outlook.Application Application; + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)] + public ThisAddIn(global::Microsoft.Office.Tools.Outlook.Factory factory, global::System.IServiceProvider serviceProvider) : + base(factory, serviceProvider, "AddIn", "ThisAddIn") { + Globals.Factory = factory; + } + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "14.0.0.0")] + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)] + protected override void Initialize() { + base.Initialize(); + this.Application = this.GetHostItem(typeof(Microsoft.Office.Interop.Outlook.Application), "Application"); + Globals.ThisAddIn = this; + global::System.Windows.Forms.Application.EnableVisualStyles(); + this.InitializeCachedData(); + this.InitializeControls(); + this.InitializeComponents(); + this.InitializeData(); + } + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "14.0.0.0")] + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)] + protected override void FinishInitialization() { + this.InternalStartup(); + this.OnStartup(); + } + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "14.0.0.0")] + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)] + protected override void InitializeDataBindings() { + this.BeginInitialization(); + this.BindToData(); + this.EndInitialization(); + } + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "14.0.0.0")] + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)] + private void InitializeCachedData() { + if ((this.DataHost == null)) { + return; + } + if (this.DataHost.IsCacheInitialized) { + this.DataHost.FillCachedData(this); + } + } + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "14.0.0.0")] + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)] + private void InitializeData() { + } + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "14.0.0.0")] + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)] + private void BindToData() { + } + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + private void StartCaching(string MemberName) { + this.DataHost.StartCaching(this, MemberName); + } + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + private void StopCaching(string MemberName) { + this.DataHost.StopCaching(this, MemberName); + } + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + private bool IsCached(string MemberName) { + return this.DataHost.IsCached(this, MemberName); + } + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "14.0.0.0")] + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)] + private void BeginInitialization() { + this.BeginInit(); + this.CustomTaskPanes.BeginInit(); + } + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "14.0.0.0")] + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)] + private void EndInitialization() { + this.CustomTaskPanes.EndInit(); + this.EndInit(); + } + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "14.0.0.0")] + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)] + private void InitializeControls() { + this.CustomTaskPanes = Globals.Factory.CreateCustomTaskPaneCollection(null, null, "CustomTaskPanes", "CustomTaskPanes", this); + } + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "14.0.0.0")] + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)] + private void InitializeComponents() { + } + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + private bool NeedsFill(string MemberName) { + return this.DataHost.NeedsFill(this, MemberName); + } + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "14.0.0.0")] + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)] + protected override void OnShutdown() { + this.CustomTaskPanes.Dispose(); + base.OnShutdown(); + } + } + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "14.0.0.0")] + internal sealed partial class Globals { + + /// + private Globals() { + } + + private static ThisAddIn _ThisAddIn; + + private static global::Microsoft.Office.Tools.Outlook.Factory _factory; + + private static ThisRibbonCollection _ThisRibbonCollection; + + private static ThisFormRegionCollection _ThisFormRegionCollection; + + internal static ThisAddIn ThisAddIn { + get { + return _ThisAddIn; + } + set { + if ((_ThisAddIn == null)) { + _ThisAddIn = value; + } + else { + throw new System.NotSupportedException(); + } + } + } + + internal static global::Microsoft.Office.Tools.Outlook.Factory Factory { + get { + return _factory; + } + set { + if ((_factory == null)) { + _factory = value; + } + else { + throw new System.NotSupportedException(); + } + } + } + + internal static ThisRibbonCollection Ribbons { + get { + if ((_ThisRibbonCollection == null)) { + _ThisRibbonCollection = new ThisRibbonCollection(_factory.GetRibbonFactory()); + } + return _ThisRibbonCollection; + } + } + + internal static ThisFormRegionCollection FormRegions { + get { + if ((_ThisFormRegionCollection == null)) { + _ThisFormRegionCollection = new ThisFormRegionCollection(Globals.ThisAddIn.GetFormRegions()); + } + return _ThisFormRegionCollection; + } + } + } + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "14.0.0.0")] + internal sealed partial class ThisRibbonCollection : Microsoft.Office.Tools.Ribbon.RibbonCollectionBase { + + /// + internal ThisRibbonCollection(global::Microsoft.Office.Tools.Ribbon.RibbonFactory factory) : + base(factory) { + } + + internal ThisRibbonCollection this[Microsoft.Office.Interop.Outlook.Inspector inspector] { + get { + return this.GetRibbonContextCollection(inspector); + } + } + + internal ThisRibbonCollection this[Microsoft.Office.Interop.Outlook.Explorer explorer] { + get { + return this.GetRibbonContextCollection(explorer); + } + } + } + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + internal sealed partial class ThisFormRegionCollection : Microsoft.Office.Tools.Outlook.FormRegionCollectionBase { + + /// + public ThisFormRegionCollection(System.Collections.Generic.IList list) : + base(list) { + } + + internal WindowFormRegionCollection this[Microsoft.Office.Interop.Outlook.Explorer explorer] { + get { + return ((WindowFormRegionCollection)(Globals.ThisAddIn.GetFormRegions(explorer, typeof(WindowFormRegionCollection)))); + } + } + + internal WindowFormRegionCollection this[Microsoft.Office.Interop.Outlook.Inspector inspector] { + get { + return ((WindowFormRegionCollection)(Globals.ThisAddIn.GetFormRegions(inspector, typeof(WindowFormRegionCollection)))); + } + } + } + + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + internal sealed partial class WindowFormRegionCollection : Microsoft.Office.Tools.Outlook.FormRegionCollectionBase { + + /// + public WindowFormRegionCollection(System.Collections.Generic.IList list) : + base(list) { + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.Designer.xml b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.Designer.xml new file mode 100644 index 0000000..37aa026 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.Designer.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.cs new file mode 100644 index 0000000..9006c34 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.cs @@ -0,0 +1,236 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; +using Outlook = Microsoft.Office.Interop.Outlook; +using Office = Microsoft.Office.Core; +using Acacia.Features; +using System.Threading; +using System.Windows.Forms; +using Acacia.Utils; +using Acacia.UI; +using Acacia.ZPush; +using System.Globalization; +using Acacia.UI.Outlook; + +namespace Acacia +{ + public partial class ThisAddIn + { + + public static ThisAddIn Instance + { + get; + private set; + } + + private Control _dispatcher; + + public void InvokeUI(Action action) + { + // [ZP-992] For some reason using the dispatcher causes a deadlock + // since switching to UI-chunked tasks. Running directly works. + action(); + } + + #region Features + + /// + /// All started features + /// + public List Features + { + get; + private set; + } + + #endregion + + public ZPushWatcher Watcher + { + get; + private set; + } + + public FeatureType GetFeature() + where FeatureType : Feature + { + foreach(Feature feature in Features) + { + if (feature is FeatureType) + return (FeatureType)feature; + } + return default(FeatureType); + } + + #region Startup / Shutdown + + private void ThisAddIn_Startup(object sender, System.EventArgs args) + { + try + { + Acacia.Features.DebugSupport.Statistics.StartupTime.Start(); + Logger.Instance.Info(this, "Starting version {0}: {1} @ {2}. Outlook version: {3}. Options: '{4}'", + LibUtils.Version, BuildVersions.REVISION, LibUtils.BuildTime, + Application.Version, + DebugOptions.GetOptions(null)); + Logger.Instance.Initialize(); + + // Check if we're enabled + if (!GlobalOptions.INSTANCE.Enabled) + { + Logger.Instance.Fatal(this, "Disabled, stopping"); + return; + } + + Instance = this; + + // Set the culture info from Outlook's language setting rather than the OS setting + int lcid = Application.LanguageSettings.get_LanguageID(Office.MsoAppLanguageID.msoLanguageIDUI); + Thread.CurrentThread.CurrentUICulture = new CultureInfo(lcid); + + // Create a dispatcher + _dispatcher = new Control(); + _dispatcher.CreateControl(); + + // The synchronization context is needed to allow background tasks to jump back to the UI thread. + // It's null in older versions of .Net, this fixes that + if (SynchronizationContext.Current == null) + { + SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext()); + } + + // Create the watcher + Watcher = new ZPushWatcher(Application); + OutlookUI.Watcher = Watcher; + + // Allow to features to register whatever they need + Features = new List(); + foreach (Type featureType in Acacia.Features.Features.FEATURES) + { + if (Feature.IsEnabled(featureType)) + { + Logger.Instance.Info(featureType, "Starting feature: '{0}'", GetFeatureTokens(featureType)); + Feature feature = (Feature)Activator.CreateInstance(featureType); + try + { + feature.Startup(); + Features.Add(feature); + Logger.Instance.Trace(featureType, "Started feature"); + } + catch(Exception e) + { + Logger.Instance.Error(featureType, "Exception in start-up: {0}", e); + } + } + else + { + Logger.Instance.Info(featureType, "Feature is disabled"); + } + } + + // Register for options page + Application.OptionsPagesAdd += App_OptionsPagesAdd; + + // Start watching events + if (DebugOptions.GetOption(null, DebugOptions.WATCHER_ENABLED)) + Watcher.Start(); + + // Done + Logger.Instance.Debug(this, "Startup done"); + Acacia.Features.DebugSupport.Statistics.StartupTime.Stop(); + } + catch (System.Exception e) + { + Logger.Instance.Fatal(this, "Startup exception: {0}", e); + } + } + + private string GetFeatureTokens(Type featureType) + { + return Feature.GetDebugTokens(featureType); + } + + private void App_OptionsPagesAdd(Microsoft.Office.Interop.Outlook.PropertyPages Pages) + { + try + { + Pages.Add(new SettingsPage(Features.ToArray()), Properties.Resources.ThisAddIn_Title); + } + catch(System.Exception e) + { + Logger.Instance.Error(this, "Exception in App_OptionsPagesAdd: {0}", e); + } + } + + private void ThisAddIn_Shutdown(object sender, System.EventArgs e) + { + // Note: Outlook no longer raises this event. If you have code that + // must run when Outlook shuts down, see http://go.microsoft.com/fwlink/?LinkId=506785 + } + + #endregion + + #region Ribbons + + private OutlookUI _outlookUI; + public OutlookUI OutlookUI + { + get + { + if (_outlookUI == null) + { + if (DebugOptions.GetOption(null, DebugOptions.ENABLED) && + DebugOptions.GetOption(null, DebugOptions.OUTLOOK_UI)) + { + _outlookUI = new OutlookUI(); + Logger.Instance.Trace(this, "OutlookUI created"); + } + else + { + Logger.Instance.Trace(this, "OutlookUI is disabled: '{0}'", DebugOptions.GetOptions(null)); + } + } + return _outlookUI; + } + } + + protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject() + { + return OutlookUI; + } + + #endregion + + #region VSTO generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InternalStartup() + { + this.Startup += new System.EventHandler(ThisAddIn_Startup); + this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown); + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ErrorUtil.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ErrorUtil.cs new file mode 100644 index 0000000..542cbb4 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ErrorUtil.cs @@ -0,0 +1,58 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.UI +{ + public static class ErrorUtil + { + // TODO: remove this + public static void HandleError(object context, string logMessage, Exception e, + string titleId, string messageId, params object[] messageParams) + { + Logger.Instance.Error(context, "{0}: {1}", logMessage, e); + string msg = StringUtil.GetResourceString(messageId); + if (messageParams.Length > 0) + msg = string.Format(msg, messageParams); + MessageBox.Show(msg, + StringUtil.GetResourceString(titleId), + MessageBoxButtons.OK, + MessageBoxIcon.Error + ); + + } + + public static void HandleErrorNew(object context, string logMessage, Exception e, + string title, string message, params object[] messageParams) + { + if (messageParams.Length > 0) + { + logMessage = string.Format(logMessage, messageParams); + message = string.Format(message, messageParams); + } + Logger.Instance.Error(context, "{0}: {1}", logMessage, e); + MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Error); + + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/FeatureSettings.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/FeatureSettings.cs new file mode 100644 index 0000000..db0714c --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/FeatureSettings.cs @@ -0,0 +1,58 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Features; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.UI +{ + public class FeatureSettings : UserControl + { + public SettingsPage Settings + { + get; + internal set; + } + + private bool _dirty; + + public bool Dirty + { + get { return _dirty; } + protected set + { + _dirty = value; + Settings?.SetFeatureDirty(this, value); + } + } + + // Should be abstract, but then the designer fails + virtual public Feature Feature + { + get { throw new NotSupportedException(); } + } + + virtual public void Apply() + { + + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.Designer.cs new file mode 100644 index 0000000..e341a36 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.Designer.cs @@ -0,0 +1,36 @@ +namespace Acacia.UI +{ + partial class GABLookupControl + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.cs new file mode 100644 index 0000000..17dc99a --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.cs @@ -0,0 +1,270 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using Acacia.ZPush; +using Acacia.Features.GAB; +using Acacia.Stubs; +using System.Collections; + +namespace Acacia.UI +{ + public partial class GABLookupControl : ComboBox + { + public GABLookupControl() : this(null) + { + } + + public GABLookupControl(GABHandler gab) + { + InitializeComponent(); + DropDownStyle = ComboBoxStyle.DropDown; + DisplayMember = "DisplayName"; + this.GAB = gab; + } + + #region Properties and events + + #region SelectedUser + + public class SelectedUserEventArgs : EventArgs + { + public readonly GABUser SelectedUser; + public readonly bool IsChosen; + + public SelectedUserEventArgs(GABUser selectedUser, bool isChosen) + { + this.SelectedUser = selectedUser; + this.IsChosen = isChosen; + } + } + + public delegate void SelectedUserEventHandler(object source, SelectedUserEventArgs e); + + [Category("Behavior")] + public event SelectedUserEventHandler SelectedUserChanged; + + public GABUser SelectedUser + { + get + { + if (SelectedValue == null) + return new GABUser(Text, Text); + else + return (GABUser)SelectedValue; + } + set + { + if (value == null) + { + SelectedIndex = -1; + Text = ""; + } + else + { + + } + } + } + + private void SetSelectedUser(GABUser user, bool isChosen) + { + if (SelectedUser != user || isChosen) + { + System.Diagnostics.Trace.WriteLine(string.Format("SELECT: {0} -> {1} : {2}", SelectedUser, user, isChosen)); + if (isChosen) + SelectedUser = user; + if (SelectedUserChanged != null) + SelectedUserChanged(this, new SelectedUserEventArgs(user, isChosen)); + } + } + + #endregion + + #region GAB + + private GABHandler _gab; + + /// + /// The GAB. This must be set to allow lookups + /// + public GABHandler GAB + { + get { return _gab; } + set { _gab = value; } + } + + #endregion + + #endregion + + protected override void OnTextChanged(EventArgs e) + { + LookupUsers(); + SelectCurrentUser(false); + } + + private void SelectCurrentUser(bool isChosen) + { + GABUser user = null; + // Select whatever is currently in the text box as a user + if (DataSource != null) + { + // Find if there's a user matching + user = ((List)DataSource).FirstOrDefault((u) => u.DisplayName == Text); + } + if (user == null && Text.Length > 0) + { + // Make a new one + user = new GABUser(Text, Text); + } + SetSelectedUser(user, isChosen); + } + + private bool _needUpdate; + + protected override void OnTextUpdate(EventArgs e) + { + _needUpdate = true; + } + + protected override void OnSelectedIndexChanged(EventArgs e) + { + base.OnSelectedIndexChanged(e); + SetSelectedUser((GABUser)SelectedItem, true); + } + + protected override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + if (e.KeyCode == Keys.Enter) + { + SelectCurrentUser(true); + } + else + { + SetSelectedUser(null, false); + } + } + + protected override void OnDataSourceChanged(EventArgs e) + { + // Suppress to prevent automatic selection + } + + private string _lastText; + + private void LookupUsers() + { + // Cannot lookup if there is no GAB + if (_gab == null) + return; + + if (!_needUpdate) + return; + _needUpdate = false; + + string text = this.Text; + // Only search if there is text + if (text.Length == 0) + { + DataSource = null; + DroppedDown = false; + _lastText = ""; + return; + } + + // Only search if the text actually changed + if (_lastText != text) + { + List users = Lookup(text, 5); + + // Sort the users if we have them + users.Sort(); + + _lastText = text; + + // Setting the datasource will trigger a select if there is a match + BeginUpdate(); + DataSource = users; + SetItemsCore(users); + DroppedDown = true; + Cursor.Current = Cursors.Default; + Text = _lastText; + SelectionLength = 0; + SelectionStart = _lastText.Length; + EndUpdate(); + } + } + + #region Lookup helpers + // TODO: these probably belong in GAB + + public List Lookup(string text, int max) + { + // Begin GAB lookup, search on full name or username + ISearch search = _gab.Contacts.Search(); + ISearchOperator oper = search.AddOperator(SearchOperator.Or); + oper.AddField("urn:schemas:contacts:cn").SetOperation(SearchOperation.Like, text + "%"); + oper.AddField("urn:schemas:contacts:customerid").SetOperation(SearchOperation.Like, text + "%"); + + // Fetch the results up to the limit. + // TODO: make limit a property + List users = new List(); + foreach (IContactItem result in search.Search(max)) + { + using (result) + { + users.Add(new GABUser(result.FullName, result.CustomerID)); + } + } + + return users; + } + + public GABUser LookupExact(string username) + { + if (_gab?.Contacts != null) + { + // Begin GAB lookup, search on full name or username + ISearch search = _gab.Contacts.Search(); + search.AddField("urn:schemas:contacts:customerid").SetOperation(SearchOperation.Equal, username); + + // Fetch the result, if any. + List users = new List(); + foreach (IContactItem result in search.Search(1)) + { + using (result) + { + return new GABUser(result.FullName, result.CustomerID); + } + } + } + + return new GABUser(username); + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/KopanoDialog.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/KopanoDialog.cs new file mode 100644 index 0000000..a2e3fbf --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/KopanoDialog.cs @@ -0,0 +1,33 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.UI +{ + public class KopanoDialog : Form + { + public KopanoDialog() + { + Icon = Properties.Resources.Kopano; + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/CommandElement.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/CommandElement.cs new file mode 100644 index 0000000..eb53650 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/CommandElement.cs @@ -0,0 +1,139 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Features; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Office = Microsoft.Office.Core; + +namespace Acacia.UI.Outlook +{ + abstract public class CommandElement + { + internal OutlookUI UI; + public readonly FeatureWithUI Owner; + public readonly string Id; + protected System.Action _callback; + internal readonly ZPushBehaviour ZPushBehaviour; + + public CheckCommandHandler CheckEnabled; + public CheckCommandHandler CheckVisible; + + public CommandElement(FeatureWithUI feature, string id, + System.Action callback, ZPushBehaviour zpushBehaviour) + { + this.Owner = feature; + this.Id = id; + this._callback = callback; + this.ZPushBehaviour = zpushBehaviour; + } + + virtual internal bool OnCheckEnabled(Office.IRibbonControl control) + { + if (CheckEnabled == null) + return true; + return CheckEnabled(this); + } + + virtual internal bool OnCheckVisible(Office.IRibbonControl control) + { + if (CheckVisible == null) + return true; + return CheckVisible(this); + } + + internal virtual void Clicked(Office.IRibbonControl control) + { + Logger.Instance.Trace(Owner, "Command {0}: Activated", Id); + _callback(); + Logger.Instance.Trace(Owner, "Command {0}: Handled", Id); + } + + private bool _isEnabled = true; + public bool IsEnabled + { + get + { + return _isEnabled; + } + + set + { + if (_isEnabled != value) + { + _isEnabled = value; + UI?.InvalidateCommand(this); + } + } + } + + private bool _isVisible = true; + public bool IsVisible + { + get + { + return _isVisible; + } + + set + { + if (_isVisible != value) + { + _isVisible = value; + UI?.InvalidateCommand(this); + } + } + } + + /// + /// Converts the element to an Xml string for inclusion in the Fluent UI. + /// Note that the polymorphism here is limited, as the callbacks must be in + /// the OutlookUI class. + /// + public string ToXml() + { + Dictionary attrs = new Dictionary + { + {"getImage", "getControlImage_" + XmlSuffix }, + {"onAction", "onCommandAction"}, + {"getLabel", "getControlLabel"}, + {"getScreentip", "getControlScreentip"}, + {"getSupertip", "getControlSupertip"}, + {"getEnabled", "getControlEnabled"}, + {"getVisible", "getControlVisible"} + }; + + // Override or add any additional attributes + Dictionary additional = XmlAttrs; + if (additional != null) + { + additional.ToList().ForEach(x => attrs[x.Key] = x.Value); + } + + // Serialize + string attrsString = string.Join(" ", attrs.Select(x => string.Format("{0}=\"{1}\"", x.Key, x.Value))); + string xml = string.Format("<{0} id=\"{1}\" {2}/>", XmlTag, Id, attrsString); + return xml; + } + + virtual protected string XmlTag { get { return "button"; } } + virtual protected string XmlSuffix { get { return "large"; } } + virtual protected Dictionary XmlAttrs { get { return null; } } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/MenuItem.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/MenuItem.cs new file mode 100644 index 0000000..94bc82a --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/MenuItem.cs @@ -0,0 +1,102 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Features; +using Acacia.Stubs; +using Acacia.Stubs.OutlookWrappers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Office = Microsoft.Office.Core; + +namespace Acacia.UI.Outlook +{ + abstract public class MenuItemBase : CommandElement + { + public readonly string MenuId; + + public MenuItemBase(FeatureWithContextMenu feature, string commandId, string menuId, System.Action callback, ZPushBehaviour zpushBehaviour) + : + base(feature, commandId, callback, zpushBehaviour) + { + this.MenuId = menuId; + } + } + + public class MenuItem : MenuItemBase + where ItemType : IBase + { + public delegate bool CheckMenuItemHandler(MenuItem menuItem, ItemType item); + new public CheckMenuItemHandler CheckEnabled; + new public CheckMenuItemHandler CheckVisible; + + new private readonly Action _callback; + + public MenuItem(FeatureWithContextMenu feature, string commandId, string menuId, Action callback, ZPushBehaviour zpushBehaviour) + : + base(feature, commandId, menuId, null, zpushBehaviour) + { + // TODO: remove callback from CommandElement + this._callback = callback; + } + + internal override bool OnCheckEnabled(Office.IRibbonControl control) + { + if (!base.OnCheckEnabled(control)) + return false; + + if (CheckEnabled != null || ZPushBehaviour == ZPushBehaviour.Disable) + using (ItemType item = Mapping.Wrap(control.Context)) + { + if (ZPushBehaviour == ZPushBehaviour.Disable && UI.ZPush.Accounts.GetAccount(item) == null) + return false; + if (CheckEnabled != null) + return CheckEnabled(this, item); + } + + return true; + } + + internal override bool OnCheckVisible(Office.IRibbonControl control) + { + if (!base.OnCheckVisible(control)) + return false; + + if (CheckVisible != null || ZPushBehaviour == ZPushBehaviour.Hide) + { + using (ItemType folder = Mapping.Wrap(control.Context)) + { + if (ZPushBehaviour == ZPushBehaviour.Hide && UI.ZPush.Accounts.GetAccount(folder) == null) + return false; + if (CheckVisible != null) + return CheckVisible(this, folder); + } + } + + return true; + } + + internal override void Clicked(Office.IRibbonControl control) + { + using (ItemType item = Mapping.Wrap(control.Context)) + { + _callback(item); + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookImageList.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookImageList.cs new file mode 100644 index 0000000..2347e02 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookImageList.cs @@ -0,0 +1,140 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Microsoft.Office.Core; +using stdole; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.UI.Outlook +{ + /// + /// An image list using Outlook images + /// + public class OutlookImageList + { + public ImageList Images { get; private set; } + + [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)] + public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count); + + private Bitmap GetBitmapFromHBitmap2(IntPtr nativeHBitmap) + { + + Bitmap bmp = Bitmap.FromHbitmap(nativeHBitmap); + if (Bitmap.GetPixelFormatSize(bmp.PixelFormat) < 32) + return bmp; + + // Special handling is required to convert a bitmap with alpha channel, FromHBitmap doesn't + // set the correct pixel format + Rectangle bmBounds = new Rectangle(0, 0, bmp.Width, bmp.Height); + BitmapData bmpData = bmp.LockBits(bmBounds, ImageLockMode.ReadOnly, bmp.PixelFormat); + Bitmap bmp2 = new Bitmap(bmpData.Width, bmpData.Height, PixelFormat.Format32bppArgb); + BitmapData bmpData2 = bmp2.LockBits(bmBounds, ImageLockMode.WriteOnly, bmp2.PixelFormat); + try + { + for (int y = 0; y < bmp.Height; ++y) + { + IntPtr target = bmpData2.Scan0 + bmpData2.Stride * y; + IntPtr source = bmpData.Scan0 + bmpData.Stride * y; + CopyMemory(target, source, (uint)Math.Abs(bmpData2.Stride)); + } + } + finally + { + bmp2.UnlockBits(bmpData2); + bmp.UnlockBits(bmpData); + } + return bmp2; + } + + private static Bitmap GetBitmapFromHBitmap(IntPtr nativeHBitmap) + { + Bitmap bmp = Bitmap.FromHbitmap(nativeHBitmap); + + if (Bitmap.GetPixelFormatSize(bmp.PixelFormat) < 32) + return bmp; + + BitmapData bmpData; + + if (IsAlphaBitmap(bmp, out bmpData)) + return GetlAlphaBitmapFromBitmapData(bmpData); + + return bmp; + } + + private static Bitmap GetlAlphaBitmapFromBitmapData(BitmapData bmpData) + { + return new Bitmap( + bmpData.Width, + bmpData.Height, + bmpData.Stride, + PixelFormat.Format32bppArgb, + bmpData.Scan0); + } + + private static bool IsAlphaBitmap(Bitmap bmp, out BitmapData bmpData) + { + Rectangle bmBounds = new Rectangle(0, 0, bmp.Width, bmp.Height); + + bmpData = bmp.LockBits(bmBounds, ImageLockMode.ReadOnly, bmp.PixelFormat); + + try + { + for (int y = 0; y <= bmpData.Height - 1; y++) + { + for (int x = 0; x <= bmpData.Width - 1; x++) + { + Color pixelColor = Color.FromArgb( + Marshal.ReadInt32(bmpData.Scan0, (bmpData.Stride * y) + (4 * x))); + + if (pixelColor.A > 0 & pixelColor.A < 255) + { + return true; + } + } + } + } + finally + { + bmp.UnlockBits(bmpData); + } + + return false; + } + public OutlookImageList(params string[] icons) + { + Images = new ImageList(); + Images.ColorDepth = ColorDepth.Depth32Bit; + Images.ImageSize = new Size(16, 16); + + CommandBars cmdBars = ThisAddIn.Instance.Application.ActiveWindow().CommandBars; + foreach (string id in icons) + { + IPictureDisp pict = cmdBars.GetImageMso(id, Images.ImageSize.Width, Images.ImageSize.Height); + var img = GetBitmapFromHBitmap2(new IntPtr(pict.Handle)); + Images.Images.Add(img); + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookUI.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookUI.cs new file mode 100644 index 0000000..f889750 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/OutlookUI.cs @@ -0,0 +1,337 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using Acacia.Features.ReplyFlags; +using Office = Microsoft.Office.Core; +using Acacia.Features; +using Acacia.ZPush; +using Acacia.Stubs; +using Acacia.Stubs.OutlookWrappers; + +namespace Acacia.UI.Outlook +{ + [System.Runtime.InteropServices.ComVisible(true)] + public class OutlookUI : Office.IRibbonExtensibility + { + private Office.IRibbonUI _officeUI; + + public OutlookUI() + { + } + + #region ZPush handling + + public ZPushWatcher ZPush { get; private set; } + private bool? _wasZPush; + + + public ZPushWatcher Watcher + { + get { return ZPush; } + set + { + if (ZPush != value) + { + ZPush = value; + if (ZPush != null) + ZPush.ZPushAccountChange += Zpush_ZPushAccountChange; + } + } + } + + private void Zpush_ZPushAccountChange(ZPushAccount account) + { + bool newZPush = account != null; + if (newZPush != _wasZPush) + { + _wasZPush = newZPush; + foreach(CommandElement command in _commandIds.Values) + { + // Menu items are handled on demand, as they may not be in the current folder + if (!(command is MenuItemBase)) + { + switch (command.ZPushBehaviour) + { + case ZPushBehaviour.Disable: + command.IsEnabled = newZPush; + break; + case ZPushBehaviour.Hide: + command.IsVisible = newZPush; + break; + } + } + } + } + } + + #endregion + + #region Commands + + private readonly Dictionary _commandIds = new Dictionary(); + private readonly List _buttonsOrdered = new List(); + + private class ContextMenu + { + public readonly string Id; + public readonly List Items = new List(); + + public ContextMenu(string id) + { + this.Id = id; + } + } + private readonly Dictionary _menus = new Dictionary(); + + public CommandType Register(CommandType command) + where CommandType : CommandElement + { + Logger.Instance.Debug(command.Owner, "{0}: Registered", command); + command.UI = this; + + _commandIds.Add(command.Id, command); + + MenuItemBase menuItem = command as MenuItemBase; + if (menuItem != null) + { + ContextMenu menu; + if (!_menus.TryGetValue(menuItem.MenuId, out menu)) + { + menu = new ContextMenu(menuItem.MenuId); + _menus.Add(menuItem.MenuId, menu); + } + menu.Items.Add(menuItem); + } + else + { + _buttonsOrdered.Add(command as RibbonButton); + } + return command; + } + + #endregion + + + #region Infrastructure + + /// + /// This is hideous, but the ribbon XML doesn't allow much in the way of configuration at runtime. + /// The only thing that changes between buttons is the id, images and strings are loaded from the + /// resources based on that. + /// + private const string CUSTOM_UI_XML = +@" + + {0} + {1} + +"; + + private const string RIBBON_XML = +@" + + + + {1} + + + + +"; + + public void onCommandActionToggle(Office.IRibbonControl control, bool isPressed) + { + onCommandAction(control); + + if (getControlPressed(control) != isPressed) + { + // Press status hasn't changed, but Outlook will think it has, force update + _officeUI?.InvalidateControl(control.Id); + } + } + + public void onCommandAction(Office.IRibbonControl control) + { + try + { + CommandElement command; + if (_commandIds.TryGetValue(control.Id, out command)) + { + command.Clicked(control); + } + } + catch(System.Exception e) + { + Logger.Instance.Error(control.Id, "Exception: {0}", e); + } + } + + public string GetCustomUI(string ribbonID) + { + string ribbon = ""; + StringBuilder menus = new StringBuilder(); + + if (_buttonsOrdered.Count > 0) + { + StringBuilder buttons = new StringBuilder(); + // First add all the large buttons + foreach (RibbonButton b in _buttonsOrdered) + if (b.Large) + buttons.AppendLine(b.ToXml()); + + // And the small buttons + foreach (RibbonButton b in _buttonsOrdered) + if (!b.Large) + buttons.AppendLine(b.ToXml()); + + ribbon = string.Format(RIBBON_XML, Properties.Resources.Ribbon_Title, buttons); + } + + // Context menus + if (_menus.Count != 0) + { + menus.Append(""); + + foreach(ContextMenu menu in _menus.Values) + { + menus.Append(string.Format("", menu.Id)); + + foreach(CommandElement b in menu.Items) + { + menus.Append(b.ToXml()); + } + + menus.Append(""); + } + + menus.Append(""); + } + + string xml = string.Format(CUSTOM_UI_XML, ribbon, menus); + return xml; + } + + public void Ribbon_Load(Office.IRibbonUI ribbonUI) + { + this._officeUI = ribbonUI; + } + + public Bitmap getControlImage_large(Office.IRibbonControl control) + { + return GetControlImage(control, ""); + } + + public Bitmap getControlImage_normal(Office.IRibbonControl control) + { + return GetControlImage(control, "_Small"); + } + + private Bitmap GetControlImage(Office.IRibbonControl control, string suffix) + { + string id = "Ribbon_" + control.Id + suffix; + object o = Properties.Resources.ResourceManager.GetObject(id); + if (o == null) + throw new InvalidDataException("Missing image resource " + id); + return o as Bitmap; + } + + public string getControlLabel(Office.IRibbonControl control) + { + return GetString(control, "Label"); + } + + public string getControlScreentip(Office.IRibbonControl control) + { + return GetString(control, "Screentip"); + } + + public string getControlSupertip(Office.IRibbonControl control) + { + return GetString(control, "Supertip"); + } + + private string GetString(Office.IRibbonControl control, string suffix) + { + string id = "Ribbon_" + control.Id + "_" + suffix; + string s = Properties.Resources.ResourceManager.GetString(id); + if (s == null) + throw new InvalidDataException("Missing string resource " + id); + return s; + } + + #endregion + + + #region Command state + + internal void InvalidateCommand(CommandElement command) + { + _officeUI?.InvalidateControl(command.Id); + } + + public bool getControlEnabled(Office.IRibbonControl control) + { + CommandElement command; + if (_commandIds.TryGetValue(control.Id, out command)) + { + if (!command.IsEnabled) + return false; + + return command.OnCheckEnabled(control); + } + return true; + } + + public bool getControlPressed(Office.IRibbonControl control) + { + CommandElement command; + if (_commandIds.TryGetValue(control.Id, out command)) + { + return (command as RibbonToggleButton)?.IsPressed ?? false; + } + return false; + } + + public bool getControlVisible(Office.IRibbonControl control) + { + CommandElement command; + if (_commandIds.TryGetValue(control.Id, out command)) + { + if (!command.IsVisible) + return false; + + return command.OnCheckVisible(control); + } + return true; + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/RibbonButton.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/RibbonButton.cs new file mode 100644 index 0000000..b66586c --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/RibbonButton.cs @@ -0,0 +1,50 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Acacia.Features; + +namespace Acacia.UI.Outlook +{ + public class RibbonButton : CommandElement + { + public readonly bool Large; + + public RibbonButton(FeatureWithRibbon feature, string id, bool large, Action callback, + ZPushBehaviour zpushBehaviour = ZPushBehaviour.None) + : + base(feature, id, callback, zpushBehaviour) + { + this.Large = large; + } + + protected override string XmlSuffix { get { return Large ? "large" : "normal"; } } + protected override Dictionary XmlAttrs + { + get + { + return new Dictionary + { + {"size", XmlSuffix } + }; + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/RibbonToggleButton.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/RibbonToggleButton.cs new file mode 100644 index 0000000..e8eefa4 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/RibbonToggleButton.cs @@ -0,0 +1,66 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Acacia.Features; + +namespace Acacia.UI.Outlook +{ + public class RibbonToggleButton : RibbonButton + { + public RibbonToggleButton(FeatureWithRibbon feature, string id, bool large, Action callback, + ZPushBehaviour zpushBehaviour = ZPushBehaviour.None) + : + base(feature, id, large, callback, zpushBehaviour) + { + } + + + private bool _isPressed = false; + public bool IsPressed + { + get + { + return _isPressed; + } + + set + { + if (_isPressed != value) + { + _isPressed = value; + UI?.InvalidateCommand(this); + } + } + } + + protected override string XmlTag { get { return "toggleButton"; } } + protected override Dictionary XmlAttrs + { + get + { + Dictionary attrs = base.XmlAttrs; + attrs["onAction"] = "onCommandActionToggle"; + attrs["getPressed"] = "getControlPressed"; + return attrs; + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/Types.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/Types.cs new file mode 100644 index 0000000..ab7e501 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/Outlook/Types.cs @@ -0,0 +1,34 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.UI.Outlook +{ + + public delegate bool CheckCommandHandler(CommandElement command); + + public enum ZPushBehaviour + { + None, + Disable, + Hide + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ProgressDialog.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ProgressDialog.Designer.cs new file mode 100644 index 0000000..44ee405 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ProgressDialog.Designer.cs @@ -0,0 +1,97 @@ +namespace Acacia.UI +{ + partial class ProgressDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ProgressDialog)); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.labelMessage = new System.Windows.Forms.Label(); + this.progressBar1 = new System.Windows.Forms.ProgressBar(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // tableLayoutPanel1 + // + resources.ApplyResources(this.tableLayoutPanel1, "tableLayoutPanel1"); + this.tableLayoutPanel1.Controls.Add(this.labelMessage, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.progressBar1, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.buttonCancel, 1, 2); + this.tableLayoutPanel1.GrowStyle = System.Windows.Forms.TableLayoutPanelGrowStyle.FixedSize; + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + // + // labelMessage + // + resources.ApplyResources(this.labelMessage, "labelMessage"); + this.tableLayoutPanel1.SetColumnSpan(this.labelMessage, 3); + this.labelMessage.Name = "labelMessage"; + // + // progressBar1 + // + resources.ApplyResources(this.progressBar1, "progressBar1"); + this.tableLayoutPanel1.SetColumnSpan(this.progressBar1, 3); + this.progressBar1.MarqueeAnimationSpeed = 50; + this.progressBar1.Name = "progressBar1"; + this.progressBar1.Style = System.Windows.Forms.ProgressBarStyle.Marquee; + // + // buttonCancel + // + resources.ApplyResources(this.buttonCancel, "buttonCancel"); + this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // ProgressDialog + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.buttonCancel; + this.Controls.Add(this.tableLayoutPanel1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ProgressDialog"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ProgressDialog_FormClosing); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label labelMessage; + private System.Windows.Forms.ProgressBar progressBar1; + private System.Windows.Forms.Button buttonCancel; + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ProgressDialog.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ProgressDialog.cs new file mode 100644 index 0000000..e65be5f --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ProgressDialog.cs @@ -0,0 +1,115 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Utils; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.UI +{ + public partial class ProgressDialog : Form + { + private readonly CancellationTokenSource cancel; + private Task task; + private bool _isComplete; + + public ProgressDialog() + { + InitializeComponent(); + + cancel = new CancellationTokenSource(); + } + + public static ResultType Execute(string resourcePrefix, Func action) + { + Logger.Instance.Info(typeof(ProgressDialog), "Opening"); + // Determine the UI context, creating a new one if required + if (SynchronizationContext.Current == null) + SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext()); + var context = TaskScheduler.FromCurrentSynchronizationContext(); + + // Create the dialog, so it is available for the task + ProgressDialog dlg = new ProgressDialog(); + // Set the strings + dlg.Text = StringUtil.GetResourceString(resourcePrefix + "_Title"); + dlg.labelMessage.Text = StringUtil.GetResourceString(resourcePrefix + "_Label"); + + // Start the task + Exception caught = null; + Task task = Task.Factory.StartNew( + () => + { + try + { + return action(dlg.cancel.Token); + } + catch (Exception e) + { + caught = e; + return default(ResultType); + } + }, + dlg.cancel.Token); + dlg.task = task; + // And close the dialog when done + task.ContinueWith(_ => { dlg._isComplete = true; dlg.DialogResult = DialogResult.OK; }, context); + + // Show the dialog + if (dlg.ShowDialog() != DialogResult.OK) + return default(ResultType); + + // Rethrow any exception. + // The framework already handles this, but that causes breaks into the debugger + if (caught != null) + throw caught; + + // Result the result + return task.Result; + } + + private void ProgressDialog_FormClosing(object sender, FormClosingEventArgs e) + { + if (!_isComplete) + { + // Cancel the close event + e.Cancel = true; + + // And cancel the current action, that will close the form + DoCancel(); + } + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + DoCancel(); + } + + private void DoCancel() + { + cancel.Cancel(); + task.ContinueWith(_ => { _isComplete = true; DialogResult = DialogResult.Cancel; }); + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ProgressDialog.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ProgressDialog.resx new file mode 100644 index 0000000..079accd --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/ProgressDialog.resx @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Top, Bottom, Left, Right + + + + True + + + GrowAndShrink + + + 3 + + + Top, Bottom, Left, Right + + + True + + + + 3, 8 + + + 3, 8, 3, 8 + + + 395, 13 + + + 0 + + + labelMessage: SET FROM CODE, NO NEED TO TRANSLATE + + + TopCenter + + + labelMessage + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel1 + + + 0 + + + Top, Bottom, Left, Right + + + 3, 32 + + + 395, 23 + + + 1 + + + progressBar1 + + + System.Windows.Forms.ProgressBar, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel1 + + + 1 + + + True + + + 163, 69 + + + 3, 11, 3, 8 + + + 75, 23 + + + 2 + + + Cancel + + + buttonCancel + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel1 + + + 2 + + + 12, 12 + + + 3 + + + 401, 100 + + + 0 + + + tableLayoutPanel1 + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelMessage" Row="0" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="progressBar1" Row="1" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="buttonCancel" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="Percent,50,AutoSize,0,Percent,50" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0" /></TableLayoutSettings> + + + True + + + 6, 13 + + + True + + + GrowAndShrink + + + 425, 117 + + + CenterParent + + + ProgressDialog: SET FROM CODE, NO NEED TO TRANSLATE + + + ProgressDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsDialog.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsDialog.Designer.cs new file mode 100644 index 0000000..32c3a77 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsDialog.Designer.cs @@ -0,0 +1,96 @@ +namespace Acacia.UI +{ + partial class SettingsDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SettingsDialog)); + this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); + this.buttonApply = new System.Windows.Forms.Button(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonOK = new System.Windows.Forms.Button(); + this.flowLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // flowLayoutPanel1 + // + this.flowLayoutPanel1.Controls.Add(this.buttonApply); + this.flowLayoutPanel1.Controls.Add(this.buttonCancel); + this.flowLayoutPanel1.Controls.Add(this.buttonOK); + resources.ApplyResources(this.flowLayoutPanel1, "flowLayoutPanel1"); + this.flowLayoutPanel1.Name = "flowLayoutPanel1"; + // + // buttonApply + // + resources.ApplyResources(this.buttonApply, "buttonApply"); + this.buttonApply.Name = "buttonApply"; + this.buttonApply.UseVisualStyleBackColor = true; + this.buttonApply.Click += new System.EventHandler(this.buttonApply_Click); + // + // buttonCancel + // + resources.ApplyResources(this.buttonCancel, "buttonCancel"); + this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + // + // buttonOK + // + resources.ApplyResources(this.buttonOK, "buttonOK"); + this.buttonOK.DialogResult = System.Windows.Forms.DialogResult.OK; + this.buttonOK.Name = "buttonOK"; + this.buttonOK.UseVisualStyleBackColor = true; + // + // SettingsDialog + // + this.AcceptButton = this.buttonOK; + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.SystemColors.Window; + this.CancelButton = this.buttonCancel; + this.Controls.Add(this.flowLayoutPanel1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "SettingsDialog"; + this.ShowInTaskbar = false; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.SettingsDialog_FormClosing); + this.flowLayoutPanel1.ResumeLayout(false); + this.flowLayoutPanel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; + private System.Windows.Forms.Button buttonApply; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonOK; + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsDialog.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsDialog.cs new file mode 100644 index 0000000..0e8d30f --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsDialog.cs @@ -0,0 +1,108 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using Microsoft.Office.Interop.Outlook; + +namespace Acacia.UI +{ + public partial class SettingsDialog : KopanoDialog, Microsoft.Office.Interop.Outlook.PropertyPageSite + { + private SettingsPage settings; + + public SettingsDialog() + { + settings = new SettingsPage(ThisAddIn.Instance.Features.ToArray()); + settings.PropertyPageSite = this; + + InitializeComponent(); + + settings.Dock = DockStyle.Fill; + Controls.Add(settings); + } + + #region PropertyPageSite implementation + + public Microsoft.Office.Interop.Outlook.Application Application + { + get + { + return ThisAddIn.Instance.Application; + } + } + + public OlObjectClass Class + { + get + { + return OlObjectClass.olApplication; + } + } + + public NameSpace Session + { + get + { + return Application.Session; + } + } + + dynamic PropertyPageSite.Parent + { + get + { + return null; + } + } + + public void OnStatusChange() + { + buttonApply.Enabled = settings.Dirty; + } + + #endregion + + private void Apply() + { + if (settings.Dirty) + { + settings.Apply(); + } + buttonApply.Enabled = false; + } + + private void buttonApply_Click(object sender, EventArgs e) + { + Apply(); + } + + private void SettingsDialog_FormClosing(object sender, FormClosingEventArgs e) + { + if (DialogResult == DialogResult.OK) + { + Apply(); + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsDialog.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsDialog.resx new file mode 100644 index 0000000..fae433e --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsDialog.resx @@ -0,0 +1,276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + True + + + False + + + + 358, 4 + + + + 4, 4, 4, 4 + + + 100, 33 + + + 0 + + + Apply + + + buttonApply + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + flowLayoutPanel1 + + + 0 + + + True + + + 250, 4 + + + 4, 4, 4, 4 + + + 100, 33 + + + 1 + + + Cancel + + + buttonCancel + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + flowLayoutPanel1 + + + 1 + + + True + + + 142, 4 + + + 4, 4, 4, 4 + + + 100, 33 + + + 2 + + + OK + + + buttonOK + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + flowLayoutPanel1 + + + 2 + + + Bottom + + + RightToLeft + + + 0, 394 + + + 4, 4, 4, 4 + + + 0, 0, 7, 0 + + + 469, 37 + + + 0 + + + flowLayoutPanel1 + + + System.Windows.Forms.FlowLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 8, 16 + + + True + + + 469, 431 + + + 4, 4, 4, 4 + + + CenterParent + + + Kopano Settings + + + SettingsDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsPage.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsPage.Designer.cs new file mode 100644 index 0000000..2ddd1a1 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsPage.Designer.cs @@ -0,0 +1,68 @@ +namespace Acacia.UI +{ + partial class SettingsPage + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.tableMain = new System.Windows.Forms.TableLayoutPanel(); + this.SuspendLayout(); + // + // tableMain + // + this.tableMain.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tableMain.AutoSize = true; + this.tableMain.ColumnCount = 1; + this.tableMain.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableMain.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableMain.Location = new System.Drawing.Point(0, 0); + this.tableMain.Name = "tableMain"; + this.tableMain.RowCount = 1; + this.tableMain.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableMain.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableMain.Size = new System.Drawing.Size(275, 211); + this.tableMain.TabIndex = 0; + // + // SettingsPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.SystemColors.Window; + this.Controls.Add(this.tableMain); + this.Name = "SettingsPage"; + this.Size = new System.Drawing.Size(275, 211); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableMain; + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsPage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsPage.cs new file mode 100644 index 0000000..7a128af --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsPage.cs @@ -0,0 +1,146 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Runtime.InteropServices; +using Acacia.Features; + +namespace Acacia.UI +{ + [ComVisible(true)] + public partial class SettingsPage : UserControl, Microsoft.Office.Interop.Outlook.PropertyPage + { + private readonly Dictionary _featuresDirty = new Dictionary(); + + public SettingsPage(Feature[] features) + { + InitializeComponent(); + + int i = 0; + foreach (Feature feature in features) + { + FeatureSettings settings = feature.GetSettings(); + if (settings != null) + { + settings.Settings = this; + _featuresDirty.Add(settings, false); + + // Wrap in a group box + GroupBox wrapper = new GroupBox(); + wrapper.Text = feature.DisplayName; + wrapper.Controls.Add(settings); + wrapper.Anchor = AnchorStyles.Left | AnchorStyles.Bottom | AnchorStyles.Top | AnchorStyles.Right; + wrapper.AutoSize = true; + wrapper.Margin = new Padding(5); + wrapper.Padding = new Padding(5); + settings.Location = Point.Empty; + settings.Dock = DockStyle.Fill; + + tableMain.RowStyles.Insert(i, new RowStyle(SizeType.AutoSize)); + tableMain.SetRow(wrapper, i); + tableMain.Controls.Add(wrapper, 0, i); + ++i; + tableMain.RowCount = i + 1; + } + } + CheckDirty(); + } + + internal void SetFeatureDirty(FeatureSettings feature, bool dirty) + { + _featuresDirty[feature] = dirty; + CheckDirty(); + } + + private void CheckDirty() + { + Dirty = _featuresDirty.Values.Aggregate((a, b) => a | b); + } + + private Microsoft.Office.Interop.Outlook.PropertyPageSite _propertyPageSite; + public Microsoft.Office.Interop.Outlook.PropertyPageSite PropertyPageSite + { + get + { + if (_propertyPageSite == null) + { + // Try to find the property dialog, so we can notify on dirty changes + Type objType = typeof(System.Object); + string assemblyPath = objType.Assembly.CodeBase.Replace("mscorlib.dll", "System.Windows.Forms.dll").Replace("file:///", ""); + string assemblyName = System.Reflection.AssemblyName.GetAssemblyName(assemblyPath).FullName; + + Type unsafeNativeMethods = Type.GetType(System.Reflection.Assembly.CreateQualifiedName(assemblyName, "System.Windows.Forms.UnsafeNativeMethods")); + Type oleObjectType = unsafeNativeMethods.GetNestedType("IOleObject"); + + System.Reflection.MethodInfo methodInfo = oleObjectType.GetMethod("GetClientSite"); + Object propertyPageSite = methodInfo.Invoke(this, null); + + _propertyPageSite = (Microsoft.Office.Interop.Outlook.PropertyPageSite)propertyPageSite; + } + return _propertyPageSite; + } + + set + { + _propertyPageSite = value; + } + } + + private bool _dirty; + public bool Dirty + { + get { return _dirty; } + private set + { + if (_dirty != value) + { + _dirty = value; + PropertyPageSite?.OnStatusChange(); + } + } + } + + public void Apply() + { + // Use ToArray to allow clearing the dirty flags in the same loop; cause a ConcurrentModifcation otherwise + foreach (FeatureSettings feature in _featuresDirty.Keys.ToArray()) + { + try + { + feature.Apply(); + _featuresDirty[feature] = false; + } + catch (System.Exception e) + { + Logger.Instance.Error(feature.Feature, "Exception applying settings: {0}", e); + } + } + _dirty = false; + } + + public void GetPageInfo(ref string HelpFile, ref int HelpContext) + { + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsPage.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsPage.resx new file mode 100644 index 0000000..29dcb1b --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/SettingsPage.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ActiveSync.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ActiveSync.cs new file mode 100644 index 0000000..69934f4 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ActiveSync.cs @@ -0,0 +1,361 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.ZPush; +using Acacia.ZPush.Connect; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.XPath; + +namespace Acacia.Utils +{ + public static class ActiveSync + { + #region Response and Request base + + public abstract class Response + { + abstract protected void ParseResponseBody(ActiveSync.RequestBase request, ZPushConnection.Response response); + + public ZPushConnection.Response RawResponse + { + get; + private set; + } + + public void ParseResponse(ActiveSync.RequestBase request, ZPushConnection.Response response) + { + RawResponse = response; + if (!response.Success) + throw new System.Exception("Response failure"); + ParseResponseBody(request, response); + } + } + + public class StatusResponse : Response + { + override protected void ParseResponseBody(ActiveSync.RequestBase request, ZPushConnection.Response response) + { + Logger.Instance.Trace(this, "ActiveSync: Status: {0}", response.Body.ToXMLString()); + } + } + + public abstract class RequestBase + { + abstract public string Command { get; } + abstract public string Body { get; } + } + + public abstract class Request : RequestBase + where ResponseType: Response + { + + } + + #endregion + + #region OOF Settings + + public enum OOFState + { + Disabled, + Enabled, + EnabledTimeBased + } + + public enum OOFTarget + { + Internal, + ExternalKnown, + ExternalUnknown + } + + public class OOFMessage + { + public string Message { get; set; } + } + + public class SettingsOOF : Response + { + public OOFState State { get; set; } + public DateTime? From { get; set; } + public DateTime? Till { get; set; } + public OOFMessage[] Message {get; set;} + public bool? SupportsTimes { get; set; } + + protected override void ParseResponseBody(ActiveSync.RequestBase request, ZPushConnection.Response response) + { + // Check capabilities + if (response.Capabilities == null) + SupportsTimes = null; + else if (response.Capabilities.Has(Constants.ZPUSH_CAPABILITY_OUT_OF_OFFICE_TIMES)) + SupportsTimes = true; + else if (response.Capabilities.Has(Constants.ZPUSH_CAPABILITY_OUT_OF_OFFICE)) + SupportsTimes = false; + else + SupportsTimes = null; + + // Parse contents + XPathNavigator nav = response.Body.CreateNavigator().SelectSingleNode("/Settings/Oof/Get"); + State = (OOFState)nav.SelectSingleNode("OofState").ValueAsInt; + From = nav.SelectSingleNode("StartTime")?.ValueAsDateTime.ToLocalTime(); + Till = nav.SelectSingleNode("EndTime")?.ValueAsDateTime.ToLocalTime(); + + // Messages + Message = new OOFMessage[3]; + foreach(XPathNavigator node in nav.Select("OofMessage")) + { + // Target + OOFTarget target; + if (node.SelectSingleNode("AppliesToInternal") != null) + target = OOFTarget.Internal; + else if (node.SelectSingleNode("AppliesToExternalKnown") != null) + target = OOFTarget.ExternalKnown; + else if (node.SelectSingleNode("AppliesToExternalUnknown") != null) + target = OOFTarget.ExternalUnknown; + else + { + Logger.Instance.Warning(this, "Unknown OOF message: {0}", node.OuterXml); + continue; + } + + // Message + OOFMessage oof = new OOFMessage(); + oof.Message = node.SelectSingleNode("ReplyMessage")?.Value; + + // Create the object + Message[(int)target] = oof; + } + } + } + + public class SettingsOOFGet : Request + { + public override string Body + { + get + { + return +@" + + + + TEXT + + + +"; + } + } + + public override string Command {get{ return "Settings"; }} + } + public class SettingsOOFSet : Request + { + private readonly SettingsOOF _value; + + public SettingsOOFSet(SettingsOOF value) + { + this._value = value; + } + + public override string Body + { + get + { + StringBuilder s = new StringBuilder(); + s.Append(""); + // State + s.Append("").Append((int)_value.State).Append(""); + + // Dates + if (_value.State == OOFState.EnabledTimeBased) + { + s.Append("").Append(_value.From.Value.ToUniversalTime().ToString(Constants.DATE_ISO_8601)).Append(""); + s.Append("").Append(_value.Till.Value.ToUniversalTime().ToString(Constants.DATE_ISO_8601)).Append(""); + } + + // Messages + if (_value.Message != null) + { + s.Append(""); + for (int i = 0; i < 3; ++i) + { + if (_value.Message[i] != null) + { + s.Append(""); + s.Append("1"); + s.Append("Text"); + s.Append(""); + s.Append(_value.Message[i].Message); // TODO: escaping + s.Append(""); + } + } + s.Append(""); + } + s.Append(""); + return s.ToString(); + } + } + + public override string Command { get { return "Settings"; } } + } + + #endregion + + #region Resolve recipients + + public enum FreeBusyType + { + Free, + Tentative, + Busy, + OutOfOffice, + NoData + } + + public struct FreeBusyData + { + public DateTime Start; + public DateTime End; + public FreeBusyType Type; + + public override string ToString() + { + return Start + "-" + End + "=" + Type; + } + } + + public class MergedFreeBusy : IEnumerable + { + public readonly DateTime StartTime; + public readonly DateTime EndTime; + private readonly string value; + + public MergedFreeBusy(DateTime startTime, string value) + { + this.StartTime = startTime; + this.EndTime = PositionToDateTime(value.Length); + this.value = value; + if (!Regex.IsMatch(value, "^[0-4]+$")) + throw new Exception("Invalid FreeBusy data: " + value); + } + + private DateTime PositionToDateTime(int pos) + { + return StartTime.AddMinutes(pos * 30); + } + + public IEnumerator GetEnumerator() + { + int currentState = -1; + int startPosition = -1; + + for (int position = 0; position < value.Length; ++position) + { + // Already checked the string is valid in constructor + char c = value[position]; + int state = c - '0'; + if (state != currentState || position == value.Length - 1) + { + if (startPosition >= 0) + { + // Report a new block + int length = position - startPosition; + yield return new FreeBusyData() + { + Start = PositionToDateTime(startPosition), + End = PositionToDateTime(position), + Type = (FreeBusyType)currentState + }; + } + currentState = state; + startPosition = position; + } + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + + public class ResolvedRecipients : Response + { + public MergedFreeBusy FreeBusy; + + protected override void ParseResponseBody(ActiveSync.RequestBase requestBase, ZPushConnection.Response response) + { + ResolveRecipientsRequest request = (ResolveRecipientsRequest)requestBase; + + // Only handle MergedFreeBusy for now + XmlNode node = response.Body.SelectSingleNode("//MergedFreeBusy/text()"); + Logger.Instance.Trace(this, "FreeBusy response for {0}: {1}", request.Recipient, node?.Value); + if (node != null) + { + FreeBusy = new MergedFreeBusy(request.StartTime, node.Value); + } + } + } + + public class ResolveRecipientsRequest : Request + { + public readonly string Recipient; + public readonly DateTime StartTime; + public readonly DateTime? EndTime; + + public ResolveRecipientsRequest(string recipient, DateTime startTime, DateTime? endTime) + { + this.Recipient = recipient; + this.StartTime = startTime; + this.EndTime = endTime; + } + + + public override string Body + { + get + { + StringBuilder s = new StringBuilder(); + s.Append(""); + s.Append(""); + s.Append("").Append(Recipient).Append(""); + s.Append(""); + s.Append("1"); + s.Append(""); + s.Append("").Append(StartTime.ToString(Constants.DATE_ISO_8601)).Append(""); + if (EndTime.HasValue) + s.Append("").Append(EndTime.Value.ToString(Constants.DATE_ISO_8601)).Append(""); + s.Append(""); + s.Append(""); + s.Append(""); + return s.ToString(); + } + } + + public override string Command { get { return "ResolveRecipients"; } } + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/CollectionUtil.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/CollectionUtil.cs new file mode 100644 index 0000000..81747a6 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/CollectionUtil.cs @@ -0,0 +1,82 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Utils +{ + public static class CollectionUtil + { + /// + /// Checks if both collections contain the same elements, not necessarily in the same order. + /// + public static bool SameElements(this IEnumerable first, ICollection second) + { + return SameElements(first, second, null); + } + + public static bool SameElements(this IEnumerable first, ICollection second, IEqualityComparer valueComparer) + { + if (first == second) return true; + if ((first == null) || (second == null)) return false; + + valueComparer = valueComparer ?? EqualityComparer.Default; + + int count = 0; + foreach (var value in first) + { + if (count >= second.Count) + return false; + + // TODO: this will fail on duplicates + if (!second.Contains(value, valueComparer)) + return false; + + ++count; + } + + return count == second.Count; + } + + public static bool SameElements(this IDictionary first, IDictionary second) + { + return SameElements(first, second, null); + } + + public static bool SameElements(this IDictionary first, IDictionary second, + IEqualityComparer valueComparer) + { + if (first == second) return true; + if ((first == null) || (second == null)) return false; + if (first.Count != second.Count) return false; + + valueComparer = valueComparer ?? EqualityComparer.Default; + + foreach (var kvp in first) + { + TValue secondValue; + if (!second.TryGetValue(kvp.Key, out secondValue)) return false; + if (!valueComparer.Equals(kvp.Value, secondValue)) return false; + } + return true; + } + + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ComRelease.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ComRelease.cs new file mode 100644 index 0000000..7488fb5 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ComRelease.cs @@ -0,0 +1,91 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Stubs; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Utils +{ + public class ComRelease : IDisposable + { + private readonly List objects = new List(); + + public Type Add(Type t) + { + objects.Add(t); + return t; + } + + public void Dispose() + { + foreach (object o in objects) + Release(o); + objects.Clear(); + } + + private static bool? _enabled; + + private static bool Enabled + { + get + { + if (!_enabled.HasValue) + { + _enabled = GlobalOptions.INSTANCE.COMRelease; + } + return _enabled.Value; + } + } + + public static void Release(object o) + { + if (!Enabled) + return; + if (o == null) + return; + + if (Logger.Instance.IsLevelEnabled(LogLevel.TraceExtra)) + { + Logger.Instance.TraceExtra(typeof(ComRelease), "Releasing object: {0:X} @ {1}", GetObjAddress(o), + new System.Diagnostics.StackTrace()); + } + Marshal.ReleaseComObject(o); + } + + private static long GetObjAddress(object o) + { + // It seems to be impossible to get an actual address, and the objects get moved around fairly frequently + return o.GetHashCode(); + } + + public static void LogWrapper(object o, IBase wrapper) + { + if (Logger.Instance.IsLevelEnabled(LogLevel.TraceExtra)) + { + if (wrapper != null) + { + Logger.Instance.TraceExtra(typeof(ComRelease), "Wrapping object: {0:X} @ {1}", GetObjAddress(o), + new System.Diagnostics.StackTrace()); + } + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DnsUtil.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DnsUtil.cs new file mode 100644 index 0000000..800cb11 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DnsUtil.cs @@ -0,0 +1,98 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Utils +{ + public static class DnsUtil + { + public static List GetTxtRecord(string name) + { + const Int16 DNS_TYPE_TEXT = 0x0010; + const Int32 DNS_QUERY_STANDARD = 0x00000000; + const Int32 DNS_ERROR_RCODE_NAME_ERROR = 9003; + const Int32 DNS_INFO_NO_RECORDS = 9501; + var queryResultsSet = IntPtr.Zero; + try + { + var dnsStatus = DnsQuery( + name, + DNS_TYPE_TEXT, + DNS_QUERY_STANDARD, + IntPtr.Zero, + ref queryResultsSet, + IntPtr.Zero + ); + if (dnsStatus == DNS_ERROR_RCODE_NAME_ERROR || dnsStatus == DNS_INFO_NO_RECORDS) + return null; + if (dnsStatus != 0) + throw new Win32Exception(dnsStatus); + DnsRecordTxt dnsRecord; + var lines = new List(); + for (var pointer = queryResultsSet; pointer != IntPtr.Zero; pointer = dnsRecord.pNext) + { + dnsRecord = (DnsRecordTxt)Marshal.PtrToStructure(pointer, typeof(DnsRecordTxt)); + if (dnsRecord.wType == DNS_TYPE_TEXT) + { + var stringArrayPointer = pointer + Marshal.OffsetOf(typeof(DnsRecordTxt), "pStringArray").ToInt32(); + for (var i = 0; i < dnsRecord.dwStringCount; ++i) + { + var stringPointer = (IntPtr)Marshal.PtrToStructure(stringArrayPointer, typeof(IntPtr)); + lines.Add(Marshal.PtrToStringUni(stringPointer)); + stringArrayPointer += IntPtr.Size; + } + } + } + if (lines.Count == 0) + return null; + return lines; + } + finally + { + const Int32 DnsFreeRecordList = 1; + if (queryResultsSet != IntPtr.Zero) + DnsRecordListFree(queryResultsSet, DnsFreeRecordList); + } + } + + [DllImport("Dnsapi.dll", EntryPoint = "DnsQuery_W", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] + static extern Int32 DnsQuery(String lpstrName, Int16 wType, Int32 options, IntPtr pExtra, ref IntPtr ppQueryResultsSet, IntPtr pReserved); + + [DllImport("Dnsapi.dll")] + static extern void DnsRecordListFree(IntPtr pRecordList, Int32 freeType); + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + struct DnsRecordTxt + { + public IntPtr pNext; + public String pName; + public Int16 wType; + public Int16 wDataLength; + public Int32 flags; + public Int32 dwTtl; + public Int32 dwReserved; + public Int32 dwStringCount; + public String pStringArray; + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/FolderUtils.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/FolderUtils.cs new file mode 100644 index 0000000..3b023f6 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/FolderUtils.cs @@ -0,0 +1,64 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Stubs; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.Utils +{ + public static class FolderUtils + { + public static OutlookConstants.SyncType GetFolderSyncType(IFolder folder, bool orig = false) + { + if (orig) + { + string type = (string)folder.GetProperty(OutlookConstants.PR_EAS_SYNCTYPE_ORIG); + return (OutlookConstants.SyncType)int.Parse(type); + } + else + { + int type = (int)folder.GetProperty(OutlookConstants.PR_EAS_SYNCTYPE); + return (OutlookConstants.SyncType)type; + } + } + + public static OutlookConstants.SyncType ParseSyncType(string type) + { + try + { + return ParseSyncType(int.Parse(type)); + } + catch (Exception) + { + return OutlookConstants.SyncType.Unknown; + } + } + + public static OutlookConstants.SyncType ParseSyncType(int type) + { + if (Enum.IsDefined(typeof(OutlookConstants.SyncType), type)) + return (OutlookConstants.SyncType)type; + return OutlookConstants.SyncType.Unknown; + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/JSONUtils.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/JSONUtils.cs new file mode 100644 index 0000000..df5de8d --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/JSONUtils.cs @@ -0,0 +1,35 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web.Script.Serialization; + +namespace Acacia.Utils +{ + public static class JSONUtils + { + public static Dictionary Deserialise(string json) + { + var serializer = new JavaScriptSerializer(); //using System.Web.Script.Serialization; + Dictionary values = serializer.Deserialize>(json); + return values; + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/LibUtils.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/LibUtils.cs new file mode 100644 index 0000000..b6d4147 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/LibUtils.cs @@ -0,0 +1,95 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Utils +{ + public static class LibUtils + { + public static String AssemblyName + { + get + { + Assembly assembly = Assembly.GetExecutingAssembly(); + string name = System.Diagnostics.FileVersionInfo.GetVersionInfo(assembly.Location).ProductName; + if (string.IsNullOrEmpty(name)) + name = assembly.GetName().Name; + return name; + } + } + + public static String Version + { + get + { + System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); + string version = assembly.GetName().Version.ToString(); + + // Strip off the last element, which contains an auto-generated value + int dot = version.LastIndexOf('.'); + if (dot > 0) + { + int lastPart; + if (!int.TryParse(version.Substring(dot + 1), out lastPart) || lastPart == 0) + { + version = version.Substring(0, dot); + } + } + + return version; + } + } + + public static DateTime BuildTime + { + get + { + // Retrieve the link time from the PE header + string filePath = System.Reflection.Assembly.GetExecutingAssembly().Location; + const int c_PeHeaderOffset = 60; + const int c_LinkerTimestampOffset = 8; + byte[] b = new byte[2048]; + System.IO.Stream s = null; + + try + { + s = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read); + s.Read(b, 0, 2048); + } + finally + { + if (s != null) + { + s.Close(); + } + } + + int i = System.BitConverter.ToInt32(b, c_PeHeaderOffset); + int secondsSince1970 = System.BitConverter.ToInt32(b, i + c_LinkerTimestampOffset); + DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + dt = dt.AddSeconds(secondsSince1970); + dt = dt.ToLocalTime(); + return dt; + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/MailEvents.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/MailEvents.cs new file mode 100644 index 0000000..2008541 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/MailEvents.cs @@ -0,0 +1,294 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Acacia.Stubs; +using Acacia.Stubs.OutlookWrappers; + +namespace Acacia.Utils +{ + /// + /// Handles registration for events on mail items. To register for these, each individual MailItem must be registered, + /// which can be done in the Application.ItemLoad event. This class hides that implementation and also ensures the + /// event registrations are removed when the item is unloaded, to prevent resource leaks. + /// + /// TODO: this name is now wrong + public class MailEvents + { + #region Events + + public delegate void MailEventHandler(IMailItem mail); + public delegate void MailResponseEventHandler(IMailItem mail, IMailItem response); + public delegate void ItemEventHandler(IItem item); + public delegate void CancellableItemEventHandler(IItem item, ref bool cancel); + public delegate void CancellableMailItemEventHandler(IMailItem item, ref bool cancel); + + /// + /// Hooks into Reply(All) and Forward events + /// + public event MailResponseEventHandler Respond; + + public event MailResponseEventHandler Reply; + private void OnReply(MailItem mail, MailItem response) + { + try + { + if ((Reply != null || Respond != null) && mail != null) + { + using (IMailItem mailWrapped = Mapping.Wrap(mail, false), + responseWrapped = Mapping.Wrap(response)) + { + if (Reply != null) + Reply(mailWrapped, responseWrapped); + if (Respond != null) + Respond(mailWrapped, responseWrapped); + } + } + } + catch (System.Exception e) + { + Logger.Instance.Error(this, "OnReply: {0}", e); + } + } + + public event MailResponseEventHandler ReplyAll; + private void OnReplyAll(MailItem mail, MailItem response) + { + try + { + if ((ReplyAll != null || Respond != null) && mail != null) + { + using (IMailItem mailWrapped = Mapping.Wrap(mail, false), + responseWrapped = Mapping.Wrap(response)) + { + if (ReplyAll != null) + ReplyAll(mailWrapped, responseWrapped); + if (Respond != null) + Respond(mailWrapped, responseWrapped); + } + } + } + catch (System.Exception e) + { + Logger.Instance.Error(this, "OnReplyAll: {0}", e); + } + } + + public event MailResponseEventHandler Forward; + private void OnForward(MailItem mail, MailItem response) + { + try + { + if ((Forward != null || Respond != null) && mail != null) + { + using (IMailItem mailWrapped = Mapping.Wrap(mail, false), + responseWrapped = Mapping.Wrap(response)) + { + if (Forward != null) + Forward(mailWrapped, responseWrapped); + if (Respond != null) + Respond(mailWrapped, responseWrapped); + } + } + } + catch (System.Exception e) + { + Logger.Instance.Error(this, "OnForward: {0}", e); + } + } + + public event MailEventHandler Read; + private void OnRead(MailItem mail) + { + try + { + if (Read != null && mail != null) + { + using (IMailItem wrapped = Mapping.Wrap(mail, false)) + { + Read(wrapped); + } + } + } + catch (System.Exception e) + { + Logger.Instance.Error(this, "OnRead: {0}", e); + } + } + + public event CancellableItemEventHandler BeforeDelete; + private void OnBeforeDelete(object item, ref bool cancel) + { + try + { + if (BeforeDelete != null && item != null) + { + using (IItem wrapped = Mapping.Wrap(item, false)) + { + if (wrapped != null) + BeforeDelete(wrapped, ref cancel); + } + } + } + catch(System.Exception e) + { + Logger.Instance.Error(this, "OnBeforeDelete: {0}", e); + } + } + + // TODO: should this be CancellableMailItemEventHandler? + public event CancellableItemEventHandler Write; + private void OnWrite(object item, ref bool cancel) + { + try + { + if (Write != null && item != null) + { + using (IItem wrapped = Mapping.Wrap(item, false)) + { + if (wrapped != null) + Write(wrapped, ref cancel); + } + } + } + catch (System.Exception e) + { + Logger.Instance.Error(this, "OnWrite: {0}", e); + } + } + + public event CancellableMailItemEventHandler ItemSend; + private void OnItemSend(object item, ref bool cancel) + { + try + { + if (ItemSend != null && item != null) + { + using (IMailItem wrapped = Mapping.WrapOrDefault(item, false)) + { + if (wrapped != null) + ItemSend(wrapped, ref cancel); + } + } + } + catch (System.Exception e) + { + Logger.Instance.Error(this, "OnItemSend: {0}", e); + } + } + + #endregion + + #region Implementation + + public MailEvents(Application app) + { + app.ItemLoad += OnItemLoad; + app.ItemSend += OnItemSend; + } + + void OnItemLoad(object item) + { + ItemEvents_10_Event hasEvents = item as ItemEvents_10_Event; + if (hasEvents != null) + { + new MailEventHooker(hasEvents, this); + } + } + + private class MailEventHooker + { + private readonly ItemEvents_10_Event item; + private readonly MailEvents events; + + public MailEventHooker(ItemEvents_10_Event item, MailEvents events) + { + this.item = item; + this.events = events; + HookEvents(true); + } + + private void HookEvents(bool add) + { + ItemEvents_10_Event events = this.item; + + if (add) + { + events.BeforeDelete += HandleBeforeDelete; + events.Forward += HandleForward; + events.Read += HandleRead; + events.Reply += HandleReply; + events.ReplyAll += HandleReplyAll; + events.Unload += HandleUnload; + events.Write += HandleWrite; + } + else + { + events.BeforeDelete -= HandleBeforeDelete; + events.Forward -= HandleForward; + events.Read -= HandleRead; + events.Reply -= HandleReply; + events.ReplyAll -= HandleReplyAll; + events.Unload -= HandleUnload; + events.Write -= HandleWrite; + } + } + + private void HandleBeforeDelete(object item, ref bool cancel) + { + events.OnBeforeDelete(item, ref cancel); + } + + private void HandleForward(object response, ref bool cancel) + { + events.OnForward(item as MailItem, response as MailItem); + } + + private void HandleRead() + { + events.OnRead(item as MailItem); + } + + private void HandleReply(object response, ref bool cancel) + { + events.OnReply(item as MailItem, response as MailItem); + } + + private void HandleReplyAll(object response, ref bool cancel) + { + events.OnReplyAll(item as MailItem, response as MailItem); + } + + private void HandleUnload() + { + // All events must be unhooked on unload, otherwise a resource leak is created. + HookEvents(false); + } + + private void HandleWrite(ref bool cancel) + { + events.OnWrite(item, ref cancel); + } + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/OutlookRegistryUtils.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/OutlookRegistryUtils.cs new file mode 100644 index 0000000..4d61861 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/OutlookRegistryUtils.cs @@ -0,0 +1,38 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Utils +{ + public static class OutlookRegistryUtils + { + + public static RegistryKey OpenOutlookKey(string suffix = null, RegistryKeyPermissionCheck permissions = RegistryKeyPermissionCheck.Default) + { + // Determine the base path + string[] versionParts = ThisAddIn.Instance.Application.Version.Split('.'); + string versionString = versionParts[0] + "." + versionParts[1]; + string baseKeyPath = string.Format(OutlookConstants.REG_KEY_BASE, versionString); + return RegistryUtil.OpenKeyImpl(baseKeyPath, suffix, false, permissions); + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/PasswordEncryption.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/PasswordEncryption.cs new file mode 100644 index 0000000..1c44562 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/PasswordEncryption.cs @@ -0,0 +1,165 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Security; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Utils +{ + public static class PasswordEncryption + { + #region Native methods + + private const string DATA_DESCRIPTION = "EAS Password"; + private const int CRYPTPROTECT_UI_FORBIDDEN = 0x1; + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private struct DATA_BLOB + { + public int cbData; + public IntPtr pbData; + } + + [DllImport("Crypt32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)] + private static extern bool CryptUnprotectData( + ref DATA_BLOB pDataIn, + out string szDataDescr, + IntPtr pOptionalEntropy, + IntPtr pvReserved, + IntPtr pPromptStruct, + int dwFlags, + ref DATA_BLOB pDataOut); + + [DllImport("Crypt32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)] + private static extern bool CryptProtectData( + ref DATA_BLOB pDataIn, + string szDataDescr, + IntPtr pOptionalEntropy, + IntPtr pvReserved, + IntPtr pPromptStruct, + int dwFlags, + ref DATA_BLOB pDataOut); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern IntPtr LocalFree(IntPtr hMem); + + #endregion + + private const byte FLAG_PROTECT_DATA = 2; + + public static SecureString Decrypt(byte[] password) + { + // The password starts with a 1 byte type identifier + if (password[0] != FLAG_PROTECT_DATA) + throw new Exception("Unknown encryption type"); + + DATA_BLOB plainTextBlob = new DATA_BLOB(); + DATA_BLOB cipherTextBlob = new DATA_BLOB(); + try + { + int cipherTextSize = password.Length - 1; + cipherTextBlob.pbData = Marshal.AllocHGlobal(cipherTextSize); + if (IntPtr.Zero == cipherTextBlob.pbData) + { + throw new Exception("Unable to allocate cipherText buffer."); + } + cipherTextBlob.cbData = cipherTextSize; + Marshal.Copy(password, 1, cipherTextBlob.pbData, cipherTextBlob.cbData); + + string descriptor; + if (!CryptUnprotectData(ref cipherTextBlob, out descriptor, IntPtr.Zero, + IntPtr.Zero, IntPtr.Zero, CRYPTPROTECT_UI_FORBIDDEN, + ref plainTextBlob)) + { + throw new Exception("Decryption failed. "); + } + + byte[] plainText = new byte[plainTextBlob.cbData]; + Marshal.Copy(plainTextBlob.pbData, plainText, 0, plainTextBlob.cbData); + + SecureString plain = new SecureString(); + foreach (char c in Encoding.Unicode.GetString(plainText)) + if (c != 0) + plain.AppendChar(c); + Array.Clear(plainText, 0, plainText.Length); + plain.MakeReadOnly(); + return plain; + } + finally + { + if (cipherTextBlob.pbData != IntPtr.Zero) + Marshal.FreeHGlobal(cipherTextBlob.pbData); + if (plainTextBlob.pbData != IntPtr.Zero) + LocalFree(plainTextBlob.pbData); + } + } + + public static byte[] Encrypt(string password) + { + DATA_BLOB plainTextBlob = new DATA_BLOB(); + DATA_BLOB cipherTextBlob = new DATA_BLOB(); + byte[] plainText = Encoding.Unicode.GetBytes(password + '\0'); + try + { + int bytesSize = plainText.Length; + plainTextBlob.pbData = Marshal.AllocHGlobal(bytesSize); + if (plainTextBlob.pbData == IntPtr.Zero) + { + throw new Exception("Unable to allocate plaintext buffer."); + } + plainTextBlob.cbData = bytesSize; + Marshal.Copy(plainText, 0, plainTextBlob.pbData, bytesSize); + + if (!CryptProtectData(ref plainTextBlob, DATA_DESCRIPTION, IntPtr.Zero, + IntPtr.Zero, IntPtr.Zero, CRYPTPROTECT_UI_FORBIDDEN, ref cipherTextBlob)) + { + throw new Exception("Encryption failed."); + } + + byte[] cipherText = new byte[cipherTextBlob.cbData + 1]; + Marshal.Copy(cipherTextBlob.pbData, cipherText, 1, cipherTextBlob.cbData); + cipherText[0] = FLAG_PROTECT_DATA; + return cipherText; + } + finally + { + if (cipherTextBlob.pbData != IntPtr.Zero) + LocalFree(cipherTextBlob.pbData); + if (plainTextBlob.pbData != IntPtr.Zero) + Marshal.FreeHGlobal(plainTextBlob.pbData); + } + } + + public static string ConvertToUnsecureString(this SecureString securePassword) + { + IntPtr unmanagedString = IntPtr.Zero; + try + { + unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword); + return Marshal.PtrToStringUni(unmanagedString); + } + finally + { + Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString); + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ReflectUtil.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ReflectUtil.cs new file mode 100644 index 0000000..4b57def --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ReflectUtil.cs @@ -0,0 +1,99 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Utils +{ + public static class ReflectUtil + { + public static object Cast(this Type Type, object data) + { + var DataParam = Expression.Parameter(typeof(object), "data"); + var Body = Expression.Block(Expression.Convert(Expression.Convert(DataParam, data.GetType()), Type)); + + var Run = Expression.Lambda(Body, DataParam).Compile(); + var ret = Run.DynamicInvoke(data); + return ret; + } + + public static TargetType Convert(object value) + { + return (TargetType)typeof(TargetType).Convert(value); + } + + public static object Convert(this Type type, object value) + { + // For value types, null becomes a default instance + if (value == null && type.IsValueType) + return Activator.CreateInstance(type); + + // Check if we need a conversion + if (!type.IsAssignableFrom(value.GetType())) + { + try + { + // Try built-in conversions + value = System.Convert.ChangeType(value, type); + } + catch(InvalidCastException e) + { + if (type.IsEnum) + { + // Try enum conversions + value = Enum.ToObject(type, Convert(value)); + } + else if (type.GetConstructor(new Type[] { value.GetType() }) != null) + { + // Call the constructor + return type.GetConstructor(new Type[] { value.GetType() }).Invoke(new object[] { value }); + } + else throw e; + } + } + + return value; + } + + public static bool IsGenericAssignableFrom(this Type _base, Type type) + { + return GetGenericArguments(type, _base) != null; + } + + public static IEnumerable AllBaseTypes(this Type type) + { + while (type.BaseType != null) + { + yield return type.BaseType; + type = type.BaseType; + } + } + + public static Type[] GetGenericArguments(this Type type, Type _base) + { + IEnumerable bases = _base.IsInterface ? type.GetInterfaces() : type.AllBaseTypes(); + return bases.Select(x => + (x.IsGenericType && x.GetGenericTypeDefinition() == _base) ? x.GetGenericArguments() : null + ).FirstOrDefault(); + + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/RegistryUtil.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/RegistryUtil.cs new file mode 100644 index 0000000..e0b6fd8 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/RegistryUtil.cs @@ -0,0 +1,109 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Utils +{ + public static class RegistryUtil + { + /// + /// Returns the registry value as a string. The value may be a string, or a byte array. + /// + public static string GetValueString(this RegistryKey key, string name) + { + object o = key.GetValue(name); + return RegToString(o); + } + + // TODO: remove, also above + public static string GetValueString(string keyPath, string valueName, string defaultValue) + { + object o = Registry.GetValue(keyPath, valueName, defaultValue); + return RegToString(o); + } + + public static string RegToString(object o) + { + if (o is byte[]) + { + string s = System.Text.Encoding.Unicode.GetString((byte[])o); + // Strip off terminating 0 byte + return s.Replace("\0", ""); + } + // Should be a string, otherwise the cast exception is good enough + return (string)o; + } + + public static ValueType GetConfigValue(string path, string valueName, ValueType defaultValue) + { + // Try current user first + foreach (bool localMachine in new bool[]{ false, true}) + { + using (RegistryKey key = OpenKeyImpl(Constants.PLUGIN_REGISTRY_BASE, path, localMachine, RegistryKeyPermissionCheck.ReadSubTree)) + { + if (key != null) + { + object value = key.GetValue(valueName); + if (value != null) + return (ValueType)value; + } + } + } + return defaultValue; + } + + public static void SetConfigValue(string path, string valueName, object value, RegistryValueKind kind) + { + // We only write to current user + using (RegistryKey key = OpenKeyImpl(Constants.PLUGIN_REGISTRY_BASE, path, false, RegistryKeyPermissionCheck.ReadWriteSubTree)) + { + if (key != null) + { + key.SetValue(valueName, value, kind); + } + } + } + + public static RegistryKey OpenKeyImpl(string baseKeyPath, string suffix, bool localMachine, RegistryKeyPermissionCheck permissions) + { + // Add the suffix + string keyPath; + if (string.IsNullOrEmpty(suffix)) + keyPath = baseKeyPath; + else + keyPath = System.IO.Path.Combine(baseKeyPath, suffix); + + // Open the key. + using (RegistryKey hive = RegistryKey.OpenBaseKey(localMachine ? RegistryHive.LocalMachine : RegistryHive.CurrentUser, RegistryView.Registry64)) + { + RegistryKey key = hive.OpenSubKey(keyPath, permissions); + if (key == null) + { + // Try creating it if writeable + if (permissions == RegistryKeyPermissionCheck.ReadWriteSubTree) + key = hive.CreateSubKey(keyPath, permissions); + } + return key; + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/StringUtil.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/StringUtil.cs new file mode 100644 index 0000000..cf3c4b8 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/StringUtil.cs @@ -0,0 +1,109 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; + +namespace Acacia.Utils +{ + public static class StringUtil + { + #region Misc + + /// + /// Removes the suffix from the string. If the suffix is not present, the original string is returned. + /// + public static string StripSuffix(this string _this, string suffix) + { + if (_this.EndsWith(suffix)) + return _this.Substring(0, _this.Length - suffix.Length); + return _this; + } + + /// + /// Removes the prefix from the string. If the prefix is not present, the original string is returned. + /// + public static string StripPrefix(this string _this, string suffix) + { + if (_this.StartsWith(suffix)) + return _this.Substring(suffix.Length); + return _this; + } + + #endregion + + #region Hex strings + + public static byte[] HexToBytes(string hex) + { + int NumberChars = hex.Length; + byte[] bytes = new byte[NumberChars / 2]; + for (int i = 0; i < NumberChars; i += 2) + bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); + return bytes; + } + + public static string BytesToHex(byte[] bytes) + { + if (bytes == null) + return null; + return BitConverter.ToString(bytes).Replace("-", ""); + } + + public static string HexToUtf8(string s) + { + return Encoding.UTF8.GetString(HexToBytes(s)); + } + + #endregion + + public static string ToXMLString(this XmlNode xml) + { + using (var stringWriter = new StringWriter()) + using (var xmlTextWriter = XmlWriter.Create(stringWriter)) + { + xml.WriteTo(xmlTextWriter); + xmlTextWriter.Flush(); + return stringWriter.GetStringBuilder().ToString(); + } + } + + + #region Resources + + public static string GetResourceString(string id) + { + string s = Properties.Resources.ResourceManager.GetString(id); + if (string.IsNullOrEmpty(s)) + throw new InvalidDataException("Missing string resource " + id); + return s; + } + + public static string GetResourceString(string id, params object[] p) + { + string s = GetResourceString(id); + return string.Format(s, p); + } + + #endregion + + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/Tasks.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/Tasks.cs new file mode 100644 index 0000000..e616f85 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/Tasks.cs @@ -0,0 +1,114 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Features; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Windows.Forms; + +namespace Acacia.Utils +{ + public class AcaciaTask + { + public readonly Feature Owner; + public readonly string Name; + public readonly Action Action; + + public AcaciaTask(Feature owner, string name, Action action) + { + Owner = owner; + Name = name; + Action = action; + } + + public string Id + { + get + { + if (Owner != null) + return Owner.Name + "." + Name; + return Name; + } + } + + /// + /// Executes the task. + /// + public bool Execute() + { + try + { + Action(); + return true; + } + catch (Exception e) + { + Logger.Instance.Error(Owner, "Exception in task {0}: {1}", Name, e); + return false; + } + } + + } + + public interface TaskExecutor + { + string Name { get; } + void ExecuteTask(AcaciaTask task); + } + + public static class Tasks + { + private static TaskExecutor _executor; + + public static TaskExecutor Executor + { + get + { + if (_executor == null) + { + switch(GlobalOptions.INSTANCE.Threading) + { + case DebugOptions.Threading.MainThread: + _executor = new TasksMainThread(); + break; + case DebugOptions.Threading.Synchronous: + _executor = new TasksSynchronous(); + break; + case DebugOptions.Threading.Background: + _executor = new TasksBackground(); + break; + } + } + return _executor; + } + set + { + _executor = value; + } + } + + public static void Task(Feature owner, string name, Action action) + { + Executor.ExecuteTask(new AcaciaTask(owner, name, action)); + } + + public static void Task(AcaciaTask task) + { + Executor.ExecuteTask(task); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksBackground.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksBackground.cs new file mode 100644 index 0000000..94da998 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksBackground.cs @@ -0,0 +1,54 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Acacia.Utils +{ + public class TasksBackground : TaskExecutor + { + private readonly BlockingCollection _tasks = new BlockingCollection(); + + public TasksBackground() + { + Thread t = new Thread(Worker); + t.SetApartmentState(ApartmentState.STA); + t.Start(); + } + + private void Worker() + { + while (!_tasks.IsCompleted) + { + AcaciaTask task = _tasks.Take(); + task.Execute(); + } + } + + public void ExecuteTask(AcaciaTask task) + { + _tasks.Add(task); + } + + public string Name { get { return "Background"; } } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksMainThread.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksMainThread.cs new file mode 100644 index 0000000..2c91c12 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksMainThread.cs @@ -0,0 +1,117 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.Utils +{ + /// + /// Executes tasks in the UI thread. + /// If standard dispatching is used, the tasks are executed straight away. This blocks the UI thread from + /// doing UI-related work, making the application hang. To this end, tasks are put in a queue, which is + /// checked for jobs on application idle events - i.e. when the application is not busy updating the UI. + /// To ensure some progress is made, a timer is also set up to execute tasks. This is also required as + /// modal dialogs prevent the application idle event from being sent. + /// + public class TasksMainThread : TaskExecutor + { + /// + /// Initialisation is done in multiple steps. First the application idle event is hooked up. The + /// first time this is triggered, it sets up the timer. This multi-stage approach prevents the + /// timer from delaying the initial start-up of Outlook. + /// + private enum InitState + { + Uninitialised, + InitialisedIdle, + Initialised + } + + /// + /// The current init state + /// + private InitState _init = InitState.Uninitialised; + + /// + /// The timer. + /// + private Timer _timer; + + /// + /// The tasks. Names are added for debug purposes. + /// + private readonly Queue _tasks = new Queue(); + + /// + /// Checks if any tasks can be executed and executes them if possible. + /// + private void PollTasks() + { + if (_tasks.Count > 0) + { + Stopwatch timer = new Stopwatch(); timer.Start(); + do + { + AcaciaTask task = _tasks.Dequeue(); + Logger.Instance.Trace(task.Id, "Beginning task"); + task.Execute(); + Logger.Instance.Info(task.Id, "Ending task: {0}ms", timer.ElapsedMilliseconds); + // Execute another task if available and we haven't taken too long. + } while (_tasks.Count > 0 && timer.ElapsedMilliseconds < 50); + } + } + + private void IdleHandler(object sender, EventArgs e) + { + if (_init == InitState.InitialisedIdle) + { + _init = InitState.Initialised; + _timer = new Timer(); + _timer.Interval = 100; + _timer.Tick += IdleHandler; + _timer.Start(); + } + + PollTasks(); + } + + /// + /// Adds a task to be executed. + /// + /// The name, for debugging and logging. + /// The action to execute + public void ExecuteTask(AcaciaTask task) + { + if (_init == InitState.Uninitialised) + { + _init = InitState.InitialisedIdle; + // Set up the idle handler + Application.Idle += IdleHandler; + } + + // Enqueue the task + _tasks.Enqueue(task); + } + + public string Name { get { return "MainThread"; } } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksSynchronous.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksSynchronous.cs new file mode 100644 index 0000000..15b67ae --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksSynchronous.cs @@ -0,0 +1,34 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.Utils +{ + public class TasksSynchronous : TaskExecutor + { + public void ExecuteTask(AcaciaTask task) + { + task.Execute(); + } + + public string Name { get { return "Synchronous"; } } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/Util.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/Util.cs new file mode 100644 index 0000000..e565bda --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/Util.cs @@ -0,0 +1,48 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.ZPush; +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Xml; + +namespace Acacia.Utils +{ + public static class Util + { + public static bool NullSafeEquals(ObjType a, ObjType b) + { + if (System.Object.ReferenceEquals(a, b)) + { + return true; + } + + // If one is null, but not both, return false. + if (((object)a == null) || ((object)b == null)) + { + return false; + } + + return a.Equals(b); + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Version.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Version.cs new file mode 100644 index 0000000..08b0551 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Version.cs @@ -0,0 +1,24 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System.Reflection; +[assembly: AssemblyVersion("0.1")] +[assembly: AssemblyFileVersion("0.1")] +public static class BuildVersions +{ + public const string VERSION = "0.1"; + public const string REVISION = "abcdef0123456789abcdef0123456789abcdef01"; +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ActiveSyncCodeSpace.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ActiveSyncCodeSpace.cs new file mode 100644 index 0000000..4abd30f --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ActiveSyncCodeSpace.cs @@ -0,0 +1,68 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + public class ActiveSyncCodeSpace : TagCodeSpace + { + public ActiveSyncCodeSpace() + { + AddCodePage(new AirSyncCodePage()); + AddCodePage(new ContactsCodePage()); + AddCodePage(new EmailCodePage()); + AddCodePage(new AirNotifyCodePage()); + AddCodePage(new CalendarCodePage()); + AddCodePage(new MoveCodePage()); + AddCodePage(new ItemEstimateCodePage()); + AddCodePage(new FolderHierarchyCodePage()); + AddCodePage(new MeetingResponseCodePage()); + AddCodePage(new TasksCodePage()); + AddCodePage(new ResolveRecipientsCodePage()); + AddCodePage(new ValidateCertCodePage()); + AddCodePage(new Contacts2CodePage()); + AddCodePage(new PingCodePage()); + AddCodePage(new ProvisionCodePage()); + AddCodePage(new SearchCodePage()); + AddCodePage(new GALCodePage()); + AddCodePage(new AirSyncBaseCodePage()); + AddCodePage(new SettingsCodePage()); + AddCodePage(new DocumentLibraryCodePage()); + AddCodePage(new ItemOperationsCodePage()); + AddCodePage(new ComposeMailCodePage()); + AddCodePage(new Email2CodePage()); + AddCodePage(new NotesCodePage()); + } + + public override int GetPublicIdentifier() + { + return 0x01; + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/AirNotifyCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/AirNotifyCodePage.cs new file mode 100644 index 0000000..bd8e98a --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/AirNotifyCodePage.cs @@ -0,0 +1,36 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + public class AirNotifyCodePage : TagCodePage + { + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/AirSyncBaseCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/AirSyncBaseCodePage.cs new file mode 100644 index 0000000..7d7db69 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/AirSyncBaseCodePage.cs @@ -0,0 +1,58 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + internal class AirSyncBaseCodePage : TagCodePage + { + public AirSyncBaseCodePage() + { + AddToken(0x05, "BodyPreference"); + AddToken(0x06, "Type"); + AddToken(0x07, "TruncationSize"); + AddToken(0x08, "AllOrNone"); + AddToken(0x0A, "Body"); + AddToken(0x0B, "Data"); + AddToken(0x0C, "EstimatedDataSize"); + AddToken(0x0D, "Truncated"); + AddToken(0x0E, "Attachments"); + AddToken(0x0F, "Attachment"); + AddToken(0x10, "DisplayName"); + AddToken(0x11, "FileReference"); + AddToken(0x12, "Method"); + AddToken(0x13, "ContentId"); + AddToken(0x14, "ContentLocation"); + AddToken(0x15, "IsInline"); + AddToken(0x16, "NativeBodyType"); + AddToken(0x17, "ContentType"); + AddToken(0x18, "Preview"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/AirSyncCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/AirSyncCodePage.cs new file mode 100644 index 0000000..7dbe4d0 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/AirSyncCodePage.cs @@ -0,0 +1,76 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + public class AirSyncCodePage : TagCodePage + { + public AirSyncCodePage() + { + AddToken(0x05, "Sync"); + AddToken(0x06, "Responses"); + AddToken(0x07, "Add"); + AddToken(0x08, "Change"); + AddToken(0x09, "Delete"); + AddToken(0x0A, "Fetch"); + AddToken(0x0B, "SyncKey"); + AddToken(0x0C, "ClientId"); + AddToken(0x0D, "ServerId"); + AddToken(0x0E, "Status"); + AddToken(0x0F, "Collection"); + AddToken(0x10, "Class"); + AddToken(0x11, "Version"); + AddToken(0x12, "CollectionId"); + AddToken(0x13, "GetChanges"); + AddToken(0x14, "MoreAvailable"); + AddToken(0x15, "WindowSize"); + AddToken(0x16, "Commands"); + AddToken(0x17, "Options"); + AddToken(0x18, "FilterType"); + AddToken(0x19, "Truncation"); + AddToken(0x1A, "RTFTrunction"); + AddToken(0x1B, "Conflict"); + AddToken(0x1C, "Collections"); + AddToken(0x1D, "ApplicationData"); + AddToken(0x1E, "DeletesAsMoves"); + AddToken(0x1F, "NotifyGUID"); + AddToken(0x20, "Supported"); + AddToken(0x21, "SoftDelete"); + AddToken(0x22, "MIMESupport"); + AddToken(0x23, "MIMETruncation"); + AddToken(0x24, "Wait"); + AddToken(0x25, "Limit"); + AddToken(0x26, "Partial"); + AddToken(0x27, "ConversationMode"); + AddToken(0x28, "MaxItems"); + AddToken(0x29, "HeartbeatInterval"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/CalendarCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/CalendarCodePage.cs new file mode 100644 index 0000000..e3616c3 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/CalendarCodePage.cs @@ -0,0 +1,89 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + public class CalendarCodePage : TagCodePage + { + public CalendarCodePage() + { + AddToken(0x05, "TimeZone"); + AddToken(0x06, "AllDayEvent"); + AddToken(0x07, "Attendees"); + AddToken(0x08, "Attendee"); + AddToken(0x09, "Attendee_Email"); + AddToken(0x0A, "Attendee_Name"); + AddToken(0x0B, "Body"); + AddToken(0x0C, "BodyTruncated"); + AddToken(0x0D, "BusyStatus"); + AddToken(0x0E, "Categories"); + AddToken(0x0F, "Category"); + AddToken(0x10, "Compressed_RTF"); + AddToken(0x11, "DTStamp"); + AddToken(0x12, "EndTime"); + AddToken(0x13, "Exception"); + AddToken(0x14, "Exceptions"); + AddToken(0x15, "Exception_IsDeleted"); + AddToken(0x16, "Exception_StartTime"); + AddToken(0x17, "Location"); + AddToken(0x18, "MeetingStatus"); + AddToken(0x19, "Organizer_Email"); + AddToken(0x1A, "Organizer_Name"); + AddToken(0x1B, "Recurrence"); + AddToken(0x1C, "Recurrence_Type"); + AddToken(0x1D, "Recurrence_Until"); + AddToken(0x1E, "Recurrence_Occurrences"); + AddToken(0x1F, "Recurrence_Interval"); + AddToken(0x20, "Recurrence_DayOfWeek"); + AddToken(0x21, "Recurrence_DayOfMonth"); + AddToken(0x22, "Recurrence_WeekOfMonth"); + AddToken(0x23, "Recurrence_MonthOfYear"); + AddToken(0x24, "Reminder_MinsBefore"); + AddToken(0x25, "Sensitivity"); + AddToken(0x26, "Subject"); + AddToken(0x27, "StartTime"); + AddToken(0x28, "UID"); + AddToken(0x29, "Attendee_Status"); + AddToken(0x2A, "Attendee_Type"); + AddToken(0x2B, "Attachment"); + AddToken(0x2C, "Attachments"); + AddToken(0x2D, "AttName"); + AddToken(0x2E, "AttSize"); + AddToken(0x2F, "AttOid"); + AddToken(0x30, "AttMethod"); + AddToken(0x31, "AttRemoved"); + AddToken(0x32, "DisplayName"); + AddToken(0x33, "DisallowNewTimeProposal"); + AddToken(0x34, "ResponseRequested"); + AddToken(0x35, "AppointmentReplyTime"); + AddToken(0x36, "ResponseType"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ComposeMailCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ComposeMailCodePage.cs new file mode 100644 index 0000000..90390a6 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ComposeMailCodePage.cs @@ -0,0 +1,53 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + internal class ComposeMailCodePage : TagCodePage + { + public ComposeMailCodePage() + { + AddToken(0x05, "SendMail"); + AddToken(0x06, "SmartForward"); + AddToken(0x07, "SmartReply"); + AddToken(0x08, "SaveInSentItems"); + AddToken(0x09, "ReplaceMime"); + AddToken(0x0A, "Type"); + AddToken(0x0B, "Source"); + AddToken(0x0C, "FolderId"); + AddToken(0x0D, "ItemId"); + AddToken(0x0E, "LongId"); + AddToken(0x0F, "InstanceId"); + AddToken(0x10, "Mime"); + AddToken(0x11, "ClientId"); + AddToken(0x12, "Status"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/Contacts2CodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/Contacts2CodePage.cs new file mode 100644 index 0000000..3bf962b --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/Contacts2CodePage.cs @@ -0,0 +1,49 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + internal class Contacts2CodePage : TagCodePage + { + public Contacts2CodePage() + { + AddToken(0x05, "CustomerId"); + AddToken(0x06, "GovernmentId"); + AddToken(0x07, "IMAddress"); + AddToken(0x08, "IMAddress2"); + AddToken(0x09, "IMAddress3"); + AddToken(0x0A, "ManagerName"); + AddToken(0x0B, "CompanyMainPhone"); + AddToken(0x0C, "AccountName"); + AddToken(0x0D, "NickName"); + AddToken(0x0E, "MMS"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ContactsCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ContactsCodePage.cs new file mode 100644 index 0000000..0c51eca --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ContactsCodePage.cs @@ -0,0 +1,97 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + public class ContactsCodePage : TagCodePage + { + public ContactsCodePage() + { + AddToken(0x05, "Anniversary"); + AddToken(0x06, "AssistantName"); + AddToken(0x07, "AssistantTelephoneNumber"); + AddToken(0x08, "Birthday"); + AddToken(0x09, "Body"); + AddToken(0x0A, "BodySize"); + AddToken(0x0B, "BodyTruncated"); + AddToken(0x0C, "Business2TelephoneNumber"); + AddToken(0x0D, "BusinessAddressCity"); + AddToken(0x0E, "BusinessAddressCountry"); + AddToken(0x0F, "BusinessAddressPostalCode"); + AddToken(0x10, "BusinessAddressState"); + AddToken(0x11, "BusinessAddressStreet"); + AddToken(0x12, "BusinessFaxNumber"); + AddToken(0x13, "BusinessTelephoneNumber"); + AddToken(0x14, "CarTelephoneNumber"); + AddToken(0x15, "Categories"); + AddToken(0x16, "Category"); + AddToken(0x17, "Children"); + AddToken(0x18, "Child"); + AddToken(0x19, "CompanyName"); + AddToken(0x1A, "Department"); + AddToken(0x1B, "Email1Address"); + AddToken(0x1C, "Email2Address"); + AddToken(0x1D, "Email3Address"); + AddToken(0x1E, "FileAs"); + AddToken(0x1F, "FirstName"); + AddToken(0x20, "Home2TelephoneNumber"); + AddToken(0x21, "HomeAddressCity"); + AddToken(0x22, "HomeAddressCountry"); + AddToken(0x23, "HomeAddressPostalCode"); + AddToken(0x24, "HomeAddressState"); + AddToken(0x25, "HomeAddressStreet"); + AddToken(0x26, "HomeFaxNumber"); + AddToken(0x27, "HomeTelephoneNumber"); + AddToken(0x28, "JobTitle"); + AddToken(0x29, "LastName"); + AddToken(0x2A, "MiddleName"); + AddToken(0x2B, "MobilePhoneNumber"); + AddToken(0x2C, "OfficeLocation"); + AddToken(0x2D, "OtherAddressCity"); + AddToken(0x2E, "OtherAddressCountry"); + AddToken(0x2F, "OtherAddressPostalCode"); + AddToken(0x30, "OtherAddressState"); + AddToken(0x31, "OtherAddressStreet"); + AddToken(0x32, "PagerNumber"); + AddToken(0x33, "RadioTelephoneNumber"); + AddToken(0x34, "Spouse"); + AddToken(0x35, "Suffix"); + AddToken(0x36, "Title"); + AddToken(0x37, "Webpage"); + AddToken(0x38, "YomiCompanyName"); + AddToken(0x39, "YomiFirstName"); + AddToken(0x3A, "YomiLastName"); + AddToken(0x3B, "CompressedRTF"); + AddToken(0x3C, "Picture"); + AddToken(0x3D, "Alias"); + AddToken(0x3E, "WeightedRank"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/DocumentLibraryCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/DocumentLibraryCodePage.cs new file mode 100644 index 0000000..fc4adfa --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/DocumentLibraryCodePage.cs @@ -0,0 +1,47 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + internal class DocumentLibraryCodePage : TagCodePage + { + public DocumentLibraryCodePage() + { + AddToken(0x05, "LinkId"); + AddToken(0x06, "DisplayName"); + AddToken(0x07, "IsFolder"); + AddToken(0x08, "CreationDate"); + AddToken(0x09, "LastModifiedDate"); + AddToken(0x0A, "IsHidden"); + AddToken(0x0B, "ContentLength"); + AddToken(0x0C, "ContentType"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/Email2CodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/Email2CodePage.cs new file mode 100644 index 0000000..87399f3 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/Email2CodePage.cs @@ -0,0 +1,51 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + internal class Email2CodePage : TagCodePage + { + public Email2CodePage() + { + AddToken(0x05, "UmCallerID"); + AddToken(0x06, "UmUserNotes"); + AddToken(0x07, "UmAttDuration"); + AddToken(0x08, "UmAttOrder"); + AddToken(0x09, "ConversationId"); + AddToken(0x0A, "ConversationIndex"); + AddToken(0x0B, "LastVerbExecuted"); + AddToken(0x0C, "LastVerbExecutionTime"); + AddToken(0x0D, "ReceivedAsBcc"); + AddToken(0x0E, "Sender"); + AddToken(0x0F, "CalendarType"); + AddToken(0x10, "IsLeapMonth"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/EmailCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/EmailCodePage.cs new file mode 100644 index 0000000..dd7a7e3 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/EmailCodePage.cs @@ -0,0 +1,98 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + public class EmailCodePage : TagCodePage + { + public EmailCodePage() + { + AddToken(0x05, "Attachment"); + AddToken(0x06, "Attachments"); + AddToken(0x07, "AttName"); + AddToken(0x08, "AttSize"); + AddToken(0x09, "Att0Id"); + AddToken(0x0A, "AttMethod"); + AddToken(0x0B, "AttRemoved"); + AddToken(0x0C, "Body"); + AddToken(0x0D, "BodySize"); + AddToken(0x0E, "BodyTruncated"); + AddToken(0x0F, "DateReceived"); + AddToken(0x10, "DisplayName"); + AddToken(0x11, "DisplayTo"); + AddToken(0x12, "Importance"); + AddToken(0x13, "MessageClass"); + AddToken(0x14, "Subject"); + AddToken(0x15, "Read"); + AddToken(0x16, "To"); + AddToken(0x17, "CC"); + AddToken(0x18, "From"); + AddToken(0x19, "ReplyTo"); + AddToken(0x1A, "AllDayEvent"); + AddToken(0x1B, "Categories"); + AddToken(0x1C, "Category"); + AddToken(0x1D, "DTStamp"); + AddToken(0x1E, "EndTime"); + AddToken(0x1F, "InstanceType"); + AddToken(0x20, "IntDBusyStatus"); + AddToken(0x21, "Location"); + AddToken(0x22, "MeetingRequest"); + AddToken(0x23, "Organizer"); + AddToken(0x24, "RecurrenceId"); + AddToken(0x25, "Reminder"); + AddToken(0x26, "ResponseRequested"); + AddToken(0x27, "Recurrences"); + AddToken(0x28, "Recurrence"); + AddToken(0x29, "Recurrence_Type"); + AddToken(0x2A, "Recurrence_Until"); + AddToken(0x2B, "Recurrence_Occurrences"); + AddToken(0x2C, "Recurrence_Interval"); + AddToken(0x2D, "Recurrence_DayOfWeek"); + AddToken(0x2E, "Recurrence_DayOfMonth"); + AddToken(0x2F, "Recurrence_WeekOfMonth"); + AddToken(0x30, "Recurrence_MonthOfYear"); + AddToken(0x31, "StartTime"); + AddToken(0x32, "Sensitivity"); + AddToken(0x33, "TimeZone"); + AddToken(0x34, "GlobalObjId"); + AddToken(0x35, "ThreadTopic"); + AddToken(0x36, "MIMEData"); + AddToken(0x37, "MIMETruncated"); + AddToken(0x38, "MIMESize"); + AddToken(0x39, "InternetCPID"); + AddToken(0x3A, "Flag"); + AddToken(0x3B, "FlagStatus"); + AddToken(0x3C, "ContentClass"); + AddToken(0x3D, "FlagType"); + AddToken(0x3E, "CompleteTime"); + AddToken(0x3F, "DisallowNewTimeProposal"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/FolderHierarchyCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/FolderHierarchyCodePage.cs new file mode 100644 index 0000000..b74d173 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/FolderHierarchyCodePage.cs @@ -0,0 +1,59 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + internal class FolderHierarchyCodePage : TagCodePage + { + public FolderHierarchyCodePage() + { + AddToken(0x05, "Folders"); + AddToken(0x06, "Folder"); + AddToken(0x07, "DisplayName"); + AddToken(0x08, "ServerId"); + AddToken(0x09, "ParentId"); + AddToken(0x0A, "Type"); + AddToken(0x0B, "Response"); + AddToken(0x0C, "Status"); + AddToken(0x0D, "ContentClass"); + AddToken(0x0E, "Changes"); + AddToken(0x0F, "Add"); + AddToken(0x10, "Delete"); + AddToken(0x11, "Update"); + AddToken(0x12, "SyncKey"); + AddToken(0x13, "FolderCreate"); + AddToken(0x14, "FolderDelete"); + AddToken(0x15, "FolderUpdate"); + AddToken(0x16, "FolderSync"); + AddToken(0x17, "Count"); + AddToken(0x18, "Version"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/GALCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/GALCodePage.cs new file mode 100644 index 0000000..90b49f4 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/GALCodePage.cs @@ -0,0 +1,50 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + internal class GALCodePage : TagCodePage + { + public GALCodePage() + { + AddToken(0x05, "DisplayName"); + AddToken(0x06, "Phone"); + AddToken(0x07, "Office"); + AddToken(0x08, "Title"); + AddToken(0x09, "Company"); + AddToken(0x0A, "Alias"); + AddToken(0x0B, "FirstName"); + AddToken(0x0C, "LastName"); + AddToken(0x0D, "HomePhone"); + AddToken(0x0E, "MobilePhone"); + AddToken(0x0F, "EmailAddress"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ItemEstimateCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ItemEstimateCodePage.cs new file mode 100644 index 0000000..dc5cbe8 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ItemEstimateCodePage.cs @@ -0,0 +1,49 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + internal class ItemEstimateCodePage : TagCodePage + { + public ItemEstimateCodePage() + { + AddToken(0x05, "GetItemEstimate"); + AddToken(0x06, "Version"); + AddToken(0x07, "Collections"); + AddToken(0x08, "Collection"); + AddToken(0x09, "Class"); + AddToken(0x0A, "CollectionId"); + AddToken(0x0B, "DateTime"); + AddToken(0x0C, "Estimate"); + AddToken(0x0D, "Response"); + AddToken(0x0E, "Status"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ItemOperationsCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ItemOperationsCodePage.cs new file mode 100644 index 0000000..2cbd265 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ItemOperationsCodePage.cs @@ -0,0 +1,60 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + internal class ItemOperationsCodePage : TagCodePage + { + public ItemOperationsCodePage() + { + AddToken(0x05, "ItemOperations"); + AddToken(0x06, "Fetch"); + AddToken(0x07, "Store"); + AddToken(0x08, "Options"); + AddToken(0x09, "Range"); + AddToken(0x0A, "Total"); + AddToken(0x0B, "Properties"); + AddToken(0x0C, "Data"); + AddToken(0x0D, "Status"); + AddToken(0x0E, "Response"); + AddToken(0x0F, "Version"); + AddToken(0x10, "Schema"); + AddToken(0x11, "Part"); + AddToken(0x12, "EmptyFolderContents"); + AddToken(0x13, "DeleteSubFolders"); + AddToken(0x14, "UserName"); + AddToken(0x15, "Password"); + AddToken(0x16, "Move"); + AddToken(0x17, "DstFldId"); + AddToken(0x18, "ConversationId"); + AddToken(0x19, "MoveAlways"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/MeetingResponseCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/MeetingResponseCodePage.cs new file mode 100644 index 0000000..ce55c3d --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/MeetingResponseCodePage.cs @@ -0,0 +1,48 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + internal class MeetingResponseCodePage : TagCodePage + { + public MeetingResponseCodePage() + { + AddToken(0x05, "CalId"); + AddToken(0x06, "CollectionId"); + AddToken(0x07, "MeetingResponse"); + AddToken(0x08, "ReqId"); + AddToken(0x09, "Request"); + AddToken(0x0A, "Result"); + AddToken(0x0B, "Status"); + AddToken(0x0C, "UserResponse"); + AddToken(0x0D, "Version"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/MoveCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/MoveCodePage.cs new file mode 100644 index 0000000..b24b499 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/MoveCodePage.cs @@ -0,0 +1,47 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + public class MoveCodePage : TagCodePage + { + public MoveCodePage() + { + AddToken(0x05, "MoveItems"); + AddToken(0x06, "Move"); + AddToken(0x07, "SrcMsgId"); + AddToken(0x08, "SrcFldId"); + AddToken(0x09, "DstFldId"); + AddToken(0x0A, "Response"); + AddToken(0x0B, "Status"); + AddToken(0x0C, "DstMsgId"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/NotesCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/NotesCodePage.cs new file mode 100644 index 0000000..1395276 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/NotesCodePage.cs @@ -0,0 +1,44 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + internal class NotesCodePage : TagCodePage + { + public NotesCodePage() + { + AddToken(0x05, "Subject"); + AddToken(0x06, "MessageClass"); + AddToken(0x07, "LastModifiedDate"); + AddToken(0x08, "Categories"); + AddToken(0x09, "Category"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/PingCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/PingCodePage.cs new file mode 100644 index 0000000..08e2344 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/PingCodePage.cs @@ -0,0 +1,48 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + internal class PingCodePage : TagCodePage + { + public PingCodePage() + { + AddToken(0x05, "Ping"); + AddToken(0x06, "AutdState"); + AddToken(0x07, "Status"); + AddToken(0x08, "HeartbeatInterval"); + AddToken(0x09, "Folders"); + AddToken(0x0A, "Folder"); + AddToken(0x0B, "Id"); + AddToken(0x0C, "Class"); + AddToken(0x0D, "MaxFolders"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ProvisionCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ProvisionCodePage.cs new file mode 100644 index 0000000..a72a48d --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ProvisionCodePage.cs @@ -0,0 +1,94 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + internal class ProvisionCodePage : TagCodePage + { + public ProvisionCodePage() + { + AddToken(0x05, "Provision"); + AddToken(0x06, "Policies"); + AddToken(0x07, "Policy"); + AddToken(0x08, "PolicyType"); + AddToken(0x09, "PolicyKey"); + AddToken(0x0A, "Data"); + AddToken(0x0B, "Status"); + AddToken(0x0C, "RemoteWipe"); + AddToken(0x0D, "EASProvisionDoc"); + AddToken(0x0E, "DevicePasswordEnabled"); + AddToken(0x0F, "AlphanumericDevicePasswordRequired"); + AddToken(0x10, "DeviceEncryptionEnabled"); + //What to do with RequireStorageCardEncryption which has the same token? + AddToken(0x11, "PasswordRecoveryEnabled"); + AddToken(0x12, "DocumentBrowseEnabled"); + AddToken(0x13, "AttachmentsEnabled"); + AddToken(0x14, "MinDevicePasswordLength"); + AddToken(0x15, "MaxInactivityTimeDeviceLock"); + AddToken(0x16, "MaxDevicePasswordFailedAttempts"); + AddToken(0x17, "MaxAttachmentSize"); + AddToken(0x18, "AllowSimpleDevicePassword"); + AddToken(0x19, "DevicePasswordExpiration"); + AddToken(0x1A, "DevicePasswordHistory"); + AddToken(0x1B, "AllowStorageCard"); + AddToken(0x1C, "AllowCamera"); + AddToken(0x1D, "RequireDeviceEncryption"); + AddToken(0x1E, "AllowUnsignedApplications"); + AddToken(0x1F, "AllowUnsignedInstallationPackages"); + AddToken(0x20, "MinDevicePasswordComplexCharacters"); + AddToken(0x21, "AllowWiFi"); + AddToken(0x22, "AllowTextMessaging"); + AddToken(0x23, "AllowPOPIMAPEmail"); + AddToken(0x24, "AllowBluetooth"); + AddToken(0x25, "AllowIrDA"); + AddToken(0x26, "RequireManualSyncWhenRoaming"); + AddToken(0x27, "AllowDesktopSync"); + AddToken(0x28, "MaxCalendarAgeFilter"); + AddToken(0x29, "AllowHTMLEmail"); + AddToken(0x2A, "MaxEmailAgeFilter"); + AddToken(0x2B, "MaxEmailBodyTruncationSize"); + AddToken(0x2C, "MaxEmailHTMLBodyTruncationSize"); + AddToken(0x2D, "RequireSignedSMIMEMessages"); + AddToken(0x2E, "RequireEncryptedSMIMEMessages"); + AddToken(0x2F, "RequireSignedSMIMEAlgorithm"); + AddToken(0x30, "RequireEncryptionSMIMEAlgorithm"); + AddToken(0x31, "AllowSMIMEEncryptionAlgorithmNegotiation"); + AddToken(0x32, "AllowSMIMESoftCerts"); + AddToken(0x33, "AllowBrowser"); + AddToken(0x34, "AllowConsumerEmail"); + AddToken(0x35, "AllowRemoteDesktop"); + AddToken(0x36, "AllowInternetSharing"); + AddToken(0x37, "UnapprovedInROMApplicationList"); + AddToken(0x38, "ApplicationName"); + AddToken(0x39, "ApprovedApplicationList"); + AddToken(0x3A, "Hash"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ResolveRecipientsCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ResolveRecipientsCodePage.cs new file mode 100644 index 0000000..ce018e1 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ResolveRecipientsCodePage.cs @@ -0,0 +1,64 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + internal class ResolveRecipientsCodePage : TagCodePage + { + public ResolveRecipientsCodePage() + { + AddToken(0x05, "ResolveRecipients"); + AddToken(0x06, "Response"); + AddToken(0x07, "Status"); + AddToken(0x08, "Type"); + AddToken(0x09, "Recipient"); + AddToken(0x0A, "DisplayName"); + AddToken(0x0B, "EmailAddress"); + AddToken(0x0C, "Certificates"); + AddToken(0x0D, "Certificate"); + AddToken(0x0E, "MiniCertificate"); + AddToken(0x0F, "Options"); + AddToken(0x10, "To"); + AddToken(0x11, "CertificateRetrieval"); + AddToken(0x12, "RecipientCount"); + AddToken(0x13, "MaxCertificates"); + AddToken(0x14, "MaxAmbiguousRecipients"); + AddToken(0x15, "CertificateCount"); + AddToken(0x16, "Availability"); + AddToken(0x17, "StartTime"); + AddToken(0x18, "EndTime"); + AddToken(0x19, "MergedFreeBusy"); + AddToken(0x1A, "Picture"); + AddToken(0x1B, "MaxSize"); + AddToken(0x1C, "Data"); + AddToken(0x1D, "MaxPictures"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/SearchCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/SearchCodePage.cs new file mode 100644 index 0000000..ffe2925 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/SearchCodePage.cs @@ -0,0 +1,66 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + internal class SearchCodePage : TagCodePage + { + public SearchCodePage() + { + //Tokens 6 and 16 are not supported + AddToken(0x05, "Search"); + AddToken(0x07, "Store"); + AddToken(0x08, "Name"); + AddToken(0x09, "Query"); + AddToken(0x0A, "Options"); + AddToken(0x0B, "Range"); + AddToken(0x0C, "Status"); + AddToken(0x0D, "Response"); + AddToken(0x0E, "Result"); + AddToken(0x0F, "Properties"); + AddToken(0x10, "Total"); + AddToken(0x11, "EqualTo"); + AddToken(0x12, "Value"); + AddToken(0x13, "And"); + AddToken(0x14, "Or"); + AddToken(0x15, "FreeText"); + AddToken(0x17, "DeepTraversal"); + AddToken(0x18, "LongId"); + AddToken(0x19, "RebuildResults"); + AddToken(0x1A, "LessThan"); + AddToken(0x1B, "GreaterThan"); + AddToken(0x1C, "Schema"); + AddToken(0x1D, "Supported"); + AddToken(0x1E, "UserName"); + AddToken(0x1F, "Password"); + AddToken(0x20, "ConversationId"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/SettingsCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/SettingsCodePage.cs new file mode 100644 index 0000000..fe53aa6 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/SettingsCodePage.cs @@ -0,0 +1,69 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + internal class SettingsCodePage : TagCodePage + { + public SettingsCodePage() + { + AddToken(0x05, "Settings"); + AddToken(0x06, "Status"); + AddToken(0x07, "Get"); + AddToken(0x08, "Set"); + AddToken(0x09, "Oof"); + AddToken(0x0A, "OofState"); + AddToken(0x0B, "StartTime"); + AddToken(0x0C, "EndTime"); + AddToken(0x0D, "OofMessage"); + AddToken(0x0E, "AppliesToInternal"); + AddToken(0x0F, "AppliesToExternalKnown"); + AddToken(0x10, "AppliesToExternalUnknown"); + AddToken(0x11, "Enabled"); + AddToken(0x12, "ReplyMessage"); + AddToken(0x13, "BodyType"); + AddToken(0x14, "DevicePassword"); + AddToken(0x15, "Password"); + AddToken(0x16, "DeviceInformaton"); + AddToken(0x17, "Model"); + AddToken(0x18, "IMEI"); + AddToken(0x19, "FriendlyName"); + AddToken(0x1A, "OS"); + AddToken(0x1B, "OSLanguage"); + AddToken(0x1C, "PhoneNumber"); + AddToken(0x1D, "UserInformation"); + AddToken(0x1E, "EmailAddresses"); + AddToken(0x1F, "SmtpAddress"); + AddToken(0x20, "UserAgent"); + AddToken(0x21, "EnableOutboundSMS"); + AddToken(0x22, "MobileOperator"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/TasksCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/TasksCodePage.cs new file mode 100644 index 0000000..00c4fb9 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/TasksCodePage.cs @@ -0,0 +1,70 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + internal class TasksCodePage : TagCodePage + { + public TasksCodePage() + { + AddToken(0x05, "Body"); + AddToken(0x06, "BodySize"); + AddToken(0x07, "BodyTruncated"); + AddToken(0x08, "Categories"); + AddToken(0x09, "Category"); + AddToken(0x0A, "Complete"); + AddToken(0x0B, "DateCompleted"); + AddToken(0x0C, "DueDate"); + AddToken(0x0D, "UTCDueDate"); + AddToken(0x0E, "Importance"); + AddToken(0x0F, "Recurrence"); + AddToken(0x10, "RecurrenceType"); + AddToken(0x11, "RecurrenceStart"); + AddToken(0x12, "RecurrenceUntil"); + AddToken(0x13, "RecurrenceOccurrences"); + AddToken(0x14, "RecurrenceInterval"); + AddToken(0x15, "RecurrenceDayOfMonth"); + AddToken(0x16, "RecurrenceDayOfWeek"); + AddToken(0x17, "RecurrenceWeekOfMonth"); + AddToken(0x18, "RecurrenceMonthOfYear"); + AddToken(0x19, "RecurrenceRegenerate"); + AddToken(0x1A, "RecurrenceDeadOccur"); + AddToken(0x1B, "ReminderSet"); + AddToken(0x1C, "ReminderTime"); + AddToken(0x1D, "Sensitivity"); + AddToken(0x1E, "StartDate"); + AddToken(0x1F, "UTCStartDate"); + AddToken(0x20, "Subject"); + AddToken(0x21, "CompressedRTF"); + AddToken(0x22, "OrdinalDate"); + AddToken(0x23, "SubOrdinalDate"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ValidateCertCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ValidateCertCodePage.cs new file mode 100644 index 0000000..26f05d8 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/ActiveSync/ValidateCertCodePage.cs @@ -0,0 +1,45 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// +// The ActiveSync WAP Binary XML (MS-ASWBXML) specification is +// developed by Microsoft (http://www.microsoft.com/) +// Details about this specification can be found at +// http://msdn.microsoft.com/en-us/library/dd299442.aspx + +namespace Acacia.WBXML.ActiveSync +{ + internal class ValidateCertCodePage : TagCodePage + { + public ValidateCertCodePage() + { + AddToken(0x05, "ValidateCert"); + AddToken(0x06, "Certificates"); + AddToken(0x07, "Certificate"); + AddToken(0x08, "CertificateChain"); + AddToken(0x09, "CheckCRL"); + AddToken(0x0A, "Status"); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/AttributeCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/AttributeCodePage.cs new file mode 100644 index 0000000..41233c4 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/AttributeCodePage.cs @@ -0,0 +1,171 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf + +using System.Collections.Generic; + +namespace Acacia.WBXML +{ + public class AttributeCodePage + { + private readonly Dictionary> attrStartNameDictionary = + new Dictionary>(); + + private readonly Dictionary attrStartTokenDictionary = + new Dictionary(); + + private readonly Dictionary attrValueNameDictionary = new Dictionary(); + private readonly Dictionary attrValueTokenDictionary = new Dictionary(); + + public void AddAttributeStart(byte token, string attributeName) + { + AddAttributeStart(token, attributeName, ""); + } + + public void AddAttributeStart(byte token, string attributeName, string prefixValue) + { + attrStartTokenDictionary.Add(token, new AttributeStart(token, attributeName, prefixValue)); + + Dictionary internalValueTokenDictionary; + if (attrStartNameDictionary.ContainsKey(attributeName)) + { + internalValueTokenDictionary = attrStartNameDictionary[attributeName]; + } + else + { + internalValueTokenDictionary = new Dictionary(); + attrStartNameDictionary.Add(attributeName, internalValueTokenDictionary); + } + + internalValueTokenDictionary.Add(prefixValue, token); + } + + public void AddAttributeValue(byte token, string attributeValue) + { + attrValueTokenDictionary.Add(token, attributeValue); + attrValueNameDictionary.Add(attributeValue, token); + } + + public virtual bool ContainsAttributeStart(byte token) + { + if (token < 128) + { + return attrStartTokenDictionary.ContainsKey(token); + } + + return false; + } + + public virtual bool ContainsAttributeStart(string name) + { + return ContainsAttributeStart(name, ""); + } + + public virtual bool ContainsAttributeStart(string name, string attributeValue) + { + if (attrStartNameDictionary.ContainsKey(name)) + { + foreach (string prefixItem in attrStartNameDictionary[name].Keys) + { + if (attributeValue.StartsWith(prefixItem)) + { + return true; + } + } + } + return false; + } + + public virtual bool ContainsAttributeValue(byte token) + { + if (token >= 128) + { + return attrValueTokenDictionary.ContainsKey(token); + } + + return false; + } + + public virtual bool ContainsAttributeValue(string attributeValue) + { + foreach (string attributeValueItem in attrValueNameDictionary.Keys) + { + if (attributeValue.Contains(attributeValueItem)) + { + return true; + } + } + + return false; + } + + public virtual AttributeValue GetAttributeValue(byte token) + { + return new AttributeValue(token, attrValueTokenDictionary[token]); + } + + public virtual AttributeValue GetAttributeValue(string attributeValue) + { + AttributeValue returnValue = null; + + foreach (string attributeValueItem in attrValueNameDictionary.Keys) + { + if (attributeValue.Contains(attributeValueItem)) + { + if (returnValue == null + || attributeValue.IndexOf(attributeValueItem) < attributeValue.IndexOf(returnValue.Value) + || attributeValueItem.Length > returnValue.Value.Length) + { + returnValue = new AttributeValue(attrValueNameDictionary[attributeValueItem], attributeValueItem); + } + } + } + + return returnValue; + } + + public virtual AttributeStart GetAttributeStart(byte token) + { + return attrStartTokenDictionary[token]; + } + + public virtual AttributeStart GetAttributeStart(string name, string prefix) + { + AttributeStart returnValue = null; + + foreach (string prefixItem in attrStartNameDictionary[name].Keys) + { + if (prefix.StartsWith(prefixItem)) + { + if (returnValue == null || prefixItem.Length > returnValue.Prefix.Length) + { + returnValue = new AttributeStart(attrStartNameDictionary[name][prefixItem], name, prefixItem); + } + } + } + + return returnValue; + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/AttributeCodeSpace.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/AttributeCodeSpace.cs new file mode 100644 index 0000000..bc545e1 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/AttributeCodeSpace.cs @@ -0,0 +1,45 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf + + +using System.Collections.Generic; + +namespace Acacia.WBXML +{ + public class AttributeCodeSpace + { + private readonly List codePages = new List(); + + public void AddCodePage(AttributeCodePage codePage) + { + codePages.Add(codePage); + } + + public virtual AttributeCodePage GetCodePage(int codepageId) + { + return codePages[codepageId]; + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/AttributeStart.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/AttributeStart.cs new file mode 100644 index 0000000..69a31cf --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/AttributeStart.cs @@ -0,0 +1,61 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf + +namespace Acacia.WBXML +{ + public class AttributeStart + { + private readonly string name; + private readonly string prefix; + private readonly byte token; + + public AttributeStart(byte token, string name) + : this(token, name, "") + { + } + + public AttributeStart(byte token, string name, string prefix) + { + this.token = token; + this.name = name; + this.prefix = prefix; + } + + public byte Token + { + get { return token; } + } + + public string Name + { + get { return name; } + } + + public string Prefix + { + get { return prefix; } + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/AttributeValue.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/AttributeValue.cs new file mode 100644 index 0000000..ad132e7 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/AttributeValue.cs @@ -0,0 +1,50 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf + + +namespace Acacia.WBXML +{ + public class AttributeValue + { + private readonly string attributeValue; + private readonly byte token; + + public AttributeValue(byte token, string attributeValue) + { + this.token = token; + this.attributeValue = attributeValue; + } + + public byte Token + { + get { return token; } + } + + public string Value + { + get { return attributeValue; } + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/EmptyCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/EmptyCodePage.cs new file mode 100644 index 0000000..bf87567 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/EmptyCodePage.cs @@ -0,0 +1,41 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf + + +namespace Acacia.WBXML +{ + public class EmptyCodePage : TagCodePage + { + public override bool ContainsTag(byte token) + { + return true; + } + + public override Tag GetTag(byte token) + { + return new Tag(token, "Tag_" + token.ToString("X2")); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/EmptyCodeSpace.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/EmptyCodeSpace.cs new file mode 100644 index 0000000..eb60ccd --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/EmptyCodeSpace.cs @@ -0,0 +1,40 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf + +namespace Acacia.WBXML +{ + internal class EmptyCodeSpace : TagCodeSpace + { + public override int GetPublicIdentifier() + { + return 0x01; + } + + public override TagCodePage GetCodePage(int codepageId) + { + return new EmptyCodePage(); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/GlobalTokens.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/GlobalTokens.cs new file mode 100644 index 0000000..ad823e6 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/GlobalTokens.cs @@ -0,0 +1,83 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf + + +using System; +using System.Collections.Generic; + +namespace Acacia.WBXML +{ + public class GlobalTokens + { + #region Names enum + + public enum Names + { + SWITCH_PAGE = 0x00, + END = 0x01, + ENTITY = 0x02, + STR_I = 0x03, + LITERAL = 0x04, + EXT_I_0 = 0x40, + EXT_I_1 = 0x41, + EXT_I_2 = 0x42, + PI = 0x43, + LITERAL_C = 0x44, + EXT_T_0 = 0x80, + EXT_T_1 = 0x81, + EXT_T_2 = 0x82, + STR_T = 0x83, + LITERAL_A = 0x84, + EXT_0 = 0xC0, + EXT_1 = 0xC1, + EXT_2 = 0xC2, + OPAQUE = 0xC3, + LITERAL_AC = 0xC4 + } + + #endregion + + private readonly Dictionary tokenDictionary = new Dictionary(); + + public GlobalTokens() + { + foreach (String tokenName in Enum.GetNames(typeof (Names))) + { + var tokenItem = (Names) Enum.Parse(typeof (Names), tokenName); + tokenDictionary.Add((byte) tokenItem, tokenItem); + } + } + + public bool Contains(byte keyValue) + { + return tokenDictionary.ContainsKey(keyValue); + } + + public Names GetToken(byte byteValue) + { + return tokenDictionary[byteValue]; + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/IANACharacterSets.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/IANACharacterSets.cs new file mode 100644 index 0000000..5c14b64 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/IANACharacterSets.cs @@ -0,0 +1,164 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf +// Details about the IANA Character Sets can be found at +// http://www.iana.org/assignments/character-sets + +using System.Collections.Generic; +using System.Text; + +namespace Acacia.WBXML +{ + public class IANACharacterSets + { + private static Dictionary characterSets; + + public static Encoding GetEncoding(int MIBenum) + { + if (characterSets == null) + { + InitializeCharacterSets(); + } + + if (characterSets.ContainsValue(MIBenum)) + { + foreach (var characterSet in characterSets) + { + if (characterSet.Value == MIBenum) + { + return Encoding.GetEncoding(characterSet.Key); + } + } + } + return Encoding.UTF8; + } + + public static int GetMIBEnum(Encoding encoding) + { + if (characterSets == null) + { + InitializeCharacterSets(); + } + + if (characterSets.ContainsKey(encoding.WebName)) + { + return characterSets[encoding.WebName]; + } + return characterSets["utf-8"]; + } + + private static void InitializeCharacterSets() + { + characterSets = new Dictionary(); + + characterSets.Add("us-ascii", 3); + characterSets.Add("iso-8859-1", 4); + characterSets.Add("iso-8859-2", 5); + characterSets.Add("iso-8859-3", 6); + characterSets.Add("iso-8859-4", 7); + characterSets.Add("iso-8859-5", 8); + characterSets.Add("ASMO-708", 9); + characterSets.Add("iso-8859-6", 9); + characterSets.Add("iso-8859-7", 10); + characterSets.Add("iso-8859-8", 11); + characterSets.Add("iso-8859-9", 12); + characterSets.Add("shift_jis", 17); + characterSets.Add("EUC-JP", 18); + characterSets.Add("ks_c_5601-1987", 36); + characterSets.Add("iso-2022-kr", 37); + characterSets.Add("euc-kr", 38); + characterSets.Add("iso-2022-jp", 39); + characterSets.Add("csISO2022JP", 39); + characterSets.Add("iso-8859-8-i", 85); + characterSets.Add("utf-8", 106); + characterSets.Add("iso-8859-13", 109); + characterSets.Add("iso-8859-15", 111); + characterSets.Add("GB18030", 114); + characterSets.Add("utf-7", 1012); + characterSets.Add("utf-16", 1015); + characterSets.Add("utf-32", 1017); + characterSets.Add("utf-32BE", 1018); + characterSets.Add("ibm850", 2009); + characterSets.Add("ibm852", 2010); + characterSets.Add("IBM437", 2011); + characterSets.Add("IBM-Thai", 2016); + characterSets.Add("gb2312", 2025); + characterSets.Add("big5", 2026); + characterSets.Add("macintosh", 2027); + characterSets.Add("IBM037", 2028); + characterSets.Add("IBM273", 2030); + characterSets.Add("IBM277", 2033); + characterSets.Add("IBM278", 2034); + characterSets.Add("IBM280", 2035); + characterSets.Add("IBM284", 2037); + characterSets.Add("IBM285", 2038); + characterSets.Add("IBM290", 2039); + characterSets.Add("IBM297", 2040); + characterSets.Add("IBM420", 2041); + characterSets.Add("IBM423", 2042); + characterSets.Add("IBM424", 2043); + characterSets.Add("IBM500", 2044); + characterSets.Add("IBM855", 2046); + characterSets.Add("ibm857", 2047); + characterSets.Add("IBM860", 2048); + characterSets.Add("ibm861", 2049); + characterSets.Add("IBM863", 2050); + characterSets.Add("IBM864", 2051); + characterSets.Add("IBM865", 2052); + characterSets.Add("ibm869", 2054); + characterSets.Add("IBM870", 2055); + characterSets.Add("IBM871", 2056); + characterSets.Add("IBM880", 2057); + characterSets.Add("IBM905", 2061); + characterSets.Add("IBM1026", 2063); + characterSets.Add("koi8-r", 2084); + characterSets.Add("hz-gb-2312", 2085); + characterSets.Add("cp866", 2086); + characterSets.Add("ibm775", 2087); + characterSets.Add("koi8-u", 2088); + characterSets.Add("IBM00858", 2089); + characterSets.Add("IBM00924", 2090); + characterSets.Add("IBM01140", 2091); + characterSets.Add("IBM01141", 2092); + characterSets.Add("IBM01142", 2093); + characterSets.Add("IBM01143", 2094); + characterSets.Add("IBM01144", 2095); + characterSets.Add("IBM01145", 2096); + characterSets.Add("IBM01146", 2097); + characterSets.Add("IBM01147", 2098); + characterSets.Add("IBM01148", 2099); + characterSets.Add("IBM01149", 2100); + characterSets.Add("IBM01047", 2102); + characterSets.Add("windows-1250", 2250); + characterSets.Add("windows-1251", 2251); + characterSets.Add("Windows-1252", 2252); + characterSets.Add("windows-1253", 2253); + characterSets.Add("windows-1254", 2254); + characterSets.Add("windows-1255", 2255); + characterSets.Add("windows-1256", 2256); + characterSets.Add("windows-1257", 2257); + characterSets.Add("windows-1258", 2258); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/OpaqueDataExpression.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/OpaqueDataExpression.cs new file mode 100644 index 0000000..fb71a69 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/OpaqueDataExpression.cs @@ -0,0 +1,41 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf + + +namespace Acacia.WBXML +{ + public class OpaqueDataExpression + { + public OpaqueDataExpression(string name, string expression) + { + TagName = name; + Expression = expression; + } + + public string TagName { get; set; } + + public string Expression { get; set; } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/StringTable.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/StringTable.cs new file mode 100644 index 0000000..1760a69 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/StringTable.cs @@ -0,0 +1,116 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf + +using System.Collections.Generic; +using System.Text; + +namespace Acacia.WBXML +{ + public class StringTable + { + private readonly Dictionary stringTableIndexDictionary = new Dictionary(); + private readonly int stringTableLength; + private readonly Dictionary stringTableValueDictionary = new Dictionary(); + + public StringTable() + { + stringTableLength = 0; + } + + public StringTable(string[] stringTableItems) + { + int stringTableIndex = 0; + foreach (string item in stringTableItems) + { + stringTableIndexDictionary.Add(stringTableIndex, item); + stringTableValueDictionary.Add(item, stringTableIndex); + + stringTableIndex += item.Length + 1; + } + stringTableLength = stringTableIndex; + } + + public int Length + { + get { return stringTableLength; } + } + + public bool ContainsString(int index) + { + return stringTableIndexDictionary.ContainsKey(index); + } + + public bool ContainsString(string stringTableValue) + { + foreach (string stringTableItem in stringTableValueDictionary.Keys) + { + if (stringTableValue.Contains(stringTableItem)) + { + return true; + } + } + + return false; + } + + public StringTableItem GetString(string stringTableValue) + { + StringTableItem returnValue = null; + + foreach (string stringTableItem in stringTableValueDictionary.Keys) + { + if (stringTableValue.Contains(stringTableItem)) + { + if (returnValue == null + || stringTableValue.IndexOf(stringTableItem) < stringTableValue.IndexOf(returnValue.Value) + || stringTableItem.Length > returnValue.Value.Length) + { + returnValue = new StringTableItem(stringTableValueDictionary[stringTableItem], stringTableItem); + } + } + } + + return returnValue; + } + + public StringTableItem GetString(int index) + { + return new StringTableItem(index, stringTableIndexDictionary[index]); + } + + public byte[] GetStringTableBytes(Encoding textEncoding) + { + var stringTableBytes = new List(); + + foreach (string item in stringTableValueDictionary.Keys) + { + stringTableBytes.AddRange(textEncoding.GetBytes(item)); + stringTableBytes.Add(0x00); + } + + return stringTableBytes.ToArray(); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/StringTableItem.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/StringTableItem.cs new file mode 100644 index 0000000..93f06a7 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/StringTableItem.cs @@ -0,0 +1,49 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf + +namespace Acacia.WBXML +{ + public class StringTableItem + { + private readonly int index; + private readonly string itemValue; + + public StringTableItem(int index, string itemValue) + { + this.index = index; + this.itemValue = itemValue; + } + + public int Index + { + get { return index; } + } + + public string Value + { + get { return itemValue; } + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/Tag.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/Tag.cs new file mode 100644 index 0000000..fbf6200 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/Tag.cs @@ -0,0 +1,49 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf + +namespace Acacia.WBXML +{ + public class Tag + { + private readonly string name; + private readonly byte token; + + public Tag(byte token, string name) + { + this.token = token; + this.name = name; + } + + public byte Token + { + get { return token; } + } + + public string Name + { + get { return name; } + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/TagCodePage.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/TagCodePage.cs new file mode 100644 index 0000000..7e27ba7 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/TagCodePage.cs @@ -0,0 +1,61 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf + +using System.Collections.Generic; + +namespace Acacia.WBXML +{ + public class TagCodePage + { + private readonly Dictionary nameDictionary = new Dictionary(); + private readonly Dictionary tokenDictionary = new Dictionary(); + + public void AddToken(byte token, string name) + { + tokenDictionary.Add(token, name); + nameDictionary.Add(name, token); + } + + public virtual bool ContainsTag(byte token) + { + return tokenDictionary.ContainsKey(token); + } + + public virtual bool ContainsTag(string name) + { + return nameDictionary.ContainsKey(name); + } + + public virtual Tag GetTag(byte token) + { + return new Tag(token, tokenDictionary[token]); + } + + public virtual Tag GetTag(string name) + { + return new Tag(nameDictionary[name], name); + } + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/TagCodeSpace.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/TagCodeSpace.cs new file mode 100644 index 0000000..2b31339 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/TagCodeSpace.cs @@ -0,0 +1,67 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf + +using System.Collections.Generic; + +namespace Acacia.WBXML +{ + public abstract class TagCodeSpace + { + private readonly List codePages = new List(); + + public void AddCodePage(TagCodePage codePage) + { + codePages.Add(codePage); + } + + public virtual TagCodePage GetCodePage(int codepageId) + { + return codePages[codepageId]; + } + + public int ContainsTag(int codepageId, string name) + { + if (codePages[codepageId].ContainsTag(name)) + { + return codepageId; + } + + for (int i = 0; i < codePages.Count; i++) + { + if (i != codepageId) + { + if (codePages[i].ContainsTag(name)) + { + return i; + } + } + } + + return -1; + } + + public abstract int GetPublicIdentifier(); + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/WBXMLDocument.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/WBXMLDocument.cs new file mode 100644 index 0000000..ad8b512 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/WBXML/WBXMLDocument.cs @@ -0,0 +1,663 @@ +// Copyright 2012 - Johan de Koning (johan@johandekoning.nl) +// +// This file is part of WBXML .Net Library. +// 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. +// +// The WAP Binary XML (WBXML) specification is developed by the +// Open Mobile Alliance (http://www.openmobilealliance.org/) +// Details about this specification can be found at +// http://www.openmobilealliance.org/tech/affiliates/wap/wap-192-wbxml-20010725-a.pdf + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Xml; + +namespace Acacia.WBXML +{ + public class WBXMLDocument : XmlDocument + { + private readonly GlobalTokens globalTokens = new GlobalTokens(); + private readonly List opaqueDataExpressions = new List(); + + private AttributeCodeSpace attributeCodeSpace = new AttributeCodeSpace(); + private int currentAttributeCodePage; + private int currentTagCodePage; + private int publicIdentifier; + private StringTable stringTable = new StringTable(); + private TagCodeSpace tagCodeSpace = new EmptyCodeSpace(); + private Encoding textEncoding = Encoding.UTF8; + private double versionNumber; + + public double VersionNumber + { + get { return versionNumber; } + set { versionNumber = value; } + } + + public int PublicIdentifier + { + get { return publicIdentifier; } + set { publicIdentifier = value; } + } + + public Encoding Encoding + { + get { return textEncoding; } + set { textEncoding = value; } + } + + public TagCodeSpace TagCodeSpace + { + get { return tagCodeSpace; } + set { tagCodeSpace = value; } + } + + public AttributeCodeSpace AttributeCodeSpace + { + get { return attributeCodeSpace; } + set { attributeCodeSpace = value; } + } + + public StringTable StringTable + { + get { return stringTable; } + set { stringTable = value; } + } + + public List OpaqueDataExpressions + { + get { return opaqueDataExpressions; } + } + + public void LoadBytes(byte[] bytes) + { + DecodeWBXML(bytes); + } + + #region Decoder + + private void DecodeWBXML(byte[] bytes) + { + currentTagCodePage = 0; + currentAttributeCodePage = 0; + + bool isAttribute = false; + bool tagHasAttributes = false; + bool tagHasContent = false; + + XmlNode activeNode = this; + XmlAttribute activeAttribute = null; + + var byteQueue = new Queue(bytes); + + //Get the WBXML version number; + versionNumber = (byteQueue.Dequeue()/10.0) + 1.0; + + //Get the value of the public identifier + publicIdentifier = GetInt(byteQueue); + + if (publicIdentifier == 0) + { + //TODO the publicIdentifier is defined as string inside the stringtable + int publicIdentifierStringTableIndex = GetInt(byteQueue); + } + + //Get the charset for text encoding + textEncoding = IANACharacterSets.GetEncoding(GetInt(byteQueue)); + + XmlDeclaration declaration = CreateXmlDeclaration("1.0", textEncoding.WebName, null); + activeNode.AppendChild(declaration); + + //Get the string table (use of the string table is not implemented) + int stringTableLength = GetInt(byteQueue); + if (stringTableLength > 0) + { + var byteStringTableQueue = new Queue(); + for (int i = 0; i < stringTableLength; i++) + { + byteStringTableQueue.Enqueue(byteQueue.Dequeue()); + } + + var stringTableList = new List(); + + while (byteStringTableQueue.Count > 0) + { + string stringTableItem = GetString(byteStringTableQueue); + stringTableList.Add(stringTableItem); + } + + stringTable = new StringTable(stringTableList.ToArray()); + } + + //WBXML body + while (byteQueue.Count > 0) + { + byte byteItem = byteQueue.Dequeue(); + if (globalTokens.Contains(byteItem)) + { + GlobalTokens.Names globalToken = globalTokens.GetToken(byteItem); + switch (globalToken) + { + case GlobalTokens.Names.SWITCH_PAGE: + currentTagCodePage = byteQueue.Dequeue(); + break; + case GlobalTokens.Names.END: + if (isAttribute) + { + isAttribute = false; + activeAttribute = null; + + if (!tagHasContent) + { + activeNode = activeNode.ParentNode; + } + } + else + { + activeNode = activeNode.ParentNode; + } + break; + case GlobalTokens.Names.ENTITY: + //TODO ENTITY is not implemented yet + int entityLength = GetInt(byteQueue); + break; + case GlobalTokens.Names.STR_I: + if (isAttribute) + { + activeAttribute.InnerText += GetString(byteQueue); + } + else + { + activeNode.AppendChild(CreateTextNode(GetString(byteQueue))); + } + break; + case GlobalTokens.Names.LITERAL: + case GlobalTokens.Names.LITERAL_A: + case GlobalTokens.Names.LITERAL_AC: + case GlobalTokens.Names.LITERAL_C: + //TODO LITERALs are not implemented yet + int literalReference = GetInt(byteQueue); + break; + case GlobalTokens.Names.EXT_I_0: + case GlobalTokens.Names.EXT_I_1: + case GlobalTokens.Names.EXT_I_2: + //TODO EXT_I_x are not implemented yet + string extiString = GetString(byteQueue); + break; + case GlobalTokens.Names.PI: + //TODO PI is not implemented yet + var piByteList = new List(); + while (byteQueue.Peek() != (byte) GlobalTokens.Names.END) + { + piByteList.Add(byteQueue.Dequeue()); + } + byteQueue.Dequeue(); + break; + case GlobalTokens.Names.EXT_T_0: + case GlobalTokens.Names.EXT_T_1: + case GlobalTokens.Names.EXT_T_2: + //TODO EXT_T_x are not implemented yet + int exttReference = GetInt(byteQueue); + break; + case GlobalTokens.Names.STR_T: + int strtReference = GetInt(byteQueue); + if (stringTable.ContainsString(strtReference)) + { + StringTableItem stringTableItem = stringTable.GetString(strtReference); + if (isAttribute) + { + activeAttribute.InnerText += stringTableItem.Value; + } + else + { + activeNode.AppendChild(CreateTextNode(stringTableItem.Value)); + } + } + break; + case GlobalTokens.Names.EXT_0: + case GlobalTokens.Names.EXT_1: + case GlobalTokens.Names.EXT_2: + //TODO EXT_x are not implemented yet + break; + case GlobalTokens.Names.OPAQUE: + int opaqueLength = GetInt(byteQueue); + byte[] opaqueByteArray = GetByteArray(byteQueue, opaqueLength); + var opaqueHexList = new List(); + foreach (byte opaqueByteItem in opaqueByteArray) + { + opaqueHexList.Add(opaqueByteItem.ToString("X2")); + } + activeNode.InnerText = String.Join("", opaqueHexList.ToArray()); + break; + } + } + else if (!isAttribute) + { + tagHasAttributes = IsBitSet(byteItem, 7); + tagHasContent = IsBitSet(byteItem, 6); + + byteItem &= 127; + byteItem &= 63; + + string tagValue; + if (tagCodeSpace.GetCodePage(currentTagCodePage).ContainsTag(byteItem)) + { + tagValue = tagCodeSpace.GetCodePage(currentTagCodePage).GetTag(byteItem).Name; + } + else + { + tagValue = "Tag_" + byteItem.ToString("X2"); + } + + XmlElement xmlElement = CreateElement(tagValue); + activeNode.AppendChild(xmlElement); + if (tagHasContent || tagHasAttributes) + { + activeNode = xmlElement; + + if (tagHasAttributes) + { + isAttribute = true; + } + } + } + else + { + if (byteItem < 128) + { + if (attributeCodeSpace.GetCodePage(currentAttributeCodePage).ContainsAttributeStart(byteItem)) + { + AttributeStart attributeStart = + attributeCodeSpace.GetCodePage(currentAttributeCodePage).GetAttributeStart(byteItem); + XmlAttribute xmlAttribute = CreateAttribute(attributeStart.Name); + xmlAttribute.InnerText = attributeStart.Prefix; + activeNode.Attributes.Append(xmlAttribute); + + activeAttribute = xmlAttribute; + } + else + { + XmlAttribute xmlAttribute = CreateAttribute("attribute_" + byteItem.ToString("X2")); + activeNode.Attributes.Append(xmlAttribute); + + activeAttribute = xmlAttribute; + } + } + else + { + if (attributeCodeSpace.GetCodePage(currentAttributeCodePage).ContainsAttributeValue(byteItem)) + { + AttributeValue attributeValue = + attributeCodeSpace.GetCodePage(currentAttributeCodePage).GetAttributeValue(byteItem); + activeAttribute.InnerText += attributeValue.Value; + } + } + } + } + } + + #endregion + + #region Encoder + + public byte[] GetBytes() + { + currentTagCodePage = 0; + currentAttributeCodePage = 0; + + var bytesList = new List(); + + //Versionnumber + bytesList.Add((byte) ((int) ((versionNumber*10) - 10))); + + //Public identifier (currently implemented as unknown) + bytesList.AddRange(GetMultiByte(tagCodeSpace.GetPublicIdentifier())); + + //Encoding + bytesList.AddRange(GetMultiByte(IANACharacterSets.GetMIBEnum(textEncoding))); + + //String table length + int stringTableLength = stringTable.Length; + if (stringTableLength > 0) + { + bytesList.AddRange(GetMultiByte(stringTableLength)); + bytesList.AddRange(stringTable.GetStringTableBytes(textEncoding)); + } + else + { + bytesList.Add(0); + } + + bytesList.AddRange(EncodeNodes(ChildNodes)); + + return bytesList.ToArray(); + } + + private byte[] EncodeNodes(XmlNodeList nodes) + { + var bytesList = new List(); + + foreach (XmlNode node in nodes) + { + bytesList.AddRange(EncodeNode(node)); + } + + return bytesList.ToArray(); + } + + private byte[] EncodeNode(XmlNode node) + { + var bytesList = new List(); + + switch (node.NodeType) + { + case XmlNodeType.Element: + bool hasAttributes = node.Attributes.Count > 0; + bool hasContent = node.HasChildNodes; + int codePage = tagCodeSpace.ContainsTag(currentTagCodePage, node.Name); + if (codePage >= 0) + { + if (currentTagCodePage != codePage) + { + bytesList.Add((byte) GlobalTokens.Names.SWITCH_PAGE); + bytesList.Add((byte) codePage); + currentTagCodePage = codePage; + } + + byte keyValue = tagCodeSpace.GetCodePage(currentTagCodePage).GetTag(node.Name).Token; + if (hasAttributes) + { + keyValue |= 128; + } + if (hasContent) + { + keyValue |= 64; + } + bytesList.Add(keyValue); + } + else + { + // TODO: better exception type + throw new Exception("Unknown tag: " + node.Name); + } + + if (hasAttributes) + { + foreach (XmlAttribute attribute in node.Attributes) + { + bytesList.AddRange(EncodeNode(attribute)); + } + bytesList.Add((byte) GlobalTokens.Names.END); + } + + if (hasContent) + { + bytesList.AddRange(EncodeNodes(node.ChildNodes)); + bytesList.Add((byte) GlobalTokens.Names.END); + } + break; + case XmlNodeType.Text: + bool isOpaqueData = false; + + if (opaqueDataExpressions.Count > 0) + { + foreach (OpaqueDataExpression expression in OpaqueDataExpressions) + { + if (expression.TagName.Equals(node.ParentNode.Name)) + { + if (node.ParentNode.SelectSingleNode(expression.Expression) != null) + { + isOpaqueData = true; + break; + } + } + } + } + + if (isOpaqueData) + { + byte[] opaqueDataBytes = GetBytes(node.Value); + bytesList.Add((byte) GlobalTokens.Names.OPAQUE); + bytesList.AddRange(GetMultiByte(opaqueDataBytes.Length)); + bytesList.AddRange(opaqueDataBytes); + } + else + { + string textValue = node.Value; + + while (textValue.Length > 0) + { + int stringTableIndex = textValue.Length; + + if (stringTable.ContainsString(textValue)) + { + StringTableItem stringTableItem = stringTable.GetString(textValue); + stringTableIndex = textValue.IndexOf(stringTableItem.Value); + + if (stringTableIndex == 0) + { + bytesList.Add((byte) GlobalTokens.Names.STR_T); + bytesList.AddRange(GetMultiByte(stringTableItem.Index)); + textValue = textValue.Substring(stringTableItem.Value.Length); + continue; + } + } + + bytesList.Add((byte) GlobalTokens.Names.STR_I); + bytesList.AddRange(textEncoding.GetBytes(textValue.Substring(0, stringTableIndex))); + bytesList.Add(0); + + textValue = textValue.Substring(stringTableIndex); + } + } + break; + case XmlNodeType.EntityReference: + bytesList.Add((byte) GlobalTokens.Names.ENTITY); + var reference = (XmlEntityReference) node; + foreach (int stringItem in reference.InnerText.ToCharArray()) + { + bytesList.AddRange(GetMultiByte(stringItem)); + } + break; + case XmlNodeType.Attribute: + if (attributeCodeSpace.GetCodePage(currentAttributeCodePage).ContainsAttributeStart(node.Name, + node.Value)) + { + AttributeStart attributeStart = + attributeCodeSpace.GetCodePage(currentAttributeCodePage).GetAttributeStart(node.Name, + node.Value); + bytesList.Add(attributeStart.Token); + + string postAttributeValue = node.Value.Substring(attributeStart.Prefix.Length); + while (postAttributeValue.Length > 0) + { + int attrValueIndex = postAttributeValue.Length; + + if ( + attributeCodeSpace.GetCodePage(currentAttributeCodePage).ContainsAttributeValue( + postAttributeValue)) + { + AttributeValue attrValue = + attributeCodeSpace.GetCodePage(currentAttributeCodePage).GetAttributeValue( + postAttributeValue); + attrValueIndex = postAttributeValue.IndexOf(attrValue.Value); + + if (attrValueIndex == 0) + { + bytesList.Add(attrValue.Token); + postAttributeValue = postAttributeValue.Substring(attrValue.Value.Length); + continue; + } + } + + int stringTableIndex = postAttributeValue.Length; + + if (stringTable.ContainsString(postAttributeValue)) + { + StringTableItem stringTableItem = stringTable.GetString(postAttributeValue); + stringTableIndex = postAttributeValue.IndexOf(stringTableItem.Value); + + if (stringTableIndex == 0) + { + bytesList.Add((byte) GlobalTokens.Names.STR_T); + bytesList.AddRange(GetMultiByte(stringTableItem.Index)); + + postAttributeValue = postAttributeValue.Substring(stringTableItem.Value.Length); + continue; + } + } + + int firstReferenceIndex = Math.Min(attrValueIndex, stringTableIndex); + bytesList.Add((byte) GlobalTokens.Names.STR_I); + bytesList.AddRange( + textEncoding.GetBytes(postAttributeValue.Substring(0, firstReferenceIndex))); + bytesList.Add(0); + + postAttributeValue = postAttributeValue.Substring(firstReferenceIndex); + } + } + break; + } + + return bytesList.ToArray(); + } + + #endregion + + #region Util Methods + + private string GetString(Queue byteQueue) + { + var byteList = new List(); + while (byteQueue.Count > 0 && byteQueue.Peek() != 0) + { + byteList.Add(byteQueue.Dequeue()); + } + + if (byteQueue.Count > 0) + { + byteQueue.Dequeue(); + } + + return textEncoding.GetString(byteList.ToArray()); + } + + private string GetString(Queue byteQueue, int length) + { + var byteList = new List(); + for (int i = 0; i < length; i++) + { + byteList.Add(byteQueue.Dequeue()); + } + return textEncoding.GetString(byteList.ToArray()); + } + + private byte[] GetMultiByte(int multiByteValue) + { + if (multiByteValue == 0) + { + return new byte[] {0x00}; + } + else + { + var multiByteList = new List(); + + while (multiByteValue > 0) + { + int byteValue = 0; + for (int i = 0; i < 7; i++) + { + if (IsBitSet(multiByteValue, i)) + { + byteValue += (int) Math.Pow(2, i); + } + } + + if (multiByteList.Count > 0) + { + byteValue += 128; + } + + multiByteList.Insert(0, (byte) byteValue); + multiByteValue >>= 7; + } + + return multiByteList.ToArray(); + } + } + + private int GetInt(Queue byteQueue) + { + var multiByteList = new List(); + while (IsBitSet(byteQueue.Peek(), 7)) + { + byte byteItem = byteQueue.Dequeue(); + byteItem &= 127; + multiByteList.Add(byteItem); + } + + //Add the next byte because it is the last part of the multibyte + //(or even the only part of the multibyte) + multiByteList.Add(byteQueue.Dequeue()); + + int returnValue = 0; + for (int i = 0; i < multiByteList.Count; i++) + { + int byteValue = multiByteList[i]; + double power = 7*(multiByteList.Count - 1 - i); + returnValue += (int) (byteValue*Math.Pow(2, power)); + } + return returnValue; + } + + private byte[] GetByteArray(Queue messageQueue, int length) + { + var byteList = new List(); + for (int i = 0; i < length; i++) + { + byteList.Add(messageQueue.Dequeue()); + } + return byteList.ToArray(); + } + + private byte[] GetBytes(string messageValue) + { + var byteList = new List(); + if (messageValue == null || messageValue.Length%2 == 1) + { + return byteList.ToArray(); + } + + for (int i = 0; i < messageValue.Length/2; i++) + { + byteList.Add((byte) Int32.Parse(messageValue.Substring(i*2, 2), NumberStyles.HexNumber)); + } + + return byteList.ToArray(); + } + + private bool IsBitSet(int byteItem, int bitNumber) + { + return ((byteItem & (1 << bitNumber)) == Math.Pow(2, bitNumber)); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/AvailableFolder.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/AvailableFolder.cs new file mode 100644 index 0000000..aec344b --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/AvailableFolder.cs @@ -0,0 +1,110 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.ZPush.Connect.Soap; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.ZPush.API.SharedFolders +{ + /// + /// A folder that is available for sharing. + /// + public class AvailableFolder : ISoapSerializable + { + #region Soap serialisation + + /// + /// Data serialised over Soap. + /// + public struct SoapData + { + public SyncId ServerId; + public SyncId ParentId; + public string DisplayName; + public OutlookConstants.SyncType Type; + public BackendId BackendId; + + // TODO: are there ever flags on available folders? They are sent by the server + public ShareFlags Flags; + } + + private readonly SoapData _data; + + /// + /// Constructor for Soap deserialisation. FixupSoap must be invoked to finish setting up the object. + /// + public AvailableFolder(SoapData data) + { + this._data = data; + Children = new List(); + } + + /// + /// Fixes up data not serialised by soap. + /// + public void FixupSoap(AvailableFolder parent, GABUser store) + { + this.Parent = parent; + this.Store = store; + } + + public SoapData SoapSerialize() { return _data; } + + #endregion + + #region Ids and properties + + public SyncId ServerId { get { return _data.ServerId; } } + public SyncId ParentId { get { return _data.ParentId; } } + public BackendId BackendId { get { return _data.BackendId; } } + + public string Name { get { return _data.DisplayName; } } + public OutlookConstants.SyncType Type { get { return _data.Type; } } + + public GABUser Store { get; private set; } + + public bool IsMailFolder { get { return OutlookConstants.IsMailType(Type); } } + + #endregion + + #region Tree structure + + /// + /// The parent folder. Null for root folders. + /// + public AvailableFolder Parent { get; private set; } + + /// + /// The child folders. Empty collection if no children are present. + /// + public ICollection Children { get; private set; } + + #endregion + + #region Standard overrides + + public override string ToString() + { + return string.Format("AvailableFolder:{0} ({1})", ServerId, Name); + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFolder.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFolder.cs new file mode 100644 index 0000000..b4e2235 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFolder.cs @@ -0,0 +1,194 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.ZPush.Connect.Soap; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static Acacia.ZPush.API.SharedFolders.SharedFoldersAPI; + +namespace Acacia.ZPush.API.SharedFolders +{ + /// + /// A share on a folder. SharedFolder objects are immutable. To modify share information, + /// there are methods that return a new instance with a specific property set. This is largely + /// done to simplify management of shares in the dialog; changes can be detected by copying the + /// initial share information and comparing it against the current, without having to worry + /// about accidentally modifying the wrong object. + /// + public class SharedFolder : ISoapSerializable + { + #region Soap serialisation + + public struct SoapData + { + public string store; + public BackendId folderid; + public BackendId parentid; + public string name; + public OutlookConstants.SyncType type; + public ShareFlags flags; + public SyncId syncfolderid; + public string origin; + public bool readable; + public bool writeable; + + + override public bool Equals(object o) + { + if (!(o is SoapData)) + return false; + SoapData rhs = (SoapData)o; + + return + store == rhs.store && + folderid == rhs.folderid && + parentid == rhs.parentid && + name == rhs.name && + type == rhs.type && + flags == rhs.flags; + } + + public override int GetHashCode() + { + return (store + folderid + parentid + name + type + flags).GetHashCode(); + } + + } + + private SoapData _data; + + /// + /// Soap deserialization constructor + /// + public SharedFolder(SoapData data) + { + this._data = data; + } + + public SoapData SoapSerialize() + { + return _data; + } + + + #endregion + + #region Setup + + /// + /// Creates an instances for the specified folder. + /// + public SharedFolder(AvailableFolder folder) + { + _data = new SoapData() + { + store = folder.Store.UserName, + folderid = folder.BackendId, + parentid = folder.Parent?.BackendId ?? BackendId.NONE, + name = folder.Name, + type = OutlookConstants.USER_SYNC_TYPES[(int)folder.Type], + flags = folder.IsMailFolder ? ShareFlags.SendAsOwner : ShareFlags.None + }; + } + + #endregion + + #region Immutable properties and ids + + public GABUser Store { get { return new GABUser(_data.store); } } + public BackendId BackendId { get { return _data.folderid; } } + public SyncId SyncId { get { return _data.syncfolderid; } } + + public Permission Permissions + { + get + { + Permission p = Permission.None; + if (_data.readable) + p |= Permission.Read; + if (_data.writeable) + p |= Permission.Write; + return p; + } + } + + #endregion + + #region Name + + public string Name { get { return _data.name; } } + + /// + /// Returns a copy with the specified name. + /// + public SharedFolder WithName(string name) + { + SoapData newData = _data; + newData.name = name; + return new SharedFolder(newData); + } + + #endregion + + #region Flags + + public ShareFlags Flags { get { return _data.flags; } } + + /// + /// Returns a copy with the specified flags. + /// + public SharedFolder WithFlags(ShareFlags flags) + { + SoapData newData = _data; + newData.flags = flags; + return new SharedFolder(newData); + } + + public bool FlagSendAsOwner { get { return Flags.HasFlag(ShareFlags.SendAsOwner); } } + + /// + /// Returns a copy with the specified 'send as owner' flag. + /// + public SharedFolder WithFlagSendAsOwner(bool value) + { + return WithFlags(value ? (_data.flags | ShareFlags.SendAsOwner) : (_data.flags & ~ShareFlags.SendAsOwner)); + } + + #endregion + + #region Standard overrides + + public override int GetHashCode() + { + return _data.GetHashCode(); + } + + override public bool Equals(object o) + { + return o is SharedFolder && _data.Equals(((SharedFolder)o)._data); + } + + public override string ToString() + { + return string.Format("SharedFolder:{0} ({1})", SyncId, Name); + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFoldersAPI.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFoldersAPI.cs new file mode 100644 index 0000000..57f7295 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFoldersAPI.cs @@ -0,0 +1,152 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Utils; +using Acacia.ZPush; +using Acacia.ZPush.Connect; +using Acacia.ZPush.Connect.Soap; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Xml; + +namespace Acacia.ZPush.API.SharedFolders +{ + public class SharedFoldersAPI : IDisposable + { + #region Setup + + private readonly ZPushConnection _connection; + private readonly bool _dispose; + + /// + /// Creates an instance with a dedicated connection. + /// + /// The account which will be connected to + public SharedFoldersAPI(ZPushAccount account) : this(account.Connect(), true) { } + + /// + /// Creates an instance on an explicit connection. + /// + /// The connection. + /// Controls whether the connection will be disposed when the API is disposed. + public SharedFoldersAPI(ZPushConnection connection, bool dispose = false) + { + this._connection = connection; + this._dispose = dispose; + } + + public void Dispose() + { + if (_dispose) + { + _connection.Dispose(); + } + } + + #endregion + + #region GetUserFolders + + private class ListUserFoldersRequest : SoapRequest> + { + private readonly string _userName; + + public ListUserFoldersRequest(string userName) + { + this._userName = userName; + } + + public override string UserName { get { return _userName; } } + } + + public ICollection GetUserFolders(GABUser user) + { + using (ZPushWebServiceInfo infoService = _connection.InfoService) + { + // Fetch raw folder list + List folders = infoService.Execute(new ListUserFoldersRequest(user.UserName)); + + // Construct the tree + Dictionary foldersByServerId = folders.ToDictionary((x) => x.ServerId); + List rootNodes = new List(); + foreach (AvailableFolder folder in folders) + { + AvailableFolder parent; + + // Add to root nodes or parent + if (folder.ParentId.IsNone) + { + rootNodes.Add(folder); + parent = null; + } + else + { + if (!foldersByServerId.ContainsKey(folder.ParentId)) + throw new Exception("Missing parent folder: " + folder.ParentId); + parent = foldersByServerId[folder.ParentId]; + parent.Children.Add(folder); + } + + folder.FixupSoap(parent, user); + } + + // Return the root nodes + return rootNodes; + } + } + + #endregion + + #region Get/Set Current Shares + + private class AdditionalFolderListRequest : SoapRequest> + { + } + + public ICollection GetCurrentShares(CancellationToken? cancel = null) + { + using (ZPushWebServiceDevice deviceService = _connection.DeviceService) + { + // Fetch + return deviceService.Execute(new AdditionalFolderListRequest()); + } + } + + private class AdditionalFolderSetListRequest : SoapRequest + { + public AdditionalFolderSetListRequest(GABUser store, ICollection shares) + { + Parameters.Add("store", store.UserName); + Parameters.Add("folders", shares); + } + } + + public void SetCurrentShares(GABUser store, ICollection shares, CancellationToken? cancel = null) + { + using (ZPushWebServiceDevice deviceService = _connection.DeviceService) + { + deviceService.Execute(new AdditionalFolderSetListRequest(store, shares)); + } + } + + #endregion + + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/Types.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/Types.cs new file mode 100644 index 0000000..e602ce3 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/Types.cs @@ -0,0 +1,45 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.ZPush.API.SharedFolders +{ + /// + /// Options that are available on a share. + /// + [Flags] + public enum ShareFlags + { + None = 0, + SendAsOwner = 1, + } + + /// + /// Permissions on a share. + /// + public enum Permission + { + None = 0, + Read = 1, + Write = 2, + ReadWrite = 3 + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/ISoapSerializable.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/ISoapSerializable.cs new file mode 100644 index 0000000..0f3e384 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/ISoapSerializable.cs @@ -0,0 +1,35 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.ZPush.Connect.Soap +{ + /// + /// Base class for SOAP serializable classes. Classes implementing this interface must also provide a constructor + /// accepting SerializableType for deserialization. + /// + /// The type used for serialization. This can be Dictionary<string, objecct>, + /// or any structure type + public interface ISoapSerializable + { + SerializableType SoapSerialize(); + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapConstants.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapConstants.cs new file mode 100644 index 0000000..88782a0 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapConstants.cs @@ -0,0 +1,32 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.ZPush.Connect.Soap +{ + public class SoapConstants + { + public const string XMLNS_XSI = "http://www.w3.org/2001/XMLSchema-instance"; + public const string XMLNS_XSD = "http://www.w3.org/2001/XMLSchema"; + public const string XMLNS_SOAP_ENC = "http://schemas.xmlsoap.org/soap/encoding/"; + public const string XMLNS_APACHE = "http://xml.apache.org/xml-soap"; + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapException.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapException.cs new file mode 100644 index 0000000..4d33c11 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapException.cs @@ -0,0 +1,29 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.ZPush.Connect.Soap +{ + public class SoapException : Exception + { + public SoapException(string message) : base(message) { } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapParameters.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapParameters.cs new file mode 100644 index 0000000..838bc12 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapParameters.cs @@ -0,0 +1,56 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.ZPush.Connect.Soap +{ + public class SoapParameters + { + private Dictionary values = new Dictionary(); + + public SoapParameters() + { + + } + + public SoapParameters(SoapParameters p1, SoapParameters p2) + { + foreach (var entry in p1.values) + values.Add(entry.Key, entry.Value); + foreach (var entry in p2.values) + values.Add(entry.Key, entry.Value); + } + + public void Add(string name, object value) + { + values.Add(name, value); + } + + internal void Serialize(StringBuilder s) + { + foreach (KeyValuePair param in values) + { + SoapSerializer.Serialize(param.Key, param.Value, s); + } + } + } + +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapRequest.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapRequest.cs new file mode 100644 index 0000000..45b9564 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapRequest.cs @@ -0,0 +1,62 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; + +namespace Acacia.ZPush.Connect.Soap +{ + /// + /// Abstract non-generic base for Soap requests. Used by the encoder to handle the parts that are not specific to the request + /// + public abstract class SoapRequestBase + { + virtual public string RequestName + { + get { return this.GetType().Name.StripSuffix("Request"); } + } + + public SoapParameters Parameters { get; protected set; } + + abstract public object ParseResponse(XmlNode part); + }; + + /// + /// Base class for a Soap request. + /// + /// + /// The type of response that is expected. Specify DBNull for void. + /// + abstract public class SoapRequest : SoapRequestBase + { + protected SoapRequest() + { + Parameters = new SoapParameters(); + } + + public override object ParseResponse(XmlNode part) + { + return SoapSerializer.Deserialize(part, typeof(ResponseType)); + } + + virtual public string UserName { get { return null; } } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapRequestEncoder.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapRequestEncoder.cs new file mode 100644 index 0000000..233ed82 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapRequestEncoder.cs @@ -0,0 +1,116 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading.Tasks; +using System.Xml; + +namespace Acacia.ZPush.Connect.Soap +{ + public class SoapRequestEncoder : RequestEncoder + { + private readonly string _xmlns; + private readonly SoapRequestBase _request; + private readonly SoapParameters _parameters; + + public SoapRequestEncoder(string xmlns, SoapParameters serviceParameters, SoapRequestBase request) + { + this._xmlns = xmlns; + this._request = request; + + if (serviceParameters != null) + { + _parameters = new SoapParameters(serviceParameters, request.Parameters); + } + else + { + _parameters = request.Parameters; + } + } + + public string ServiceName { get; set; } + + #region Encoding + + private const string PREFIX = @" + + + <{0}> +"; + private const string SUFFIX = @" + + +"; + + public override HttpContent GetContent() + { + StringBuilder s = new StringBuilder(); + s.Append(string.Format(PREFIX, _request.RequestName, _xmlns)); + _parameters.Serialize(s); + + s.Append(string.Format(SUFFIX, _request.RequestName)); + + ByteArrayContent content = new ByteArrayContent(Encoding.UTF8.GetBytes(s.ToString())); + content.Headers.ContentType = new MediaTypeHeaderValue("text/xml"); + return content; + } + + #endregion + + #region Decoding + + public override object ParseResponse(Stream result) + { + // Parse xml + XmlDocument xml = new XmlDocument(); + xml.Load(result); + + // Check if it's an error message + CheckFaultResponse(xml); + + // Select the respone data + // TODO: do this with proper xmlns + XmlNode part = xml.SelectSingleNode("//*[local-name()='" + _request.RequestName + "Response']/return"); + + // Let the request handle it + return _request.ParseResponse(part); + } + + private void CheckFaultResponse(XmlNode response) + { + XmlNode fault = response?.SelectSingleNode("//*[local-name()='Fault']"); + if (response == null || fault != null) + { + string message = fault?.SelectSingleNode("faultstring")?.InnerText; + throw new SoapException(message); + } + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapSerializer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapSerializer.cs new file mode 100644 index 0000000..114a1c1 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapSerializer.cs @@ -0,0 +1,439 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Xml; + +namespace Acacia.ZPush.Connect.Soap +{ + public class SoapSerializer + { + public static object Deserialize(XmlNode part, Type expectedType) + { + if (expectedType == null) + throw new ArgumentException("expectedType is null"); + + return DeserializeNode(part, expectedType); + } + + public static void Serialize(string name, object value, StringBuilder s) + { + if (value == null) + { + s.Append(string.Format("<{0} xsi:nil=\"true\"/>", name)); + } + else + { + // Type-specific parsing + // Try simple types first + TypeHandler handler = LookupType(value.GetType()); + if (handler != null) + { + handler.Serialize(name, value, s); + return; + } + + // Check if serializable + if (typeof(ISoapSerializable<>).IsGenericAssignableFrom(value.GetType())) + { + Type bound = typeof(ISoapSerializable<>).MakeGenericType(value.GetType().GetGenericArguments(typeof(ISoapSerializable<>))); + MethodInfo method = bound.GetMethod("SoapSerialize"); + object serializable = method.Invoke(value, new object[0]); + Serialize(name, serializable, s); + return; + } + + // Enums + if (value.GetType().IsEnum) + { + Serialize(name, (int)value, s); + return; + } + + // Serialize as structure + TYPE_HANDLER_OBJECT.Serialize(name, value, s); + } + } + + private static object DeserializeNode(XmlNode part, Type expectedType) + { + // Check for null + if (part.Attributes["nil", SoapConstants.XMLNS_XSI] != null) + return null; + + // Type-specific parsing + TypeHandler type = LookupType(part); + return type.Deserialize(part, expectedType); + } + + #region Builtin types + + private abstract class TypeHandler + { + public string FullName + { + get { return _xmlns + ":" + _name; } + } + + public Type HandlesType { get { return _baseType; } } + + private readonly string _xmlns; + private readonly string _name; + private readonly Type _baseType; + + protected TypeHandler(string xmlns, string name, Type baseType) + { + this._xmlns = xmlns; + this._name = name; + this._baseType = baseType; + } + + public object Deserialize(XmlNode node, Type expectedType) + { + if (expectedType != null && _baseType != null) + { + // Check if the expected type matches the type + if (!_baseType.IsAssignableFrom(expectedType)) + throw new InvalidOperationException("Expected " + expectedType + ", found " + _baseType); + } + + object value = DeserializeContents(node, expectedType); + + if (expectedType != null) + { + // Check if it's the expected type + return expectedType.Cast(value); + } + + return value; + } + + abstract protected object DeserializeContents(XmlNode node, Type expectedType); + + abstract public void Serialize(string name, object value, StringBuilder s); + } + + #region Primitives + + private class TypeHandlerBoolean : TypeHandler + { + public TypeHandlerBoolean() : base(SoapConstants.XMLNS_XSD, "boolean", typeof(bool)) { } + + public override void Serialize(string name, object value, StringBuilder s) + { + s.Append(string.Format("<{0} xsi:type=\"xsd:boolean\">{1}", name, value)); + } + + protected override object DeserializeContents(XmlNode node, Type expectedType) + { + return node.InnerText.ToLower().Equals("true"); + } + } + private class TypeHandlerInt : TypeHandler + { + public TypeHandlerInt() : base(SoapConstants.XMLNS_XSD, "int", typeof(int)) { } + + public override void Serialize(string name, object value, StringBuilder s) + { + s.Append(string.Format("<{0} xsi:type=\"xsd:int\">{1}", name, value)); + } + + protected override object DeserializeContents(XmlNode node, Type expectedType) + { + return int.Parse(node.InnerText); + } + } + + private class TypeHandlerString : TypeHandler + { + public TypeHandlerString() : base(SoapConstants.XMLNS_XSD, "string", typeof(string)) { } + + public override void Serialize(string name, object value, StringBuilder s) + { + // TODO: this needs escaping + s.Append(string.Format("<{0} xsi:type=\"xsd:string\">{1}", name, value)); + } + + protected override object DeserializeContents(XmlNode node, Type expectedType) + { + return node.InnerText; + } + } + + #endregion + + #region List + + private class TypeHandlerList : TypeHandler + { + public TypeHandlerList() : base(SoapConstants.XMLNS_SOAP_ENC, "Array", typeof(System.Collections.ICollection)) { } + + protected override object DeserializeContents(XmlNode node, Type expectedType) + { + // Create a list instance + System.Collections.IList list = (System.Collections.IList)Activator.CreateInstance(expectedType); + Type entryType = expectedType.GetGenericArguments()[0]; + + foreach (XmlNode child in node.ChildNodes) + { + object element = DeserializeNode(child, entryType); + list.Add(element); + } + + return list; + } + + public override void Serialize(string name, object value, StringBuilder s) + { + System.Collections.ICollection list = (System.Collections.ICollection)value; + s.Append(string.Format("<{0} xsi:type=\"soap-enc:Array\" soap-enc:arrayType=\"ns2:Map[{1}]\">\n", name, list.Count)); + foreach (object element in list) + { + SoapSerializer.Serialize("item", element, s); + } + s.Append(string.Format("\n", name)); + } + } + + #endregion + + #region Objects + + private abstract class TypeHandlerObject : TypeHandler + { + + public TypeHandlerObject(string xmlns, string name) : base(xmlns, name, null) + { + + } + + protected override object DeserializeContents(XmlNode node, Type expectedType) + { + // Determine if the expected type is an ISoapSerializable + if (!typeof(ISoapSerializable<>).IsGenericAssignableFrom(expectedType)) + throw new InvalidOperationException("Cannot parse type " + expectedType); + + // Get the serialization type + Type serializationType = expectedType.GetGenericArguments(typeof(ISoapSerializable<>))[0]; + + // Get the values as a dictionary + Dictionary values = new Dictionary(); + DeserializeMembers(node, serializationType, values); + + // Create the object + return CreateCustomInstance(values, serializationType, expectedType); + } + + abstract protected void DeserializeMembers(XmlNode node, Type serializationType, Dictionary values); + + private object CreateCustomInstance(Dictionary node, Type serializationType, Type finalType) + { + object instance; + if (serializationType == typeof(Dictionary)) + { + instance = node; + } + else + { + // Initialise the serialization type + instance = Activator.CreateInstance(serializationType); + foreach (FieldInfo field in serializationType.GetFields()) + { + object value = null; + if (node.TryGetValue(field.Name.ToLower(), out value)) + { + value = SoapConvert(field.FieldType, value); + field.SetValue(instance, value); + } + } + } + + // Return the final type + return Activator.CreateInstance(finalType, instance); + } + + private object SoapConvert(Type type, object value) + { + // Check if any conversion is needed + if (value != null && type.IsAssignableFrom(value.GetType())) + return value; + + if (value != null) + { + // Try Soap conversion + if (typeof(ISoapSerializable<>).IsGenericAssignableFrom(type)) + { + // Get the serialization type + Type serializationType = type.GetGenericArguments(typeof(ISoapSerializable<>))[0]; + if (serializationType.IsAssignableFrom(value.GetType())) + { + // Create the instance + return Activator.CreateInstance(type, value); + } + } + } + + // Or standard conversions + return type.Convert(value); + } + + public override void Serialize(string name, object value, StringBuilder s) + { + Dictionary dict; + if (typeof(Dictionary).IsAssignableFrom(value.GetType())) + { + dict = (Dictionary < string, object> )value; + } + else + { + // Convert toe dictionary + dict = new Dictionary(); + foreach (FieldInfo field in value.GetType().GetFields()) + { + object fieldValue = field.GetValue(value); + dict.Add(field.Name, fieldValue); + } + } + + // Encode + SerializeMembers(name, dict, s); + } + + protected abstract void SerializeMembers(string name, Dictionary fields, StringBuilder s); + } + + private class TypeHandlerStruct : TypeHandlerObject + { + public TypeHandlerStruct() : base(SoapConstants.XMLNS_SOAP_ENC, "Struct") + { + + } + + protected override void DeserializeMembers(XmlNode node, Type expectedType, Dictionary dict) + { + foreach (XmlNode child in node.ChildNodes) + { + string key = child.Name.ToLower(); + object value = DeserializeNode(child, null); + dict.Add(key, value); + } + } + + protected override void SerializeMembers(string name, Dictionary fields, StringBuilder s) + { + throw new NotImplementedException(); + } + } + + + private class TypeHandlerMap : TypeHandlerObject + { + public TypeHandlerMap() : base(SoapConstants.XMLNS_APACHE, "Map") + { + + } + + protected override void DeserializeMembers(XmlNode node, Type expectedType, Dictionary dict) + { + foreach (XmlNode child in node.ChildNodes) + { + string key = (string)DeserializeNode(child.SelectSingleNode("key"), typeof(string)); + object value = DeserializeNode(child.SelectSingleNode("value"), null); + dict.Add(key, value); + } + } + + protected override void SerializeMembers(string name, Dictionary fields, StringBuilder s) + { + s.Append(string.Format("<{0} xsi:type=\"ns2:Map\">\n", name)); + foreach (var entry in fields) + { + s.Append("").Append(entry.Key).Append(""); + SoapSerializer.Serialize("value", entry.Value, s); + s.Append("\n"); + } + s.Append(string.Format("\n", name)); + } + } + + #endregion + + + private readonly static Dictionary TYPES_BY_FULL_NAME = new Dictionary(); + private readonly static Dictionary TYPES_BY_TYPE = new Dictionary(); + private readonly static TypeHandler TYPE_HANDLER_OBJECT = new TypeHandlerMap(); + + static SoapSerializer() + { + RegisterTypeHandler(new TypeHandlerBoolean()); + RegisterTypeHandler(new TypeHandlerInt()); + RegisterTypeHandler(new TypeHandlerString()); + RegisterTypeHandler(new TypeHandlerList()); + RegisterTypeHandler(new TypeHandlerStruct()); + RegisterTypeHandler(TYPE_HANDLER_OBJECT); + } + + private static void RegisterTypeHandler(TypeHandler type) + { + TYPES_BY_FULL_NAME.Add(type.FullName, type); + if (type.HandlesType != null) + TYPES_BY_TYPE.Add(type.HandlesType, type); + } + + private static TypeHandler LookupType(Type type) + { + TypeHandler handler; + + // Check exact type first + if (TYPES_BY_TYPE.TryGetValue(type, out handler)) + return handler; + + // Try subtypes + foreach (KeyValuePair entry in TYPES_BY_TYPE) + if (entry.Key.IsAssignableFrom(type)) + return entry.Value; + + return null; + } + + private static TypeHandler LookupType(XmlNode part) + { + XmlAttribute typeAttr = part.Attributes["type", SoapConstants.XMLNS_XSI]; + if (typeAttr == null) + throw new Exception("Missing type"); + string value = typeAttr.Value; + string[] parts = value.Split(new char[] { ':' }, 2); + string fullName; + if (parts.Length == 1) + fullName = parts[0]; + else + fullName = part.GetNamespaceOfPrefix(parts[0]) + ":" + parts[1]; + + TypeHandler type; + if (!TYPES_BY_FULL_NAME.TryGetValue(fullName, out type)) + throw new Exception("Unknown type: " + fullName); + return type; + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/ZPushConnection.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/ZPushConnection.cs new file mode 100644 index 0000000..e527ed8 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/ZPushConnection.cs @@ -0,0 +1,320 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.ZPush.Connect.Soap; +using Acacia.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using Acacia.ZPush.Connect; +using Acacia.WBXML; +using Acacia.Stubs.OutlookWrappers; +using System.Text.RegularExpressions; +using Acacia.WBXML.ActiveSync; +using System.Security; + +namespace Acacia.ZPush.Connect +{ + /// + /// A connection to a ZPush server. + /// + public class ZPushConnection : IDisposable + { + #region SSL Error Handling + + static ZPushConnection() + { + ServicePointManager.ServerCertificateValidationCallback = HandleCertificateError; + } + + private static readonly Dictionary _allowCertificateErrors = new Dictionary(); + private static bool HandleCertificateError(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + if (sslPolicyErrors == SslPolicyErrors.None) + return true; + + HttpWebRequest request = sender as HttpWebRequest; + if (request == null) + return false; + + bool allow = false; + if (!_allowCertificateErrors.TryGetValue(request.Host, out allow)) + { + ThisAddIn.Instance.InvokeUI(() => + { + allow = MessageBox.Show( + string.Format(Properties.Resources.SSLFailed_Body, request.Host), + Properties.Resources.SSLFailed_Title, + MessageBoxButtons.YesNo, + MessageBoxIcon.Error + ) == DialogResult.Yes; + }); + _allowCertificateErrors.Add(request.Host, allow); + } + + return allow; + } + + #endregion + + #region Setup + + private readonly ZPushAccount _account; + private readonly CancellationToken? _cancel; + + public ZPushConnection(ZPushAccount account, CancellationToken? cancel) + { + if (account == null) + throw new ArgumentException("account cannot be null"); + this._account = account; + this._cancel = cancel; + } + + public void Dispose() + { + } + + public ZPushAccount Account { get { return _account; } } + + #endregion + + #region Web Services + + public ZPushWebServiceInfo InfoService + { + get + { + return new ZPushWebServiceInfo(this); + } + } + + public ZPushWebServiceDevice DeviceService + { + get + { + return new ZPushWebServiceDevice(this); + } + } + + #endregion + + #region Requests + + public object Execute(string url, RequestEncoder request) + { + // TODO: when other use of InitRequestHeader is removed, it can be merged here + using (HttpClient _client = CreateClient(_account)) + { + // Content + using (HttpContent content = request.GetContent()) + using (HttpResponseMessage response = _client.PostAsync(url, content, _cancel ?? CancellationToken.None).Result) + using (HttpContent responseContent = response.Content) + { + Logger.Instance.Debug(this, "Response: {0}", responseContent.ReadAsStringAsync().Result); + return request.ParseResponse(responseContent.ReadAsStreamAsync().Result); + } + } + } + + private static HttpClient CreateClient(ZPushAccount _account) + { + HttpClient _client = new HttpClient(); + + // Set up the authorization header + // TODO: it would be nice to let the system handle the SecureString for the password. However, + // when specifying credentials for an HttpClient, they are only used after a 401 is received + // on the first request, basically doubling the number of requests. + using (SecureString pass = _account.Password) + { + var byteArray = Encoding.UTF8.GetBytes(_account.UserName + ":" + pass.ConvertToUnsecureString()); + var header = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray)); + _client.DefaultRequestHeaders.Authorization = header; + } + + // Client information + string pluginInfo = string.Format("{0}/{1}/{2}", + BuildVersions.VERSION, BuildVersions.REVISION, LibUtils.BuildTime.ToString(Constants.DATE_ISO_8601)); + _client.DefaultRequestHeaders.Add(Constants.ZPUSH_HEADER_PLUGIN, pluginInfo); + + // Other headers + // TODO: only for activesync + _client.DefaultRequestHeaders.Add("MS-ASProtocolVersion", "14.0"); + _client.DefaultRequestHeaders.Add("Accept", "*/*"); + + return _client; + } + + #endregion + + #region ActiveSync + // TODO: this needs an update to using Soap-style request handling + + public class Response : IDisposable + { + public bool Success + { + get; + private set; + } + + public WBXMLDocument Body + { + get; + private set; + } + + public string GABName + { + get; + private set; + } + + public ZPushCapabilities Capabilities + { + get; + private set; + } + + public string ZPushVersion + { + get; + private set; + } + + private string GetStringHeader(HttpResponseMessage response, string name) + { + IEnumerable values; + if (!response.Headers.TryGetValues(name, out values)) + return null; + + return string.Join("", values); + } + + public Response(HttpResponseMessage response) + { + Logger.Instance.Trace(this, "Response received: {0} {1}\n{2}", (int)response.StatusCode, response.ReasonPhrase, response.Headers); + + // Check for ZPush headers + // GAB name is now hex encoded, but also support old-style for transition + string gabNameOrig = GetStringHeader(response, Constants.ZPUSH_HEADER_GAB_NAME); + if (gabNameOrig != null && new Regex("^[0-9a-fA-F]+$").IsMatch(gabNameOrig)) + GABName = StringUtil.HexToUtf8(gabNameOrig); + else + GABName = gabNameOrig; + + Capabilities = ZPushCapabilities.Parse(GetStringHeader(response, Constants.ZPUSH_HEADER_CAPABILITIES)); + ZPushVersion = GetStringHeader(response, Constants.ZPUSH_HEADER_VERSION); + + // Check for success + Success = response.IsSuccessStatusCode; + if (Success) + { + // Parse the body + using (HttpContent responseContent = response.Content) + { + byte[] result = responseContent.ReadAsByteArrayAsync().Result; + Body = new WBXMLDocument(); + Body.VersionNumber = 1.3; + Body.TagCodeSpace = new ActiveSyncCodeSpace(); + Body.Encoding = Encoding.UTF8; + Body.LoadBytes(result); + } + } + + Logger.Instance.Trace(this, "Response parsed: {0}", Body == null ? "Failure" : Body.ToXMLString()); + } + + public void Dispose() + { + } + } + + private class Request : DisposableWrapper + { + private const string ACTIVESYNC_URL = "https://{0}/Microsoft-Server-ActiveSync?DeviceId={1}&Cmd={2}&User={3}&DeviceType={4}"; + + private readonly ZPushAccount _account; + private readonly CancellationToken _cancel; + private HttpClient _client; + + public Request(ZPushAccount account, CancellationToken cancel) + { + this._account = account; + this._cancel = cancel; + this._client = CreateClient(account); + } + + protected override void DoRelease() + { + if (_client != null) + { + _client.Dispose(); + _client = null; + } + } + + public Response Execute(ActiveSync.RequestBase request) + { + string url = string.Format(ACTIVESYNC_URL, _account.ServerURL, _account.DeviceId, + request.Command, _account.UserName, "WindowsOutlook"); + + // Parse the body + WBXMLDocument doc = new WBXMLDocument(); + doc.LoadXml(request.Body); + doc.VersionNumber = 1.3; + doc.TagCodeSpace = new ActiveSyncCodeSpace(); + doc.Encoding = Encoding.UTF8; + byte[] contentBody = doc.GetBytes(); + + using (HttpContent content = new ByteArrayContent(contentBody)) + { + Logger.Instance.Trace(this, "Sending request: {0} -> {1}", _account.ServerURL, doc.ToXMLString()); + content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.ms-sync.wbxml"); + using (HttpResponseMessage response = _client.PostAsync(url, content, _cancel).Result) + { + return new Response(response); + } + } + } + } + + public ResponseType Execute(ActiveSync.Request request) + where ResponseType : ActiveSync.Response, new() + { + using (Request requestMessage = new Request(_account, _cancel ?? CancellationToken.None)) + { + using (Response response = requestMessage.Execute(request)) + { + ResponseType typed = new ResponseType(); + typed.ParseResponse(request, response); + return typed; + } + } + } + + #endregion + } + +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/ZPushRequestEncoder.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/ZPushRequestEncoder.cs new file mode 100644 index 0000000..aa650e6 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/ZPushRequestEncoder.cs @@ -0,0 +1,33 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.ZPush.Connect +{ + public abstract class RequestEncoder + { + public abstract HttpContent GetContent(); + + public abstract object ParseResponse(Stream result); + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/ZPushWebService.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/ZPushWebService.cs new file mode 100644 index 0000000..8110c4a --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/ZPushWebService.cs @@ -0,0 +1,93 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.ZPush.Connect.Soap; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Xml; + +namespace Acacia.ZPush.Connect +{ + abstract public class ZPushWebService : IDisposable + { + protected readonly ZPushConnection _connection; + + public ZPushWebService(ZPushConnection connection) + { + this._connection = connection; + } + + public void Dispose() + { + + } + + protected abstract string ServiceName { get; } + + private const string ACTIVESYNC_URL = "https://{0}/Microsoft-Server-ActiveSync?DeviceId={1}&Cmd={2}&User={3}&DeviceType={4}"; + + public ResponseType Execute(SoapRequest request) + { + // Create the url + string url = string.Format(ACTIVESYNC_URL, _connection.Account.ServerURL, "webservice", + ServiceName, + // TODO: this username is a bit of a quick hack. + request.UserName ?? _connection.Account.UserName, + "webservice"); + + // Set up the encoding + SoapRequestEncoder encoder = new SoapRequestEncoder(_connection.Account.ServerURL, ServiceParameters, request); + encoder.ServiceName = ServiceName; + + // Execute the request + return (ResponseType) _connection.Execute(url, encoder); + } + + virtual protected SoapParameters ServiceParameters { get { return null; } } + } + + public class ZPushWebServiceInfo : ZPushWebService + { + protected override string ServiceName { get { return "WebserviceInfo"; } } + + public ZPushWebServiceInfo(ZPushConnection connection) : base(connection) + { + } + } + + public class ZPushWebServiceDevice : ZPushWebService + { + protected override string ServiceName { get { return "WebserviceDevice"; } } + + public ZPushWebServiceDevice(ZPushConnection connection) : base(connection) + { + } + + override protected SoapParameters ServiceParameters + { + get + { + SoapParameters parameters = new SoapParameters(); + parameters.Add("devid", _connection.Account.DeviceId.ToLower()); + return parameters; + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Delegates.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Delegates.cs new file mode 100644 index 0000000..d3eede1 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Delegates.cs @@ -0,0 +1,31 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Stubs; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.ZPush +{ + public delegate void ItemEventHandler(IItem item); + public delegate void TypedItemEventHandler(TypedItem item) + where TypedItem : IItem; + + public delegate void FolderEventHandler(IFolder folder); +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/FolderRegistration.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/FolderRegistration.cs new file mode 100644 index 0000000..402b985 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/FolderRegistration.cs @@ -0,0 +1,61 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Features; +using Acacia.Stubs; +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.ZPush +{ + public abstract class FolderRegistration + { + public readonly Feature Feature; + + protected FolderRegistration(Feature feature) + { + this.Feature = feature; + } + + abstract public bool IsApplicable(IFolder folder); + } + + public class FolderRegistrationTyped : FolderRegistration + { + private readonly ItemType _itemType; + + public FolderRegistrationTyped(Feature feature, ItemType itemType) + : + base(feature) + { + this._itemType = itemType; + } + + public override bool IsApplicable(IFolder folder) + { + return folder.ItemType == _itemType; + } + + public override string ToString() + { + return Feature.Name + ":" + _itemType.ToString(); + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/GABUser.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/GABUser.cs new file mode 100644 index 0000000..f269e45 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/GABUser.cs @@ -0,0 +1,100 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.ZPush +{ + public class GABUser : IComparable + { + public static readonly GABUser USER_PUBLIC = new GABUser(Properties.Resources.SharedFolders_PublicFolders, "SYSTEM"); + + public static string MapPublicName(string name) + { + // Bit of a hack to show public folders under the right group + if (name == USER_PUBLIC.UserName) + name = USER_PUBLIC.FullName; + return name; + } + + public readonly string FullName; + public readonly string UserName; + + public GABUser(string displayName, string userName) + { + this.FullName = displayName; + this.UserName = userName; + } + + public GABUser(string userName) + { + this.FullName = userName; + this.UserName = userName; + } + + public int CompareTo(GABUser other) + { + return FullName.CompareTo(other.FullName); + } + + public string DisplayName + { + get + { + if (this.Equals(USER_PUBLIC) || !HasFullName) + return FullName; + return FullName + " (" + UserName + ")"; + } + } + + public bool HasFullName + { + get { return !FullName.Equals(UserName); } + } + + public string PublicName + { + get + { + if (UserName.Equals(USER_PUBLIC.UserName)) + return USER_PUBLIC.FullName; + return UserName; + } + } + + public override bool Equals(object obj) + { + if (obj is GABUser) + return UserName.Equals(((GABUser)obj).UserName); + return false; + } + + public override int GetHashCode() + { + return UserName.GetHashCode(); + } + + public override string ToString() + { + return DisplayName; + } + } + +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ItemsWatcher.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ItemsWatcher.cs new file mode 100644 index 0000000..70ea154 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ItemsWatcher.cs @@ -0,0 +1,46 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Acacia.Stubs; + +namespace Acacia.ZPush +{ + class ItemsWatcher + { + public event ItemEventHandler ItemEvent; + + internal ItemsWatcher() + { + } + + internal void OnItemAdd(ZPushFolder zPushFolder, IItem item) + { + if (ItemEvent != null) + ItemEvent(item); + } + + internal void OnItemChange(ZPushFolder zPushFolder, IItem item) + { + if (ItemEvent != null) + ItemEvent(item); + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs new file mode 100644 index 0000000..3e70eac --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs @@ -0,0 +1,297 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Stubs; +using Acacia.Utils; +using Acacia.ZPush.Connect; +using Microsoft.Office.Interop.Outlook; +using Microsoft.Win32; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Security; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Acacia.ZPush +{ + [TypeConverter(typeof(ExpandableObjectConverter))] + public class ZPushAccount : LogContext + { + #region Miscellaneous + + private readonly string _regPath; + private readonly Store _store; + + /// + /// Constructor. + /// + /// They registry key containing the account settings. + /// The store this account represents. + internal ZPushAccount(string regPath, Store store) + { + this._regPath = regPath; + this._store = store; + + // Cache the SmtpAddress, it is used as the key + SmtpAddress = RegistryUtil.GetValueString(_regPath, OutlookConstants.REG_VAL_EMAIL, null); + } + + [Browsable(false)] + public string LogContextId + { + get + { + return "ZPushAccount(" + SmtpAddress + ")"; + } + } + + public override string ToString() + { + return SmtpAddress; + } + + /// + /// Triggers an Outlook send/receive operation. + /// + public void SendReceive() + { + ThisAddIn.Instance.Application.Session.SendAndReceive(false); + } + + #endregion + + #region Properties + + [Browsable(false)] + public Store Store + { + get + { + return _store; + } + } + + public string DisplayName + { + get + { + return RegistryUtil.GetValueString(_regPath, OutlookConstants.REG_VAL_DISPLAYNAME, null); + } + } + + public string SmtpAddress + { + get; + private set; + } + + public string UserName + { + get + { + return RegistryUtil.GetValueString(_regPath, OutlookConstants.REG_VAL_EAS_USERNAME, null); + } + } + + public string ServerURL + { + get + { + return RegistryUtil.GetValueString(_regPath, OutlookConstants.REG_VAL_EAS_SERVER, null); + } + } + + public string DeviceId + { + get + { + return RegistryUtil.GetValueString(_regPath, OutlookConstants.REG_VAL_EAS_DEVICEID, null); + } + } + + [Browsable(false)] + public SecureString Password + { + get + { + byte[] encrypted = (byte[])Registry.GetValue(_regPath, OutlookConstants.REG_VAL_EAS_PASSWORD, null); + return PasswordEncryption.Decrypt(encrypted); + } + } + + public string StoreID + { + get { return GetStoreId(_regPath); } + } + + public static string GetStoreId(string regPath) + { + return StringUtil.BytesToHex((byte[])Registry.GetValue(regPath, OutlookConstants.REG_VAL_EAS_STOREID, null)); + } + + public string DomainName + { + get + { + int index = SmtpAddress.IndexOf('@'); + if (index < 0) + return SmtpAddress; + else + return SmtpAddress.Substring(index + 1); + } + } + + #endregion + + #region Identification and capabilities + + public enum ConfirmationType + { + Unknown, + IsZPush, + IsNotZPush + } + + public ConfirmationType Confirmed + { + get; + private set; + } + + public delegate void ConfirmationHandler(ZPushAccount account); + + private ConfirmationHandler _confirmedChanged; + public event ConfirmationHandler ConfirmedChanged + { + add + { + _confirmedChanged += value; + if (Confirmed != ConfirmationType.Unknown) + value(this); + } + + remove + { + _confirmedChanged -= value; + } + } + + public ZPushCapabilities Capabilities + { + get; + private set; + } + + public string GABFolder + { + get; + private set; + } + + public string GABFolderLinked + { + get; + private set; + } + + public string ZPushVersion + { + get; + private set; + } + + public void LinkedGABFolder(IFolder folder) + { + GABFolderLinked = folder.EntryId; + } + + internal void OnConfirmationResponse(ZPushConnection.Response response) + { + Capabilities = response.Capabilities; + GABFolder = response.GABName; + ZPushVersion = response.ZPushVersion; + Confirmed = Capabilities == null ? ConfirmationType.IsNotZPush : ConfirmationType.IsZPush; + Logger.Instance.Info(this, "ZPush confirmation: {0} -> {1}, {2}", Confirmed, Capabilities, GABFolder); + + if (_confirmedChanged != null) + _confirmedChanged(this); + } + + #endregion + + #region Connections + + /// + /// Creates a new connection to the server for this account. + /// + /// If specified, a cancellation token for the connection. + /// The connection. The caller must dispose this when no longer needed. + public ZPushConnection Connect(CancellationToken? cancel = null) + { + return new ZPushConnection(this, null); + } + + #endregion + + #region Feature-specific data + + private readonly ConcurrentDictionary _featureData = new ConcurrentDictionary(); + private string FeatureKey(Features.Feature feature, string key) + { + return feature.Name + ":" + key; + } + + /// + /// Retrieves feature-specific data. + /// + /// The type of the data. + /// The feature owning the data. + /// A key identifying the data. This is unique per feature. + /// The data, or null if no data was found. + public DataType GetFeatureData(Features.Feature feature, string key) + { + object val = null; + _featureData.TryGetValue(FeatureKey(feature, key), out val); + return (DataType)val; + } + + /// + /// Sets feature-specific data on the account. This can be used to cache data for an account + /// that will only be updated periodically. + /// + /// The feature owning the data. + /// A key indentifying the data. This is unique per feature. + /// The data. Specify null to remove the entry. + public void SetFeatureData(Features.Feature feature, string key, object data) + { + if (data == null) + { + object dummy; + _featureData.TryRemove(FeatureKey(feature, key), out dummy); + } + else + { + _featureData[FeatureKey(feature, key)] = data; + } + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccounts.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccounts.cs new file mode 100644 index 0000000..d563775 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccounts.cs @@ -0,0 +1,392 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Stubs; +using Acacia.Utils; +using Microsoft.Office.Interop.Outlook; +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.ZPush +{ + /// + /// Maintains the mapping from Outlook accounts to ZPush accounts, which + /// provide additional functionality and workarounds. + /// + public class ZPushAccounts + { + private readonly ZPushWatcher _watcher; + private readonly Application _app; + private readonly NameSpace _session; + private readonly Stores _stores; + + /// + /// ZPushAccounts indexed by SMTPAddress. Null values are not allowed. + /// + private readonly Dictionary _accountsBySmtp = new Dictionary(); + + /// + /// ZPushAccounts indexed by store id. Null values are allowed, if a store has been + /// determined to not be associated with a ZPushAccount. This is required to determine when a store is new. + /// + private readonly Dictionary _accountsByStoreId = new Dictionary(); + + public ZPushAccounts(ZPushWatcher watcher, Application app) + { + this._watcher = watcher; + this._app = app; + this._session = app.Session; + this._stores = _session.Stores; + } + + internal void Start() + { + // Register for new stores + // The store remove event is not sent, so don't register for that + _stores.StoreAdd += StoreAdded; + + if (GlobalOptions.INSTANCE.ZPushCheck) + { + // Process existing accounts + using (ComRelease com = new ComRelease()) + foreach (Account account in com.Add(_session.Accounts)) + { + Tasks.Task(null, "AccountCheck", () => + { + try + { + // TODO: check if EAS account + // account gets released by GetAccount, save DisplayName for log purposes. + string displayName = account.DisplayName; + Logger.Instance.Trace(this, "Checking account: {0}", displayName); + ZPushAccount zpush = GetAccount(account); + if (zpush == null) + { + Logger.Instance.Trace(this, "Not a ZPush account: {0}", displayName); + } + else + { + Logger.Instance.Trace(this, "ZPush account: {0}", zpush); + _watcher.OnAccountDiscovered(zpush, true); + } + } + catch (System.Exception e) + { + Logger.Instance.Error(this, "Exception processing account: {0}", e); + } + }); + } + + Tasks.Task(null, "AccountCheckDone", () => + { + _watcher.OnAccountsScanned(); + + if (GlobalOptions.INSTANCE.AccountTimer) + { + // Set up timer to check for removed accounts + _watcher.Timed(Config.ACCOUNT_CHECK_INTERVAL, CheckAccountsRemoved); + } + }); + } + } + + private void CheckAccountsRemoved() + { + try + { + // Collect all the store ids + HashSet stores = new HashSet(); + foreach (Store store in _stores) + { + try + { + stores.Add(store.StoreID); + } + finally + { + ComRelease.Release(store); + } + } + + // Check if any relevant ones are removed + List> removed = new List>(); + foreach(KeyValuePair account in _accountsByStoreId) + { + if (!stores.Contains(account.Key)) + { + Logger.Instance.Trace(this, "Store not found: {0} - {1}", account.Value, account.Key); + removed.Add(account); + } + } + + // Process any removed stores + foreach(KeyValuePair remove in removed) + { + Logger.Instance.Debug(this, "Account removed: {0} - {1}", remove.Value, remove.Key); + _accountsBySmtp.Remove(remove.Value.SmtpAddress); + _accountsByStoreId.Remove(remove.Key); + _watcher.OnAccountRemoved(remove.Value); + } + } + catch(System.Exception e) + { + Logger.Instance.Error(this, "Exception in CheckAccountsRemoved: {0}", e); + } + } + + public IEnumerable GetAccounts() + { + return _accountsBySmtp.Values; + } + + /// + /// Returns the ZPushAccount on which the folder is located. + /// + /// The ZPushAccount, or null if the folder is not on a zpush account + public ZPushAccount GetAccount(IFolder folder) + { + ZPushAccount zpush = null; + using (IStore store = folder.Store) + _accountsByStoreId.TryGetValue(store.StoreID, out zpush); + return zpush; + } + public ZPushAccount GetAccount(IStore store) + { + ZPushAccount zpush = null; + _accountsByStoreId.TryGetValue(store.StoreID, out zpush); + return zpush; + } + public ZPushAccount GetAccount(IBase item) + { + if (item is IFolder) + return GetAccount((IFolder)item); + else if (item is IStore) + return GetAccount((IStore)item); + if (item.Parent != null) + return GetAccount(item.Parent); + return null; + } + + public ZPushAccount GetAccount(MAPIFolder folder) + { + ZPushAccount zpush = null; + Store store = folder.Store; + try + { + string storeId = store?.StoreID; + if (storeId == null) + return null; + _accountsByStoreId.TryGetValue(storeId, out zpush); + return zpush; + } + finally + { + ComRelease.Release(store); + } + } + + public ZPushAccount GetAccount(string smtpAddress) + { + ZPushAccount account = null; + _accountsBySmtp.TryGetValue(smtpAddress, out account); + return account; + } + + /// + /// Returns the ZPush account associated with the Outlook account. + /// + /// The account. This function will release the handle + /// The ZPushAccount, or null if not a ZPush account. + private ZPushAccount GetAccount(Account account) + { + try + { + // Only EAS accounts can be zpush accounts + if (account.AccountType != OlAccountType.olEas) + return null; + + // Check for a cached value + ZPushAccount zpush; + if (_accountsBySmtp.TryGetValue(account.SmtpAddress, out zpush)) + return zpush; + + // Create a new account + return CreateFromRegistry(account); + } + finally + { + ComRelease.Release(account); + } + } + + /// + /// Event handler for Stores.StoreAdded event. + /// + internal void StoreAdded(Store s) + { + try + { + using (ComRelease com = new ComRelease()) + { + Logger.Instance.Trace(this, "StoreAdded: {0}", s.StoreID); + foreach (Store store in com.Add(com.Add(_app.Session).Stores)) + { + if (!_accountsByStoreId.ContainsKey(store.StoreID)) + { + Logger.Instance.Trace(this, "New store: {0}", store.DisplayName); + ZPushAccount zpush = TryCreateFromRegistry(store); + if (zpush == null) + { + // Add it to the cache so it is not evaluated again. + _accountsByStoreId.Add(store.StoreID, null); + Logger.Instance.Trace(this, "Not a ZPush store: {0}", store.DisplayName); + } + else + { + Logger.Instance.Trace(this, "New ZPush store: {0}: {1}", store.DisplayName, zpush); + _watcher.OnAccountDiscovered(zpush, false); + } + } + else ComRelease.Release(store); + } + } + } + catch(System.Exception e) + { + Logger.Instance.Error(this, "StoreAdded Exception: {0}", e); + } + } + + #region Registry + + private void Register(ZPushAccount zpush) + { + // Register the new account + _accountsBySmtp.Add(zpush.SmtpAddress, zpush); + _accountsByStoreId.Add(zpush.StoreID, zpush); + Logger.Instance.Trace(this, "Account registered: {0} -> {1}", zpush.DisplayName, zpush.Store.StoreID); + } + + /// + /// Creates the ZPushAccount for the account, from the registry values. + /// + /// The account. + /// The associated ZPushAccount + /// If the registry key cannot be found + private ZPushAccount CreateFromRegistry(Account account) + { + using (ComRelease com = new ComRelease()) + using (RegistryKey baseKey = FindRegistryKey(account)) + { + if (baseKey == null) + throw new System.Exception("Unknown account: " + account.SmtpAddress); + + // Get the store id + string storeId = ZPushAccount.GetStoreId(baseKey.Name); + + // Find the store + Store store = _app.Session.GetStoreFromID(storeId); + + // Done, create and register + ZPushAccount zpush = new ZPushAccount(baseKey.Name, store); + Register(zpush); + return zpush; + } + } + + /// + /// Creates the ZPushAccount for the store, from the registry. + /// + /// The store + /// The ZPushAccount, or null if no account is associated with the store + private ZPushAccount TryCreateFromRegistry(Store store) + { + using (RegistryKey baseKey = FindRegistryKey(store)) + { + if (baseKey == null) + return null; + ZPushAccount zpush = new ZPushAccount(baseKey.Name, store); + Register(zpush); + return zpush; + } + } + + private RegistryKey OpenBaseKey() + { + NameSpace session = _app.Session; + string path = string.Format(OutlookConstants.REG_SUBKEY_ACCOUNTS, session.CurrentProfileName); + ComRelease.Release(session); + return OutlookRegistryUtils.OpenOutlookKey(path); + } + + /// + /// Finds the registry key for the account. + /// + /// The registry key, or null if it cannot be found + private RegistryKey FindRegistryKey(Account account) + { + // Find the registry key by email adddress + using (RegistryKey key = OpenBaseKey()) + { + if (key != null) + { + foreach (string subkey in key.GetSubKeyNames()) + { + RegistryKey accountKey = key.OpenSubKey(subkey); + if (accountKey.GetValueString(OutlookConstants.REG_VAL_EMAIL) == account.SmtpAddress) + { + return accountKey; + } + accountKey.Dispose(); + } + } + } + return null; + } + + /// + /// Finds the registry key for the account associated with the store. + /// + /// The registry key, or null if it cannot be found + private RegistryKey FindRegistryKey(Store store) + { + // Find the registry key by store id + using (RegistryKey key = OpenBaseKey()) + { + if (key != null) + { + foreach (string subkey in key.GetSubKeyNames()) + { + RegistryKey accountKey = key.OpenSubKey(subkey); + string storeId = ZPushAccount.GetStoreId(accountKey.Name); + if (storeId != null && storeId == store.StoreID) + { + return accountKey; + } + accountKey.Dispose(); + } + } + } + return null; + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushCapabilities.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushCapabilities.cs new file mode 100644 index 0000000..9792e08 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushCapabilities.cs @@ -0,0 +1,58 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.ZPush +{ + public class ZPushCapabilities + { + private readonly HashSet _capabilities = new HashSet(); + + private ZPushCapabilities() + { + + } + + public static ZPushCapabilities Parse(string capabilities) + { + if (capabilities == null) + return null; + + ZPushCapabilities caps = new ZPushCapabilities(); + foreach (string capability in capabilities.Split(',')) + { + caps._capabilities.Add(capability); + } + return caps; + } + + public bool Has(string capability) + { + return _capabilities.Contains(capability); + } + + public override string ToString() + { + return string.Join(",", _capabilities); + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushChannel.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushChannel.cs new file mode 100644 index 0000000..b129e74 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushChannel.cs @@ -0,0 +1,96 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Acacia.Stubs; +using Acacia.Features; +using Acacia.Utils; + +namespace Acacia.ZPush +{ + public class ZPushChannel + { + private readonly ZPushWatcher _watcher; + private readonly ZPushAccount _account; + private readonly Feature _feature; + private readonly string _name; + + public ZPushChannel(ZPushWatcher watcher, ZPushAccount account, Feature feature, string name) + { + this._watcher = watcher; + this._account = account; + this._feature = feature; + this._name = name; + } + + private class FolderRegistrationZPushChannel : FolderRegistration + { + private readonly ZPushChannel _channel; + + public FolderRegistrationZPushChannel(ZPushChannel channel) + : + base(channel._feature) + { + this._channel = channel; + } + + public override bool IsApplicable(IFolder folder) + { + if (folder.Name != _channel._name) + return false; + // Only watch for root folders on the specified account + if (!folder.IsAtDepth(1)) + return false; + if (_channel._watcher.Accounts.GetAccount(folder) != _channel._account) + return false; + Logger.Instance.Info(this, "ZPUSHREG: {0} - {1}", folder, _channel._account); + return true; + } + + public override string ToString() + { + return Feature.Name + ":" + _channel._name; + } + } + + public void Start() + { + _watcher.WatchFolder(new FolderRegistrationZPushChannel(this), Watcher_WatchingFolder); + } + + private void Watcher_WatchingFolder(IFolder folder) + { + Logger.Instance.Info(this, "ZPUSHCANNEL FOLDER: {0} on {1}", folder.Name, _account.DisplayName); + + // Hide the folder + folder.AttrHidden = true; + + // Notify any listeners + if (Available != null) + { + Tasks.Task(null, "Watcher_WatchingFolder", () => Available(folder)); + } + } + + public event FolderEventHandler Available; + + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushChannels.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushChannels.cs new file mode 100644 index 0000000..07684b2 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushChannels.cs @@ -0,0 +1,43 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Acacia.Stubs; +using Acacia.Features; + +namespace Acacia.ZPush +{ + public class ZPushChannels + { + private readonly ZPushWatcher _watcher; + + public ZPushChannels(ZPushWatcher watcher) + { + this._watcher = watcher; + } + + public ZPushChannel Get(Feature feature, ZPushAccount account, string name) + { + ZPushChannel channel = new ZPushChannel(_watcher, account, feature, name); + return channel; + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushFolder.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushFolder.cs new file mode 100644 index 0000000..78b99ab --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushFolder.cs @@ -0,0 +1,282 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Stubs; +using Acacia.Stubs.OutlookWrappers; +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.Linq; +using Acacia.Utils; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.ZPush +{ + public class ZPushFolder : FolderWrapper + { + private readonly Items _items; + private readonly Folders _subFolders; + private ZPushFolder _parent; + private readonly ZPushWatcher _watcher; + private List _itemsWatchers = new List(); + + /// + /// Children folders indexed by EntryID + /// + protected readonly Dictionary _children = new Dictionary(); + + internal ZPushFolder(ZPushWatcher watcher, Folder folder) + : + this(watcher, null, folder) + { + Initialise(); + } + + private ZPushFolder(ZPushWatcher watcher, ZPushFolder parent, Folder folder) + : + base(folder) + { + Logger.Instance.Trace(this, "Watching folder: {1}: {0}", folder.EntryID, folder.Name); + this._parent = parent; + this._watcher = watcher; + this._items = folder.Items; + this._subFolders = folder.Folders; + } + + private void Initialise() + { + // Register the events + HookEvents(true); + + // Notify the watcher + _watcher.OnFolderDiscovered(this); + + // Recurse the children + foreach (Folder subfolder in this._subFolders) + { + Tasks.Task(null, "WatchChild", () => WatchChild(subfolder)); + } + } + + public override void Dispose() + { + Logger.Instance.Trace(this, "Disposing folder: {0}", _item.Name); + Cleanup(); + base.Dispose(); + ComRelease.Release(_items); + ComRelease.Release(_subFolders); + } + + internal ItemsWatcher ItemsWatcher() + { + ItemsWatcher watcher = new ItemsWatcher(); + _itemsWatchers.Add(watcher); + return watcher; + } + + public void ReportExistingItems(TypedItemEventHandler handler) + where TypedItem : IItem + { + foreach(IItem item in Items) + { + if (item is TypedItem) + handler((TypedItem)item); + } + } + + private void HookEvents(bool register) + { + if (register) + { + // Item events + _items.ItemAdd += Items_ItemAdd; + _items.ItemChange += Items_ItemChange; + + // Folder events + _subFolders.FolderAdd += SubFolders_FolderAdd; + _subFolders.FolderRemove += SubFolders_FolderRemove; + _subFolders.FolderChange += SubFolders_FolderChange; + } + else + { + // Item events + _items.ItemAdd -= Items_ItemAdd; + _items.ItemChange -= Items_ItemChange; + + // Folder events + _subFolders.FolderAdd -= SubFolders_FolderAdd; + _subFolders.FolderRemove -= SubFolders_FolderRemove; + _subFolders.FolderChange -= SubFolders_FolderChange; + } + } + + private void Cleanup() + { + Logger.Instance.Trace(this, "Unwatching folder: {0}", _item.Name); + // The events need to be unhooked explicitly, otherwise we get double notifications if a folder is moved + HookEvents(false); + foreach (ZPushFolder child in _children.Values) + { + child.Dispose(); + } + _children.Clear(); + } + + /// + /// Watches the child folder. + /// + /// The child folder. Ownership will be taken. + private void WatchChild(Folder child) + { + if (!_children.ContainsKey(child.EntryID)) + { + if (_watcher.ShouldFolderBeWatched(this, child)) + { + Logger.Instance.Trace(this, "Registering child on {0}: {1}", this, child.FullFolderPath); + + // Make sure we register the entry id actually before registering any listerners. + // That will cause change notifications, which require the entryid to be registered. + ZPushFolder folder = new ZPushFolder(_watcher, this, child); + _children.Add(child.EntryID, folder); + folder.Initialise(); + return; + } + else + { + Logger.Instance.Trace(this, "Excluding child on {0}: {1}", this, child.FullFolderPath); + } + } + + // Release the folder if not used + ComRelease.Release(child); + } + + #region Event handlers + + private void SubFolders_FolderAdd(MAPIFolder folder) + { + Logger.Instance.Debug(this, "Folder added in {0}: {1}", this._item.Name, folder.Name); + WatchChild((Folder)folder); + } + + private void SubFolders_FolderRemove() + { + Logger.Instance.Debug(this, "Folder removed from {0}", this._item.Name); + + // Helpfully, Outlook doesn't tell us which folder was removed. Could use the BeforeFolderMove event instead, + // but that doesn't fire if a folder was removed on the server. + // Hence, fetch all the remaining folder ids, and remove any folder that no longer exists. + HashSet remaining = new HashSet(); + foreach (Folder child in _subFolders) + { + try + { + remaining.Add(child.EntryID); + } + catch (System.Exception e) { Logger.Instance.Warning(this, "Ignoring failed child: {0}", e); } + } + + // Find the folders that need to be removed. There should be only one, but with Outlook we can never be sure, + // so compare all. We cannot modify the dictionary during iteration, so store entries to be removed in a + // temporary list + List> remove = new List>(); + foreach (var entry in _children) + { + if (!remaining.Contains(entry.Key)) + { + remove.Add(entry); + } + } + + // Actually remove the folders + foreach (var entry in remove) + { + Logger.Instance.Debug(this, "Removing subfolder {0}, {1}", this._item.Name, entry.Key); + _children.Remove(entry.Key); + entry.Value.Cleanup(); + } + } + + private void SubFolders_FolderChange(MAPIFolder folder) + { + try + { + Logger.Instance.Debug(this, "Folder changed in {0}: {1}", this._item.Name, folder.Name); + ZPushFolder child; + if (_children.TryGetValue(folder.EntryID, out child)) + { + _watcher.OnFolderChanged(child); + // TODO: release folder? + } + else + { + // On a clean profile, we sometimes get a change notification, but not an add notification + // Create it now + // This will send a discover notification if required, which is just as good as a change notification + Logger.Instance.Debug(this, "Folder change on unreported folder in {0}: {1}, {2}, {3}", this._item.Name, folder.Name, folder.EntryID, folder.Store.DisplayName); + WatchChild((Folder)folder); + } + } + catch(System.Exception e) + { + Logger.Instance.Trace(this, "FolderChange exception: {0}: {1}", Name, e); + } + } + + private void Items_ItemAdd(object oItem) + { + try + { + using (IItem item = Mapping.Wrap(oItem)) + { + if (item != null) + { + Logger.Instance.Trace(this, "New item {0}: {1}", Name, item.EntryId); + foreach (ItemsWatcher watcher in _itemsWatchers) + watcher.OnItemAdd(this, item); + } + } + } + catch(System.Exception e) + { + Logger.Instance.Trace(this, "ItemAdd exception: {0}: {1}", Name, e); + } + } + + private void Items_ItemChange(object oItem) + { + try + { + using (IItem item = Mapping.Wrap(oItem)) + { + if (item != null) + { + Logger.Instance.Trace(this, "Changed item {0}", Name); + foreach (ItemsWatcher watcher in _itemsWatchers) + watcher.OnItemChange(this, item); + } + } + } + catch (System.Exception e) + { + Logger.Instance.Trace(this, "ItemChange exception: {0}: {1}", Name, e); + } + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs new file mode 100644 index 0000000..39c7a3d --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs @@ -0,0 +1,171 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Stubs; +using Acacia.Stubs.OutlookWrappers; +using Acacia.Utils; +using Microsoft.Office.Interop.Outlook; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.ZPush +{ + /// + /// Manages a local store in which Z-Push data is stored. + /// + /// TODO: merge with Store where possible + public class ZPushLocalStore : DisposableWrapper + { + private Store _store; + + public IFolder RootFolder + { + get + { + return Mapping.Wrap(_store.GetRootFolder()); + } + } + + public string StoreId { get { return _store.StoreID; } } + + private ZPushLocalStore(Store store) + { + this._store = store; + HideAllFolders(); + } + + protected override void DoRelease() + { + ComRelease.Release(_store); + _store = null; + } + + private bool IsCustomFolder(IFolder folder) + { + return Features.GAB.FeatureGAB.IsGABContactsFolder(folder); + } + + private void HideAllFolders() + { + if (GlobalOptions.INSTANCE.LocalFolders_Hide) + { + // Hide the folders that are not custom folders + using (ComRelease com = new ComRelease()) + { + foreach (Folder sub in com.Add(com.Add(_store.GetRootFolder()).Folders)) + { + using (IFolder wrapped = Mapping.Wrap(sub)) + { + wrapped.AttrHidden = !IsCustomFolder(wrapped); + } + } + } + } + } + + public static ZPushLocalStore GetInstance(Application App) + { + try + { + // Try to find the existing store + // Start with creating the filename prefix (without sequence number or extension) + string basePath1 = GlobalOptions.INSTANCE.LocalFolders_Path; + if (string.IsNullOrEmpty(basePath1)) + basePath1 = Constants.LOCAL_STORE_DEFAULT_DIRECTORY; + string basePath = Environment.ExpandEnvironmentVariables(basePath1); + string prefix = System.IO.Path.Combine(basePath, Constants.LOCAL_STORE_FILENAME); + Logger.Instance.Debug(typeof(ZPushLocalStore), "Opening store with prefix {0}", prefix); + + // See if a store with this prefix exists + Store store = FindInstance(App, prefix); + if (store != null) + return new ZPushLocalStore(store); + + // Doesn't exist, create it + Logger.Instance.Debug(typeof(ZPushLocalStore), "No existing store found"); + // Make sure the local path exists + Directory.CreateDirectory(basePath); + + // Try without a sequence number; if it already exists keep increment the sequence + // number while an existing file is found + // We do not reuse an existing file, we don't know what state it is in + string path = prefix + "." + Constants.LOCAL_STORE_EXTENSION; + for (int i = 1; File.Exists(path); ++i) + { + path = prefix + " (" + i + ")." + Constants.LOCAL_STORE_EXTENSION; + } + + // Path found, create the store + Logger.Instance.Info(typeof(ZPushLocalStore), "Creating new store: {0}", path); + App.Session.AddStore(path); + store = App.Session.Stores[App.Session.Stores.Count]; + Logger.Instance.Debug(typeof(ZPushLocalStore), "Created new store: {0}", store.FilePath); + + // Set the display name + using (IFolder root = Mapping.Wrap(store.GetRootFolder())) + { + root.Name = Properties.Resources.LocalStore_DisplayName; + } + + // Done + return new ZPushLocalStore(store); + } + catch(System.Exception e) + { + Logger.Instance.Error(typeof(ZPushLocalStore), "Exception: {0}", e); + return null; + } + } + + private static Store FindInstance(Application app, string prefix) + { + foreach (Store store in app.Session.Stores) + { + if (store.IsDataFileStore && store.FilePath.StartsWith(prefix)) + { + Logger.Instance.Info(typeof(ZPushLocalStore), "Opening existing store: {0}", store.FilePath); + return store; + } + } + return null; + } + + internal void EmptyDeletedItems() + { + using (ComRelease com = new ComRelease()) + { + MAPIFolder f = _store.GetDefaultFolder(OlDefaultFolders.olFolderDeletedItems); + if (f != null) + { + com.Add(f); + + // Normal enumeration fails when deleting. Do it like this. + Folders folders = com.Add(f.Folders); + for (int i = folders.Count; i > 0; --i) + com.Add(folders[i]).Delete(); + + Items items = com.Add(f.Items); + for (int i = items.Count; i > 0; --i) + com.Add(items[i]).Delete(); + } + } + } + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushSync.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushSync.cs new file mode 100644 index 0000000..5dabaa0 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushSync.cs @@ -0,0 +1,225 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Features; +using Acacia.Utils; +using Acacia.ZPush.Connect; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Acacia.ZPush +{ + /// + /// Helper for synchronising state with ZPush servers + /// + public class ZPushSync + { + #region SyncTask + + /// + /// Represents a SyncTask. This is not specific for an account. When tasks are executed, GetInstance is + /// used to create a task instance for each account, which will be executed by the system task manager. + /// + private class SyncTask + { + private readonly Feature _owner; + private readonly string _name; + private readonly SyncAction _action; + private readonly SyncActionConnection _actionConnection; + + public SyncTask(Feature owner, string name, SyncAction action, SyncActionConnection actionConnection) + { + this._owner = owner; + this._name = name; + this._action = action; + this._actionConnection = actionConnection; + } + + public AcaciaTask GetInstance(ZPushAccount account) + { + if (_actionConnection != null) + { + return new AcaciaTask(_owner, _name, () => + { + // TODO: reuse connections + using (ZPushConnection con = account.Connect()) + { + _actionConnection(con); + } + }); + } + else + { + return new AcaciaTask(_owner, _name, () => _action(account)); + } + } + } + + #endregion + + #region Setup + + private readonly Microsoft.Office.Interop.Outlook.SyncObject _syncObject; + private readonly Timer _timer; + private ZPushWatcher _watcher; + private bool _started; + private readonly List _tasks = new List(); + + public readonly bool Enabled; + public readonly TimeSpan Period; + + public ZPushSync(ZPushWatcher watcher, Microsoft.Office.Interop.Outlook.Application app) + { + // Get the settings + Enabled = GlobalOptions.INSTANCE.ZPushSync; + Period = GlobalOptions.INSTANCE.ZPushSync_Period; + if (Period.Ticks == 0) + Period = Constants.ZPUSH_SYNC_DEFAULT_PERIOD; + + // Set up a timer and events if enabled + if (Enabled) + { + _watcher = watcher; + _timer = new Timer(); + _timer.Interval = (int)Period.TotalMilliseconds; + _timer.Tick += _timer_Tick; + _timer.Start(); + + // Need to keep a reference to keep receiving events + _syncObject = app.Session.SyncObjects.AppFolders; + _syncObject.SyncStart += SyncObject_SyncStart; + watcher.AccountDiscovered += Watcher_AccountDiscovered; + } + } + + #endregion + + #region Public interface + + /// + /// Starts the synchronisation engine. After it is started, new tasks can no longer be added. + /// + public void Start() + { + _started = true; + } + + /// + /// Delegate for an account-specific task. + /// + /// The account + public delegate void SyncAction(ZPushAccount account); + + /// + /// Delegate for an account-specific task that will connect to the ZPush server. + /// The account can be obtained from the connection. + /// + /// The connection to the ZPush server. This must not be dispose by + /// the task, as it may be reused for different tasks + public delegate void SyncActionConnection(ZPushConnection connection); + + + /// + /// Adds a synchronisation task. + /// + /// The feature owning the task. + /// The task's name, for logging. + /// The action to execute. + public void AddTask(Feature owner, string name, SyncAction action) + { + if (_started) + throw new Exception("Already started, cannot add task"); + _tasks.Add(new SyncTask(owner, name, action, null)); + } + + + /// + /// Adds a synchronisation task that will use a connection to ZPUsh. + /// + /// The feature owning the task. + /// The task's name, for logging. + /// The action to execute. + public void AddTask(Feature owner, string name, SyncActionConnection action) + { + if (_started) + throw new Exception("Already started, cannot add task"); + _tasks.Add(new SyncTask(owner, name, null, action)); + } + + #endregion + + #region Task execution + + /// + /// Executes the tasks for all known ZPush accounts + /// + private void ExecuteTasks() + { + foreach (ZPushAccount account in _watcher.Accounts.GetAccounts()) + ExecuteTasks(account); + } + + /// + /// Executes the tasks for the specified ZPush account. The tasks are pushed into the system + /// task queue. + /// + private void ExecuteTasks(ZPushAccount account) + { + foreach (SyncTask task in _tasks) + { + Tasks.Task(task.GetInstance(account)); + } + } + + /// + /// Timer callback, executes any tasks. + /// + private void _timer_Tick(object sender, EventArgs e) + { + ExecuteTasks(); + } + + /// + /// Invoked when a new ZPush account is discovered, runs tasks for that account. + /// This is also invoked at start-up, so triggers initial sync. + /// + private void Watcher_AccountDiscovered(ZPushAccount account) + { + ExecuteTasks(account); + } + + /// + /// Invoked when an explicit send and receive is performed, invokes any tasks. + /// + private void SyncObject_SyncStart() + { + // TODO: this checks _started, others don't. Also, this is probably invoked on + // start-up, as is AccountDiscoverd. Does that mean tasks are invoked twice + // on start-up? + if (_started) + { + // Explicit sync, run tasks + ExecuteTasks(); + } + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushTypes.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushTypes.cs new file mode 100644 index 0000000..219b4a0 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushTypes.cs @@ -0,0 +1,112 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Utils; +using Acacia.ZPush.Connect.Soap; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Acacia.ZPush +{ + /// + /// Helper base for ZPush ids + /// + public abstract class ZPushId : ISoapSerializable + { + protected readonly string _id; + + public ZPushId(string id) + { + this._id = id; + } + + /// + /// Constructor for Soap deserialization, for cases in which '0' is encoded as an int + /// + /// + public ZPushId(int id) + { + this._id = id.ToString(); + } + + public bool IsNone { get { return _id == "0"; } } + + public string SoapSerialize() { return _id; } + + #region Standard overrides + + public override string ToString() + { + return _id.ToString(); + } + + public override int GetHashCode() + { + return _id.GetHashCode(); + } + + public override bool Equals(object obj) + { + return (this.GetType() == obj.GetType()) && ((ZPushId)obj)._id.ToLower().Equals(_id.ToLower()); + } + + #endregion + } + + public class SyncId : ZPushId + { + public static readonly SyncId NONE = new SyncId("0"); + + public SyncId(string id) : base(id) { } + public SyncId(int id) : base(id) { } + + /// + /// Checks if this is a SyncId for a shared folders + /// + public bool IsShared { get { return _id.StartsWith("S"); } } + + #region Standard overrides + + public static bool operator ==(SyncId l, SyncId r) { return Util.NullSafeEquals(l, r); } + public static bool operator !=(SyncId l, SyncId r) { return !Util.NullSafeEquals(l, r); } + + public override bool Equals(object obj) { return base.Equals(obj); } + public override int GetHashCode() { return base.GetHashCode(); } + + #endregion + } + + public class BackendId : ZPushId + { + public static readonly BackendId NONE = new BackendId("0"); + + public BackendId(string id) : base(id) { } + public BackendId(int id) : base(id) { } + + #region Standard overrides + + public static bool operator ==(BackendId l, BackendId r) { return Util.NullSafeEquals(l, r); } + public static bool operator !=(BackendId l, BackendId r) { return !Util.NullSafeEquals(l, r); } + + public override bool Equals(object obj) { return base.Equals(obj); } + public override int GetHashCode() { return base.GetHashCode(); } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushWatcher.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushWatcher.cs new file mode 100644 index 0000000..571cfb8 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushWatcher.cs @@ -0,0 +1,408 @@ +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Features.OutOfOffice; +using Acacia.Stubs; +using Acacia.Stubs.OutlookWrappers; +using Acacia.Utils; +using Acacia.ZPush.Connect; +using Microsoft.Office.Interop.Outlook; +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Acacia.ZPush +{ + /// + /// Global watcher for ZPush accounts and events on items and folders in those accounts. + /// A global watcher is used, as a lot of features are interested in the same accounts, + /// and it is easier to centralise all event registrations. + /// + public class ZPushWatcher + { + private readonly Application _app; + public readonly ZPushAccounts Accounts; + public readonly ZPushSync Sync; + private Explorer _explorer; + + + #region Setup + + public ZPushWatcher(Application app) + { + this._app = app; + Sync = new ZPushSync(this, app); + Accounts = new ZPushAccounts(this, app); + + // Need to keep a link to keep receiving events + _explorer = app.ActiveExplorer(); + _explorer.SelectionChange += Explorer_SelectionChange; + } + + /// + /// Starts watching for events + /// + public void Start() + { + // Start sync tasks + Sync.Start(); + + // Look for Z-Push accounts + Accounts.Start(); + + // Notify any listeners of current selection. + Explorer_SelectionChange(); + } + + #endregion + + #region Timers + + public void Delayed(int millis, System.Action action) + { + RegisterTimer(millis, action, false); + } + + public void Timed(int millis, System.Action action) + { + RegisterTimer(millis, action, true); + } + + private void RegisterTimer(int millis, System.Action action, bool repeat) + { + System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer(); + timer.Interval = millis; + timer.Tick += (s, eargs) => + { + try + { + action(); + if (!repeat) + { + timer.Enabled = false; + timer.Dispose(); + } + } + catch(System.Exception e) + { + Logger.Instance.Trace(this, "Exception in timer: {0}", e); + } + }; + timer.Start(); + } + + #endregion + + #region Accounts + + public delegate void AccountHandler(ZPushAccount account); + public delegate void AccountsScannedHandler(); + + /// + /// Account events. When registered, any existing accounts will also be reported when the watcher is started. + /// + public event AccountHandler AccountDiscovered; + public event AccountHandler AccountRemoved; + + /// + /// Raised after the initial account scan is performed. Any registered accounts will have been notified. + /// + public event AccountsScannedHandler AccountsScanned; + + /// + /// Handles a new account. + /// + /// The account. + /// True if the account is an existing account, false if + /// it is a new account + internal void OnAccountDiscovered(ZPushAccount account, bool isExisting) + { + // Notify any account listeners + if (AccountDiscovered != null) + AccountDiscovered(account); + + // Register any events + HandleFolderWatchers(account); + + // Send an OOF request to get the OOF state and capabilities + Tasks.Task(null, "ZPushCheck: " + account.DisplayName, () => + { + // TODO: if this fails, retry? + ActiveSync.SettingsOOF oof; + using (ZPushConnection connection = new ZPushConnection(account, new System.Threading.CancellationToken(false))) + { + oof = connection.Execute(new ActiveSync.SettingsOOFGet()); + } + account.OnConfirmationResponse(oof.RawResponse); + + // [ZO-109] Always update the current selection, it might have changed. + Explorer_SelectionChange(); + + // Notify the OOF feature. + // TODO: this coupling is pretty hideous + ThisAddIn.Instance.GetFeature()?.OnOOFSettings(account, oof); + }); + } + + internal void OnAccountsScanned() + { + if (AccountsScanned != null) + AccountsScanned(); + } + + internal void OnAccountRemoved(ZPushAccount account) + { + // Notify any account listeners + if (AccountRemoved != null) + AccountRemoved(account); + + // TODO: unregister event listeners + } + + #endregion + + #region Selection + + public delegate void ZPushAccountChangeHandler(ZPushAccount account); + + public event ZPushAccountChangeHandler ZPushAccountChange; + public event FolderEventHandler ActiveFolderChange; + + private void Explorer_SelectionChange() + { + try + { + if (ActiveFolderChange != null) + { + MAPIFolder active = _explorer.CurrentFolder; + if (active != null) + { + using (IFolder folder = Mapping.Wrap(active)) + { + try + { + ActiveFolderChange(folder); + } + catch (System.Exception e) { Logger.Instance.Error(this, "Exception in Explorer_SelectionChange.ActiveFolderChange: {0}", e); } + } + } + } + // TODO: cache value + if (ZPushAccountChange != null) + { + try + { + ZPushAccountChange(CurrentZPushAccount()); + } + catch (System.Exception e) { Logger.Instance.Error(this, "Exception in Explorer_SelectionChange.ZPushAccountChange: {0}", e); } + } + } + catch(System.Exception e) { Logger.Instance.Error(this, "Exception in Explorer_SelectionChange: {0}", e); } + } + + public ZPushAccount CurrentZPushAccount() + { + if (_explorer.CurrentFolder == null) + return null; + + MAPIFolder folder = _explorer.CurrentFolder; + try + { + return Accounts.GetAccount(folder); + } + finally + { + ComRelease.Release(folder); + } + } + + #endregion + + #region Folders + + private class FolderWatcher + { + public FolderEventHandler Discovered; + public FolderEventHandler Changed; + + public void OnDiscovered(IFolder folder) + { + if (Discovered != null) + Discovered(folder); + } + + public void OnChanged(IFolder folder) + { + if (Changed != null) + Changed(folder); + } + } + + private readonly Dictionary _folderWatchers = new Dictionary(); + private ZPushFolder _rootFolder; + + private void HandleFolderWatchers(ZPushAccount account) + { + // We need to keep the object alive to keep receiving events + _rootFolder = new ZPushFolder(this, (Folder)account.Store.GetRootFolder()); + } + + public void WatchFolder(FolderRegistration folder, FolderEventHandler handler, FolderEventHandler changedHandler = null) + { + if (!DebugOptions.GetOption(null, DebugOptions.WATCHER_ENABLED)) + return; + + FolderWatcher watcher; + if (!_folderWatchers.TryGetValue(folder, out watcher)) + { + watcher = new FolderWatcher(); + _folderWatchers.Add(folder, watcher); + } + + watcher.Discovered += handler; + if (changedHandler != null) + watcher.Changed += changedHandler; + + // Check existing folders for events + foreach(ZPushFolder existing in _allFolders) + { + if (folder.IsApplicable(existing)) + { + DispatchFolderEvent(folder, watcher, existing, true); + } + } + } + + private readonly List _allFolders = new List(); + + internal void OnFolderDiscovered(ZPushFolder folder) + { + Logger.Instance.Trace(this, "Folder discovered: {0}", folder); + _allFolders.Add(folder); + DispatchFolderEvents(folder, true); + } + + internal void OnFolderChanged(ZPushFolder folder) + { + Logger.Instance.Trace(this, "Folder changed: {0}", folder); + DispatchFolderEvents(folder, false); + } + + private void DispatchFolderEvents(ZPushFolder folder, bool isNew) + { + // See if anybody is interested + foreach (KeyValuePair entry in _folderWatchers) + { + if (entry.Key.IsApplicable(folder)) + { + DispatchFolderEvent(entry.Key, entry.Value, folder, isNew); + } + } + } + + private void DispatchFolderEvent(FolderRegistration reg, FolderWatcher watcher, ZPushFolder folder, bool isNew) + { + Logger.Instance.Debug(this, "Folder event: {0}, {1}, {2}", folder, reg, isNew); + if (isNew) + watcher.OnDiscovered(folder); + else + watcher.OnChanged(folder); + } + + internal bool ShouldFolderBeWatched(ZPushFolder parent, Folder child) + { + if (parent.IsAtDepth(0)) + { + // Special mail folders cause issues, they are disallowed + if (child.DefaultItemType != OlItemType.olMailItem) + return true; + + return !IsBlackListedMailFolder(child); + } + return true; + } + + private static readonly OlDefaultFolders[] BLACKLISTED_MAIL_FOLDERS = + { + OlDefaultFolders.olFolderOutbox, + OlDefaultFolders.olFolderDrafts, + OlDefaultFolders.olFolderConflicts, + OlDefaultFolders.olFolderSyncIssues, + OlDefaultFolders.olFolderRssFeeds, + OlDefaultFolders.olFolderManagedEmail + }; + + private static bool IsBlackListedMailFolder(Folder folder) + { + string entryId = folder.EntryID; + using (ComRelease com = new ComRelease()) + { + Store store = com.Add(folder.Store); + foreach(OlDefaultFolders defaultFolder in BLACKLISTED_MAIL_FOLDERS) + { + try + { + if (entryId == com.Add(store.GetDefaultFolder(defaultFolder)).EntryID) + return true; + } + catch (System.Exception) { } + } + } + return false; + } + + #endregion + + #region Items + + public void WatchItems(IFolder folder, TypedItemEventHandler handler, bool reportExisting) + where TypedItem : IItem + { + if (!DebugOptions.GetOption(null, DebugOptions.WATCHER_ENABLED)) + return; + + // Must have a ZPush folder to watch events, create one if necessary + ZPushFolder zPushFolder; + if (!(folder is ZPushFolder)) + { + // TODO + throw new NotImplementedException(); + } + else + { + zPushFolder = (ZPushFolder)folder; + } + + // Register the handlers + ItemsWatcher watcher = zPushFolder.ItemsWatcher(); + watcher.ItemEvent += (item) => + { + if (item is TypedItem) + handler((TypedItem)item); + }; + + // Report existing if requested + if (reportExisting) + zPushFolder.ReportExistingItems(handler); + } + + #endregion + } +} diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/packages.config b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/packages.config new file mode 100644 index 0000000..fccc652 --- /dev/null +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/PluginDebugger/App.config b/src/AcaciaZPushPlugin/PluginDebugger/App.config new file mode 100644 index 0000000..e66135d --- /dev/null +++ b/src/AcaciaZPushPlugin/PluginDebugger/App.config @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/PluginDebugger/Kopano.ico b/src/AcaciaZPushPlugin/PluginDebugger/Kopano.ico new file mode 100644 index 0000000000000000000000000000000000000000..0b80522fe0d35a771be5385301e2e0e0d5377d9f GIT binary patch literal 370070 zcmeHw3A`jpU1q)4GxTr{u-w;c?g15$U6f_IUu9Lj?ir9FKxM7a3nxRMuUUS(V4X z`WGFM8JQ9P>-)z)A|vxP8Y_*PHTYX;9B7<%;IziipuDx^kIz_XybkB0$RD>GjSrl4 zdgEaai;v%R|3>4h&pW+w;DA5AZKLtZ^G|Qw7CGB{?rDw2L*8I2r4zMj9riN`m;@>+fp*k#*l$OjJD~hQq&=jc zC%f(S$kkPpbz{pUP-_XaoAJ2cjyCQH%zwyZ|0d+8kbaTEX-Cm2;sT2UYHcaTeAOh- z@#B6c>Ja;X>#={*W1sjBd_W66z~%x~vjO9$o)QrD4@a#u_8I##3IB-?Xt_ARd_X-d z#<;GE1Q^egml4<>?gN^b3$)D#RK*sIk9tX9f^lEiSKb!~w40a^Cf*g0JPgYppHgsJZB<-w%^x>ar7=2?>}6?aX;+~}$SnF@OC`*f^e10*3t=1!uRJ1WGP}F7`{aw`WkyZ{vQ+?a;_yyaWvUiCN+bb{^={n9cY4b@?i2g>r^u1pI)905 z&q!Ua1d_kY6J!5lz)#uM`3?KaH6iQ0q!JMJfq9PmhW(Q2(a1IlOe+E4-NpQd{b?m< z*P8^&Er9_0_poul+`2UCO#;(Mz+(Psq-EEd1gax}ij4dBqej4st@BsMG>wy-C6J8! z%~qLXe#3swc4Ey}PXeiN|56;6@fn|Czj~%=9OW#5)VOch&spBqyh)%a5=h2_-Vy0Q;BYZwlFbAG+lDPMsb<+W7Y<|BJ`{jmS^=@=I8c^?-di zw)FrCqsBjs^KOm^AHey38OMFYzPDeD>5BQ!0=B>6@qW_h#J_yNukaT5fK{9`A5c^L zR|)$V|DEmERFxd}`B}1?u`hc7KHSwCD%>`^ju({_6pPr z3^ilcuwN~O1G915f3)%139&!O2gGZFHW#Rtaiq90?56}$@wPcu*jHRHjE~F1 z^?+ZcIF4h_5Zbae!IIlXn*8osUuoz2pFyl|F~3(Vp6?0!=K!xKJpL8akHdXf&wJ!I z-2MO@+nQh+KqWq|0`}X@w!=Pnsr5QP%@EjkF+cJH!0JDG>ZQ}JoEt;2lT3-6h{g6n{M3y1dhx0E{~1-DNECPyU6bhynoSSex5o1C|}X% z1K@is4oK;wh=&38?}hTGN{Ic>wxjmFDO=fFdHk zOOs*0D~l?XfOkFXd%DMdUgLh+AB1thCS}Sv05sThfr1%Wg8isv<9@+(GY>h*v%U)( zcL(mivS9qvAA~-@JsTuV<^$%@YPR>582dN+`AHD-+w=X^V zZ}pQnrqVE@9#BY^$ydHfe?>>uU>;`IPLuh81X z0QT(Ej1ov;|I--%%d)3e>-?7q`!?OH)0aw{vU@l7xu+R7R%k(af#r#uhJ{bGY2KI08_%G_bKg4}l z4t;=I4{(2L%$^HOX$^QT=3{>3hW)9fSH2s7cdhxqrG#VuFdyLd2V4!_z>_^2oX{-0 zYkeh-`6K^~FS2$1acU3N{2vUQ?0Wo{ZR{WE1MJ=5aaIu5C(rlGJKz5_zSC=adnQx2 zy9(de(q6w;mwfCW?*r_cqC+jCi~aIG-#6?JRqwzG%==wj3?Fb8VE^kC82d;10GkU8 zG=pRxEPOy&*ZGrizwUpNYp{j~p9S7E_CL>Kf7$Q&g!s*(oU94ry8-cOL1pu-`0Q%zqNJbN}(D@r`a<>+3=F z+8q9{av1+7#~%E@m}kGPxE7c)zOpxZej<pNleWp7yU?Sg31W86P0*x5|tC zPa5`npqt47zKJFLzrtg`?y-N`*Y*1Vd`k?nD$RO;;$&cdt)%0Af_?Y^XRnzUf6W`w zyMDVDIeWg?*rzgZCp#;RAqox2Lm(ziWl^p)Z^dg{)5N< z(Eo*Tz!tRu*%j*h0a)vEYZL8g<4oZGuSU60!4F0`Ja7um*T*l)qy5 zpL(xz=mTCsja>Ks<@*5O+r@Oi&~rT2Zz?e6<%@*ByZA%iij( zMM(gd*WCZd{n$@iUIvEB-e;c=;P=xZ%Z1JbH0P&&fuHwz%nMsZ!@TGbeYVaoU@j*ri`TelrKeKsH=mXq(0A!oH4*-T7c98!B60u+8Ilr*anEwFH9l2qjf>_W`&#CZ@ ztDD0<|K9MQ8UE98K<+*O`+M9vL-g3rDsc3-NW{M|#&VI8==vDwvY3BCcu#l3F^T8k z2M(b8ZI6GBU1eX3D+>L6aX?<{0l<;dWhZL?2+G>mU&QfW*#9_U{R6Z=&}-v91+m~C zZIN9f|Bt}@_YD8J_`T2vyn^zEoHL&bwDjHXsP#(Vsi*ijsL?qK(f9bvX7``P38FPWi?)`hkpS#X_+J(ut18a5udgE!^BQ}XiGR`XEb;)F++1@UKUTkZ3BcywWB6YR{<#)FU+{hWjlmzH=24z1 z1^})!{@)4ZE0BtSe_{Uw==o9dg?uW$c#r)SBLUdl`@9`0Ce`?4dH(YO`G99o+t9;Q z<0Nn;{NEkr>yV0s|8KRT_Jhb5a>G9bQIH?(%-IdeLHPrQ|D}xo^sjp6`YT=+)8XHL z) z{BsTP5cxuG_@^KW_=C+^{GWfEpT@n875_h#rZFx4JAVA%Sa07B82hTne-YOIMZ=58 zS38Of{}e=leu@E*+xp*f@GtBihYs#T(?C8IPCCuV&Et+7JjA{KA1xsMFYPp&w<2$y zD5jNV`z>Dr0sigz-*WJ;=YMadHC*++?wZUr)^Rvm*BanEJ^uCVeVNby!ga`BAU~jO zs=3WHGO%l>m%y&KH~4`!BQYMe_5a2B0m=Fb?ERbR*`GA7Z)O2suk`pY%Kl$H2RshC zj*wpS0n*y?bKC#Bv^7A*{WrkpKAo0;=l@g1{h{>;Q^=o!6pp*g9{)pHxHcJ)ZqXa^ zVCBV2Ab9_0(~tjJi`Lqd<=Mvr#6AS^j2T=wn-9ps0A^?dn0K;A{zQ*|*=T6DR-WH4NUkUGcfx;`s)D>%;RjsYK7;D|ZUK%~ zc@ob9ABb{M_5o__5A)CmM5Nh#0Hv__pVt47+xI``$M`TmnP4B7e?GO$zYCTn_GLLo z4kqscya$*nY77v@0m)ndYZn#=NRbQ5IR>$-Yc6c8q5Lf*+A!^Pm@V7+>0}dP-_7?S z+f~E>nT`9QsVD|O-uCzp$K9fpyKz9P9gz>bBVay&f>_WG&zzhcUUfm^4A|wDJ?`~f z+OR$y*3Y#9@IIi3>j3gap$}-0cF=4-KuXLx2i~2%Fh|-p z{AU*Tbg_S-U+c>m`!W^a$HjEW*O9JABG$AIN4P6eE+4?TKtw)}n-7pebIz~p?g9K` z!+$3D53%1}>&q$TA7maIT_5m9kN+aa0Q5!j0p0xp_IE%BsW$U-z`XOd$Y1R7Z+n1d zkNZRHcjx;VuJcb~0Qei=F0Mm@J zck@N$4?*I4sKmPYfbn<_ePW3Hc&%@V*q8cSt#~Z}e;??VJ^qV64+wq0cky16iv!FD zNTb>3z`BbSu^0GODF1`UzdZw(9RKo_e3!?~_qm@R&-k5Ov)9<U$cR+VUj?D*5uJ>85g#8{h{7*Ia>5lusyFAN^`3LD;?*<%+qMHH#Zz-t{u=RjJ z%FXB;Ft0VhU-S64HNf%Xe~5h-^J727zH1k});Ea>0P}8+*J*9s66JT7&T= zGarzx-2n4i16)J-JKhIqUK_4+Svg)CrEC}@#p6EYm&bnoY_-gNH5Kpy{=Gpw+jKE& z)-tMNd$41-R)w5@kN#pL;@s8%`(pt4#FKb;_rKCsD6=wPUv}O0-{EaXhb#_|P%Nh% zYYpHxJpOGBpcnrGWBxK>UuKT@-^F|02fPc%jJeD7Z16jv*X9CJXa+gPvl#!!8b9Xo z&lo`CUESmU5c|)gxaa+5R|YDZtBFd)0a0W=U@j}@-mGy9&#vwO-0yfFVE7N_`@no9 zurIAwzz1-zu=xNfbk6+Wy6XV%_4u#*96MqvNB6fg2htvlhJVK)~zve7E*dVu+W zIdQMsfqAU~Jjdg|&TD|e{tcKLJ%=*N@_T)fc@gqXD>5HY1Vt>F24LRV0rLAIUFm&* za8Rc;0P%by_VK!Pe(vpAvU+mu-r|5<#ap_@f&B|S{_7S4^kE-9pwifvamoj5v|G2p zyt<5ggo3$%eM3ZgohAq7>pTbO$Nu~3fqmHs-W7B);QGPx`+&B6Q&ei5I0ycn{*NDP z+#BWZ`WQgCsPY^@Jn}uhpP|5ZFQ^yxWh5B;OYZ~lEzyYl*j{02b@KeW?sEYBUEr!e z2N3r8_jqfKeOXBr;(){l*j{0&b)p;?&>Y}#!T2wXR4oP&U&MaAr?)2a{c*<7^6w0_ znj58E4}cHQ{s8y4uEz0f^=?nQdmjMbslPce@fq&}s<;l=hkg7#zFMsHO={hWK-Ie@UA%=ZoZgAKR)-e3iMK-980V6d8d&I0q=3vd?7S9>2I z%#?i&AU=}$e$}7v_b7LUgG$8#<^v|OfWQa5+2g+oF+hlYy~ArU{{$A%^#M^8<^rbk zF**TdDlR54SKV^&oM0>Kc;G1F=2aK>KU|#Eh;j_T9js3zt$9?xMkInZ-D1Cw|^8phGsREY( zC+=C`SKs3PM(Brp3{a+Lfg$$e`M&?wNd?riR2Jj|@ZLaK*8{GwIAFX9l{f|nu^;d2 zv%Njz6+XokDIZYAZ;5?ZJ^*_j?b+Y}-Rs*xtb#B2ppOBHz7Am6AE3)TPNjT6S>GFs zC>!_yTMrmuBtZ=DXpev4tB7j>qV0On8h^XP#{B_W&F)m-1Na@GGR6T{=x>bRy+Mlu z2ABr0r0<0Ph4%qPi~)rGs}D&2&XB!3+;1wty!He>0_E>{ zA0WIHAr25NUF_Sq->=9V&s4w%T!Fut*rtf=-Qj*i34Fl$9{)v&0Sx>7>RQSfy*pgu zIN(b7fDVOcaX_yL0rQ#z+zVxWCw$q@1BLzWeBbu=^eS$_N9F?-Ebs+(r#-X4|Ihds zV43(A_Pa5^VSj z-Unnk4-ocGpzUX~TYG;$5Pk`ZsW{+mWsC#N2XqY&xQw3%9BbSS5&ELF&S1xl=9VAkymz_Ynqp!|U;eL#qPx7LUIZQL)hJxoe^1$@92;K7~? zK;ih?fi4EXxP4dP_wosSfMI`9uvGNAO8J1A|J`9=Uh{w-MERTE2Mk*e5cWCWeF1gb0n^8r=XuJL9P7%zdq z2b_U&8P@}@wDo}TdbTS}0>dOAAAs)&@wq@LeE|NxfIS-=reHg75*Q-^^8sT7WYs2t zic28y0VSRbSR7DsGd1>dlt9V{{4X4raGzl79Eu3E@5@nC*0f2Wk`hRKK-6X&P*xvc z>j9OtPGf2j5~zp|usC25#$tU`QUc}!Dyddu$|Nwc1k49aEGoOuBv45Szz4YRO>{cZ z8F>HxkCALmu#%cKrc45ZB_JQL(Q57o{{P5)z+gGqS(89jC4fD4aU5VipsFf1zDxom zC4h0?`2fTLH?ufkq^PXYBv45Sm=CC=T8$}_z{C=$fDgC|YZ{Ls!|kYT`vfP}yj^G# zh$WEtfOX6TBCH9PZ?Evxp!w0{#(aQTwMk%l2>?HCJs@hg=mY*|34H+LfY=AL?0tdh zEx_)my96rW0}uzaZ7xuELpJ_rmO#n}{9y^>0P_JeYu|1(32+YGGZ!!)U`AmQsF?)h z1KR5yt_PS8sG0taU6VjXe1JU{FjF=O%qW4t2b^BwIKX_sjQY3ROah4yh+3uh0i9NR z)ii1nFbPa2feQEl>_i>&0rfU#<9-GSbfU=N=G^FP&ISHQ34Fj!p2n*%?mwO^@9A|D{^ zUk&WXv47OE`M;U5NnlP1l)wjcv9Ec*VSi4o+wCTSt^^9~148Wo7%4`~Z{vPfbyhM7 zWFmnA`hWoYEg$nohW$*mZH<@&`Xx{x9}r`|*}__16z}+@C;4c8N(KPYEo*2N?GA zRG_tO5|~p0c;CkDvu!`>oUGRa`mo=zaeq#2+3hBQ>?P3hd+pl?4`<~A`mm3^Jr?t4 zuR3edB#?;&^u8^=B{r`QFzjcd5o^RGuviJ`ox3@FfMI{JDzn~90+~ucK42r7dVfHO z{c}i^#r&D7#u_sTEJOnG0r)#Zr=k2Nq;cO6>BD}@{?6Y*bY-2G1oDsoeE{&kg1Nvx zlz)GO59q@_uC=wkJd|Q>ngkXo0s4UU#v%EDL2*EceYcvf1PHCx)uRLe_D2eU?2i%v*&ihUvOh`y zJFb3nr~tNI{m|;YE!K}vpu2sz0XX(Y$S-Dpxcp=G*M`z(>_Y*~q2k$b>e(DxzwPRW zR-5)AA2a^gKEB^)CeC;g?0+*|pThn{>G~A*x6<_~?DvfVz1Tn12ZJ3)-==T&WZx*T z?dsL*iM~-_i}i{2PxN^)cYDJAZh90*vA@%8D(*7H{&sp4NU^__9tC>YCsdo_#pOE< z{x)?EPqFU~n?d~!It|%efTOXVFwySrS#{X@( z6ZkLIusaOc@7^B^z+Ej_umyJm&$^rX*!Skk3wU)O`$7F?Qon|he!MgOHE}8y4@>%~ zHWolEo=sIE@77ZQaeYwj;lZmYfE^Y>_JewI?dn7JgL>Y!&HKApku&63CxC6{p|c6@ zr`EPuzlMhN3+tP{9(nQ$>(_k!W>VYRKl*j;2i0C7?A6iDEM$LBeaL=KJt}zr(0Vk? z`cOPQ_m`x89DhUWy?jQ=cZ&iF^%Lq>`WvR-wK4Y5^!ADCl3&>Vrmr7npSWq8^o0rx z?k8V6tPcec)bq5f4+Rj^v)NJjBw3^Iy@vV|>^~R`L;N>UANwC(sh_*S{kMrzF*%_C zy7jyxt`7x})W=-8!%zTQx*$I34nqMX^>L%y?s9hJe@T5z)Q+p)RIS%IPp-Lhv4ENb z>f>{yyj-Ah5*? zy8L*=bp_z+yNBLlyEkm}{x17{0&w+Ra%2&kqG*TrujvSRN&v3D8PumNz+Ju>)Tb=K zT^>}Y1;F|)H@uJpbrsI$LiW=Fpn^j7(*j_9$bO#yP`?(^mlnWQuS4v!0Mu{x+@BJ_ zcGvjh%VLvCXx>S&pB6yh{5Xz65}EC$*iQ?fe}2Bx;7>&N&+mIJpnrWJWdTV`l0r%V zTRN{iC4h@`KFJ+@iPFEBoL6Cs7bF7cUtif~eb)!*wj|$i^_$6Yy3i|tbZwsn^j(k= zKwo`I0Dbi-2=v!)k%2@2{q@_dHv#kuMrU@MfHrm5mzxDR0X6#sqZ26~pwmfS69{Z3 z45tgR0Mci>$Ib_gfN=j@uzRm7Z9zlHAd;%%;Wp}f2fp5mc2K|8d#dM%5NP(C={=wY zZ1$e&Iidi1PNWVXfKlvo7)*wM)UEO1)=2g#fKlu-4pIGLmQ-=x_<#Y}*DKd04R`N6Xf68CRQ>7G7-scQpKWHwL{8<6fF zGFtb2HW1lZPOO4)U*3pXYm@-quUajKB6|s zpFls4qX>}O_+JoPz}n90;bye*hD{VuwHvIh{Gco?;o+@p5^4F`w;i0 z`+``VbpIn8tyPrs(miqiSh9@VbYCFdLmwRLP4@-S$)d>cI+yO>f#WRac#8A?4edUL zJRvvSFG{&%`f<9)Gu-yNo8O!6$H=Qn)zp0xasFdE8>=Y46UlI2B?XV*#p(Xg`pRR@ zeYEL*gq*5aMcs4%#^E^DGu&5E$wPRe?vWJhy$faY`9ow?wbQ2is%dm`eio?vN0Tb_ zXLG#C)syR$b#XWStO8qk*B8u9bj&YB*o%kE} zRo4B=?y<%`=>C>eve`iVJiU#*G&Rt@i!-3}XCi$O>43L^ea!3lOX2?AIL>R1w``v; z-9HI>zY%E<>F?`o1F`Ot`F)jj@9+&>caXl1MBU%ubK1bYiGAd?@dGu~{ez+3?|Plz zOW%WX`2pHMW&D8CJ;r;yn?v2dx8k~AA$E^n*f<8eeRHMVsh94dZ~6U0UiVpHKeQFuKq38r)BU>B{b?xY73UYq z=WF~8^#Ar8us_HK3gri4-Mcm2I_v%c(Eayv#J}ty^aJ;$4WiF|vc*N`?WW(Oz22&w z?!D}_&b#Gxf1}T(uRLz~8@Ihfx+ zY9nvl7t-fTo{)9y`;RvEqs(}mdRdh3A7ul%jRn;Gk?4^t&FEa}K2O{iTKBX8=vu!2 zN4@UTI$88_I2L4X1JJj#_h!^O9pyhqs-@2l@UOW4#a{o*@cn5UlMQ?oG-WmxQ1|T? zzN5T;XcgsJ<37;8@c$QH|B`)LCyPE79ht=g(79XRME)iu;$GiEWqF>Y@9q36+BrnO_G6$>1t?7>6N7=V2pvHqJb_CKDH{$J0&O#jYahT(Ei=cWI@9I5~H)~%qg zZ+QLBI{xdvk8iBIzst2k1|1n#cS>XU-;&|GwA1#_?J7 zuh@Zh@Ka&?uCtQ;2YI>i5_wtYfBY87-6{4#y61W5N$WpP^!gWuXVE|Jp$#aN+6Evq zt^d3e<+9*kxc@xfRg&(V9aG=wAHTWIbI5N4z3m`{e!SK;0G&JEh`em;zr_7Ls8{4; z=i$(~e89`R{^uD3WHa<5rS=1X{(l~2;$PUBXI#$fUePv{?r9^?lVZTzq5M^E1M`jp z@*}0S0bvLEqrLu%y8hGE{e_9oAB%hHUO(tuKH$lL{;50RdDdL|XZ};{4|(4_M06A> zhtA!&iM+`BKjzlGWDdQ^2F~+(&te>)-IUS>pm*mNk#q0&KO)h07s&@m_gtS;tTz?z zrF-QqeA9tt=E6x?Jr+Rk zngbMR|F?9X8SbeI{eXMeK-+8p0)hS=rjS1piT;1t`#+`oOmQ#WE01lUQ+peLz7+%T z-QQ)$0Mh;Eu%?^IcrSeq$~&!y-*Pk?==y*^^gcj($ZIY?s9p8>S-b~+H|h(t%st)@ z(tCK0HW01X+Xf_Ogt})pWjfWDpGBR}HxpT}CT zbpILjQ5f70v4Pt80q8`r;0L`8Wa$H>`$CNOX`QE!7KYRT&y=t=jrp_2J&7j-Ybv|XdHO8*T3{Q&D>x2loI!2Y#e6SvCNFv-Gh5I+qXFK$-r3(lH>^ePQQ#Y28kGoEi&$569dC za-+|~{UEcHxrao1Q;TE+uk=1Zx*awSsQz+XUpd{&Mxdh=B*g=jwE^gG<@g1SmEHF@ zPD6Rznm{ddpRxhxBVh|wwgJrt*I)zRL?ZUnu|TN%yHG~B#>qzVs$%Z_fNbD*aa_r< zK)OVJ5J`UvRyI&e-OHY9WCPkO`k!C}@&Wn=2gm!`;9j~{UPBvruD1c&!DV&U{Ss{8 zr`acLZYk@8(6#))FQd%0oja2r*rw0{y^pZQvN@1+W9?{Famlau*|xl1*Le zYGVV?IrP55R2SV&%4f<3eh0^S%?p<62Tb=vO`oV>U2eMpeJU*+6%FAWuK=Ov=*Y zf#O+|vw>!^Mr1ZnJQd|mk&6izV*}43Gv)_!SLxIpI2%~(Sg<-Zk#<9_5?Fu@aIKi> zXURxAitO2Kt{R=b@stg`4#!!p5$SK9Uv&6UPjtF(M{To#>D83$9khW~)YfyutYSjF zqw)yY&Ha}(7!lEQV8|X}L16|!mru#+dDzARr zyr30L>IY2sc`0Iv?eg!L!4AgRK&boMl3d(lYduTUTb5m?o*AX%0n>e!!Y*iAZY=2f zf!E@gYed)k{3FOM)+?y)vLXvQ4#$F5d);p%Ka+hRH=m!CunXFbw}BO`6Re{ALZmg4 zirmEr1tmLovi9QNjXqa)jS4>BNgZ!*_MX^k_8vFZdX7&u&g?lp+1TH6e4??h=XkfV z(sR7iX!IO!HyWGaiLF$9qxb$(jo$W8HhTL%(deabx6w;Kx^ITvm81Kwd6LEb>;18~ zmkK=hr=$YU{Yk07bALiA@Z6t}3btb5?@C5q_&Z*P>VC(|Slw@X9Z2|FUPluCme-;0 zey`zm?7QdjCOO)Q&!d}|0N*{2*HEqQ(XAsu-Se0dQ1?8h1k^pwI|6omvpl8*wtctm zcr)pq?YJv__iTp*sQdW%OdhjW*AI*6Him|~ejl4z>(;OExap2}*j|Ijo5ArWZgYow zaeXsEPJFyJ=J?E1efoI7{k{FA=}FTI{?;6Uj=z;Ye$(Q3anoze&R zZn8rV;zWb{)^yC4aNY@A`bO>)!ebUh0FT{;DSHwDxGwH!+Y^A}O?I^7&*PYfdm>=V zGa>?H?;>D3rXwL>+Z%=?u;T?O0usD=0(ON*Pe6iKPe6iaPe6iq5#YoCf+Yd@3lZ=& za>L)2Y%V@bAmI-a3Fuf7(6J<-V-cWZ5ujrckQ|qRfP`2U5|sI~>G3W-9;V03J?UPp zZZ%bk^X<*v-VM9n)g!L{TzD#81B_tbrpD@~6ec-P;7$eVY^FZjM6Qin_-U-+D9NxZvQ2>jj# z>61wO=BSI6kuPlSybRvGo>z7+bl=%~zvrEQlkIw>$N2i(Ww1ovov#D0ukyU}ThsjR zH2)R_W$I0-nWx?lPEz_e*f^ zOk*7N&L8-d?tjViu5YY|{HJB`Sby)_{$RUVm;} z2j9OqM)#pDWFmtC@a}YfO+4Q5yW+C(kk?`5xn$sY*Edg|RXKuhRQN zJ>Oh|W(w!7Dr*j#IqzOSn&Um(^B(dtYk80i9LCru_;h9Dn!}4n@vL0WDad;+`wPLd zeBTp1|FhbDT2`S99v{k@W&Xg^=a9&&_!Qsaxyw+WDc~uUkiS2 zi*%*uaTNbQ!TTz}|3^apJx`zU{ExE#FXEaz`RkqSu$r1PWty&$zwWkte=W^kAsx}3rmp!=#~#W3dKP{wV{E z2@972c$N>?hcf@R7WF8e(t1uG>pJ?nsd<+?3LpbvVBFeg$bTlh7eNNloowLFD1Qfu ze2&6Fro0zK2J!>H=J{9b9_pOsTzJnw2A{#6&zWOo@Fg3#HOhbQWguQ910BzWckwzb zpTi$;PT~GGAabYAVSNlb51wTMkN5nC>jC1Oe~b1o??*ndpC8oUsBh6-vQ|h zNaVjmnvmya^Wr(3FIff;2G6Z!@h({`O9tRwcyKl$dX|wdQ3g|wC3(qb88XO=ms#62 z8MyV6705yJMtzGxzCRofR94;0Jg)(qHewO}=aL*hv_!90tKpv1UeS9Mwv;L-(0iP{!&7IHP&t{*V+V`?ryvxNP3>!GN3mM*~jye0MW0>@?$ido9kl;t!ha`R`Yp^4~5v z8GkMVAK=(@*X`;e7}OXBj4P`?Z}%uxE=Z0Hf~3L<~Eu@zJD7{BHx$f zI`6O3eQHPTsvnZgenp4qO6U~b;zN9iPw~wLC75|2d>L`SL!L3m^M|M$L1c zin8L@S9%^!D>4tDO>%!4%Jjjfki^4pc^(R>g8{TFZX_S#;kU^{(SBoSC;jAw>3XCe zBK^n<5d(vcw9SNa7wxno?vvA)Rz}*N?B(vp=w;i`lyZNPr`_qQinMF(H*ekoxj!A{ z(7ss?k7@4{$(^(#@!jQIaWMt$^p_LUPML%DTO!>IiM(V!Mod9_DEEW!Y4(^Qv*J%M(`1e4f|eB@ZHf<|XA$lr>j=iaaJJaCW9+19*m*4-8r$5|tHB9d5^Wx!kY#Z%3Oo6_aAW6>5 z!}4$PTAaHX^I3oD3;8EJ{gc{%ng@>6Jm+kg^nkWsNzokA?`*Ds^t<<8J^hdI^bfKh zV&EtIbu-yM?}faww4YapZGyi2NMFvA2hg7tew{r_9-vvi{|L%jKVU8#Q2shUvmVf2 z7XDLm?}>>59-b1=nkf%~{AV4%2GUMD;tzB?`5+H@kpHJH=F$V`SNyi1tPB0Gi~3e#Fy1O#Y(%Riq2o_Sm~< z9hMKVrA+h?@bF&GLwX#Zi+1q@9>&=c`C*!BdnY%02B{#e?HpZKQM1D1Uke%8cpG=QUZ=u70QBVPabfc;K8exAnt-htQTL)x*e` zk31mdzJ43CgI^}ydU>CznN}pS;tf8 zAspkJ-&_{W>3#zqo`musOmnQ@dG4!v2=7N;CLXx>}bH2s*hL=O?hO zh{wBYalYg8ZGV1iGd|C4OStY7w=p3<$!$%@Phg`J^W8J|{)9PhKa)9b-_Lw&6Mx7E zIqq0Nj@wV-pn==50jkl!?I#*d#6f2wUu!gQ`-uj=%7oi@8~c%OB8L|qn)~Z?pW0Eo z>PP*Gj)X4JDZ0f68tCCue4_z(9u35~q&ooEcdgZ_yb50QnF9$wm6vc zN1I_2$o~V<|3%U}ySe+$pzjBw{52%v@M0ur($SQg4@4j0`z)0I35k7k?+tUllXC04 zXh7S8`sUarKl+y_3*VW_V1mBifooi!$|;8|enH>-){bNz^8F6>gSypp--x~Enyby( zx5I*u|EJbRs_%csF>P!jz9|p%%emiqNcZ%|6UUeH^o{;B|9>sYoHu_I>2{OSFhSpM zXIr>#6{$zALEn$_ee+w_q~YU8V`-SPZ$}IIq0L>6#D4i4Me8;rX+YmjZpdlpgY-R= z?@+er?~D#FMy(%* zG~C|bE8gGf`{P{Trb+t_+d$vk_aV7!-HyD6Ni=X>#@QtLx((7deV_8@7qM-e+lS=% zH8Yix9HGwx(~8Fw0~=)Zy-_L>i=S2w~BLl_5U~QgFp1~cHe&}|M%eB zD*I=07Y_IjJUbmCpGN+d;`$^SLi_hZ`UaBxtnBZ-I42rhKWP%sj-w6vr1tkQ^^Kfu zyLOR30O{*UqCvU{8D4omhE(!YK0B8#SxAZUw1F7vc%|laMHP zem9XhWj>T|^{spo8rb(38h*$3eepDXPentsp9b_LJ=_9ievkTYY!kV&54Ar@KBpX< zZqP5+Ux)gRadZSU+z;h}_JH%NNVJEfANGkfSNtj3(5`Sn8g`J<{=wmb*M~Id{w(qd zXm~%ax!D3~kS;X;`V{)VRi6F(ww)cLulpi>1&O-&5K?Y)zqJ0)m+awTD1QLy4xY9i zf0Vv&*s)ut;Svp(5q6PwP~P6#+j}|EzMJ+=?LV=1^2`&PC)ReG__wyRxpU_B-p>A) z@9pe65AT{WvCMO<<2AgN_wZh};o4%GY@23L8e^ zh8Nv;-_;kcxMx4<`*F>nd%vZ7c|H6FZiu?I2y@h*DLwcWYFnaFKGkvbG{GP-VwQ&r`;>ERb{)_In@2U$1+wYJz zxc0<0K6P*c{Df_=jQehmL>xWdA3HheI_0PKu$H@tbzJ1vAbs + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); + this.Properties = new System.Windows.Forms.PropertyGrid(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); + this.buttonEnableAll = new System.Windows.Forms.Button(); + this.buttonDisableAll = new System.Windows.Forms.Button(); + this.buttonClearLog = new System.Windows.Forms.Button(); + this.buttonOpenLog = new System.Windows.Forms.Button(); + this.buttonExport = new System.Windows.Forms.Button(); + this.buttonImport = new System.Windows.Forms.Button(); + this.tableLayoutPanel1.SuspendLayout(); + this.flowLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // Properties + // + this.Properties.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.Properties.Location = new System.Drawing.Point(3, 3); + this.Properties.Name = "Properties"; + this.Properties.Size = new System.Drawing.Size(356, 534); + this.Properties.TabIndex = 0; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.Controls.Add(this.flowLayoutPanel1, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.Properties, 0, 0); + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 1; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 540F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(449, 540); + this.tableLayoutPanel1.TabIndex = 1; + // + // flowLayoutPanel1 + // + this.flowLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.flowLayoutPanel1.AutoSize = true; + this.flowLayoutPanel1.Controls.Add(this.buttonEnableAll); + this.flowLayoutPanel1.Controls.Add(this.buttonDisableAll); + this.flowLayoutPanel1.Controls.Add(this.buttonClearLog); + this.flowLayoutPanel1.Controls.Add(this.buttonOpenLog); + this.flowLayoutPanel1.Controls.Add(this.buttonExport); + this.flowLayoutPanel1.Controls.Add(this.buttonImport); + this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; + this.flowLayoutPanel1.Location = new System.Drawing.Point(365, 3); + this.flowLayoutPanel1.Name = "flowLayoutPanel1"; + this.flowLayoutPanel1.Size = new System.Drawing.Size(81, 534); + this.flowLayoutPanel1.TabIndex = 1; + // + // buttonEnableAll + // + this.buttonEnableAll.Location = new System.Drawing.Point(3, 3); + this.buttonEnableAll.Name = "buttonEnableAll"; + this.buttonEnableAll.Size = new System.Drawing.Size(75, 23); + this.buttonEnableAll.TabIndex = 0; + this.buttonEnableAll.Text = "Enable All"; + this.buttonEnableAll.UseVisualStyleBackColor = true; + this.buttonEnableAll.Click += new System.EventHandler(this.buttonEnableAll_Click); + // + // buttonDisableAll + // + this.buttonDisableAll.Location = new System.Drawing.Point(3, 32); + this.buttonDisableAll.Name = "buttonDisableAll"; + this.buttonDisableAll.Size = new System.Drawing.Size(75, 23); + this.buttonDisableAll.TabIndex = 1; + this.buttonDisableAll.Text = "Disable All"; + this.buttonDisableAll.UseVisualStyleBackColor = true; + this.buttonDisableAll.Click += new System.EventHandler(this.buttonDisableAll_Click); + // + // buttonClearLog + // + this.buttonClearLog.Location = new System.Drawing.Point(3, 61); + this.buttonClearLog.Name = "buttonClearLog"; + this.buttonClearLog.Size = new System.Drawing.Size(75, 23); + this.buttonClearLog.TabIndex = 2; + this.buttonClearLog.Text = "Delete Log"; + this.buttonClearLog.UseVisualStyleBackColor = true; + this.buttonClearLog.Click += new System.EventHandler(this.buttonClearLog_Click); + // + // buttonOpenLog + // + this.buttonOpenLog.Location = new System.Drawing.Point(3, 90); + this.buttonOpenLog.Name = "buttonOpenLog"; + this.buttonOpenLog.Size = new System.Drawing.Size(75, 23); + this.buttonOpenLog.TabIndex = 3; + this.buttonOpenLog.Text = "Open Log"; + this.buttonOpenLog.UseVisualStyleBackColor = true; + this.buttonOpenLog.Click += new System.EventHandler(this.buttonOpenLog_Click); + // + // buttonExport + // + this.buttonExport.Location = new System.Drawing.Point(3, 119); + this.buttonExport.Name = "buttonExport"; + this.buttonExport.Size = new System.Drawing.Size(75, 23); + this.buttonExport.TabIndex = 4; + this.buttonExport.Text = "Save Config"; + this.buttonExport.UseVisualStyleBackColor = true; + this.buttonExport.Click += new System.EventHandler(this.buttonExport_Click); + // + // buttonImport + // + this.buttonImport.Location = new System.Drawing.Point(3, 148); + this.buttonImport.Name = "buttonImport"; + this.buttonImport.Size = new System.Drawing.Size(75, 23); + this.buttonImport.TabIndex = 5; + this.buttonImport.Text = "Load Config"; + this.buttonImport.UseVisualStyleBackColor = true; + this.buttonImport.Click += new System.EventHandler(this.buttonImport_Click); + // + // MainForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(448, 537); + this.Controls.Add(this.tableLayoutPanel1); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "MainForm"; + this.Text = "Plugin Debugger"; + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.flowLayoutPanel1.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.PropertyGrid Properties; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; + private System.Windows.Forms.Button buttonEnableAll; + private System.Windows.Forms.Button buttonDisableAll; + private System.Windows.Forms.Button buttonClearLog; + private System.Windows.Forms.Button buttonOpenLog; + private System.Windows.Forms.Button buttonExport; + private System.Windows.Forms.Button buttonImport; + } +} + diff --git a/src/AcaciaZPushPlugin/PluginDebugger/MainForm.cs b/src/AcaciaZPushPlugin/PluginDebugger/MainForm.cs new file mode 100644 index 0000000..e322fce --- /dev/null +++ b/src/AcaciaZPushPlugin/PluginDebugger/MainForm.cs @@ -0,0 +1,245 @@ +/// Project : Kopano OL Extension + +/// +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Xml; +using System.Xml.Serialization; + +namespace PluginDebugger +{ + public partial class MainForm : Form + { + + public MainForm() + { + InitializeComponent(); + + // Initialise the options + Properties.SelectedObject = new Options(); + + // Expand the first two levels + ExpandItems(RootItem, 2); + } + + private GridItem RootItem + { + get + { + GridItem root = Properties.SelectedGridItem; + while (root?.Parent != null) + root = root.Parent; + return root; + } + } + + private void ExpandItems(GridItem root, int depth) + { + if (root != null && depth > 0) + { + foreach (GridItem g in root.GridItems) + { + g.Expanded = true; + ExpandItems(g, depth - 1); + } + } + } + + private void DoEnable(bool enable) + { + Properties.ExpandAllGridItems(); + EnableItems(RootItem, enable); + Properties.Refresh(); + } + + private void EnableItems(GridItem item, bool enable) + { + if (item != null) + { + OptionsConverter.CanEnable desc = item.PropertyDescriptor as OptionsConverter.CanEnable; + desc?.Enable(enable); + + foreach (GridItem g in item.GridItems) + { + EnableItems(g, enable); + } + } + } + + private void buttonEnableAll_Click(object sender, EventArgs e) + { + DoEnable(true); + } + + private void buttonDisableAll_Click(object sender, EventArgs e) + { + DoEnable(false); + } + + private string LoggerPath + { + get { return LoggerHelpers.LoggerPath("Kopano OL Extension"); } + } + + private void buttonClearLog_Click(object sender, EventArgs e) + { + try + { + File.Delete(LoggerPath); + } + catch (Exception) { } + } + + private void buttonOpenLog_Click(object sender, EventArgs e) + { + try + { + Process.Start(LoggerPath); + } + catch (Exception) { } + } + + + private void SerializeItems(GridItem item, XmlNode parent) + { + if (item != null) + { + OptionsConverter.CanEnable desc = item.PropertyDescriptor as OptionsConverter.CanEnable; + if (desc != null) + { + string name = item.PropertyDescriptor.Name; + object value = item.PropertyDescriptor.GetValue(desc.Object); + + if (value == null || (value is string && string.IsNullOrEmpty((string)value))) + { + // Skip + } + else if (desc.Object != value) + { + XmlAttribute attr = parent.OwnerDocument.CreateAttribute(name); + attr.Value = value.ToString(); + parent.Attributes.Append(attr); + } + else + { + XmlNode newNode = parent.OwnerDocument.CreateElement(name); + parent.AppendChild(newNode); + parent = newNode; + } + } + + foreach (GridItem g in item.GridItems) + { + SerializeItems(g, parent); + } + } + } + + private void DeserializeItems(GridItem item, XmlNode parent) + { + if (item != null) + { + item.Expanded = true; + + OptionsConverter.CanEnable desc = item.PropertyDescriptor as OptionsConverter.CanEnable; + if (desc != null && parent != null) + { + string name = item.PropertyDescriptor.Name; + //object value = item.PropertyDescriptor.GetValue(desc.Object); + + if (desc.Object != item.PropertyDescriptor.GetValue(desc.Object)) + { + // Attribute + XmlAttribute attr = parent.Attributes[name]; + if (attr != null) + { + if (item.PropertyDescriptor.Converter.CanConvertFrom(typeof(string))) + { + object value = item.PropertyDescriptor.Converter.ConvertFromString(attr.Value); + item.PropertyDescriptor.SetValue(desc.Object, value); + } + } + } + else + { + parent = parent.SelectSingleNode(name); + } + } + + foreach (GridItem g in item.GridItems) + { + DeserializeItems(g, parent); + } + } + } + + private void buttonExport_Click(object sender, EventArgs e) + { + SaveFileDialog dlg = new SaveFileDialog(); + dlg.Filter = "Config files (*.kpdcfg)|*.kpdcfg"; + + if (dlg.ShowDialog() == DialogResult.OK) + { + using (StreamWriter sw = new StreamWriter(dlg.FileName)) + { + XmlDocument doc = new XmlDocument(); + doc.AppendChild(doc.CreateElement("Options")); + SerializeItems(RootItem, doc.DocumentElement); + doc.Save(sw); + } + } + } + + private void buttonImport_Click(object sender, EventArgs args) + { + OpenFileDialog dlg = new OpenFileDialog(); + dlg.Filter = "Config files (*.kpdcfg)|*.kpdcfg"; + + if (dlg.ShowDialog() == DialogResult.OK) + { + try + { + using (StreamReader sw = new StreamReader(dlg.FileName)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(sw); + if (xml.DocumentElement.Name != "Options") + throw new Exception("Invalid Xml file"); + DeserializeItems(RootItem, xml.DocumentElement); + Properties.Refresh(); + } + } + catch(Exception e) + { + MessageBox.Show(e.Message + "\n" + e.StackTrace, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } + } +} diff --git a/src/AcaciaZPushPlugin/PluginDebugger/MainForm.resx b/src/AcaciaZPushPlugin/PluginDebugger/MainForm.resx new file mode 100644 index 0000000..cbdd805 --- /dev/null +++ b/src/AcaciaZPushPlugin/PluginDebugger/MainForm.resx @@ -0,0 +1,6293 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAYAAAAAAAEAIAAoIAQAZgAAAICAAAABACAAKAgBAI4gBABAQAAAAQAgAChCAAC2KAUAMDAAAAEA + IACoJQAA3moFACAgAAABACAAqBAAAIaQBQAQEAAAAQAgAGgEAAAuoQUAKAAAAAABAAAAAgAAAQAgAAAA + AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQgIAAAAAQ0FDIkJAQlkAAAAAQTtFAUNAQgEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBDFEJAQbxCQEH/QkBBbAAAAABCPkACAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QgIAAAAAQkBEFUJAQb9CQEH/QkBB/UJAQf5CQEFwAAAAAEJA + QAJDQUMBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAENAQQIAAAAAQ0BDFUJAQb5CQEH/QkBB/EJAQf5CQEH+QkBB/kJA + QXAAAAAAQkBBAkNBQgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAENAQQIAAAAARUBBFUJAQb5CQEH/QkBB/EJAQf9CQEH/QkBB/kJA + Qf5CQEH+QkBBcAAAAABBQEACQ0FCAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQAIAAAAARUBBFUJAQb5CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH+QkBB/kJAQf5CQEFwAAAAAEE/QAJDQkIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAENAQQIAAAAARUBBFUJAQb5CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf5CQEH+QkBB/kJAQXAAAAAAQj9BAkNCQQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQUA/FkJAQb9CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/kJAQf5CQEH+QkBBcAAAAABCP0ACQkFBAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFAQQIAAAAAP0BBFkJAQcFCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH+QkBB/kJAQf5CQEBwAAAAAEE/QAJCQEEBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFAQQIAAAAAQD9AFkFAQcFCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH+QkBB/kJAQHAAAAAAQT9BAkJA + QQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFAQQIAAAAAQD9AFkFAQcFCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/kJAQf5CQEH+QUBBcAAA + AABBQEECQUBBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFAQQIAAAAAQD9AFkFAQcFCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH+QkBB/kJA + Qf5BQEFwAAAAAEFAQQJBQEEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFAQAIAAAAAQEBAFkFAQcFCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf5CQEH+QkBB/kFAQXAAAAAAQkBBAkJAQQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAREFCF0FAQcFCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/kJAQf5CQEH+QUBBcAAAAABCQEECQkBBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQ0FCF0JAQcFCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH+QkBB/kJAQf5CQEFwAAAAAEJAQQJCP0EBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQ0FCF0JAQcFCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH+QkBB/kJAQXAAAAAAQkBBAkNBQQEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQ0FCF0JAQcFCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/kJAQf5CQEH+QkBBcAAAAABCQEECQ0FCAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QQIAAAAAQz5CF0JAQcFCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH+QkBB/kJAQf5CP0FxAAAAAEE+ + QQJDQkIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QQIAAAAAQz9CF0JAQcFCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH+QkBB/0NA + QXQAAAAAQT4/AkRBQgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QQIAAAAAQz9CF0JAQcFCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/kJA + Qf5CQEH/Q0BBdAAAAABBPj8CQ0FCAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQz9CF0JAQcJCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH+QkBB/kJAQf9DQEF0AAAAAEE/QAJDQEEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QAIAAAAAQz9CF0JAQcFCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf5CQEH+QkBB/0NAQXQAAAAAQj9AAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQAIAAAAAQ0BBGEJAQcJCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/kJAQf5CQEH9QkBBe0lHUQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQAIAAAAAQ0E/GEJAQcRCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQdBDQUQSAAAAAEJAQgEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQAIAAAAAQ0E/F0JAQcJCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdRBP0EoAAAAAEJAQQEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQAIAAAAAQ0E/F0JAQcJCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdVCQEEpAAAAAEJAQQIAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQAIAAAAAQ0E/F0JAQcJCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdRCQEEoAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQ0E/GEJAQcJCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdRCQEEoAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFAQQIAAAAAQUFAGEJAQcJCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdRCQEEoAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFAQQIAAAAAQEFCGEJAQcJCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdRCQEEpAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFAQQIAAAAAQEFCGEJAQcJCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdRCQEEpAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFAQQIAAAAAQEFBGEJAQcJCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdRCQEEpAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFAQQIAAAAAQEFBGEJAQcJCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdRCQEEpAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFAQQIAAAAAQEFBGEJAQcNCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdNCQEEpAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQUFBGEJAQcNCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdNCQEEpAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBBGEJAQcNCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdJCQEEpAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBBGUJAQcRCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdBCQEEnAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBBGEJAQcRCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdBCQEEnAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQj5BGUJAQcNCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdBCQEEmAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBAGkJAQcVCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdBCQEEmAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAARUFCGkJAQcdCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdBCQEEmAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QAIAAAAARUFCGkJAQcdCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc9CQEEmAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAENBQgIAAAAARUJDG0JAQcdCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdBCQEEmAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAENBQgIAAAAAREJDGkJAQcdCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc9CQEEmAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQ0BBG0JAQcdCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc9CQEElAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QQIAAAAAQ0BBG0JAQchCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc9CQEElAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QQIAAAAAQkBBG0JAQchCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc9CQEElAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBBG0JAQchCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc9CQEElAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBBHEJAQchCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc9CQEElAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QQIAAAAAQkBBG0JAQchCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc9CQEElAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBBHEJAQchCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc9CQEEkAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QQIAAAAAQj9BHEJAQchCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc9CQEEkAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBBHEJAQclCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc9CQEEkAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QQIAAAAAQj9BHEJAQclCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc9CQEEkAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQj9BHEJAQchCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc9CQEEkAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQj9BHEJAQclCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc9CQEEkAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwswAB8bIAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQMAAAAAQj9BHEJAQclCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdBCQEEjAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADxswABAAAAAPC0AAHwswABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQAIAAAAAQkBAHEJAQclCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdBCQEEjAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADxsgACAAAAAPCzACHxsgAHAAAAAPGyAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQAIAAAAAQkBAHEJAQclCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdBCQEEkAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwswADAAAAAPCzAD7wswDn8LMAfAAAAADwswAD8LIAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQAIAAAAAQkBAHEJAQcpCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc9DQEAkAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwswADAAAAAPCzAD7wswDo8LMA//CzAP/wswB6AAAAAO+0AALwsgABAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQAIAAAAAQkBAHEJAQcpCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdBBQUEjAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwswADAAAAAO+zADPwswDm8LMA//CzAPvwswD+8LMA//CzAHkAAAAA8LQAA/CzAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBAHEJAQcpCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdBBQUEjAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwsgADAAAAAPCzACjwswDc8LMA//CzAPzwswD/8LMA/vCzAP7wswD/8LMAeAAAAADwtAAC8LMAAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBAHEJAQcpCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdBBQUEjAAAAAEFBQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwswACAAAAAPC0AB/wswDT8LMA//CzAPzwswD/8LMA//CzAP/wswD+8LMA/vCzAP/wswB4AAAAAPCz + AAPwswABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAENAQQIAAAAAQ0BBHEJAQcpCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdBBQUEjAAAAAEFBQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwswACAAAAAPCyABTwswDH8LMA//CzAPzwswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD98LMA//Cz + AHwAAAAA8LQAA/CzAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAENAQQIAAAAAQ0BBHEJAQcpCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdBBQUEiAAAAAEFBQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwswABAAAAAO61AAXwswCr8LMA//CzAPzwswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA/vCz + AP7wswD/8LMAeAAAAADwtAAD8bMAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAENAQQIAAAAAQ0BBHEJAQcpCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdBBQUEiAAAAAEFBQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA8bMAAgAAAADwswCN8LMA//CzAPzwswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD+8LMA/vCzAP/wswB5AAAAAPCzAAPwswABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAENAQQIAAAAAQ0BBHEJAQcpCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdBBQUEiAAAAAEFBQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA8LMAAwAAAADwswBy8LMA//CzAP3wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP7wswD+8LMA//CzAHsAAAAA77IAAvCzAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBBHEJAQcpCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdFBQUEiAAAAAEFBQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA77MAAwAAAADwswBH8LMA+PCzAP/wswD+8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA/vCzAP3wswD/8LMAegAAAADwswAD8LMAAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBBHEJAQcpCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdFCP0IiAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA77MAAgAAAADvswAg8LMA3fCzAP/wswD98LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD+8LMA/vCzAP/wswB8AAAAAPCzAALxtAABAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBBHEJAQcpCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdFCP0IiAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA77MAAQAAAADssAAF8LMAtPCzAP/wswD88LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD98LMA//CzAH0AAAAA77IAAvCz + AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQUBBHUJAQcpCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdFCP0IiAAAAAEI/QgMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAPGyAAIAAAAA8LMAhPCzAP/wswD88LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA/vCzAP3wswD/8LMAfgAA + AADvsgAC8bQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBBHEJAQcpCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdJCP0IiAAAAAEI/QgMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAPCyAAMAAAAA8LMARvCzAPvwswD+8LMA/vCzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD+8LMA/fCz + AP/wswB9AAAAAO+yAALwswABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQj9BHUJAQctCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdFCP0IiAAAAAEI/QgMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAPGyAAEAAAAA8bIAF/CzANbwswD/8LMA/fCzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP7wswD98LMA//CzAH0AAAAA8LIAAvG0AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQj9BHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdJCQEIhAAAAAEJAQgMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswACAAAAAPCzAJzwswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA/vCzAP3wswD/8LMAfQAAAADvsgAC8LMAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQj9BHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdJCQEIhAAAAAEJAQgMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswADAAAAAPCzAFvwswD/8LMA/fCzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD+8LMA/fCzAP/wswB/AAAAAPCyAALwswABAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBBHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQdJCQEIhAAAAAEJAQgMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADvswACAAAAAO+yABvwswDc8LMA//CzAP3wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD98LMA//CzAHwAAAAA77MAAvCzAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBBHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQdJCQEIhAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMAAgAAAADwswCX8LMA//CzAPzwswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA/vCzAP3wswD/8LMAfAAAAADwsgAC8bIAAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQMAAAAAQkBBHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQdJCQEIhAAAAAEJAQgMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8bMAAwAAAADwswBH8LMA/fCzAP/wswD+8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD+8LMA/fCzAP/wswB9AAAAAPC0 + AALxsgABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQMAAAAAQkBBHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQdJDQEEhAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8bMAAQAAAADyswAM8LMAzvCzAP/wswD98LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD98LMA//Cz + AH8AAAAA8LQAAvGyAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQMAAAAAQkBBHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQdJDQEAgAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAMAAAAA8LMAcvCzAP/wswD88LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA/vCz + AP3wswD/8LMAfQAAAADwtAAC8bIAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQMAAAAAQkBBHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQc9CP0AeAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC0AAEAAAAA8LQAH/CzAOLwswD/8LMA/vCzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD+8LMA/fCzAP/wswB9AAAAAPC0AALwswABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQMAAAAAQkBBHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQc9DPkAeAAAAAEM/QAMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwsgACAAAAAPCzAJDwswD/8LMA/PCzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP7wswD98LMA//CzAH0AAAAA8LQAAvGyAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJBQQMAAAAAQkFBHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQc9DPkAeAAAAAEI/QAMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwsgACAAAAAPCyADXwswD18LMA//CzAP7wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA/vCzAP3wswD/8LMAfwAAAADwswAC8bMAAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJBQQMAAAAAQkFBHkJAQc5CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQc9DPkAeAAAAAEM/QAMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAQAAAADwswCk8LMA//CzAPzwswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD+8LMA/fCzAP/wswB+AAAAAO60AALysgABAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJBQgMAAAAAQ0FCHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQc9DPkAeAAAAAEM/QAMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LQAAgAAAADwtAA48LMA+PCzAP/wswD+8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD98LMA//CzAH0AAAAA7rQAAvGy + AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJBQgMAAAAAQkFCHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQc9DPkAeAAAAAEM/QAMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPOzAAEAAAAA8LMAp/CzAP/wswD88LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA/vCzAP3wswD/8LMAfQAA + AADtswAC8bMAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJBQgMAAAAAQkFCHUJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQc9DPkAeAAAAAEM/QAMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC0AAIAAAAA8LQAO/CzAPrwswD/8LMA/vCz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD+8LMA/fCz + AP/wswB/AAAAAO+0AALwswABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJBQgMAAAAAQkFCHUJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQc9DPkAeAAAAAEM/QAMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswACAAAAAPCzAKHwswD/8LMA/PCz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP7wswD98LMA//CzAH0AAAAA7rMAAvCzAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJBQQMAAAAAQkFCHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQc9DQEAeAAAAAENAQAMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwsgACAAAAAPCyACrwswDw8LMA//Cz + AP7wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA/vCzAP3wswD/8LMAfQAAAADvsgAC8LMAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQMAAAAAQkFCHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQc5BQUEeAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8bQAAwAAAADwswCI8LMA//Cz + APzwswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD+8LMA/fCzAP/wswB9AAAAAO+yAALwtAABAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQMAAAAAQkFBHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQc9BQUEeAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LQAAQAAAADxtAAY8LMA4fCz + AP/wswD+8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD98LMA//CzAH0AAAAA7rMAAvCzAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQMAAAAAQkBBHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQc5BQUEeAAAAAEFBQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAMAAAAA8LMAavCz + AP/wswD98LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA/vCzAP3wswD/77MAfwAAAADvsgAC77MAAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQMAAAAAQkBBHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQc9BQUEeAAAAAEFBQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPGzAAEAAAAA/7MAAfCz + AMPwswD/8LMA/fCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD+8LMA/fCzAP/vtAB9AAAAAO+0 + AALwswABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQMAAAAAQkBBHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQc5BQUEeAAAAAEFBQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADvswADAAAAAO+z + AD/wswD78LMA//CzAP7wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD977MA/++0 + AHwAAAAA7rMAAvCzAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQMAAAAAQj9BHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc5CP0IeAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAgAA + AADwswCW8LMA//CzAPzwswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA/vCz + AP3vswD/77QAfQAAAADtswAC8bMAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QQMAAAAAQj9BHUJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc5CP0IeAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LIAAQAA + AADxsgAY8LMA4vCzAP/wswD+8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD+8LMA/fCzAP/wtACAAAAAAO+yAALxtAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QQMAAAAAQj9BHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc5CP0IeAAAAAEI/QgMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCz + AAMAAAAA8LMAWvCzAP/wswD98LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP7wswD98LMA//CzAH0AAAAA7rIAAvGzAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QQMAAAAAQj5BHkJAQc1CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc5CP0IeAAAAAEI/QgMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADzswABAAAAAPCzAKfwswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA/vCzAP3wswD/8LMAfgAAAADvsgAC8bMAAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QQMAAAAAQj5BHkJAQc1CQEH/QkBB+0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc5CP0IeAAAAAEI/QgMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwswABAAAAAPCzABvwswDn8LMA//CzAP7wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD+8LMA/fCzAP/wswCAAAAAAPGzAALvtAABAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QQMAAAAAQj5BHUJAQc1CQEH/QkBB+0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc1DQEAeAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA8LMAAwAAAADwswBf8LMA//CzAP3wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD98LMA//CzAIEAAAAA8bMAAvCz + AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QQMAAAAAQj5BHUJAQc1CQEH/QkBB+0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc1DQEAeAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAPCzAAEAAAAA8LMApvCzAP/wswD88LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA/vCzAP3wswD/8LMAgQAA + AADxsgAC8LMAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QgMAAAAAQj5CHkJAQc1CQEH/QkBB+0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc1DQEAfAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAPCzAAEAAAAA77QAEfCzAN7wswD/8LMA/fCzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD+8LMA/fCz + AP/wswCAAAAAAPGzAALwswABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQgMAAAAAQkBDHkJAQc5CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQc1DQEAfAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswADAAAAAPCzAEjwswD+8LMA//CzAP7wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP7wswD98LMA//CzAIAAAAAA8bMAAvCzAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQgMAAAAAQUBDHkJAQc5CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQcxDQEAfAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8bIAAwAAAADwswCC8LMA//CzAPzwswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA/vCzAP3wswD/8LMAgAAAAADxtAAC8LMAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQMAAAAAQUBDH0JAQc5CQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQcxDQEAfAAAAAENAQAMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LQAAQAAAADwwQAC8LMAxPCzAP/wswD98LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD+8LMA/fCzAP/wswCDAAAAAPG0AALwswABAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQUBBIUJAQdBCQEH/QkBB+0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQcxDQEAfAAAAAENAQAMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAO+zAAIAAAAA77MAH/CzAOnwswD/8LMA/vCzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD98LMA//CzAIEAAAAA8bQAAvCzAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQT9BIEJAQdBCQEH/QkBB+0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQctCQEEfAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswADAAAAAPCzAE/wswD/8LMA//CzAP7wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA/vCzAP3wswD/8LMAgAAAAADxtAAC8LMAAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJBQQIAAAAAQkFBGEJAQctCQEH/QkBB+0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQcxCPkEdAAAAAEI/QQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8bMAAwAAAADwswB88LMA//CzAPzwswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD+8LMA/fCzAP/wswCAAAAAAPCz + AALvswABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQgEAAAAAQkBED0JAQbhCQEH/QkBB+0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQcpCQEEfAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAs/CzAP/wswD98LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD98LMA//Cz + AIEAAAAA8rQAAu+zAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCP0EBAAAAAEJAQZxCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQctCP0EdAAAAAEI/QQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAEAAAAA8LQADfCzANzwswD/8LMA/fCz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA/vCz + AP3wswD/8LMAggAAAADztQAC77MAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEDAAAAAEI/QWVCQEH/QkBB/UJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQcxCQEEgAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwtAACAAAAAPC0AC/wswDw8LMA//Cz + AP7wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD+8LMA/fCzAP/wswCBAAAAAPOzAALvswABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCP0ECAAAAAEJAQi9CQEHsQkBB/0JAQf5CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQclCQEEeAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAAAADwswBT8LMA//Cz + AP7wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP7wswD98LMA//CzAIEAAAAA8LIAAvCzAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEIBAAAAAAAAAABCQEGwQkBB/0JAQfxCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQctCQEEfAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCyAAMAAAAA8LMAdvCz + AP/wswD88LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA/vCzAP3wswD/8LMAgQAAAADxswAC8LMAAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQUBAAwAAAABBQEFaQkBB/0JAQf1CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQclCQEEfAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwtgABAAAAAPCz + AJ/wswD/8LMA/fCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD+8LMA/fCzAP/wswCDAAAAAPG1AALwswABAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQj9BAQAAAABCPUEJQkBBzEJAQf9CQEH9QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQcpCQEEdAAAAAEI/QQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwsgABAAAAAPCe + AAHwswDC8LMA//CzAP3wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD98LMA//CzAIEAAAAA8LMAAvCz + AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQMAAAAAQkBBWEJAQf9CQEH+QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQctCQEEgAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA77MAAQAA + AADusgAJ8LMA2fCzAP/wswD98LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA/vCzAP3wswD/8LMAgQAA + AADwswAC8LMAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJBQQEAAAAAQExDAkJAQb5CQEH/QkBB/EJA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQchCQEEfAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCz + AAIAAAAA77MAIPCzAOjwswD/8LMA/vCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD+8LMA/fCz + AP/wswCBAAAAAPGzAALwswABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEECAAAAAENAQjZCQEH7QkBB/0JA + Qf5CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQcpCP0EgAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADxswACAAAAAPGzADnwswD18LMA//CzAP7wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP7wswD98LMA//CzAIIAAAAA8LMAAvCzAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQT9BAwAAAABCQEGGQkBB/0JA + QfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQchCQEEfAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA8LMAAwAAAADwswBR8LMA//CzAP7wswD+8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA/vCzAP3wswD/8bMAhgAAAADvswAB8bMAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQj9BAQAAAABBPEEIQkBBzEJA + Qf9CQEH9QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JAQcpCPkEdAAAAAEI/QQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAPCzAAQAAAAA8LMAYfCzAP/wswD98LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD+8LMA/fCzAP/wswCEAAAAAPCzAALwswABAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE/QQIAAAAAQT9AKUJA + QfVCQEH/QkBB/kJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQcpCQEEgAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADvswAEAAAAAPCzAG3wswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD98LMA//C0AIMAAAAA8bUAAfCzAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBQEEDAAAAAEFA + QWFCQEH/QkBB/UJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQchCQEEgAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8bMAAwAAAADwswCA8LMA//CzAPzwswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA/vCzAP3wswD/8LQAhAAAAADvtgABAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBCAwAA + AABBQEGPQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQdhCQEEhAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPGzAAIAAAAA8LMAkfCzAP/wswD88LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD+8LMA/fCzAP/wswB5AAAAAO+z + AAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ0FBATw6 + QQEAAAAAQkBBrUJAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH+QkBB/0JAQfxCQEFQAAAAAEJAQQQAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswABAAAAAPCzAJ7wswD/8LMA/fCzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP3wswD/8LMA+fCz + AEAAAAAA8LMAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQEAAAAAQkBBCkJAQc1CQEH/QkBB/UJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/EJAQf9CQEG0PDVBAUJBQQFCQEEBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAQAAAADwswCl8LMA//CzAP3wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA+/Cz + AP/wswC3AAAAAAAAAADwswABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCP0EBAAAAAEI+QRJCQEHhQkBB/0JAQf5CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH/QkBBYgAAAABCQEEDAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAqvCzAP/wswD98LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP7wswD/8LMA9++yAC0AAAAA8LMAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQkBBAQAAAABCQEEWQkBB60JAQf9CQEH+QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH/QkBB+EJAQTcAAAAAQkBBAgAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzALDwswD/8LMA/fCz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA/vCzAP/wswBgAAAAAPCzAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEJAQQEAAAAAQkBBG0JAQfNCQEH/QkBB/kJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH+QkBB/0JAQedBQEIpAAAAAEFA + QgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswABAAAAAAAAAADwswC28LMA//Cz + AP3wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAPzwswD/8LMAeAAAAADwswADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCP0EBAAAAAEM/QhpCQEHyQkBB/0JAQf5CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/kJAQf9CQEHqQUBBKwAA + AABBQEECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAQAAAAAAAAAA8LMAtvCz + AP/wswD98LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD88LMA//CzAHUAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBCAQAAAABCQEIVQkBB6EJAQf9CQEH+QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH/QkBB/EJA + QT0AAAAAQkBBAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCz + ALDwswD/8LMA/fCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA/vCzAP/wswBXAAAAAPCzAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEM/QQEAAAAARD5CEUJAQd5CQEH/QkBB/UJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJA + Qf9CQEF0AAAAAEJAQAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAQAA + AADwswCq8LMA//CzAP3wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA/vCzAP/wswDv8LMAIgAAAADwswACAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDP0ABAAAAAEY8PQhCQEHGQkBB/0JAQf1CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf1CQEH/QkBByUM/PwwAAAAAQ0BAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCz + AAEAAAAA8LMApfCzAP/wswD98LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAPvwswD/8LMAowAAAADtsAABAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEVAPgEAAAAAQkBBp0JAQf9CQEH8QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/kJAQf9CQEFuAAAAAEJAQQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwsAABAAAAAPCzAJ7wswD/8LMA/fCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP3wswD/8LMA6++zAC0AAAAA8LMAAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCP0EDAAAAAEJAQYZCQEH/QkBB+0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf5CQEH/QkBB70JAQUYAAAAAQkBBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA8bMAAgAAAADwswCR8LMA//CzAPzwswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+vCzAFsAAAAA77IAAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAwAAAABCQEFUQkBB/0JA + Qf5CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/kJAQf9CQEHoQkBBQAAAAABCQEEDAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAPGzAAMAAAAA8LMAf/CzAP/wswD88LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD+8LMA/fCzAGoAAAAA77MAAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQEAAAAAQT9AIEJA + QfBCQEH/QkBB/kJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQehCQEFAAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADvswAEAAAAAPCzAG3wswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD+8LMA/PCyAGwAAAAA77EAAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDQEEBAAAAAE5D + QQJCQEG8QkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB6UJAQUEAAAAAQkBBAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMABAAAAADwswBg8LMA//CzAP3wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD+8LMA/PGzAGsAAAAA8LQAAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQMAAAAAQkBBc0JAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHoQkBBPwAA + AABCQEEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAMAAAAA8LMAUPCzAP/wswD+8LMA/vCzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD+8LMA/PG0AGkAAAAA8LMAAvGzAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEECAAAAAEM/QCdCQEHyQkBB/0JAQf5CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JA + QehCQEFAAAAAAEJAQQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADxswACAAAAAPGzADnwswD18LMA//CzAP7wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD+8LMA/PCzAG0AAAAA8LIAAvGzAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEY8QQEAAAAAQkBBqkJAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf1CQEH/QkBB6UJAQUEAAAAAQT9AAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAgAAAADxsgAf8LMA5/CzAP/wswD+8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD+8LMA/PCzAGwAAAAA8LMAAvG0AAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEECAAAAAEJAQUJCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/UJAQf9CQEHoQkFCQAAAAABBQEEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO+yAAEAAAAA7bEACPCzANjwswD/8LMA/fCz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD+8LMA/PCzAGsAAAAA8LMAAvG0AAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQ0FBAQAAAAAAAAAAQkBBtkJAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQehCQUJBAAAAAEJAQQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswABAAAAAPCzAAHwswDA8LMA//Cz + AP3wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD+8LMA/PCyAGsAAAAA8LMAAvG0AAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEECAAAAAEJAQT5CQEH5QkBB/0JAQf5CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB6UJAQUAAAAAAQkBBAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPOwAAEAAAAA8LMAnfCz + AP/wswD98LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD+8LMA/PCyAGkAAAAA8LMAAvG0AAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAERAQQIAAAAAQkBBlUJAQf9CQEH8QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHoQkBBQAAAAABCP0EDAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswADAAAAAPCz + AHXwswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD+8LMA/PCyAGwAAAAA8LMAAvGzAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBQEABAAAAAEFAQBlCQEHYQkBB/0JA + Qf1CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQepCQEFBAAAAAEI/ + QQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAA + AADwswBT8LMA//CzAP7wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD+8LMA/PCyAGwAAAAA8LIAAvGyAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQgIAAAAAQkBCR0JA + QfhCQEH/QkBB/kJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB6EJA + QUAAAAAAQT9AAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCz + AAIAAAAA8LMALvCzAO/wswD/8LMA/vCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD+8LMA/PCyAGsAAAAA8LIAAvGyAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQUFBAgAA + AABBP0F3QkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJA + Qf9CQEHqQj9BQQAAAABBP0ADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwswABAAAAAO+zAAzwswDb8LMA//CzAP3wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+vCzAGkAAAAA77MAAvCyAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEM+ + QQFBREABAAAAAEI/QZJCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH9QkBB/0JAQelCP0FAAAAAAEE/QAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMAs/CzAP/wswD98LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD+8LMA/PCzAGoAAAAA77MAAvGyAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQ0BBAQAAAABGQEAGQkBBoUJAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf1CQEH/QkBB6UI/QUEAAAAAQj9BAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswADAAAAAPCzAH3wswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD+8LMA/PCzAGsAAAAA77IAA/KzAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEECAAAAAENBRAtCQEGpQkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHqQj9BQAAAAABBP0ADAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAAAADwswBP8LMA//CzAP/wswD+8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD+8LMA/PCzAGsAAAAA77MAAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QgIAAAAAQkBFC0JAQadCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQelCP0E/AAAAAEE/QAMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAIAAAAA8LMAH/CzAOnwswD/8LMA/vCzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD+8LMA/PCzAGsAAAAA77MAAvGzAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBCAgAAAABCQEULQkBBp0JAQf9CQEH8QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB6UJAQT8AAAAAQUBAAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswABAAAAAPCzAALwswDE8LMA//CzAP3wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA/PC0AGcAAAAA8LMAAvGzAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEACAAAAAEJAPQtCQEGnQkBB/0JA + QfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHpQj9BPwAA + AABBP0ADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAMAAAAA8LMAhfCzAP/wswD88LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD+8LMA/PCzAGsAAAAA77MAAvGzAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkA9C0JA + QahCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JA + QelCQEE/AAAAAEE/QAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwtAADAAAAAPC0AEvwswD/8LMA//Cz + AP7wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD+8LMA/PCzAGoAAAAA77MAAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBAAgAA + AABCQD0LQkBBp0JAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf1CQEH/QkBB6UJAQD8AAAAAQT9AAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8bMAAQAAAADxsgAU8LMA4PCz + AP/wswD+8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD+8LMA/O+zAGoAAAAA77MAAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEACAAAAAEJAPQtCQEGnQkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/UJAQf9CQEHqQkBBPwAAAABBP0ADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2swABAAAAAPCz + AKvwswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+++zAGgAAAAA77MAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAENBQQIAAAAARkRBC0JAQadCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQepCQEE/AAAAAEE/QAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAA + AADwswBl8LMA//CzAP3wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+vC0AGUAAAAA8LQAAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQ0FAAgAAAABGREELQkBBp0JAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB6kJAQT8AAAAAQT9AAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCz + AAIAAAAA8LMAI/CzAOzwswD/8LMA/vCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+/CyAGcAAAAA77IAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDQUECAAAAAEZEQQtCQEGnQkBB/0JAQfxCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHqQkBBPwAAAABBP0ADAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswCx8LMA//CzAP3wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+/CyAGcAAAAA8LIAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAENBQQIAAAAAREJBCkJAQadCQEH/QkBB/EJA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQepCQEE/AAAAAEE/ + QQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAPCzAAMAAAAA8LMAZfCzAP/wswD98LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+/CyAGcAAAAA8LAAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQT9BAgAAAAA+PEEKQkBBp0JA + Qf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB6kJA + QT8AAAAAQj9AAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswACAAAAAO+0ACHwswDq8LMA//CzAP7wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+vCzAGYAAAAA8LEAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEECAAAAAD48 + QQpCQEGnQkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJA + Qf9CQEHqQUBBQAAAAABBP0ADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPOzAAEAAAAA8LMApfCzAP/wswD88LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+/CzAGYAAAAA8LEAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE/ + QQIAAAAAPjxBCkJAQadCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH9QkBB/0JAQepBQEFAAAAAAEFAQAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswADAAAAAPCzAE3wswD/8LMA/vCzAP7wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+/CzAGcAAAAA8LIAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQT9CAgAAAABBP0QKQkBBp0JAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf1CQEH/QkBB6kFAQT8AAAAAQT9ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAQAAAADxtAAJ8LMA0fCzAP/wswD98LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+/CzAGcAAAAA77EAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEECAAAAAEJAQgpCQEGnQkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHqQUBBPwAAAABBP0AEAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswADAAAAAPCzAHzwswD/8LMA/PCz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+vCzAGYAAAAA77EAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQgIAAAAAQkBCCkJAQadCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQepBQEE/AAAAAEFAQQQAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAgAAAADwswAo8LMA7vCz + AP/wswD+8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+/CzAGYAAAAA77IAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAgAAAABCQEIKQkBBp0JAQf9CQEH8QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB6kFAQT8AAAAAQUBBBAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswACAAAAAPCz + AJ7wswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+/CzAGcAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEECAAAAAEJAQApCQEGnQkBB/0JA + QfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHqQUBBPwAA + AABBP0ADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAgAA + AADwswA78LMA+vCzAP/wswD+8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+/CzAGcAAAAA77MAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBACkJA + QadCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JA + QepBQEE/AAAAAEE/QAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAPCzALXwswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+vCzAGYAAAAA77MAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAgAA + AABCQEAKQkBBp0JAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf1CQEH/QkBB6kJAQT8AAAAAQj9BAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA8LMAAwAAAADwswBN8LMA//CzAP7wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+/CzAGUAAAAA77IAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEECAAAAAEJAQApCQEGnQkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/UJAQf9CQEHqQkBBPwAAAABCP0EDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAO+yAAEAAAAA3qEAAfCzAL/wswD/8LMA/fCzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+/CzAGcAAAAA8LQAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEJAQQIAAAAAQ0FBCkJAQadCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQetCQEE/AAAAAEI/QQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAAAADwswBN8LMA//CzAP7wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+/CzAGYAAAAA8LIAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAgAAAABDQUEKQkBBqEJAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB6kJAQT8AAAAAQT9BBAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPGzAAEAAAAAAAAAAPCzALzwswD/8LMA/PCzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+/CzAGYAAAAA8LIAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEECAAAAAENBQQpCQEGnQkBB/0JAQfxCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHqQkBBQAAAAABBP0EDAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAAAADwswBJ8LMA//CzAP7wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+fCzAGUAAAAA8LIAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQ0FBC0JAQahCQEH/QkBB/EJA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQetCP0FAAAAAAEI/ + QAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswABAAAAAPCzAK7wswD/8LMA/PCz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+/CzAGcAAAAA8LEAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAgAAAABBP0ELQkBBqEJA + Qf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB6kI/ + QUAAAAAAQj9AAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAgAAAADwswA18LMA9fCz + AP/wswD+8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+/CzAGcAAAAA8LIAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEECAAAAAEE/ + QQtCQEGoQkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJA + Qf9CQEHrQ0BBQgAAAABBP0ADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswACAAAAAPCz + AJDwswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+/CzAGcAAAAA8LIAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE/ + QQIAAAAAQT9BC0JAQahCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH9QkBB/0JAQexDQEFDAAAAAEI/QAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAQAA + AADwswAe8LMA4PCzAP/wswD98LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+fCzAGUAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQT9BAgAAAABBP0ELQkBBqEJAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf1CQEH/QkBB7ENAQUMAAAAAQj9AAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADvswADAAAAAPCzAGbwswD/8LMA/fCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+/CzAGcAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEECAAAAAEJAQgtCQEGoQkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHsQ0BBQwAAAABCP0ADAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAPqxAAHLyAAB8LMAuPCzAP/wswD88LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+/CzAGcAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBCC0JAQahCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQexDQEFDAAAAAEI/QAMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswACAAAAAPCzADLwswDy8LMA//CzAP7wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+/CzAGcAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBCAgAAAABCQEILQkBBqEJAQf9CQEH8QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7ENAQUMAAAAAQj9AAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAO+0AAMAAAAA8LMAfPCzAP/wswD98LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+fCzAGUAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEICAAAAAEJAQgtCQEGnQkBB/0JA + QfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHsQ0BBQwAA + AABCP0ADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswABAAAAAPGzAAjwswDB8LMA//CzAPzwswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+vCzAGcAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBAC0JA + QadCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JA + QexDQEFEAAAAAEI/QAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPGzAAIAAAAA8bMAMPCzAO7wswD/8LMA/vCz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+fCzAGQAAAAA77MAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAgAA + AABDQEAKQkBBpUJAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf1CQEH/QkBB7ENAQUQAAAAAQj9AAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8bMAAwAAAADwswBt8LMA//Cz + AP3wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+fCzAGQAAAAA77IAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEACAAAAAENAQApCQEGlQkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/UJAQf9CQEHsQkBBRAAAAABCP0ADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADxtQABAAAAAPCz + AKnwswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+PCzAGMAAAAA77IAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEJAQQIAAAAAQ0BACkJAQaRCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQexCQEFEAAAAAEI/QAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAgAA + AADwtAAa8LMA1/CzAP/wswD88LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+fCzAGQAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAgAAAABBQUEKQkBBpEJAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7EJAQUQAAAAAQj9AAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwswADAAAAAPCzAD/wswD08LMA//CzAP7wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+fCzAGQAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEECAAAAAEFBQQpCQEGkQkBB/0JAQfxCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHsQkBBRAAAAABCP0ADAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAO+0AAMAAAAA8LMAbvCzAP/wswD98LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+PCzAGMAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQUFBCkJAQaRCQEH/QkBB/EJA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQexCQEFDAAAAAEI/ + QAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA77IAAgAAAADwswCY8LMA//CzAPzwswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+fCzAGIAAAAA8bMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAgAAAABCP0IKQkBBpEJA + Qf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7EJA + QUQAAAAAQj9AAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAEAAAAA77MACvCzALbwswD/8LMA/PCzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+fCzAGMAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEECAAAAAEI/ + QgpCQEGkQkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJA + Qf9CQEHrQkBBRAAAAABCP0ADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8bQAAgAAAADxswAZ8LMA0PCzAP/wswD88LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+fCzAGMAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQIAAAAAQj9CCkJAQaRCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH9QkBB/0JAQetCQEFEAAAAAEJAQAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswACAAAAAPCzACzwswDj8LMA//Cz + AP3wswD/8LMA//CzAP/wswD/8LMA//CzAP7wswD/8LMA+PCzAGEAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQkBBAgAAAABCP0IKQkBBpEJAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf1CQEH/QkBB7EI/QUQAAAAAQj9AAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPGzAAMAAAAA8LMAQPCz + AO3wswD/8LMA/fCzAP/wswD/8LMA//CzAP7wswD/8LMA+fCzAGMAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEECAAAAAEJAQgpCQEGkQkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHsQj9BRQAAAABCP0EDAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAA + AADwswBO8LMA8/CzAP/wswD98LMA//CzAP7wswD/8LMA+fCzAGMAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBCCkJAQaNCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQexCP0FEAAAAAEI/QQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADvswADAAAAAPCzAFrwswD48LMA//CzAPzwswD/8LMA+PCzAGMAAAAA8LIAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAgAAAABCQEIKQkBBo0JAQf9CQEH8QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7EI/QUUAAAAAQj9BAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAPC0AAMAAAAA8LMAYvCzAPnwswD/8LMA+PCzAGAAAAAA77MAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEECAAAAAEJAQgpCQEGjQkBB/0JA + QfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHsQj9BRQAA + AABCQEEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LIAAwAAAADwswBl8LMA7/CzAGMAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQ0BACkJA + QaNCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JA + QetCP0FFAAAAAEJAQQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADxrwAB7LMAAvCzACTyswADAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAgAA + AABDQEAJQkBBo0JAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf1CQEH/QkBB60I/QUUAAAAAQkBBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC0AAEAAAAA8LMAAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEECAAAAAENAQAlCQEGjQkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/UJAQf9CQEHsQj9BRgAAAABCP0EDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEJAQQIAAAAAQ0BACkJAQaJCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQexCQEBGAAAAAEJAQQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAgAAAABBQUEJQkBBokJAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7EJAQEYAAAAAQkBBAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEECAAAAAEFBQQlCQEGhQkBB/0JAQfxCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHrQkBARgAAAABCQEEDAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQUFBCUJAQaJCQEH/QkBB/EJA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQetCQEBGAAAAAEJA + QQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAgAAAABBQUEJQkBBokJA + Qf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB60JA + QEYAAAAAQkBBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEECAAAAAEFB + QQlCQEGiQkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJA + Qf9CQEHrQkBARgAAAABCQEEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQIAAAAAQUFBCEJAQaFCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH9QkBB/0JAQexCQEBGAAAAAEJAQQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQkBBAgAAAABCP0IJQkBBoUJAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf1CQEH/QkBB7ENAQUYAAAAAQkBBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEECAAAAAEI/QglCQEGhQkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHsQ0BBRgAAAABCQEEDAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQj9CCEJAQaFCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQexCQEFGAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAgAAAABCP0IIQkBBoEJAQf9CQEH8QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7EJAQUcAAAAAQkBBAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEECAAAAAEJAQghCQEGgQkBB/0JA + QfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHsQkBBRgAA + AABCQEEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBCCEJA + QaBCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JA + QexCQEFHAAAAAEJAQQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAgAA + AABCQEIIQkBBoEJAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf1CQEH/QkBB7EJAQUcAAAAAQkBBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEECAAAAAEJAQghCQEGgQkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/UJAQf9CQEHsQkBBRwAAAABCQEEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEJAQQEAAAAAQ0NACEI/QZ1CP0H/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQexCQEFHAAAAAEJAQQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAQAAAABEQT8HQj9BnEI/Qf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7EJAQUcAAAAAQkBBAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDQEEBAAAAAENBPwdCP0GcQj9B/0JAQfxCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHsQkBBRwAAAABCQEEDAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/QQEAAAAAREE/BkI/QZxCP0H/QkBB/EJA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQexCQEFHAAAAAEJA + QQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQj9BAQAAAABEQT8GQj9BnEI/ + Qf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7EJA + QUcAAAAAQkBBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCP0EBAAAAAERB + PwZCP0GcQj9B/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJA + Qf9CQEHtQkBBSgAAAABCQEIDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/ + QQEAAAAARD4/BkJAQZxCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH9QkBB/0JAQe5CQEFJAAAAAEJAQgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQkBBAQAAAABAQkEGQkBBm0JAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf1CQEH/QkBB7UJAQUkAAAAAQkFBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEEBAAAAAEBCQQZCQEGbQkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHuQkBCSgAAAABCQEIDAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQEAAAAAQEJBBkJAQZpCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQe5CQEJKAAAAAEJAQgMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAQAAAABAQkEGQkBBmkJAQf9CQEH8QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7kJAQkoAAAAAQkBCAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBAAAAAEI+QwZCQEGaQkBB/0JA + QfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHuQkBCSgAA + AABCQEIDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQEAAAAAQj5DBkJA + QZpCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JA + Qe5CQEJJAAAAAEJAQgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAQAA + AABCPkMFQkBBmkJAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf1CQEH/QkBB7kJAQkkAAAAAQkBCAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEEBAAAAAEJAQQVCQEGaQkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/UJAQf9CQEHuQkBCSQAAAABDQUICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEJAQQEAAAAAQkBBBUJAQZpCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQe1CQEJMAAAAAEI/QgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAQAAAABCQEEFQkBBmEJAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQfpCQEH/QkBB1URARRUAAAAAQ0BDAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDQEABAAAAAEhAOwVCQEGZQkBB/0JAQfxCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7UI/Qk4AAAAAQkBBAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAENAQAEAAAAASEA7BUJAQZlCQEH/QkBB/EJA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7kI/QkwAAAAAQkBBAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ0BAAQAAAABIQDsFQkBBmUJA + Qf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7kJAQkwAAAAAQkBBAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDQEABAAAAAEhA + OwVCQEGZQkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7kJAQksAAAAAQkBBAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAENA + QAEAAAAASEA7BUJAQZlCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7kJAQUwAAAAAQkBAAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQ0BAAQAAAABIQDsFQkBBmUJAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/Qj9B7UI/QEkAAAAAQj9BAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABDQEABAAAAAEhAOwVCQEGZQkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/Qj9B7UI/QUgAAAAAQT9CAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQAEAAAAAP0U/BUJAQZlCQEH/QkBB/EJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/Qj9B7UI/QUkAAAAAQj9BAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkFBAQAAAAA8RkEFQkBBmUJAQf9CQEH8QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7UI/QUkAAAAAQj9BAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBQUEBAAAAADxGQQVCQEGZQkBB/0JA + QfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7UJAQUgAAAAAQj9BAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFBQQEAAAAAPEZBBUJA + QZlCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7UJAQUgAAAAAQj9BAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBCAQAA + AABCOkcFQkBBmUJAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7UJAQUgAAAAAQz9BAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABBQEEBAAAAAEI8RQVCQEGZQkBB/0JAQfxCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7UJAQUgAAAAAQkBBAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEI/QgEAAAAAQj5DBUJAQZlCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7UJAQUgAAAAAQkBBAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAQAAAABCPkMFQkBBmUJAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7UJAQUgAAAAAQkBBAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBAAAAAERAPwVCQEGZQkBB/0JAQfxCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7UJAQUcAAAAAQkBBAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQEAAAAAQEJBBEJAQZdCQEH/QkBB/EJA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7UJAQUcAAAAAQUBCAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAUBCQQFCPkMDQkBBlkJA + Qf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB7UJAQUcAAAAAQkBBAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkQ9AUI+ + QwNCQEGXQkBB/0JAQfxCQEH/QkBB/0JAQf1CQEH/QkBB7UJAQUgAAAAAQkBBAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQFCRD0BQj5DA0JAQZZCQEH/QkBB/EJAQfxCQEH/QkBB7kJAQUgAAAAAQkBBAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQkBBAQAAAABCPkMEQkBBl0JAQf9CQEH/QkBB7UJAQUgAAAAAQkBBAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEEBQEJBAUVAPgJCQEGXQkBB70JAQUUAAAAAQkBBAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQEAAAAAQ0BADkNAQSgAAAAAQkFBAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////////////////////// + /////////////////8//////////////////////////////////////////h/////////////////// + //////////////////////8D/////////////////////////////////////////gH///////////// + ///////////////////////////8AP////////////////////////////////////////gAf/////// + ////////////////////////////////8AA////////////////////////////////////////gAB// + /////////////////////////////////////8AAD/////////////////////////////////////// + gAAH//////////////////////////////////////8AAAP///////////////////////////////// + /////gAAAf/////////////////////////////////////8AAAA//////////////////////////// + //////////gAAAB/////////////////////////////////////8AAAAD////////////////////// + ///////////////gAAAAH////////////////////////////////////8AAAAAP//////////////// + ////////////////////gAAAAAf///////////////////////////////////8AAAAAA/////////// + /////////////////////////gAAAAAB///////////////////////////////////8AAAAAAD///// + //////////////////////////////gAAAAAAH//////////////////////////////////8AAAAAAA + P//////////////////////////////////gAAAAAAB//////////////////////////////////8AA + AAAAAP//////////////////////////////////gAAAAAAB//////////////////////////////// + //8AAAAAAAP//////////////////////////////////gAAAAAAB/////////////////////////// + ///////8AAAAAAAP//////////////////////////////////gAAAAAAB////////////////////// + ////////////8AAAAAAAP//////////////////////////////////gAAAAAAB///////////////// + /////////////////8AAAAAAAP//////////////////////////////////gAAAAAAB//////////// + //////////////////////8AAAAAAAP//////////////////////////////////gAAAAAAB/////// + ///////////////////////////8AAAAAAAP//////////////////////////////////gAAAAAAB// + ////////////////////////////////8AAAAAAAP//////////////////////////////////gAAAA + AAB//////////////////////////////////8AAAAAAAP////////////////////////////////// + gAAAAAAB//////////////////////////////////8AAAAAAAP///////////////////////////// + /////gAAAAAAB//////////////////////////////////8AAAAAAAP//////////////////////// + //////////gAAAAAAB//////////////////////////////////8AAAAAAAP/////////////////// + ///////////////gAAAAAAB//////////////////////////////////8AAAAAAAP////////////// + ////////////////////gAAAAAAB//////////////////////////////////8AAAAAAAP///////// + /////////////////////////gAAAAAAB//////////////////////////////////8AAAAAAAP//// + //////////////////////////////gAAAAAAB//////////////////////////////////8AAAAAAA + P//////////////////////////////////gAAAAAAB//////////////////////////////////8AA + AAAAAP//////////////////////////////////gAAAAAAB///////////3//////////////////// + //8AAAAAAAP//////////+P//////////////////////gAAAAAAB///////////wf////////////// + ///////8AAAAAAAP//////////+A//////////////////////gAAAAAAB///////////wB///////// + ////////////8AAAAAAAP//////////+AD/////////////////////gAAAAAAB///////////wAH/// + /////////////////8AAAAAAAP//////////+AAP////////////////////gAAAAAAB///////////4 + AAf///////////////////8AAAAAAAP///////////AAA////////////////////gAAAAAAB/////// + ////4AAB///////////////////8AAAAAAAP///////////AAAD///////////////////gAAAAAAB// + /////////4AAAH//////////////////8AAAAAAAP///////////gAAAP//////////////////gAAAA + AAB///////////8AAAAf/////////////////8AAAAAAAP///////////gAAAA////////////////// + gAAAAAAB///////////+AAAAB/////////////////8AAAAAAAP///////////wAAAAD//////////// + /////gAAAAAAB///////////+AAAAAH////////////////8AAAAAAAP///////////4AAAAAP////// + //////////gAAAAAAB////////////AAAAAAf///////////////8AAAAAAAP///////////8AAAAAA/ + ///////////////gAAAAAAB////////////gAAAAAB///////////////8AAAAAAAP///////////8AA + AAAAD///////////////gAAAAAAB////////////wAAAAAAH//////////////8AAAAAAAP///////// + //+AAAAAAAP//////////////gAAAAAAB////////////4AAAAAAAf/////////////8AAAAAAAP//// + ////////AAAAAAAA//////////////gAAAAAAB////////////8AAAAAAAB/////////////8AAAAAAA + P////////////gAAAAAAAD/////////////gAAAAAAB////////////+AAAAAAAAH////////////8AA + AAAAAP////////////wAAAAAAAAP////////////gAAAAAAB/////////////AAAAAAAAAf///////// + //8AAAAAAAP////////////8AAAAAAAAA////////////gAAAAAAB/////////////gAAAAAAAAB//// + ///////8AAAAAAAP////////////+AAAAAAAAAD///////////gAAAAAAB/////////////wAAAAAAAA + AH//////////8AAAAAAAP/////////////AAAAAAAAAAH//////////gAAAAAAB/////////////8AAA + AAAAAAAf/////////8AAAAAAAP/////////////gAAAAAAAAAA//////////gAAAAAAB//////////// + /+AAAAAAAAAAA/////////8AAAAAAAP/////////////4AAAAAAAAAAB/////////gAAAAAAB/////// + ///////AAAAAAAAAAAD////////8AAAAAAAP/////////////8AAAAAAAAAAAH////////gAAAAAAB// + ////////////wAAAAAAAAAAAP///////8AAAAAAAP/////////////+AAAAAAAAAAAAf///////gAAAA + AAB//////////////4AAAAAAAAAAAA///////8AAAAAAAP//////////////gAAAAAAAAAAAB/////// + gAAAAAAB//////////////+AAAAAAAAAAAAD//////8AAAAAAAP//////////////4AAAAAAAAAAAAH/ + /////gAAAAAAB///////////////AAAAAAAAAAAAAP/////8AAAAAAAP//////////////8AAAAAAAAA + AAAAf/////wAAAAAAB///////////////wAAAAAAAAAAAAA/////+AAAAAAAP///////////////AAAA + AAAAAAAAAB/////wAAAAAAB///////////////8AAAAAAAAAAAAAD/////AAAAAAAP////////////// + /gAAAAAAAAAAAAAH////4AAAAAAB///////////////+AAAAAAAAAAAAAAP////gAAAAAAP///////// + //////4AAAAAAAAAAAAAAf///8AAAAAAB////////////////gAAAAAAAAAAAAAA////wAAAAAAP//// + ///////////+AAAAAAAAAAAAAAB///+AAAAAAB////////////////4AAAAAAAAAAAAAAD///4AAAAAA + P////////////////gAAAAAAAAAAAAAAH///gAAAAAB////////////////+AAAAAAAAAAAAAAAP//+A + AAAAAP////////////////wAAAAAAAAAAAAAAAf//wAAAAAB/////////////////AAAAAAAAAAAAAAA + B///AAAAAAP////////////////8AAAAAAAAAAAAAAAD//8AAAAAA/////////////////wAAAAAAAAA + AAAAAAH//wAAAAAH/////////////////AAAAAAAAAAAAAAAAf//AAAAAAf////////////////8AAAA + AAAAAAAAAAAB//8AAAAAB/////////////////wAAAAAAAAAAAAAAAH//wAAAAAH//////////////// + /AAAAAAAAAAAAAAAAf//AAAAAAf////////////////8AAAAAAAAAAAAAAAB//8AAAAAB/////////// + //////wAAAAAAAAAAAAAAAH//wAAAAAD/////////////////AAAAAAAAAAAAAAAAf//AAAAAAP///// + ///////////8AAAAAAAAAAAAAAAD//8AAAAAAf////////////////wAAAAAAAAAAAAAAAf//4AAAAAA + /////////////////gAAAAAAAAAAAAAAD///gAAAAAB////////////////+AAAAAAAAAAAAAAAf//+A + AAAAAD////////////////4AAAAAAAAAAAAAAD///8AAAAAAH////////////////gAAAAAAAAAAAAAA + f///wAAAAAAP///////////////+AAAAAAAAAAAAAAD////AAAAAAAf///////////////4AAAAAAAAA + AAAAAf///+AAAAAAA////////////////gAAAAAAAAAAAAAD////4AAAAAAB///////////////+AAAA + AAAAAAAAAAf////wAAAAAAD///////////////4AAAAAAAAAAAAAD/////AAAAAAAH////////////// + /wAAAAAAAAAAAAAf////+AAAAAAAP///////////////AAAAAAAAAAAAAD/////8AAAAAAAf//////// + //////8AAAAAAAAAAAAAf/////4AAAAAAA///////////////wAAAAAAAAAAAAD//////gAAAAAAB/// + ////////////AAAAAAAAAAAAAf//////AAAAAAAD//////////////+AAAAAAAAAAAAD//////+AAAAA + AAH//////////////4AAAAAAAAAAAAf//////8AAAAAAAP//////////////gAAAAAAAAAAAD/////// + 4AAAAAAAf/////////////+AAAAAAAAAAAAf///////wAAAAAAA//////////////4AAAAAAAAAAAD// + //////gAAAAAAB//////////////wAAAAAAAAAAAf////////AAAAAAAD//////////////AAAAAAAAA + AAD////////+AAAAAAAH/////////////8AAAAAAAAAAAf////////8AAAAAAAP/////////////4AAA + AAAAAAAD/////////4AAAAAAAf/////////////gAAAAAAAAAAf/////////wAAAAAAA//////////// + /+AAAAAAAAAAD//////////gAAAAAAB/////////////8AAAAAAAAAAf//////////AAAAAAAD////// + ///////wAAAAAAAAAD//////////+AAAAAAAH/////////////AAAAAAAAAAf//////////8AAAAAAAP + ////////////+AAAAAAAAAD///////////4AAAAAAAf////////////4AAAAAAAAAf///////////wAA + AAAAA/////////////wAAAAAAAAD////////////gAAAAAAB/////////////AAAAAAAAAf///////// + ///AAAAAAAD////////////8AAAAAAAAD////////////+AAAAAAAH////////////4AAAAAAAAf//// + ////////8AAAAAAAP////////////gAAAAAAAD/////////////4AAAAAAAf////////////AAAAAAAA + f/////////////wAAAAAAA////////////8AAAAAAAD//////////////gAAAAAAB////////////4AA + AAAAAf//////////////AAAAAAAD////////////gAAAAAAD//////////////+AAAAAAAH///////// + ///AAAAAAAf//////////////8AAAAAAAP///////////8AAAAAAD///////////////4AAAAAAAf/// + ////////4AAAAAAf///////////////wAAAAAAA////////////gAAAAAD////////////////gAAAAA + AB////////////AAAAAAf////////////////AAAAAAAD///////////+AAAAAD////////////////+ + AAAAAAAH///////////4AAAAAf////////////////8AAAAAAAP///////////wAAAAD//////////// + /////4AAAAAAAf///////////gAAAAf/////////////////wAAAAAAA///////////+AAAAD/////// + ///////////gAAAAAAB///////////8AAAAf//////////////////AAAAAAAD///////////4AAAD// + ////////////////+AAAAAAAH///////////gAAAf//////////////////8AAAAAAAP///////////A + AAD///////////////////4AAAAAAAf//////////+AAAf///////////////////wAAAAAAA/////// + ////8AAD////////////////////gAAAAAAB///////////wAAf////////////////////AAAAAAAD/ + //////////gAD////////////////////+AAAAAAAH///////////AAf////////////////////8AAA + AAAAP//////////+AD/////////////////////4AAAAAAAf//////////8Af/////////////////// + //wAAAAAAA///////////4D//////////////////////gAAAAAAB///////////wf////////////// + ////////AAAAAAAD///////////j//////////////////////+AAAAAAAH///////////f///////// + /////////////8AAAAAAAP//////////////////////////////////4AAAAAAAf/////////////// + ///////////////////wAAAAAAA///////////////////////////////////gAAAAAAB////////// + /////////////////////////AAAAAAAD//////////////////////////////////+AAAAAAAH//// + //////////////////////////////8AAAAAAAP//////////////////////////////////4AAAAAA + Af//////////////////////////////////wAAAAAAA///////////////////////////////////g + AAAAAAB///////////////////////////////////AAAAAAAD////////////////////////////// + ////+AAAAAAAH//////////////////////////////////8AAAAAAAP//////////////////////// + //////////4AAAAAAAf//////////////////////////////////wAAAAAAA/////////////////// + ////////////////gAAAAAAB///////////////////////////////////AAAAAAAD///////////// + /////////////////////+AAAAAAAH//////////////////////////////////8AAAAAAAP/////// + ///////////////////////////4AAAAAAAf//////////////////////////////////wAAAAAAA// + /////////////////////////////////gAAAAAAB///////////////////////////////////AAAA + AAAD//////////////////////////////////+AAAAAAAH///////////////////////////////// + /8AAAAAAAP//////////////////////////////////4AAAAAAAf/////////////////////////// + ///////wAAAAAAA///////////////////////////////////gAAAAAAB////////////////////// + /////////////AAAAAAAD//////////////////////////////////+AAAAAAAH//////////////// + //////////////////8AAAAAAAP//////////////////////////////////4AAAAAAAf////////// + ////////////////////////wAAAAAAA///////////////////////////////////gAAAAAAB///// + //////////////////////////////AAAAAAAD//////////////////////////////////+AAAAAAA + f//////////////////////////////////8AAAAAAD///////////////////////////////////4A + AAAAAf///////////////////////////////////wAAAAAD//////////////////////////////// + ////gAAAAAf////////////////////////////////////AAAAAD/////////////////////////// + /////////+AAAAAf////////////////////////////////////8AAAAD////////////////////// + ///////////////4AAAAf/////////////////////////////////////wAAAD///////////////// + /////////////////////gAAAf//////////////////////////////////////AAAD//////////// + //////////////////////////+AAAf//////////////////////////////////////8AAD/////// + ////////////////////////////////4AAf///////////////////////////////////////wAD// + //////////////////////////////////////gAf/////////////////////////////////////// + /AD////////////////////////////////////////+Af////////////////////////////////// + //////8D/////////////////////////////////////////4f///////////////////////////// + ////////////z////////////////////////////////////////////////////////////////ygA + AACAAAAAAAEAAAEAIAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAQAAAABCQEMHQkBBkEJAQSsAAAAAQkBBAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQFBQD0BTEBjAUJAQZ5CQEH/QkBB0UJAQRwAAAAAQkBBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBPUBBAWJAQQFCQEGjQkBB/0JAQflCQEH/QkBB1kJA + QR0AAAAAQkBBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQUBBAUFA + QQFBQEEBQkBBokJAQf9CQEH7QkBB/0JAQfxCQEH/QkBB1kJBQR0AAAAAQkBBAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFAQQFHQUIBLDs8AUJAQaRCQEH/QkBB+0JAQf9CQEH/QkBB/0JA + QfxCQEH/QkBB1kJAQB0AAAAAQkBBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBQEEBR0FCAS47 + PAFCQEGkQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQfxCQEH/QkBB1kBAQR0AAAAAQkBBAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAUI+QAFDREUBQkBBpEJAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQfxCQEH/QkBB1kBAQR0AAAAAQkBBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQFBPkABRkRFAUJA + QaRCQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQfxCQEH/QkBB1kJA + QR0AAAAAQkBBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEEBQUFAAUY8RQFCQEGkQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQfxCQEH/QkBB1kJAQR4AAAAAQkBBAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAkFBPwFGPEUBQkBBpEJA + Qf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + QfxCQEH/QkBB2ERAQR8AAAAAQ0BBAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEJAQQFBQT8BRjxFAUJAQaRCQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQfxCQEH/QkBB10NAQR4AAAAAQ0BBAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEABQT9BAUZEPgJCQEGlQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQfpCQEH/QkBByENBSAMAAAAAQkBCAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQkBBAkA/QgFGRD0BQkBBpUJAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQfVCQEFSAAAAAENB + QQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQFAP0QBRkQ3AUJAQaVCQEH/QkBB+0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/UJAQf9CQEH4QkBBTQAAAABCQEECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABBQEECRT9AATVERQFCQEGlQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB90JAQU0AAAAAQkBBBAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAkY/QQE1REEBQkBBpUJAQf9CQEH7QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH9QkBB/0JAQfhCQEFNAAAAAEJAQQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQJGP0EBNkRBAkJAQaVCQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEH3QkBBTAAAAABCQEEEAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEECQkBBAUJAQQJCQEGlQkBB/0JAQftCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf1CQEH/QkBB90JAQUwAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAkJA + QQFCQEECQkBBpkJAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQfZCQEFKAAAAAEJAQQQAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQJCQUIBQj4+AkJAQaZCQEH/QkBB+0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJA + Qf9CQEH2QkBBSgAAAABCQEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEECPz9AAUpD + RAJCQEGnQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB9kJAQUoAAAAAQkBBBAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAj89PgFKSEkCQkBBp0JAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JA + QfZCQEFKAAAAAEJAQQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQJBQEEBRUBBAkJA + QadCQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEH2QkBBSgAAAABCQEEEAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEECQkBBAUJAQQJCQEGoQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB9kJA + QUoAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAkJAQQFCQEECQkBBqEJA + Qf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQfZCQEFKAAAAAEJAQQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEJAQQJCQEEBQkBBAkJAQahCQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEH2QkBBSQAA + AABCQEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEECQkBBAUJAQQJCQEGoQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf1CQEH/QkBB9kJAQUkAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQkBBAkJBQQFCPUECQkBBqEJAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQfZCQEFJAAAAAEJA + QQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCz + AALwswAB8LMAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQJCQEIBQkA+AkJAQahCQEH/QkBB+0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/UJAQf9CQEH2QkBBSQAAAABCQEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswAB8LQAA/CzAAsAAAAA8LMAAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEECQkBCAUJAPgJCQEGoQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB9kJAQUkAAAAAQkBBBAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMABAAA + AADwswBh8LMA1vCzACAAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAkJAQgFCQD4CQkBBqUJAQf9CQEH7QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH9QkBB/0JAQfZCQEFJAAAAAEJAQQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAQAAAAA8LMAUfCzAPvwswD/8LMA2fCzACAAAAAA8LMAAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQJCQEEBQkBBAkJAQalCQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEH2QkBBSQAAAABCQEEEAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswADAAAAAPCz + AEPwswD38LMA//CzAPrwswD/8LMA2fCzACEAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEECQkBBAUJAQQJCQEGpQkBB/0JAQftCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf1CQEH/QkBB9kJAQUkAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAAAADwswAq8LMA6vCzAP/wswD98LMA//CzAPzwswD/8LMA2fCz + ACAAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAkNA + QQFCQEEDQkBBqUJAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQfZCQEFJAAAAAEJAQQQAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAEAAAAA8LMAEvCz + ANTwswD/8LMA/PCzAP/wswD/8LMA//CzAPzwswD/8LMA2vCzACAAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQJCQUEBQkBBA0JAQalCQEH/QkBB+0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJA + Qf9CQEH2QkBBSQAAAABCQEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMAAgAAAADwswCp8LMA//CzAPvwswD/8LMA//CzAP/wswD/8LMA//Cz + APzwswD/8LMA2vCzACEAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEECQkFBAUJA + QQJCQEGpQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB90JAQUkAAAAAQkBBBAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAQAAAAA8LMAcfCz + AP/wswD78LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAPzwswD/8LMA2/CzACIAAAAA8LMAAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAkJCQQFBPUADQkBBqkJAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JA + QfdCQEFJAAAAAEJAQQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswACAAAAAPCzADLwswD28LMA//CzAP7wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAPzwswD/8LMA2/CzACEAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQJCQEEBQT9BA0JA + QatCQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEH3QkBBSQAAAABCQEEEAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAQAAAADvsgAF8LMAx/Cz + AP/wswD88LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAPzwswD/8LMA2/Cz + ACEAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEECQkBBAUFAQQNCQEGrQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB90JA + QUkAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswADAAAAAPCzAHbwswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAPzwswD/8LMA2/CzACEAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAkJAQQFBQEEDQkBBq0JA + Qf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQfZCQEFIAAAAAEJAQQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAgAAAADwswAl8LMA8fCz + AP/wswD+8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + APzwswD/8LMA2/CzACEAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEJAQQJBP0ABQkBBA0JAQatCQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEH1QkBBRwAA + AABCQEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswACAAAAAPCzAKHwswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAPzwswD/8LMA2/CzACIAAAAA8LMAAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQUECQj1AAUNDQgNCQEGrQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf1CQEH/QkBB9kJAQUcAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAgAAAADwswA78LMA/vCz + AP7wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAPzwswD/8LMA3PCzACIAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQkFCAkI9PgFCREQDQkBBq0JAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQfZCQEFHAAAAAEJA + QQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADxswACAAAAAPCzALHwswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAPzwswD/8LMA2/Cz + ACIAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQJCPT8BQkNEA0JAQatCQEH/QkBB+0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/UJAQf9CQEH2QkBBRwAAAABCQEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAgAAAADwswA98LMA//Cz + AP7wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAPzwswD/8LMA3PCzACIAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEECQj4/AUJDRARCQEGrQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB9kJAQUcAAAAAQkBBBAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswACAAAAAPCzAKXwswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + APzwswD/8LMA2/CzACIAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAkI+QQFCQEEEQkBBq0JAQf9CQEH7QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH9QkBB/0JAQfZCQEFHAAAAAEJAQQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAgAAAADwswAm8LMA9fCz + AP/wswD+8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAPzwswD/8LMA3PCzACMAAAAA8LMAAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEI/ + QQJCQEEBQj5BBEJAQatCQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEH2QkBBRwAAAABCQEEEAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswAEAAAAAPCzAIDwswD/8LMA+/CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAPzwswD/8LMA2++0ACEAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCP0ECQkFBAUI+QQRCQEGrQkBB/0JAQftCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf1CQEH/QkBB9kJAQUYAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAQAAAADwsgAI8LMA1/Cz + AP/wswD98LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAPzwswD/8LMA2/C0 + ACMAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAkJB + QQFCPUEEQkBBq0JAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQfVCQEFHAAAAAEJAQQQAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswADAAAAAPCzAEXwswD/8LMA/vCzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAPzwswD/8LMA3PCzACIAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQgJCR0IBQjlBBEJAQaxCQEH/QkBB+0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJA + Qf9CQEH1QkBBRwAAAABCQEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAMAAAAA8LMAlfCz + AP/wswD78LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + APzwswD/8LMA3fCzACQAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEECQkc+AUI6 + RARCQEGrQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB9UJAQUYAAAAAQkBBBAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswABAAAAAPCzAAfwswDb8LMA//CzAP3wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAPzwswD/8LMA3fCzACMAAAAA8LMAAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAkZAOAE/QEgEQkBBrEJAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JA + QfVCQEFGAAAAAEJAQQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAMAAAAA8LMAN/Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAPzwswD/8LMA3PCzACMAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQEAAAAAP0BBBUJA + Qa1CQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEH1QkBBRwAAAABCQEEEAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMABAAAAADwswB18LMA//CzAPvwswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAPzwswD/8LMA3vCz + ACQAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEEBQkFFAUI+PQJCQEGsQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB9UJA + QUYAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswADAAAAAPCz + AK7wswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAPzwswD/8LMA3fCzACQAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBBl0JA + Qf9CQEH6QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQfRCQEFFAAAAAEJAQQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMAAQAAAADwtAAH8LMA3fCzAP/wswD98LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + APzwswD/8LMA3fCzACQAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEEDAAAAAEJAQWJCQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEH0QkBBRgAA + AABCQEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswACAAAAAPCz + ACbwswD58LMA//CzAP7wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAPzwswD/8LMA3fCzACQAAAAA8LMAAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAQAAAABBQEEbQkBB6EJA + Qf9CQEH+QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf1CQEH/QkBB9EJAQUYAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAMAAAAA8LMASvCzAP/wswD98LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAPzwswD/8LMA3fCzACQAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEEDAAAAAEJAQYtCQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQfVCQEFGAAAAAEJA + QQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMABAAA + AADwswBt8LMA//CzAPvwswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAPzwswD/8LMA3fCz + ACQAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAQAAAABDQEEUQkBB50JA + Qf9CQEH+QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/UJAQf9CQEH0QkBBRQAAAABCQEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswAEAAAAAPCzAIvwswD/8LMA+/CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAPzwswD/8LMA3fCzACQAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEEDAAAAAEJAQVlCQEH/QkBB/EJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB9EJAQUUAAAAAQkBBBAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCz + AAMAAAAA8LMAqPCzAP/wswD88LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + APzwswD/8LMA3/CzACUAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQMAAAAAQkBBnUJA + Qf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH+QkBB/0JAQfRCQEFGAAAAAEJAQQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAgAAAADwswC38LMA//CzAPzwswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAPzwswD/8LMA3vCzACUAAAAA8LMAAgAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEHMQkBB/0JAQf1CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH/QkBBVwAAAABCQEEFAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAPCzAMfwswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAPvwswD/8LMA1vCzAA8AAAAA8LMAAQAAAAAAAAAAAAAAAEJAQQEAAAAAQkBBDUJA + QeRCQEH/QkBB/UJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH8QkBB/0JAQcAAAAAAQkBBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAQAAAAAAAAAA8LMAzvCzAP/wswD98LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAPrwswD/8LMAdwAA + AADwswAEAAAAAAAAAAAAAAAAQkBBAQAAAABCQEEVQkBB8EJAQf9CQEH+QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQftCQEH/QkBBiwAAAABCQEEEAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwswABAAAAAPCzAAPwswDT8LMA//CzAP3wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA/PCzAP/wswCzAAAAAPCzAAIAAAAAAAAAAAAAAABCP0EBAAAAAEI/ + QRRCQEHvQkBB/0JAQf5CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB+0JAQf9CQEGPAAAAAEJAQQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAEAAAAA8LMAA/CzANPwswD/8LMA/fCz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD88LMA//Cz + AK8AAAAA8LMAAgAAAAAAAAAAAAAAAEI/QQEAAAAAQj5BDEJAQeJCQEH/QkBB/UJAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQcpEPj0BQkBBAkJA + QQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA8LMAAQAAAAAAAAAA8LMAzvCzAP/wswD98LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAPrwswD/8LMAbQAAAADwswAEAAAAAAAAAAAAAAAAAAAAAEI+ + PwEAAAAAQkBBx0JAQf9CQEH8QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQWsAAAAAQkBBBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswDG8LMA//Cz + APzwswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD78LMA//Cz + AMnvswAKAAAAAPCzAAEAAAAAAAAAAAAAAAAAAAAAQkBBBAAAAABCQEGWQkBB/0JAQftCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH/QkBB/UJA + QVwAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswACAAAAAPCzALfwswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA/PCzAP/wswDU8LMAGwAAAADwswABAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEEDAAAAAEJAQVBCQEH/QkBB/UJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH+QkBB/kJAQVwAAAAAQkBBBAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAMAAAAA8LMAp/Cz + AP/wswD88LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAPvwswD/8LMA1PGz + ABsAAAAA8LMAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFAQQEAAAAAQUBBDkJAQeBCQEH/QkBB/UJA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf5CQEH+QkBB/kJAQVwAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMABAAAAADwswCL8LMA//CzAPvwswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD88LMA//CzANTwswAcAAAAAPCzAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEJAQQMAAAAAQkBBfkJAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH+QkBB/kJAQVwAAAAAQkBBBAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswAEAAAAAPCz + AGzwswD/8LMA+/CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA+/CzAP/wswDU8LMAHAAA + AADwswADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAQAAAABCQEERQkBB3kJA + Qf9CQEH9QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf1CQEH+QkBB/kJAQVwAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAMAAAAA8LMASfCzAP/wswD98LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAPvwswD/8LMA1PCyABsAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAwAAAABCQEFSQkBB/0JAQf1CQEH+QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH+QkBB/kJA + QVwAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAgAA + AADwswAm8LMA+fCzAP/wswD+8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD78LMA//CzANTwsgAbAAAAAPCz + AAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAwAA + AABCQEGDQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH+QkBB/kJAQVwAAAAAQkBBBAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswABAAAAAPCzAAfwswDd8LMA//CzAP3wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA+/CzAP/wswDT8LMAGwAAAADwswADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQUFBAgAAAABCQEGVQkBB/0JAQftCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf5CQEH+QkBB/kJAQVwAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwswADAAAAAPCzAK7wswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAPvwswD/8LMA1PCzABsAAAAA8LMAAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEIBQkA/AgAAAABCQEGWQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH+QkBB/kJAQVsAAAAAQkBBBAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAQAAAAA8LMAdfCzAP/wswD78LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD78LMA//CzANPwswAbAAAAAPCzAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBCAgAAAABCQEGWQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf5CQEH+QkBB/kJAQVsAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA8LMAAwAAAADwswA48LMA//CzAP7wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA+/CzAP/wswDU8LMAGwAAAADwswADAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEEBQkBDAgAAAABCQEGWQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH+QkBB/kJA + QVsAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswABAAAAAPCzAAjwswDd8LMA//Cz + AP3wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + APvwswD/8LMA0++zABsAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDQUABQT9BAgAA + AABCQEGWQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH+QkBB/kJAQVsAAAAAQkBBBAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswADAAAAAPCzAJrwswD/8LMA+/CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD78LMA//CzANLwtAAaAAAAAPCzAAMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDQUABQD5BAgAAAABCQEGWQkBB/0JAQftCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf5CQEH+QkBB/kJAQVsAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAMAAAAA8LMASvCz + AP/wswD98LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA+/Cz + AP/wswDS8LMAGgAAAADwswADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEEBREJBAgAAAABCQEGWQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH+QkBB/kJAQVwAAAAAQkBBBAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMAAQAAAADwswAM8LMA3vCzAP/wswD98LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAPvwswD/8LMA0vCzABkAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBREJBAgAAAABCQEGWQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf5CQEH+QkBB/kJAQVwAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAA + AADwswCJ8LMA//CzAPvwswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD78LMA//Cz + ANLwswAaAAAAAPCzAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABBP0EBQkBBAgAAAABCQEGWQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH+QkBB/kJA + QVwAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswACAAAAAPCzAC7wswD78LMA//CzAP7wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA+/CzAP/wswDS8LMAGQAAAADwswADAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBAAwAA + AABCQEGVQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH+QkBB/kJAQVwAAAAAQkBBBAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwswACAAAAAPCzALDwswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAPvwswD/8LMA0vCz + ABoAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBAgAAAABCQEGWQkBB/0JAQftCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf5CQEH+QkBB/kJAQVwAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAMAAAAA8LMARvCzAP/wswD98LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD78LMA//CzANHwswAZAAAAAPCzAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEEBQkBBAwAAAABCQEGVQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH+QkBB/kJAQVwAAAAAQkBBBAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAPCzAAEAAAAA8LMAvPCzAP/wswD88LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA+/CzAP/wswDS8LMAGgAA + AADwswADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBAwAAAABCQEGWQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf5CQEH+QkBB/kJAQVwAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAAAADwswBH8LMA//Cz + AP3wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAPvwswD/8LMA0fCzABkAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEEBQkBBAwAAAABCQEGVQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH+QkBB/kJA + QVwAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMAAgAAAADwswCw8LMA//CzAPzwswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD78LMA//CzANLwswAZAAAAAPCz + AAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBAwAA + AABCQEGVQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH+QkBB/kNAQV4AAAAAQkBBBAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswACAAAAAPCz + ADHwswD48LMA//CzAP7wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA+/CzAP/wswDR8LMAGgAAAADwswADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBAgAAAABCQEGWQkBB/0JAQftCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf5CQEH+QkBB/0NAQV4AAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswADAAAAAPCzAIjwswD/8LMA+/CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAPvwswD/8LMA0vCzABkAAAAA8LMAAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEEBQkBBAgAAAABCQEGVQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH9QkBB/0NAQV4AAAAAQkBBBAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCz + AAEAAAAA8LMADfCzANXwswD/8LMA/fCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD78LMA//CzANHwswAaAAAAAPCzAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBAgAAAABCQEGVQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf5CQEH9QkBB/0JAQV4AAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAMAAAAA8LMARPCzAP7wswD+8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA+/CzAP/wswDR8LMAGQAAAADwswADAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEEBQkBBAgAAAABCQEGUQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH9QkBB/0JA + QV4AAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAPCzAAMAAAAA8LMAhvCzAP/wswD78LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + APvwswD/8LMA0PCzABkAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBAgAA + AABCQEGUQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH9QkBB/0JAQV4AAAAAQkBBBAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAe+xAAHwtQAE8LMAvPCz + AP/wswD88LMA//CzAP/wswD/8LMA//CzAP/wswD78LMA//CzANDwswAZAAAAAPCzAAMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBAwAAAABCQEGUQkBB/0JAQftCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf5CQEH9QkBB/0JAQV4AAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMAAgAAAADwswAf8LMA4/CzAP/wswD98LMA//CzAP/wswD/8LMA+/Cz + AP/wswDQ8LMAGAAAAADwswADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEEBQkBBAwAAAABCQEGTQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH9QkBB/0JAQV4AAAAAQkBBBAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAA + AADwswA88LMA9vCzAP/wswD98LMA//CzAPvwswD/8LMA0PCzABgAAAAA8LMAAwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBAwAAAABCQEGTQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf5CQEH9QkBB/0JAQV4AAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMABAAAAADwswBW8LMA//CzAP3wswD68LMA//Cz + ANDwswAYAAAAAPCzAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEEBQkBBAwAAAABCQEGTQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH9QkBB/0JA + QV4AAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA8LMABAAAAADwswBo8LMA//CzAP/wswDP8LMAGAAAAADwswADAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBAwAA + AABCQEGTQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH9QkBB/0JAQV8AAAAAQkBBBAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMABAAAAADwswB38LMA0vCz + ABcAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBAwAAAABCQEGTQkBB/0JAQftCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf5CQEH9QkBB/0JAQV8AAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LQAAe+zAATwswALAAAAAPCzAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEEBQkBBAwAAAABCQEGTQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH9QkBB/0JAQV8AAAAAQkBBBAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAvCz + AAHwswABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBAwAAAABCQEGSQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf5CQEH9QkBB/0JAQV8AAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEEBQkBBAwAAAABCQEGSQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH9QkBB/0JA + QV8AAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBAwAA + AABCQEGSQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH9QkBB/0JAQV8AAAAAQkBBBAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBAwAAAABCQEGSQkBB/0JAQftCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf5CQEH+QkBB/0JAQWAAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEEBQkBBAwAAAABCQEGSQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH9QkBB/0JAQWAAAAAAQkBBBAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBAwAAAABCQEGSQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf5CQEH9QkBB/0JAQWAAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEEBQkBBAwAAAABCQEGRQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH9QkBB/0JA + QWAAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBAwAA + AABCQEGQQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH9QkBB/0JAQWAAAAAAQkBBBAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCP0EBQkFBAwAAAABCP0GPQkBB/0JAQftCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf5CQEH9QkBB/0JAQWAAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCP0EBQkFBAwAAAABCP0GPQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH9QkBB/0JAQWAAAAAAQkBBBAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCP0EBQkBBAwAAAABCQEGPQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf5CQEH9QkBB/0JAQWEAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCP0EBQj9BAwAAAABCQEGPQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH9QkBB/0JA + QWEAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQj9BAwAA + AABCQEGPQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH9QkBB/0JAQWIAAAAAQkBBBAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBAwAAAABCQEGPQkBB/0JAQftCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf5CQEH9QkBB/0JAQWEAAAAAQkBBAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEEBQkBBAwAAAABCQEGPQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf5CQEH+QkBB/kJAQWkAAAAAQkBAAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBAwAAAABCQEGOQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQfpCQEH/QkBBwUU6UAEAAAAAQkBCAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEEBQUBCAwAAAABCQEGPQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQcVCP0IRAAAAAEI/ + QgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDQEABQUBCAwAA + AABCQEGOQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB+0JAQf9CQEHGQkBCEgAAAABCQEICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDQEABQUBCAwAAAABCQEGOQkBB/0JAQftCQEH/QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQftCQEH/QkBBxEI+QBEAAAAAQj9BAgAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEABQj9BAwAAAABCQEGOQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH7QkBB/0JAQcRCPkERAAAAAEJAQQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEABQz9BAwAAAABCQEGOQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JAQf9CQEHEQkBBEQAAAABCQEECAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEEBQkFAAwAAAABCQEGOQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH/QkBB/0JA + QftCQEH/QkBBxEJAQREAAAAAQkBBAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBQEEBQkBBAwAA + AABCQEGOQkBB/0JAQftCQEH/QkBB/0JAQf9CQEH7QkBB/0JAQcRCQEEQAAAAAEJAQQIAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCP0EBQkBBAwAAAABCQEGOQkBB/0JAQftCQEH/QkBB+0JA + Qf9CQEHEQkBBEAAAAABCQEECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEEBQkBBAwAAAABCQEGNQkBB/0JAQflCQEH/QkBBxUJAQREAAAAAQkBBAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBAwAAAABCQEGIQkBB/0JA + QcBCQEEPAAAAAEJAQQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEEBQkBBAUNAQAJCQEFyQkBBHwAAAABCQEEDAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////// + //v////////////////////x////////////////////4P///////////////////8B///////////// + //////+AP///////////////////AB///////////////////gAP//////////////////wAB/////// + ///////////4AAP/////////////////8AAB/////////////////+AAAP/////////////////AAAB/ + ////////////////gAAA/////////////////wAAAf////////////////4AAAP////////////////8 + AAAH////////////////+AAAD/////////////////AAAB/////////////////gAAA///////////// + ////wAAAf////////////////4AAAP////////////////8AAAH////////////////+AAAD//////// + /////////AAAB/////////////////gAAA/////////////////wAAAf////////////////4AAAP/// + /////////////8AAAH////////////////+AAAD/////////////////AAAB/////9///////////gAA + A/////+P//////////wAAAf/////B//////////4AAAP/////gP/////////8AAAH/////wB//////// + /+AAAD/////4AP/////////AAAB/////+AB/////////gAAA//////AAP////////wAAAf/////gAB// + //////4AAAP/////4AAP///////8AAAH/////8AAB///////+AAAD/////+AAAP///////AAAB////// + gAAB///////gAAA//////wAAAP//////wAAAf/////8AAAB//////4AAAP/////+AAAAP/////8AAAH/ + /////gAAAB/////+AAAD//////wAAAAP/////AAAB//////8AAAAB/////gAAA///////AAAAAP////w + AAAf//////gAAAAB////4AAAP//////4AAAAAP///8AAAH//////+AAAAAB///+AAAD///////gAAAAA + P///AAAB///////wAAAAAB///gAAA///////8AAAAAAP//4AAAf///////AAAAAAB//8AAAP///////w + AAAAAAP/+AAAH///////8AAAAAAB//gAAD///////+AAAAAAAP/4AAB////////gAAAAAAB/8AAA//// + ////4AAAAAAAP/AAAf///////+AAAAAAAB/wAAH////////gAAAAAAAf8AAB////////4AAAAAAAD/AA + Af///////+AAAAAAAA/wAAH////////gAAAAAAAf8AAB////////4AAAAAAAH/AAAP///////+AAAAAA + AD/4AAB////////gAAAAAAB/+AAAP///////4AAAAAAA//wAAB////////AAAAAAAf/8AAAP///////w + AAAAAAP//gAAB///////8AAAAAAH//4AAAP///////AAAAAAD///AAAB///////wAAAAAB///4AAAP// + ////+AAAAAA////AAAB///////gAAAAAf///4AAAP//////4AAAAAP////AAAB//////+AAAAAH////4 + AAAP//////wAAAAD/////AAAB//////8AAAAB/////4AAAP//////AAAAA//////AAAB//////4AAAAf + /////4AAAP/////+AAAAP//////AAAB//////wAAAH//////4AAAP/////8AAAD///////AAAB////// + gAAB///////4AAAP/////4AAA////////AAAB//////AAAf///////4AAAP/////wAAP////////AAAB + /////+AAH////////4AAAP/////wAD/////////AAAB/////8AB/////////4AAAP/////gA//////// + //AAAB/////8Af/////////4AAAP/////gP//////////AAAB/////8H//////////4AAAP/////j/// + ////////AAAB/////9///////////4AAAP/////////////////AAAB/////////////////4AAAP/// + //////////////AAAB/////////////////4AAAP/////////////////AAAB/////////////////4A + AAP/////////////////AAAB/////////////////4AAAP/////////////////AAAB///////////// + ////4AAAP/////////////////AAAB/////////////////4AAAP/////////////////AAAB/////// + //////////4AAAP/////////////////AAAB/////////////////4AAAP/////////////////AAAB/ + ////////////////4AAA//////////////////AAAf/////////////////4AAP///////////////// + /AAH//////////////////4AD///////////////////AB///////////////////4A///////////// + ///////Af///////////////////4P////////////////////H///////////////////////////// + //8oAAAAQAAAAIAAAAABACAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQMAAAAAQkBBmkJAQVoAAAAAQkBBBQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQMAAAAAQkBBjkJA + Qf9CQEH0QkBBRwAAAABCQEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAUNA + QQMAAAAAQkBBk0JAQf9CQEH6QkBB/0JAQfhCQEFJAAAAAEJAQQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQkBBAUJAQQMAAAAAQkBBk0JAQf9CQEH7QkBB/0JAQf1CQEH/QkBB+EJAQUkAAAAAQkBBBAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQMAAAAAQkBBk0JAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/UJA + Qf9CQEH4QkBBSAAAAABCQEECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQMAAAAAQkBBk0JAQf9CQEH7QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH9QkBB/UJAQf5CQEFAAAAAAEJAQQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQMAAAAAQkBBk0JA + Qf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JAQf9CQEHNQkBBGgAAAABCQEEBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJA + QQMAAAAAQkBBk0JAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JAQf9CQEHJQkBBEgAA + AABCQEEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQkBBAUJAQQMAAAAAQkBBk0JAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JA + Qf9CQEHJQkBBEgAAAABCQEEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQMAAAAAQkBBk0JAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB+0JAQf9CQEHIQkBBEQAAAABCQEEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQMAAAAAQkBBlEJAQf9CQEH7QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JAQf9CQEHIQkBBEQAAAABCQEEDAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQMAAAAAQkBBlEJA + Qf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JAQf9CQEHIQkBBEQAAAABCQEEDAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJA + QQMAAAAAQkBBlEJAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JAQf9CQEHIQkBBEQAA + AABCQEEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswAC8LMAAwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQkBBAUJAQQMAAAAAQkBBlEJAQf9CQEH6QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JA + Qf9CQEHIQkBBEAAAAABCQEECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwswAB8LMAAQAAAADwswACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQMAAAAAQkBBlUJAQf9CQEH6QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB+0JAQf9CQEHIQkBBEAAAAABCQEECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswACAAAAAPCzACTwswBDAAAAAPCzAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQMAAAAAQkBBlUJAQf9CQEH6QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JAQf9CQEHIQkBBEAAAAABCQEECAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswABAAAAAPCzAA7wswDM8LMA//CzAEgAAAAA8LMABQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQMAAAAAQkBBlUJA + Qf9CQEH6QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JAQf9CQEHIQkBBEAAAAABCQEECAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAfCyAAHwswC18LMA//Cz + APzwswD58LMASgAAAADwswAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJA + QQMAAAAAQkBBlUJAQf9CQEH6QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JAQf9CQEHIQkBBEAAA + AABCQEECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAA + AADwswCH8LMA//CzAPvwswD98LMA/vCzAPnwswBLAAAAAPCzAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQkBBAUJAQQMAAAAAQkBBlkJAQf9CQEH6QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JA + Qf9CQEHIQkBBEAAAAABCQEECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA8LMAAwAAAADwswBF8LMA//CzAP3wswD/8LMA//CzAP3wswD+8LMA+fCzAEsAAAAA8LMABQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQMAAAAAQkBBlkJAQf9CQEH6QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB+0JAQf9CQEHIQkBBEAAAAABCQEECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMAAQAAAADwswAJ8LMA0/CzAP/wswD98LMA//CzAP/wswD/8LMA/fCz + AP7wswD58LMASwAAAADwswAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQMAAAAAQkBBlkJAQf9CQEH6QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JAQf9CQEHHQkBBEAAAAABCQEECAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAMAAAAA8LMAdvCzAP/wswD78LMA//Cz + AP/wswD/8LMA//CzAP/wswD98LMA/vCzAPnwswBMAAAAAPCzAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQMAAAAAQkBBlkJA + Qf9CQEH6QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JAQf9CQEHHQkBBEAAAAABCQEECAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAEAAAAA8LMAE/Cz + AOXwswD/8LMA/vCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP3wswD+8LMA+fCzAEwAAAAA8LMABQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJA + QQMAAAAAQkBBlkJAQf9CQEH6QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JAQf9CQEHHQkBBEAAA + AABCQEECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwswAEAAAAAPCzAHDwswD/8LMA+/CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA/fCz + AP7wswD58LMATAAAAADwswAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQkBBAUJAQQMAAAAAQkBBlkJAQf9CQEH6QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JA + Qf9CQEHHQkBBEAAAAABCQEECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswABAAAAAPGyAAHwswDP8LMA//CzAP3wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD98LMA/vCzAPnwswBMAAAAAPCzAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJBQQMAAAAAQkBBlkJAQf9CQEH6QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB+0JAQf9CQEHHQkBBEAAAAABCQEECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAAAADwswA78LMA//CzAP7wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP3wswD+8LMA+fCzAEwAAAAA8LMABQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBCAUJAQAMAAAAAQkBBlkJAQf9CQEH6QkBB/0JA + Qf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JAQf9CQEHHQkBBEAAAAABCQEECAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAQAAAAA8LMAhfCz + AP/wswD78LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA/fCz + AP7wswD68LMATAAAAADwswAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQIAAAAAQkBBlkJA + Qf9CQEH6QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JAQf9CQEHGQkBBEAAAAABCQEECAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwswABAAAAAPCzAMTwswD/8LMA/PCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD98LMA/vCzAPrwswBNAAAAAPCzAAUAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQMAAAAAQkBBfkJAQf9CQEH6QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JAQf9CQEHGQkBBEAAA + AABCQEECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswABAAAAAPCzABPwswDs8LMA//CzAP7wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP3wswD+8LMA+vCzAE0AAAAA8LMABQAA + AAAAAAAAAAAAAEJAQQIAAAAAQkBBL0JAQfpCQEH+QkBB/kJAQf9CQEH/QkBB/0JAQf9CQEH/QkBB+0JA + Qf9CQEHGQkBBEAAAAABCQEECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAgAAAADwswAy8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA/fCz + AP7wswD68LMATQAAAADwswAEAAAAAAAAAABCQEEEAAAAAEJAQZRCQEH/QkBB+0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB/UJAQf9CQEHGQkBBDwAAAABCQEECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAMAAAAA8LMAT/Cz + AP/wswD88LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD98LMA/vCzAPrwswBOAAAAAPCzAAIAAAAAAAAAAAAAAABCQEHTQkBB/0JA + Qf1CQEH/QkBB/0JAQf9CQEH/QkBB/UJAQf9CQEHPQkBBEAAAAABCQEECAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwswAEAAAAAPCzAGPwswD/8LMA+/CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP3wswD+8LMA+/CzAEYAAAAA8LMAAwAA + AABCQEERQkBB7UJAQf9CQEH+QkBB/0JAQf9CQEH/QkBB/0JAQfxCQEH/QkBBVAAAAABCQEEFAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMABAAAAADwswBt8LMA//CzAPvwswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA+/Cz + AP/wswDJAAAAAPCzAAEAAAAAQkBBEEJAQexCQEH/QkBB/kJAQf9CQEH/QkBB/0JAQf9CQEH8QkBB/0JA + QVgAAAAAQkBBBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAQAAAAA8LMAbfCzAP/wswD78LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAPvwswD/8LMAxQAAAADwswABAAAAAAAAAABCQEHRQkBB/0JAQf1CQEH/QkBB/0JA + Qf9CQEH/QkBB/UJAQf9CQEHWQkBBFgAAAABCQEEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswAEAAAAAPCz + AGPwswD/8LMA+/CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP3wswD/8LMA+PCzAEAAAAAA8LMAA0JAQQQAAAAAQkBBj0JA + Qf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH9QkBB/0JAQdBCQEEWAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA8LMAAwAAAADwswBP8LMA//CzAPzwswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP3wswD/8LMA+PCzAEcAAAAA8LMAAgAA + AABCQEECAAAAAEJAQSlCQEH3QkBB/0JAQf5CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQftCQEH/QkBB0EJA + QRYAAAAAQkBBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAIAAAAA8LMAMvCzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP3wswD/8LMA9/Cz + AEcAAAAA8LMABAAAAAAAAAAAAAAAAEJAQQMAAAAAQkBBdUJAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB+0JAQf9CQEHQQkBBFgAAAABCQEEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswABAAAAAPCzABPwswDs8LMA//Cz + AP7wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP3wswD/8LMA9/CzAEcAAAAA8LMABAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBAgAAAABCQEGKQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQdBCQEEWAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCz + AAEAAAAA8LMAxPCzAP/wswD88LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP3wswD/8LMA9/CzAEcAAAAA8LMABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEEDAAAAAEJAQYtCQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQftCQEH/QkBB0EJA + QRYAAAAAQkBBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswAEAAAAAPCzAIbwswD/8LMA+/CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP3wswD/8LMA9/CzAEcAAAAA8LMABAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQMAAAAAQkBBi0JAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB+0JAQf9CQEHQQkBBFgAAAABCQEEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAAAADwswA98LMA//CzAP7wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP3wswD/8LMA9/CzAEYAAAAA8LMABAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBBAAAAABCQEGLQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQdBCQEEWAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAEAAAAA8LMAA/Cz + ANLwswD/8LMA/fCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP3wswD/8LMA9/Cz + AEYAAAAA8LMABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQFCQEEEAAAAAEJAQYtCQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQftCQEH/QkBB0EJA + QRYAAAAAQkBBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA8LMABAAAAADwswB28LMA//CzAPvwswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP3wswD/8LMA9/CzAEYAAAAA8LMABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQQAAAAAQkBBi0JAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB+0JAQf9CQEHQQkBBFgAAAABCQEEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAEAAAAA8LMAF/CzAOnwswD/8LMA/vCzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP3wswD/8LMA9/CzAEYAAAAA8LMABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBBAAAAABCQEGLQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQdBCQEEWAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAAAADwswB98LMA//Cz + APvwswD/8LMA//CzAP/wswD/8LMA//CzAP3wswD/8LMA9/CzAEYAAAAA8LMABAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQFCQEEEAAAAAEJAQYtCQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQftCQEH/QkBB0UNA + QRYAAAAAQkBBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCz + AAEAAAAA8LMADfCzANnwswD/8LMA/fCzAP/wswD/8LMA//CzAP3wswD/8LMA9/CzAEYAAAAA8LMABAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQQAAAAAQkBBi0JAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB+0JAQf9CQEHRQkBBFwAAAABCQEEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAAAADwswBO8LMA//CzAPzwswD/8LMA//CzAP3wswD/8LMA9vCz + AEUAAAAA8LMABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBBAAAAABCQEGKQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQdFCQEEXAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswADAAAAAPCzAJHwswD/8LMA+/Cz + AP3wswD/8LMA9vCzAEUAAAAA8LMABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQFCQEEEAAAAAEJAQYpCQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQftCQEH/QkBB0UJA + QRcAAAAAQkBBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAQAA + AADwswAF8LMAv/CzAP/wswD98LMA9vCzAEUAAAAA8LMABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQQAAAAAQkBBiUJAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB+0JAQf9CQEHRQkBBFwAAAABCQEEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswACAAAAAPCzABTwswDV8LMA/fCzAEMAAAAA8LMABAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBBAAAAABCQEGJQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQdFCQEEXAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAIAAAAA8LMAKvCzAEEAAAAA8LMABAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQFCQEEEAAAAAEJAQYlCQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQftCQEH/QkBB0UJA + QRcAAAAAQkBBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAvCz + AAEAAAAA8LMAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQQAAAAAQkBBiUJAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB+0JAQf9CQEHRQkBBFwAAAABCQEEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswAC8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBBAAAAABCQEGJQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQdFCQEEXAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQFCQEEEAAAAAEJAQYlCQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQftCQEH/QkBB0UJA + QRcAAAAAQkBBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQQAAAAAQkBBiEJAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB+0JAQf9CQEHRQkBBFwAAAABCQEEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkFBBAAAAABCQEGIQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf9CQEH7QkBB/0JAQdJCQEEYAAAAAEJAQQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQFCQEEEAAAAAEJAQYdCQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf9CQEH/QkBB/0JAQftCQEH/QkBB0kJA + QRgAAAAAQkBBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQQAAAAAQkBBh0JAQf9CQEH7QkBB/0JAQf9CQEH/QkBB/0JA + Qf9CQEH/QkBB+0JAQf9CQEHXQkBBIAAAAABCQEECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBBAAAAABCQEGHQkBB/0JA + QftCQEH/QkBB/0JAQf9CQEH/QkBB/0JAQf1CQEH+QkBB+kJAQTsAAAAAQkBBAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQFCQEEEAAAAAEJAQYdCQEH/QkBB+0JAQf9CQEH/QkBB/0JAQf1CQEH/QkBB80JAQT4AAAAAQkBBAgAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQQAAAAAQkBBh0JAQf9CQEH7QkBB/0JAQf1CQEH/QkBB80JA + QT4AAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEBQkBBBAAAAABCQEGHQkBB/0JA + QfpCQEH/QkBB80JAQT8AAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQFCQEEEAAAAAEJAQYNCQEH/QkBB70JAQTwAAAAAQkBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBAUJAQQMAAAAAQkBBjEJAQVAAAAAAQkBBBAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////3/////////+P// + ///////wf////////+A/////////wB////////+AD////////wAP///////+AB////////wAP/////// + +AB////////wAP///////+AB////////wAP///////+AB////////wAP///////+AB//8/////wAP//h + ////+AB//8D////wAP//wH///+AB//+AP///wAP//4Af//+AB///AA///wAP//8AB//+AB///gAD//wA + P//+AAH/+AB///wAAP/wAP///AAAf/AB///8AAA/4AP///wAAB/AB////AAAD8AP///8AAAHwB////wA + AAPAH////AAAA8AP///8AAAHwAf///wAAA/gA////AAAH/AB///8AAA/8AD///wAAH/4AH///AAA//wA + P//+AAH//gAf//4AA///AA///wAH//+AB///AA///8AD//+AH///4AH//4A////wAP//wH////gAf//A + /////AA//+H////+AB//8/////8AD////////4AH////////wAP////////gAf////////AA//////// + +AB////////8AD////////4AH////////wAP////////gA/////////AH////////+A/////////8H// + ///////4//////////3/////KAAAADAAAABgAAAAAQAgAAAAAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBBQAAAABCQEFrQkBBlwAAAABCQEEDQkBBAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEEAAAAAEJAQVdCQEH7QkBB/0JAQYYAAAAAQkBBBEJA + QQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQUAAAAAQkBBWkJAQf9CQEH+QkBB+0JA + Qf9CQEGKAAAAAEJAQQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBBQAAAABCQEFaQkBB/0JA + Qf1CQEH+QkBB/0JAQftCQEH/QkBBjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEFAAAAAEJA + QVpCQEH/QkBB/UJAQf5CQEH/QkBB/0JAQf1CQEH9QkBB+UJAQS0AAAAAQkBBAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQUAAAAAQkBBWkJAQf9CQEH9QkBB/kJAQf9CQEH/QkBB/UJAQf5CQEH8QkBBUAAAAABCQEECAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQkBBBQAAAABCQEFaQkBB/0JAQf1CQEH+QkBB/0JAQf9CQEH9QkBB/kJAQfxCQEFSAAAAAEJA + QQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEEFAAAAAEJAQVpCQEH/QkBB/UJAQf5CQEH/QkBB/0JAQf1CQEH+QkBB/EJA + QVEAAAAAQkBBBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQUAAAAAQkBBWkJAQf9CQEH9QkBB/kJAQf9CQEH/QkBB/UJA + Qf5CQEH8QkBBUQAAAABCQEEFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBBQAAAABCQEFbQkBB/0JAQf1CQEH+QkBB/0JA + Qf9CQEH9QkBB/kJAQfxCQEFRAAAAAEJAQQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAfCz + AALwswACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEFAAAAAEJAQVtCQEH/QkBB/UJA + Qf5CQEH/QkBB/0JAQf1CQEH+QkBB+0JAQVEAAAAAQkBBBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADwswABAAAAAPCzAAvwswAG8LMAAfCzAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQUAAAAAQkBBW0JA + Qf9CQEH9QkBB/kJAQf9CQEH/QkBB/UJAQf5CQEH8QkBBUQAAAABCQEEEAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAPCzAAEAAAAA8LMABfCzAMTwswCVAAAAAPCzAATwswABAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBBAAA + AABCQEFbQkBB/0JAQf1CQEH+QkBB/0JAQf9CQEH9QkBB/kJAQfxCQEFQAAAAAEJAQQUAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAIAAAAA8LMAo/CzAP/wswD/8LMAiwAAAADwswAD8LMAAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEEFAAAAAEJAQVtCQEH/QkBB/UJAQf5CQEH/QkBB/0JAQf1CQEH+QkBB/EJAQVEAAAAAQkBBBQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAAAADwswBt8LMA//CzAPrwswD78LMA//Cz + AIwAAAAA8LMAA/CzAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEJAQQUAAAAAQkBBXEJAQf9CQEH9QkBB/kJAQf9CQEH/QkBB/UJAQf5CQEH8QkBBUAAA + AABCQEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswACAAAAAPCzACbwswDy8LMA//Cz + AP7wswD/8LMA+/CzAP/wswCMAAAAAPCzAATwswABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBBAAAAABCQEFcQkBB/0JAQf1CQEH+QkBB/0JAQf9CQEH9QkBB/kJA + QftCQEFQAAAAAEJAQQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswACAAAAAPCz + AKbwswD/8LMA+/CzAP/wswD/8LMA//CzAPvwswD/8LMAjAAAAADwswAE8LMAAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEFAAAAAEJAQVxCQEH/QkBB/UJAQf5CQEH/QkBB/0JA + Qf1CQEH+QkBB+0JAQVAAAAAAQkBBBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCz + AAIAAAAA8LMAMvCzAP3wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD78LMA//CzAIwAAAAA8LMAA/Cz + AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQUAAAAAQkBBXEJAQf9CQEH9QkBB/kJA + Qf9CQEH/QkBB/UJAQf5CQEH7QkBBUAAAAABCQEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAPCzAAMAAAAA8LMAlfCzAP/wswD78LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA+/Cz + AP/wswCMAAAAAPCzAAPwswABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBBAAAAABCQEFcQkBB/0JA + Qf1CQEH+QkBB/0JAQf9CQEH9QkBB/kJAQftCQEFQAAAAAEJAQQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMAAQAAAADwswAM8LMA4vCzAP/wswD+8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAPvwswD/8LMAjQAAAADwswAD8LMAAQAAAAAAAAAAAAAAAAAAAABCQEEDAAAAAEJA + QVxCQEH/QkBB/UJAQf5CQEH/QkBB/0JAQf1CQEH+QkBB+0JAQVAAAAAAQkBBBQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAAAADwswBC8LMA//CzAP3wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD78LMA//CzAI0AAAAA8LMAA/CzAAEAAAAAAAAAAEJA + QQMAAAAAQkBBTEJAQf9CQEH9QkBB/kJAQf9CQEH/QkBB/UJAQf5CQEH7QkBBTwAAAABCQEEEAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMABAAAAADwswB58LMA//Cz + APvwswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA+/CzAP/wswCNAAAAAPCz + AAPwswABAAAAAAAAAABCQEEKQkBB3EJAQf9CQEH8QkBB/0JAQf9CQEH+QkBB/0JAQftCQEFPAAAAAEJA + QQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAA + AADwswCk8LMA//CzAPvwswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + APvwswD/8LMAjQAAAADwswACAAAAAAAAAABCQEFMQkBB/0JAQfxCQEH/QkBB/0JAQf5CQEH/QkBB/EJA + QVAAAAAAQkBBBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA8LMAAgAAAADwswC/8LMA//CzAPzwswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD78LMA//CzAI4AAAAA8LMAAQAAAABCQEF5QkBB/0JAQftCQEH/QkBB/0JA + QftCQEH/QkBBiQAAAABCQEEGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMAAQAAAADwswDL8LMA//CzAP3wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA+vCzAP/wswBPAAAAAAAAAABCQEF4QkBB/0JA + QftCQEH/QkBB/0JAQftCQEH/QkBBjQAAAABCQEEGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAQAAAADwswDL8LMA//CzAP3wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA+vCzAP/wswBMAAAAAAAA + AABCQEFKQkBB/0JAQfxCQEH/QkBB/0JAQf5CQEH/QkBB/kJAQVgAAAAAQkBBBQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAgAAAADwswC/8LMA//Cz + APzwswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD78LMA//Cz + AIgAAAAA8LMAAgAAAABCQEEHQkBB2EJAQf9CQEH8QkBB/0JAQf9CQEH+QkBB/0JAQf5CQEFYAAAAAEJA + QQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAA + AADwswCk8LMA//CzAPvwswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + APvwswD/8LMAiQAAAADwswACAAAAAEJAQQMAAAAAQkBBRkJAQf1CQEH+QkBB/UJAQf9CQEH/QkBB/kJA + Qf1CQEH+QkBBWAAAAABCQEEFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA8LMABAAAAADwswB58LMA//CzAPvwswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA+/CzAP/wswCIAAAAAPCzAATwswABAAAAAAAAAABCQEEDAAAAAEJAQVRCQEH9QkBB/kJA + Qf1CQEH/QkBB/0JAQf5CQEH9QkBB/kJAQVgAAAAAQkBBBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAAAADwswBC8LMA//CzAP3wswD/8LMA//CzAP/wswD/8LMA//Cz + AP/wswD/8LMA//CzAP/wswD78LMA//CzAIgAAAAA8LMABPCzAAEAAAAAAAAAAAAAAAAAAAAAQkBBBAAA + AABCQEFUQkBB/UJAQf5CQEH+QkBB/0JAQf9CQEH+QkBB/UJAQf5CQEFYAAAAAEJAQQUAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAQAAAADwswAN8LMA4/CzAP/wswD+8LMA//Cz + AP/wswD/8LMA//CzAP/wswD/8LMA//CzAPvwswD/8LMAiAAAAADwswAE8LMAAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEJAQQUAAAAAQkBBVEJAQf1CQEH+QkBB/UJAQf9CQEH/QkBB/kJAQf1CQEH+QkBBWAAA + AABCQEEFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAMAAAAA8LMAmPCz + AP/wswD78LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA+/CzAP/wswCIAAAAAPCzAATwswABAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEFAAAAAEJAQVRCQEH9QkBB/kJAQf1CQEH/QkBB/0JA + Qf5CQEH9QkBB/kJAQVgAAAAAQkBBBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCz + AAIAAAAA8LMANvCzAP/wswD+8LMA//CzAP/wswD/8LMA//CzAP/wswD78LMA//CzAIcAAAAA8LMABPCz + AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBBAAAAABCQEFUQkBB/UJA + Qf5CQEH9QkBB/0JAQf9CQEH+QkBB/UJAQf5CQEFYAAAAAEJAQQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADwswACAAAAAPCzAKvwswD/8LMA/PCzAP/wswD/8LMA//CzAPvwswD/8LMAhwAA + AADwswAE8LMAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQUAAAAAQkBBVEJAQf1CQEH+QkBB/UJAQf9CQEH/QkBB/UJAQf1CQEH+QkBBWAAAAABCQEEFAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswACAAAAAPCzACvwswD18LMA//CzAP7wswD/8LMA+/Cz + AP/wswCHAAAAAPCzAATwswABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCQEEFAAAAAEJAQVRCQEH9QkBB/kJAQf1CQEH/QkBB/0JAQf5CQEH9QkBB/0JA + QVkAAAAAQkBBBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAAAADwswB08LMA//Cz + APrwswD78LMA//CzAIcAAAAA8LMABPCzAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBBAAAAABCQEFTQkBB/UJAQf5CQEH9QkBB/0JA + Qf9CQEH+QkBB/UJAQf5CQEFZAAAAAEJAQQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCz + AAIAAAAA8LMAq/CzAP/wswD/8LMAhgAAAADwswAE8LMAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQUAAAAAQkBBU0JA + QfxCQEH+QkBB/UJAQf9CQEH/QkBB/kJAQf1CQEH+QkBBWQAAAABCQEEEAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAPCzAAEAAAAA8LMACPCzAMvwswCQAAAAAPCzAATwswABAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEEFAAAAAEJAQVNCQEH8QkBB/kJAQf1CQEH/QkBB/0JAQf5CQEH9QkBB/0JAQVkAAAAAQkBBBQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswABAAAAAPCzAAzwswAG8LMAAfCzAAEAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAQkBBBAAAAABCQEFTQkBB/EJAQf5CQEH9QkBB/0JAQf9CQEH+QkBB/UJA + Qf5CQEFZAAAAAEJAQQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAfCzAALwswACAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQUAAAAAQkBBU0JAQfxCQEH+QkBB/UJA + Qf9CQEH/QkBB/kJAQf1CQEH/QkBBWQAAAABCQEEFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCz + AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEFAAAAAEJA + QVJCQEH8QkBB/kJAQf1CQEH/QkBB/0JAQf5CQEH9QkBB/0JAQVkAAAAAQkBBBQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQkBBBAAAAABCQEFSQkBB/EJAQf5CQEH9QkBB/0JAQf9CQEH+QkBB/UJAQf9CQEFaAAAAAEJA + QQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQUAAAAAQkBBUkJAQfxCQEH+QkBB/UJAQf9CQEH/QkBB/kJA + Qf1CQEH+QkBBWAAAAABCQEECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEFAAAAAEJAQVFCQEH8QkBB/kJA + Qf1CQEH/QkBB/0JAQf1CQEH8QkBB+kJAQS4AAAAAQkBBAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBBQAA + AABCQEFRQkBB/EJAQf5CQEH9QkBB/0JAQftCQEH/QkBBggAAAABCQEEBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEJAQQUAAAAAQkBBUkJAQfxCQEH+QkBB+0JAQf9CQEGCAAAAAEJBQQIAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEEAAAAAEJAQU9CQEH4QkBB/0JAQX4AAAAAQkBBBEJA + QQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBBQAAAABCQEFjQkBBjAAA + AABCQEEEQkBBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///v///wAA///8f///AAD///g///8AAP// + 8B///wAA///gH///AAD//8A///8AAP//gH///wAA//8A////AAD//gH///8AAP/8A////wAA//gH//// + AAD/8A//n/8AAP/gH/8P/wAA/8A//wf/AAD/gH/+A/8AAP8A//wB/wAA/gH//AD/AAD8A//4AH8AAPgH + //gAPwAA8A//+AAfAADgH//4AA8AAMA///AABwAAwH//8AADAADAf//wAAMAAMB///AAAwAAwH//8AAD + AADAP//wAAcAAOAf//gADwAA8A//+AAfAAD4B//4AD8AAPwD//gAfwAA/gH//AD/AAD/AP/8Af8AAP+A + f/4D/wAA/8A//wf/AAD/4B//D/8AAP/wD/+f/wAA//gH////AAD//AP///8AAP/+Af///wAA//8A//// + AAD//4B///8AAP//wD///wAA///gH///AAD///Af//8AAP//+D///wAA///8////AAD///7///8AACgA + AAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEEAAAAAEJAQTRCQEG9QkBBFgAAAABCQEECAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBBAAAAABCQEEnQkBB30JAQf9CQEHEQkBBDwAA + AABCQEEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQQAAAAAQkBBKEJAQeRCQEH/QkBB+UJA + Qf9CQEHRQkBBDQAAAABCQEEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEEAAAAAEJAQShCQEHkQkBB/0JA + QfxCQEH7QkBB/0JAQa9CQEEFAAAAAEJAQQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBBAAAAABCQEEoQkBB5EJA + Qf9CQEH8QkBB+0JAQf9CQEGmQkBBAQAAAABCQEEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQQAAAAAQkBBKUJA + QeRCQEH/QkBB/EJAQftCQEH/QkBBpgAAAABCQEECQkBBAQAAAAAAAAAAAAAAAPCzAATwswABAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEEEAAAAAEJA + QSlCQEHkQkBB/0JAQfxCQEH7QkBB/0JAQaYAAAAAQkBBAkJAQQEAAAAAAAAAAAAAAADwswACAAAAAPCz + AALwswABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQkBBBAAA + AABCQEEpQkBB5UJAQf9CQEH8QkBB+0JAQf9CQEGmAAAAAEJAQQJCQEEBAAAAAAAAAAAAAAAAAAAAAPCz + AAjwswCD8LMAHQAAAADwswADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQQAAAAAQkBBKUJAQeVCQEH/QkBB/EJAQftCQEH/QkBBpgAAAABCQEECQkBBAQAAAAAAAAAAAAAAAPCz + AAMAAAAA8LMAjfCzAP/wswDG8LMAEQAAAADwswADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABCQEEEAAAAAEJAQSlCQEHlQkBB/0JAQfxCQEH7QkBB/0JAQaUAAAAAQkBBAkJAQQEAAAAAAAAAAAAA + AADwswADAAAAAPCzAE3wswD/8LMA+fCzAP/wswDK8LMAEQAAAADwswADAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAQkBBBAAAAABCQEEpQkBB5UJAQf9CQEH8QkBB+0JAQf9CQEGlAAAAAEJAQQJCQEEBAAAAAAAA + AAAAAAAA8LMAAQAAAADwswAE8LMA0PCzAP/wswD98LMA+/CzAP/wswDK8LMAEQAAAADwswADAAAAAAAA + AAAAAAAAAAAAAEJAQQMAAAAAQkBBKUJAQeVCQEH/QkBB/EJAQftCQEH/QkBBpQAAAABCQEECQkBBAQAA + AAAAAAAAAAAAAAAAAADwswADAAAAAPCzAFTwswD/8LMA/PCzAP/wswD/8LMA+/CzAP/wswDK8LMAEQAA + AADwswADAAAAAAAAAABCQEECAAAAAEJAQSpCQEHlQkBB/0JAQfxCQEH7QkBB/0JAQaUAAAAAQkBBAkJA + QQEAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAMAAAAA8LMArPCzAP/wswD88LMA//CzAP/wswD/8LMA+/Cz + AP/wswDK8LMAEQAAAADwswADAAAAAAAAAABCQEEhQkBB5UJAQf9CQEH8QkBB/EJAQf9CQEGlAAAAAEJA + QQJCQEEBAAAAAAAAAAAAAAAAAAAAAAAAAADwswABAAAAAPCzAAvwswDj8LMA//CzAP7wswD/8LMA//Cz + AP/wswD/8LMA+/CzAP/wswDK8LMAEgAAAADwswACAAAAAEJAQadCQEH/QkBB+kJAQf1CQEH/QkBBpQAA + AABCQEECQkBBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCzAAIAAAAA8LMAJvCzAPzwswD/8LMA/vCz + AP/wswD/8LMA//CzAP/wswD/8LMA+/CzAP/wswDL8LMAEQAAAABCQEEOQkBB40JAQf9CQEH7QkBB/0JA + QcEAAAAAQkBBA0JAQQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAAAADwswA48LMA//Cz + AP7wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD/8LMA+vCzAP/wswC8AAAAAEJAQQ1CQEHiQkBB/0JA + QftCQEH/QkBBxAAAAABCQEECQkBBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwswADAAAAAPCz + ADjwswD/8LMA/vCzAP/wswD/8LMA//CzAP/wswD/8LMA//CzAP/wswD68LMA//CzALoAAAAAAAAAAEJA + QaVCQEH/QkBB+kJAQf1CQEH/QkBBqkJAQQJCQEEBQkBBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPCz + AAIAAAAA8LMAJvCzAPzwswD/8LMA/vCzAP/wswD/8LMA//CzAP/wswD/8LMA+/CzAP/wswDJ8LMAEAAA + AAAAAAAAQkBBHkJAQeJCQEH/QkBB/EJAQfxCQEH/QkBBq0JAQQJCQEEBQkBBAgAAAAAAAAAAAAAAAAAA + AAAAAAAA8LMAAQAAAADwswAL8LMA4/CzAP/wswD+8LMA//CzAP/wswD/8LMA//CzAPvwswD/8LMAyPCz + ABAAAAAA8LMAAkJAQQIAAAAAQkBBJkJAQeFCQEH/QkBB/EJAQftCQEH/QkBBqkJAQQJCQEEBQkBBAgAA + AAAAAAAAAAAAAAAAAAAAAAAA8LMAAwAAAADwswCt8LMA//CzAPzwswD/8LMA//CzAP/wswD78LMA//Cz + AMfwswAQAAAAAPCzAAIAAAAAAAAAAEJAQQMAAAAAQkBBJUJAQeJCQEH/QkBB/EJAQftCQEH/QkBBqkJA + QQJCQEEBQkBBAgAAAAAAAAAAAAAAAAAAAADwswADAAAAAPCzAFfwswD/8LMA/PCzAP/wswD/8LMA+/Cz + AP/wswDH8LMADwAAAADwswADAAAAAAAAAAAAAAAAAAAAAEJAQQQAAAAAQkBBJUJAQeJCQEH/QkBB/EJA + QftCQEH/QkBBq0JAQQJCQEEBQkBBAgAAAAAAAAAAAAAAAPCzAAEAAAAA8LMABvCzANPwswD/8LMA/fCz + APvwswD/8LMAx/CzAA8AAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQQAAAAAQkBBJUJA + QeFCQEH/QkBB/EJAQftCQEH/QkBBq0NAQQJCQEEBQkBBAgAAAAAAAAAAAAAAAPCzAAMAAAAA8LMAUfCz + AP/wswD48LMA//CzAMfwswAPAAAAAPCzAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQQAAAAAQkBBJUJAQeFCQEH/QkBB/EJAQftCQEH/QkBBq0JAQQJCQEEBQkBBAgAAAAAAAAAAAAAAAPCz + AAMAAAAA8LMAkvCzAP/wswDE8LMADwAAAADwswADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEJAQQQAAAAAQkBBJUJAQeFCQEH/QkBB/EJAQftCQEH/QkBBq0I/QQJCQEEBQkBBAgAA + AAAAAAAA8LMAAQAAAADwswAK8LMAhfCzABoAAAAA8LMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQQAAAAAQkBBJUJAQeFCQEH/QkBB/EJAQftCQEH/QkBBq0JA + QQJCQEEBQkBBAgAAAAAAAAAAAAAAAPCzAAIAAAAA8LMAAvCzAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQQAAAAAQkBBJEJAQeFCQEH/QkBB/EJA + QftCQEH/QkBBq0JAQQJCQEEBQkBBAQAAAAAAAAAA8LMAAfCzAATwswABAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQQAAAAAQkBBJEJA + QeBCQEH/QkBB/EJAQftCQEH/QkBBq0JAQQIAAAAAQkBBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQQAAAAAQkBBJEJAQeBCQEH/QkBB/EJAQftCQEH/QkBBtUJAQQYAAAAAQkBBAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAEJAQQQAAAAAQkBBJEJAQeFCQEH/QkBB+UJAQf9CQEHNQkBBDAAAAABCQEEBAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQMAAAAAQkBBI0JAQdxCQEH/QkBBv0JAQQ0AAAAAQkBBAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQQQAAAAAQkBBMEJAQbZCQEEUAAAAAEJA + QQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//7////8 + f///+D////A////gf///wP///4H///8D/f/+B/j//A/4f/gf8D/wP/Af4H/gD8D/4AeB/+ADg//gAYP/ + 4AGB/+ADwP/gB+B/4A/wP/Af+B/wP/wP+H/+B/j//wP9//+B////wP///+B////wP///+D////x////+ + //8oAAAAEAAAACAAAAABACAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQIAAAAAQkBBCkJAQblCQEFRAAAAAEJAQQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQIAAAAAQkBBB0JAQbJCQEH/QkBBzT08QwQAAAAAwZQSAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQIAAAAAQkBBB0JAQbZCQEH/QkBB5kJAQS8AAAAAkXQjA+6yAQHwswACAAAAAAAAAAAAAAAAAAAAAEJA + QQIAAAAAQkBBB0JAQbZCQEH/QkBB50JAQS8AAAAAAAAAAPCzAAvwswAnAAAAAPCzAAMAAAAAAAAAAEJA + QQIAAAAAQkBBB0JAQbZCQEH/QkBB50JAQS8AAAAAjnIlBwAAAADwswB58LMA//CzAD0AAAAA8LMABAAA + AAAAAAAAQkBBCEJAQbdCQEH/QkBB5kJAQS8AAAAAdGEuBQAAAADwswAc8LMA7/CzAP/wswDz8LMAQAAA + AADwswAEQkBBBUJAQbNCQEH/QkBB50JAQS8AAAAAQkBBBPy7AAQAAAAA8LMAaPCzAP/wswD58LMA//Cz + APbwswA/AAAAAEJAQXJCQEH/QkBB6kJAQSkAAAAAQkBBBAAAAADusgEEAAAAAPCzAJTwswD/8LMA+/Cz + AP3wswD/8LMA9vCzAEJCQEFxQkBB/0JAQetCQEEsAAAAAEJAQQQAAAAA7rIBBAAAAADwswCU8LMA//Cz + APvwswD98LMA//CzAPXwswBBQkBBBEJAQbBCQEH/QkBB6EJAQTEAAAAAQkBBBPu6AAQAAAAA8LMAaPCz + AP/wswD58LMA//CzAPXwswA+AAAAAAAAAABCQEEGQkBBtUJAQf9CQEHoQkBBMQAAAAB0YS4GAAAAAPCz + AB3wswDw8LMA//CzAPLwswA/AAAAAPCzAARCQEECAAAAAEJAQQZCQEGzQkBB/0JAQehCQEExAAAAAIxx + JQcAAAAA8LMAe/CzAP/wswA8AAAAAPCzAAQAAAAAAAAAAEJAQQJCQEEBQkBBBkJAQbNCQEH/QkBB6EJA + QTIAAAAAAAAAAPCzAAzwswAnAAAAAPCzAAMAAAAAAAAAAAAAAAAAAAAAQkBBAkJAQQFCQEEGQkBBtEJA + Qf9CQEHoQkBBMgAAAACQdCQD7bEBAfCzAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEECQkBBAUJA + QQZCQEGvQkBB/0JAQc08PEMEAAAAAMGUEgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJA + QQIAAAAAQkBBCUJAQbZCQEFOAAAAAEJAQQIAAAAAAAAAAAAAAAAAAAAAAAAAAP7/AAD8fwAA+P8AAPH/ + AADj7wAAx8cAAI/DAACfgQAAn4EAAI/DAADHxwAA4+8AAPH/AAD4/wAA/H8AAP7/AAA= + + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/PluginDebugger/Options.cs b/src/AcaciaZPushPlugin/PluginDebugger/Options.cs new file mode 100644 index 0000000..e911007 --- /dev/null +++ b/src/AcaciaZPushPlugin/PluginDebugger/Options.cs @@ -0,0 +1,49 @@ +/// Project : Kopano OL Extension + +/// +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia; +using Acacia.Features; +using Acacia.Features.DebugSupport; +using Acacia.Features.SendAs; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Serialization; + +namespace PluginDebugger +{ + [TypeConverter(typeof(OptionsConverter))] + public class Options + { + public GlobalOptions Global { get; set; } + public Feature[] Features { get; set; } + + public Options() + { + Global = GlobalOptions.INSTANCE; + // Create an instance of each feature + Features = Acacia.Features.Features.FEATURES.Select(x => (Acacia.Features.Feature)Activator.CreateInstance(x)).ToArray(); + } + } +} diff --git a/src/AcaciaZPushPlugin/PluginDebugger/OptionsInfra.cs b/src/AcaciaZPushPlugin/PluginDebugger/OptionsInfra.cs new file mode 100644 index 0000000..566b2ff --- /dev/null +++ b/src/AcaciaZPushPlugin/PluginDebugger/OptionsInfra.cs @@ -0,0 +1,384 @@ +/// Project : Kopano OL Extension + +/// +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia; +using Acacia.Utils; +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Acacia.Features; +using System.Reflection; +using System.Globalization; +using System.Collections; +using System.Diagnostics; +using System.Drawing.Design; +using System.Drawing; + +namespace PluginDebugger +{ + public enum Category + { + Global, + Features, + } + + public class CategoryAttribute : System.ComponentModel.CategoryAttribute + { + // Add tabs; these are not printed, but are used for the sorting + public CategoryAttribute(Category order) + : + base(order.ToString().PadLeft(typeof(Category).GetEnumNames().Length - (int)order + order.ToString().Length, '\t')) + { + + } + } + + public class OptionsConverter : ExpandableObjectConverter + { + private class NestedPropertyConverter : ExpandableObjectConverter + { + private AcaciaPropertyDescriptor _prop; + + public NestedPropertyConverter(AcaciaPropertyDescriptor prop) + { + this._prop = prop; + } + + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + return true; + return base.CanConvertFrom(context, sourceType); + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value is string) + return bool.Parse((string)value); + return base.ConvertFrom(context, culture, value); + } + + public override bool GetPropertiesSupported(ITypeDescriptorContext context) + { + return true; + } + + public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) + { + PropertyDescriptorCollection props = new PropertyDescriptorCollection(null); + foreach(AcaciaPropertyDescriptor prop in _prop.Children) + { + props.Add(prop); + } + return props; + } + + public override bool GetStandardValuesSupported(ITypeDescriptorContext context) + { + return true; + } + + public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) + { + List values = new List(new bool[] {false, true }); + return new StandardValuesCollection(values); + } + } + + public interface CanEnable + { + object Object { get; } + void Enable(bool enable); + } + + public class AcaciaPropertyDescriptor : PropertyDescriptor, CanEnable + { + private readonly object _obj; + private readonly PropertyDescriptor _orig; + private readonly AcaciaOptionAttribute _acaciaAttr; + public readonly List Children = new List(); + private AcaciaPropertyDescriptor Parent; + public string VisibleName; + + public AcaciaPropertyDescriptor(object obj, AcaciaOptionAttribute acaciaAttr, PropertyDescriptor orig) + : + base(orig) + { + this._obj = obj; + this._acaciaAttr = acaciaAttr; + this._orig = orig; + } + + /// + /// Creates a grouping attributes + /// + /// + public AcaciaPropertyDescriptor(object obj, string name) + : + base(name, new Attribute[0]) + { + this._obj = obj; + this._acaciaAttr = null; + this._orig = null; + } + + public void Enable(bool enable) + { + if (PropertyType == typeof(bool)) + SetValue(_obj, enable); + } + + public object Object { get { return _obj; } } + + public void MakeChild(AcaciaPropertyDescriptor child, string childName) + { + Children.Add(child); + child.Parent = this; + child.VisibleName = childName; + } + + public override string DisplayName + { + get + { + return VisibleName ?? base.DisplayName; + } + } + + public override string Description + { + get + { + return _acaciaAttr?.Description ?? ""; + } + } + + public override TypeConverter Converter + { + get + { + if (Children.Count > 0) + return new NestedPropertyConverter(this); + return base.Converter; + } + } + + public override Type ComponentType + { + get + { + return _orig?.ComponentType ?? typeof(string); + } + } + + public override bool IsReadOnly { get { return _orig?.IsReadOnly ?? true; } } + public override Type PropertyType { get { return _orig?.PropertyType ?? typeof(string); } } + + private object GetEffectiveComponent(object component) + { + if (Parent != null) + component = Parent._obj; + return component; + } + + public override bool CanResetValue(object component) + { + return _orig.CanResetValue(GetEffectiveComponent(component)); + } + + public override object GetValue(object component) + { + return _orig?.GetValue(GetEffectiveComponent(component)) ?? ""; + } + + public override void ResetValue(object component) + { + if (_orig != null) + _orig.ResetValue(GetEffectiveComponent(component)); + } + + public override void SetValue(object component, object value) + { + if (_orig != null) + _orig.SetValue(GetEffectiveComponent(component), value); + } + + public override bool ShouldSerializeValue(object component) + { + return _orig?.ShouldSerializeValue(GetEffectiveComponent(component)) ?? false; + } + + public AttributeCollection GetAttributes() + { + return new AttributeCollection(); + } + } + + private class FeatureWrapperConverter : ExpandableObjectConverter + { + public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) + { + PropertyDescriptorCollection allProperties = TypeDescriptor.GetProperties(value); + Dictionary properties = new Dictionary(); + + // Select all properties with AcaciaOptionAttribute and wrap those + foreach (PropertyDescriptor pd in allProperties) + { + foreach(Attribute attr in pd.Attributes) + { + AcaciaOptionAttribute acaciaAttr = attr as AcaciaOptionAttribute; + if (acaciaAttr != null) + { + // Check if it's supported + if (acaciaAttr.Interface?.IsInstanceOfType(value) == false) + continue; + + properties.Add(pd.Name, new AcaciaPropertyDescriptor(value, acaciaAttr, pd)); + break; + } + } + } + + // Group by name + PropertyDescriptorCollection root = new PropertyDescriptorCollection(null); + foreach(KeyValuePair entry in properties.ToArray()) + { + string[] nameParts = entry.Key.Split(new char[] { '_' }, 2); + if (nameParts.Length == 2) + { + AcaciaPropertyDescriptor parent; + if (!properties.ContainsKey(nameParts[0])) + { + // Add a grouping attribute + parent = new AcaciaPropertyDescriptor(value, nameParts[0]); + properties[nameParts[0]] = parent; + root.Add(parent); + } + else parent = properties[nameParts[0]]; + + parent.MakeChild(entry.Value, nameParts[1]); + } + else + { + root.Add(entry.Value); + } + } + + return root; + } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(string)) + return true; + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(string)) + { + // Show full registry string + Feature feature = value as Feature; + return DebugOptions.GetOptions(feature?.Name); + } + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public class OptionsPropertyDescriptor : PropertyDescriptor, CanEnable + { + private readonly object _value; + + public OptionsPropertyDescriptor(object value, string name, params Attribute[] attributes) + : + base(name, attributes) + { + this._value = value; + } + + public void Enable(bool enable) + { + if (PropertyType == typeof(bool)) + SetValue(_value, enable); + } + + public object Object { get { return _value; } } + + public override bool CanResetValue(object component) { return false; } + public override Type ComponentType { get { return typeof(Options); } } + public override object GetValue(object component) { return _value; } + public override bool IsReadOnly { get { return true; } } + public override Type PropertyType { get { return _value.GetType(); } } + public override void ResetValue(object component) { SetValue(component, null); } + public override void SetValue(object component, object value) { } + public override bool ShouldSerializeValue(object component) { return false; } + + public override TypeConverter Converter + { + get + { + return new FeatureWrapperConverter(); + } + } + } + + + public override bool GetPropertiesSupported(ITypeDescriptorContext context) + { + return true; + } + + public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) + { + PropertyDescriptorCollection properties = new PropertyDescriptorCollection(null); + + Options options = value as Options; + if (options != null) + { + // Add Global options + properties.Add(new OptionsPropertyDescriptor(options.Global, "Global", + new CategoryAttribute(Category.Global), + new DescriptionAttribute("Global options for the Kopano Outlook Extension.") + )); + + // Add Features + foreach (Acacia.Features.Feature feature in options.Features) + { + string description = "Shows the registry setting for the feature."; + AcaciaOptionAttribute acacia = feature.GetType().GetCustomAttribute(); + if (acacia != null) + description = acacia.Description; + + properties.Add(new OptionsPropertyDescriptor(feature, feature.Name, + new CategoryAttribute(Category.Features), + new DescriptionAttribute(description) + )); + } + } + + return properties; + } + } + +} diff --git a/src/AcaciaZPushPlugin/PluginDebugger/PluginDebugger.csproj b/src/AcaciaZPushPlugin/PluginDebugger/PluginDebugger.csproj new file mode 100644 index 0000000..7532954 --- /dev/null +++ b/src/AcaciaZPushPlugin/PluginDebugger/PluginDebugger.csproj @@ -0,0 +1,104 @@ + + + + + Debug + AnyCPU + {9258AD17-0A25-4669-A95C-93EC70882551} + WinExe + Properties + PluginDebugger + PluginDebugger + v4.5.2 + 512 + true + + + AnyCPU + true + full + false + ..\Build\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + ..\Build\Release\ + TRACE + prompt + 4 + + + Kopano.ico + + + + + + + + + + + + + + + + + Form + + + MainForm.cs + + + + + + + MainForm.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + + + + {1a7427a5-f814-4b07-98b2-c67d758b65d6} + AcaciaZPushPlugin + + + + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/PluginDebugger/Program.cs b/src/AcaciaZPushPlugin/PluginDebugger/Program.cs new file mode 100644 index 0000000..5524b71 --- /dev/null +++ b/src/AcaciaZPushPlugin/PluginDebugger/Program.cs @@ -0,0 +1,42 @@ +/// Project : Kopano OL Extension + +/// +/// Copyright 2016 Kopano b.v. +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License, version 3, +/// as published by the Free Software Foundation. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program.If not, see. +/// +/// Consult LICENSE file for details + +using Acacia.Features.DebugSupport; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace PluginDebugger +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(true); + Application.Run(new MainForm()); + } + } +} diff --git a/src/AcaciaZPushPlugin/PluginDebugger/Properties/AssemblyInfo.cs b/src/AcaciaZPushPlugin/PluginDebugger/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..a9d41ae --- /dev/null +++ b/src/AcaciaZPushPlugin/PluginDebugger/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PluginDebugger")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PluginDebugger")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("9258ad17-0a25-4669-a95c-93ec70882551")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/AcaciaZPushPlugin/PluginDebugger/Properties/Resources.Designer.cs b/src/AcaciaZPushPlugin/PluginDebugger/Properties/Resources.Designer.cs new file mode 100644 index 0000000..42d99ee --- /dev/null +++ b/src/AcaciaZPushPlugin/PluginDebugger/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace PluginDebugger.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PluginDebugger.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/src/AcaciaZPushPlugin/PluginDebugger/Properties/Resources.resx b/src/AcaciaZPushPlugin/PluginDebugger/Properties/Resources.resx new file mode 100644 index 0000000..ffecec8 --- /dev/null +++ b/src/AcaciaZPushPlugin/PluginDebugger/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/PluginDebugger/Properties/Settings.Designer.cs b/src/AcaciaZPushPlugin/PluginDebugger/Properties/Settings.Designer.cs new file mode 100644 index 0000000..85e56ac --- /dev/null +++ b/src/AcaciaZPushPlugin/PluginDebugger/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace PluginDebugger.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/src/AcaciaZPushPlugin/PluginDebugger/Properties/Settings.settings b/src/AcaciaZPushPlugin/PluginDebugger/Properties/Settings.settings new file mode 100644 index 0000000..abf36c5 --- /dev/null +++ b/src/AcaciaZPushPlugin/PluginDebugger/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/AcaciaZPushPlugin/PluginDebugger/Spacing.png b/src/AcaciaZPushPlugin/PluginDebugger/Spacing.png new file mode 100644 index 0000000000000000000000000000000000000000..611d0a873ebc50a984ae0f9f3789baaa28f4ced9 GIT binary patch literal 161 zcmeAS@N?(olHy`uVBq!ia0vp^EFjFm1|(O0oL2{=7>k44ofy`glX(e}Nq6*hWMJ6X z&;2Kn70Bl-@Q5sCVBk9p!i>lBSEK+1B}!Z)N`mv#O3D+9QW**oGxJLH@={9_O!N%& yEOU(O{D5kNJY5_^B*K$_{Qqyyr55?Xo|&OYP5)xpq`WmiSq4v6KbLh*2~7Y4ohw2B literal 0 HcmV?d00001 diff --git a/translations/KOE.pot b/translations/KOE.pot new file mode 100644 index 0000000..8d55bfe --- /dev/null +++ b/translations/KOE.pot @@ -0,0 +1,772 @@ +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonGC.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonGC.Text" +msgid "Run GC" +msgstr "" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonRefresh.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonRefresh.Text" +msgid "Refresh" +msgstr "" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonClose.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonClose.Text" +msgid "Close" +msgstr "" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonLog.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonLog.Text" +msgid "Log" +msgstr "" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\$this.Text" +msgid "Debug" +msgstr "" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugSupportSettings\labelLogLevel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugSupportSettings\\labelLogLevel.Text" +msgid "Log level:" +msgstr "" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugSupportSettings\buttonShowLog.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugSupportSettings\\buttonShowLog.Text" +msgid "Open log file location" +msgstr "" + +#: AcaciaZPushPlugin\Features\FreeBusy\FreeBusySettings\checkGABLookup.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\FreeBusy\\FreeBusySettings\\checkGABLookup.Text" +msgid "Look up contacts in Global Address Book" +msgstr "" + +#: AcaciaZPushPlugin\Features\FreeBusy\FreeBusySettings\labelUseAccount.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\FreeBusy\\FreeBusySettings\\labelUseAccount.Text" +msgid "Use account: " +msgstr "" + +#: AcaciaZPushPlugin\Features\GAB\GABSettings\buttonGABResync.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\GAB\\GABSettings\\buttonGABResync.Text" +msgid "Resynchronise Global Address Books" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\chkEnable.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\chkEnable.Text" +msgid "Enable out-of-office auto-responding" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\radioNoTime.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\radioNoTime.Text" +msgid "until further notice" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\radioTime.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\radioTime.Text" +msgid "from" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\timeFrom.CustomFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\timeFrom.CustomFormat" +msgid "HH:mm" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\labelTill.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\labelTill.Text" +msgid "until" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\timeTill.CustomFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\timeTill.CustomFormat" +msgid "HH:mm" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\labelBody.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\labelBody.Text" +msgid "AutoReply only once to each sender with the following text:" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\btnCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\btnCancel.Text" +msgid "Cancel" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\btnSave.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\btnSave.Text" +msgid "Save" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\$this.Text" +msgid "Out of Office Assistant for {0}" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\labelSelectUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\labelSelectUser.Text" +msgid "Open folders for user" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonOpenUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonOpenUser.Text" +msgid "Open" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelName.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelName.Text" +msgid "Share as" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelSendAs.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelSendAs.Text" +msgid "Send as owner" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelPermissions.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelPermissions.Text" +msgid "Permissions" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\labelPermissionsValue.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\labelPermissionsValue.Text" +msgid "Permissions" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\$this.Text" +msgid "Shared Folders - {0}" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\labelIntro.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\labelIntro.Text" +msgid "Please select any folders you wish to close and click \"Close\"" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\buttonRemove.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\buttonRemove.Text" +msgid "Close" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\buttonCancel.Text" +msgid "Done" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\labelNoFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\labelNoFolders.Text" +msgid "You currently have no shared folders open" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\label1.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\label1.Text" +msgid "Folders are being loaded" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\$this.Text" +msgid "Manage Shared Folders - {0}" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\radioPublicFolder.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\radioPublicFolder.Text" +msgid "Open public folder" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\radioUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\radioUser.Text" +msgid "Open folder from user:" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonUpdateFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonUpdateFolders.Text" +msgid "Update" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelName.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelName.Text" +msgid "Name:" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelWarningRecursive.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelWarningRecursive.Text" +msgid "Please note that the subfolders of the selected folder will not be shared." +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelNoUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelNoUser.Text" +msgid "Please select a user to see the available shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelFoldersLoading.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelFoldersLoading.Text" +msgid "Folders are being loaded" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelNoFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelNoFolders.Text" +msgid "No shared folders were found" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonOpen.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonOpen.Text" +msgid "Open" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\$this.Text" +msgid "Add Shared Folder - {0}" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Failed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Failed" +msgid "Unable to retrieve Out of Office settings. You can still enable or disable Out of Office, but applying the settings might fail." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Label" +msgid "Retrieving current Out of Office settings" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Title" +msgid "Out of Office Assistant" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_DifferentState +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_DifferentState" +msgid "" +"Out of office has been enabled, but the server could not handle your full request.\n" +"\n" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Disabled +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Disabled" +msgid "Out of Office has been disabled." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_DisableFailed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_DisableFailed" +msgid "Unable to disable Out of Office." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Enabled +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Enabled" +msgid "Out of Office has been enabled until further notice." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_EnabledTimeBased +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_EnabledTimeBased" +msgid "Out of Office has been enabled from {0} till {1}." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_EnableFailed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_EnableFailed" +msgid "Unable to enable Out of Office." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Failed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Failed" +msgid "Unable to apply Out of Office settings" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Label" +msgid "Applying Out of Office settings" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Title" +msgid "Out of Office Assistant" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Label" +msgid "Debug" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Screentip" +msgid "Debug dialog" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Supertip" +msgid "Opens the debug dialog, which shows information on the Kopano Outlook Extension." +msgstr "" + +#. The group label for the ribbon +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_GroupMain_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_GroupMain_Label" +msgid "Kopano" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Label" +msgid "Out-of-Office" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Screentip" +msgid "Change Out-of-Office settings" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Supertip" +msgid "Opens a dialog which allows Out-of-Office settings to be viewed or modified." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Label" +msgid "Open shared folder" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Screentip" +msgid "Open another user\'s shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Supertip" +msgid "Open another user\'s shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Label" +msgid "Settings" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Screentip" +msgid "Settings dialog" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Supertip" +msgid "Opens the settings dialog, which allows configuration of the plugin and access to support functions." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFStartup_Message +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFStartup_Message" +msgid "Out of Office is currently enabled on account \'{0}\'. Would you like to change the settings?" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFStartup_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFStartup_Title" +msgid "Out of Office Assistant" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\GABEvent_Body +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GABEvent_Body" +msgid "Modifications to the Global Address Book are not allowed. Please contact your administrator if you think changes are required." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\GABEvent_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GABEvent_Title" +msgid "Global Address Book" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\GAB_FolderFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GAB_FolderFormat" +msgid "Address Book for {0}" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\LocalStore_DisplayName +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\LocalStore_DisplayName" +msgid "Kopano Folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_DebugSupport +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_DebugSupport" +msgid "Support" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_FreeBusy +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_FreeBusy" +msgid "Free/Busy" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_GAB +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_GAB" +msgid "Global Address Book" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_Notes +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_Notes" +msgid "Notes" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_OutOfOffice +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_OutOfOffice" +msgid "Out of office" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_ReplyFlags +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_ReplyFlags" +msgid "Reply flags" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\ThisAddIn_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\ThisAddIn_Title" +msgid "Kopano" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SSLFailed_Body +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SSLFailed_Body" +msgid "There is an error with the security certificate for server {0}. Do you want to allow the connection anyway?" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SSLFailed_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SSLFailed_Title" +msgid "Certificate error" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Title" +msgid "Kopano" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Label" +msgid "Opening shared folder" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Label" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Screentip" +msgid "Manage shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Supertip" +msgid "Open the \"Manage Shared Folders\" dialog, which can be used to remove shared folders." +msgstr "" + +#. {0} will be replaced with the folder name +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Confirm +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Confirm" +msgid "Close shared folder {0}?" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Label" +msgid "Closing shared folder" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Failure" +msgid "Unable to open the shared folder. Please ensure you have permission to open the shared folder." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Failure" +msgid "Unable to close the shared folder." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Label" +msgid "WebApp" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Screentip" +msgid "Open WebApp" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Supertip" +msgid "Open WebApp in the system default browser" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Label" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Screentip" +msgid "Manage shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Supertip" +msgid "Open the \"Shared Folders\" dialog, which can be used to add or remove shared folders." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_PublicFolders +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_PublicFolders" +msgid "Public folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Loading +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Loading" +msgid "Retrieving shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Loading_Error +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Loading_Error" +msgid "There was an error retrieving shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_None +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_None" +msgid "No shared folders are available" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Failure" +msgid "Unable to retrieve shared folders. Please try again later." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Label" +msgid "Retrieving shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Unsaved_Changes +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Unsaved_Changes" +msgid "There are unsaved changes. Do you really want to to discard these?" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Setting_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Setting_Failure" +msgid "Unable to open the shared folder. Please ensure you have permission to open the shared folder." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Setting_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Setting_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Label" +msgid "Manage shared folder" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Screentip" +msgid "Manage this folder in the Shared Folders dialog" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Supertip" +msgid "Open the \"Shared Folders\" dialog for the currently selected folder." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Label" +msgid "Applying changes to shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Failure" +msgid "Unable to apply the changes to the shared folders. Please try again later." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_None +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_None" +msgid "None" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_Read +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_Read" +msgid "Read" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_Write +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_Write" +msgid "Write" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Success +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Success" +msgid "The changes to the shared folders have been applied successfully." +msgstr "" + +#: AcaciaZPushPlugin\UI\ProgressDialog\labelMessage.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\labelMessage.Text" +msgid "labelMessage: SET FROM CODE, NO NEED TO TRANSLATE" +msgstr "" + +#: AcaciaZPushPlugin\UI\ProgressDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "" + +#: AcaciaZPushPlugin\UI\ProgressDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\$this.Text" +msgid "ProgressDialog: SET FROM CODE, NO NEED TO TRANSLATE" +msgstr "" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonApply.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonApply.Text" +msgid "Apply" +msgstr "" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonOK.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonOK.Text" +msgid "OK" +msgstr "" + +#: AcaciaZPushPlugin\UI\SettingsDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\$this.Text" +msgid "Kopano Settings" +msgstr "" + diff --git a/translations/de.po b/translations/de.po new file mode 100644 index 0000000..276084e --- /dev/null +++ b/translations/de.po @@ -0,0 +1,842 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: 2016-11-02 09:35+0000\n" +"Last-Translator: Felix \n" +"Language-Team: German \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 2.4\n" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonGC.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonGC.Text" +msgid "Run GC" +msgstr "GC ausführen" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonRefresh.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonRefresh.Text" +msgid "Refresh" +msgstr "Aktualisieren" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonClose.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonClose.Text" +msgid "Close" +msgstr "Schließen" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonLog.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonLog.Text" +msgid "Log" +msgstr "Protokoll" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\$this.Text" +msgid "Debug" +msgstr "Debug" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugSupportSettings\labelLogLevel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugSupportSettings\\labelLogLevel.Text" +msgid "Log level:" +msgstr "Protokollstufe:" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugSupportSettings\buttonShowLog.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugSupportSettings\\buttonShowLog.Text" +msgid "Open log file location" +msgstr "Speicherort des Protokolls öffnen" + +#: AcaciaZPushPlugin\Features\FreeBusy\FreeBusySettings\checkGABLookup.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\FreeBusy\\FreeBusySettings\\checkGABLookup.Text" +msgid "Look up contacts in Global Address Book" +msgstr "Kontakte im Globalen Adressbuch nachschlagen" + +#: AcaciaZPushPlugin\Features\FreeBusy\FreeBusySettings\labelUseAccount.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\FreeBusy\\FreeBusySettings\\labelUseAccount.Text" +msgid "Use account: " +msgstr "Account verwenden: " + +#: AcaciaZPushPlugin\Features\GAB\GABSettings\buttonGABResync.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\GAB\\GABSettings\\buttonGABResync.Text" +msgid "Resynchronise Global Address Books" +msgstr "Globales Adressbuch neu synchronisieren" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\chkEnable.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\chkEnable.Text" +msgid "Enable out-of-office auto-responding" +msgstr "Abwesenheitsbenachrichtigung aktivieren" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\radioNoTime.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\radioNoTime.Text" +msgid "until further notice" +msgstr "Bis auf weiteres" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\radioTime.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\radioTime.Text" +msgid "from" +msgstr "Von" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\timeFrom.CustomFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\timeFrom.CustomFormat" +msgid "HH:mm" +msgstr "HH:mm" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\labelTill.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\labelTill.Text" +msgid "until" +msgstr "bis" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\timeTill.CustomFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\timeTill.CustomFormat" +msgid "HH:mm" +msgstr "HH:mm" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\labelBody.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\labelBody.Text" +msgid "AutoReply only once to each sender with the following text:" +msgstr "Text der Abwesenheitsbenachrichtigung:" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\btnCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\btnCancel.Text" +msgid "Cancel" +msgstr "Abbrechen" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\btnSave.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\btnSave.Text" +msgid "Save" +msgstr "Speichern" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\$this.Text" +msgid "Out of Office Assistant for {0}" +msgstr "Assistent für Abwesenheitsbenachrichtigungen für Account {0}" + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Failed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Failed" +msgid "Unable to retrieve Out of Office settings. You can still enable or disable Out of Office, but applying the settings might fail." +msgstr "Konnte derzeitige Abwesenheitsbenachrichtigung nicht empfangen. Die Abwesenheitsbenachrichtigung kann verändert werden aber das Speichern könnte fehlschlagen." + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Label" +msgid "Retrieving current Out of Office settings" +msgstr "Derzeitige Abwesenheitsbenachrichtigung wird abgerufen" + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Title" +msgid "Out of Office Assistant" +msgstr "Assistent für Abwesenheitsbenachrichtigungen" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_DifferentState +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_DifferentState" +msgid "" +"Out of office has been enabled, but the server could not handle your full request.\n" +"\n" +msgstr "" +"Eine Abwesenheitsbenachrichtigung wurde aktiviert, aber der Server konnte den Request nicht vollständig bearbeiten.\n" +"\n" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Disabled +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Disabled" +msgid "Out of Office has been disabled." +msgstr "Abwesenheitsbenachrichtigung wurde deaktiviert." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_DisableFailed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_DisableFailed" +msgid "Unable to disable Out of Office." +msgstr "Abwesenheitsbenachrichtigung konnte nicht deaktiviert werden." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Enabled +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Enabled" +msgid "Out of Office has been enabled until further notice." +msgstr "Abwesenheitsbenachrichtigung wurde bis auf weiteres aktiviert." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_EnabledTimeBased +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_EnabledTimeBased" +msgid "Out of Office has been enabled from {0} till {1}." +msgstr "Abwesenheitsbenachrichtigung wurde für den Zeitraum von {0} bis {1} gesetzt." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_EnableFailed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_EnableFailed" +msgid "Unable to enable Out of Office." +msgstr "Abwesenheitsbenachrichtigung konnte nicht aktiviert werden." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Failed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Failed" +msgid "Unable to apply Out of Office settings" +msgstr "Abwesenheitseinstellungen konnten nicht angewandt werden" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Label" +msgid "Applying Out of Office settings" +msgstr "Abwesenheitseinstellungen werden angewandt" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Title" +msgid "Out of Office Assistant" +msgstr "Assistent für Abwesenheitsbenachrichtigungen" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Label" +msgid "Debug" +msgstr "Debug" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Screentip" +msgid "Debug dialog" +msgstr "Debugeinstellungen" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Supertip" +msgid "Opens the debug dialog, which shows information on the Kopano Outlook Extension." +msgstr "Öffnet das Protokollfenster mit weiteren Informationen zur Kopano OL Extension." + +#. The group label for the ribbon +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_GroupMain_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_GroupMain_Label" +msgid "Kopano" +msgstr "Kopano" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Label" +msgid "Out-of-Office" +msgstr "Abwesenheits-benachrichtigung" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Screentip" +msgid "Change Out-of-Office settings" +msgstr "Einstellen der Abwesenheitsbenachrichtigung ändern" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Supertip" +msgid "Opens a dialog which allows Out-of-Office settings to be viewed or modified." +msgstr "Öffnet einen Dialog zum betrachten und bearbeiten der Abwesenheitsbenachrichtigung." + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OpenSharedFolders_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OpenSharedFolders_Label" +msgid "Open shared folders" +msgstr "Gemeinsame Ordner öffnen" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OpenSharedFolders_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OpenSharedFolders_Screentip" +msgid "Open shared folders - Screentip" +msgstr "Gemeinsame Ordner öffnen - Screentip" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OpenSharedFolders_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OpenSharedFolders_Supertip" +msgid "Open shared folders - Supertip" +msgstr "Gemeinsame Ordner öffnen - Supertip" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Label" +msgid "Settings" +msgstr "Einstellungen" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Screentip" +msgid "Settings dialog" +msgstr "Einstellungsfenster" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Supertip" +msgid "Opens the settings dialog, which allows configuration of the plugin and access to support functions." +msgstr "Öffnet einen Dialog zur Konfiguration des Plugins und für den Zugriff auf Supportfunktionen." + +#: AcaciaZPushPlugin\Properties\Resources\OOFStartup_Message +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFStartup_Message" +msgid "Out of Office is currently enabled on account \'{0}\'. Would you like to change the settings?" +msgstr "Eine Abwesenheitsbenachrichtigung ist derzeit für den Account \'{0}\' aktiviert. Möchten Sie dies ändern?" + +#: AcaciaZPushPlugin\Properties\Resources\OOFStartup_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFStartup_Title" +msgid "Out of Office Assistant" +msgstr "Assistent für Abwesenheitsbenachrichtigungen" + +#: AcaciaZPushPlugin\Properties\Resources\GABEvent_Body +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GABEvent_Body" +msgid "Modifications to the Global Address Book are not allowed. Please contact your administrator if you think changes are required." +msgstr "Änderung am Globalen Adressbuch sind nicht erlaubt. Bitte kontaktieren Sie Ihren Administrator falls Änderungen notwendig sind." + +#: AcaciaZPushPlugin\Properties\Resources\GABEvent_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GABEvent_Title" +msgid "Global Address Book" +msgstr "Globales Adressbuch" + +#: AcaciaZPushPlugin\Properties\Resources\GAB_FolderFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GAB_FolderFormat" +msgid "Address Book for {0}" +msgstr "Adressbuch für {0}" + +#: AcaciaZPushPlugin\Properties\Resources\LocalStore_DisplayName +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\LocalStore_DisplayName" +msgid "Kopano Folders" +msgstr "Kopano Ordner" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_DebugSupport +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_DebugSupport" +msgid "Support" +msgstr "Support" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_FreeBusy +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_FreeBusy" +msgid "Free/Busy" +msgstr "Frei/Gebucht" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_GAB +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_GAB" +msgid "Global Address Book" +msgstr "Globales Adressbuch" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_Notes +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_Notes" +msgid "Notes" +msgstr "Notizen" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_OutOfOffice +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_OutOfOffice" +msgid "Out of office" +msgstr "Abwesenheitsbenachrichtigung" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_ReplyFlags +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_ReplyFlags" +msgid "Reply flags" +msgstr "Antwortpfeile" + +#: AcaciaZPushPlugin\Properties\Resources\ThisAddIn_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\ThisAddIn_Title" +msgid "Kopano" +msgstr "Kopano" + +#: AcaciaZPushPlugin\Properties\Resources\SSLFailed_Body +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SSLFailed_Body" +msgid "There is an error with the security certificate for server {0}. Do you want to allow the connection anyway?" +msgstr "Es gab ein Problem mit dem Sicherheitszertifikat des Servers {0}. Soll die Verbindung dennoch erfolgen?" + +#: AcaciaZPushPlugin\Properties\Resources\SSLFailed_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SSLFailed_Title" +msgid "Certificate error" +msgstr "Zertifikatfehler" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Title" +msgid "Kopano" +msgstr "Kopano" + +#: AcaciaZPushPlugin\UI\ProgressDialog\labelMessage.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\labelMessage.Text" +msgid "labelMessage: SET FROM CODE, NO NEED TO TRANSLATE" +msgstr "labelMessage: SET FROM CODE, NO NEED TO TRANSLATE" + +#: AcaciaZPushPlugin\UI\ProgressDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "Abbrechen" + +#: AcaciaZPushPlugin\UI\ProgressDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\$this.Text" +msgid "ProgressDialog: SET FROM CODE, NO NEED TO TRANSLATE" +msgstr "ProgressDialog: SET FROM CODE, NO NEED TO TRANSLATE" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonApply.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonApply.Text" +msgid "Apply" +msgstr "Anwenden" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "Abbrechen" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonOK.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonOK.Text" +msgid "OK" +msgstr "OK" + +#: AcaciaZPushPlugin\UI\SettingsDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\$this.Text" +msgid "Kopano Settings" +msgstr "Kopano Einstellungen" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\labelIntro.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\labelIntro.Text" +msgid "Please select any folders you wish to close and click \"Close\"" +msgstr "Bitte wählen Sie die Ordner aus die Sie schließen möchten und klicken Sie anschließend aus \"Schließen\"" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\buttonRemove.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\buttonRemove.Text" +msgid "Close" +msgstr "Schließen" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\buttonCancel.Text" +msgid "Done" +msgstr "Fertig" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\labelNoFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\labelNoFolders.Text" +msgid "You currently have no shared folders open" +msgstr "Sie haben derzeit keine geteilten Ordner geöffnet" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\label1.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\label1.Text" +msgid "Folders are being loaded" +msgstr "Ordner werden geladen" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\$this.Text" +msgid "Manage Shared Folders - {0}" +msgstr "Geteilte Ordner verwalten" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelUser.Text" +msgid "User:" +msgstr "Benutzer:" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonUpdateFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonUpdateFolders.Text" +msgid "Update" +msgstr "Aktualisieren" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelName.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelName.Text" +msgid "Name:" +msgstr "Name:" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\checkReadOnly.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\checkReadOnly.Text" +msgid "Read only" +msgstr "Nur lesend" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelNoUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelNoUser.Text" +msgid "Please select a user to see the available shared folders" +msgstr "Bitte wählen Sie einen Benutzer aus um dessen geteilte Ordner anzuzeigen" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\label1.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\label1.Text" +msgid "Folders are being loaded" +msgstr "Ordner werden geladen" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelNoFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelNoFolders.Text" +msgid "No shared folders were found" +msgstr "Keine geteilten Ordner gefunden" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "Abbrechen" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonOpen.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonOpen.Text" +msgid "Open" +msgstr "Öffnen" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\$this.Text" +msgid "Add Shared Folder - {0}" +msgstr "Geteilten Ordner hinzufügen - {0}" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Label" +msgid "Open shared folder" +msgstr "Geteilten Ordner öffnen" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Screentip" +msgid "Open another user\'s shared folders" +msgstr "Die geteilten Ordner eines anderen Benutzers öffnen" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Supertip" +msgid "Open another user\'s shared folders" +msgstr "Die geteilten Ordner eines anderen Benutzers öffnen" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Label" +msgid "Opening shared folder" +msgstr "Geteilte Ordner öffnen" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Title" +msgid "Shared folders" +msgstr "Geteilte Ordner" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Label" +msgid "Shared folders" +msgstr "Geteilte Ordner" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Screentip" +msgid "Manage shared folders" +msgstr "Geteilte Ordner verwalten" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Supertip" +msgid "Open the \"Manage Shared Folders\" dialog, which can be used to remove shared folders." +msgstr "Öffnen Sie den \"Geteilte Ordner öffnen\" Dialog um geteilte Ordner wieder zu schließen." + +#. {0} will be replaced with the folder name +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Confirm +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Confirm" +msgid "Close shared folder {0}?" +msgstr "Geteilten Ordner {0} schließen?" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Label" +msgid "Closing shared folder" +msgstr "Geteilter Ordner wird geschlossen" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Title" +msgid "Shared folders" +msgstr "Geteilte Ordner" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Failure" +msgid "Unable to open the shared folder. Please ensure you have permission to open the shared folder." +msgstr "Geteilter Ordner kann nicht geöffnet werden. Bitte prüfen Sie Ihre Berechtigungen." + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Failure" +msgid "Unable to close the shared folder." +msgstr "Geteilter Ordner kann nicht geschlossen werden." + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\radioPublicFolder.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\radioPublicFolder.Text" +msgid "Open public folder" +msgstr "Öffentlichen Ordner öffnen" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\radioUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\radioUser.Text" +msgid "Open folder from user:" +msgstr "Öffne geteilten Ordner von Benutzer:" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelWarningRecursive.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelWarningRecursive.Text" +msgid "Please note that the subfolders of the selected folder will not be shared." +msgstr "Bitte beachten Sie, dass Unterordner nicht automatisch mit geöffnet werden." + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelFoldersLoading.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelFoldersLoading.Text" +msgid "Folders are being loaded" +msgstr "Ordner werden geladen" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Label" +msgid "WebApp" +msgstr "WebApp" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Screentip" +msgid "Open WebApp" +msgstr "WebApp öffnen" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Supertip" +msgid "Open WebApp in the system default browser" +msgstr "WebApp im voreingestellten Webbrowser öffnen" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonApply.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonApply.Text" +msgid "Apply" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonClose.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonClose.Text" +msgid "Close" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\labelSelectUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\labelSelectUser.Text" +msgid "Open folders for user" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonOpenUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonOpenUser.Text" +msgid "Open" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\$this.Text" +msgid "Shared Folders - {0}" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Label" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Screentip" +msgid "Manage shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Supertip" +msgid "Open the \"Shared Folders\" dialog, which can be used to add or remove shared folders." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_PublicFolders +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_PublicFolders" +msgid "Public folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Loading +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Loading" +msgid "Retrieving shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Loading_Error +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Loading_Error" +msgid "There was an error retrieving shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_None +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_None" +msgid "No shared folders are available" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Failure" +msgid "Unable to retrieve shared folders. Please try again later." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Label" +msgid "Retrieving shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Unsaved_Changes +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Unsaved_Changes" +msgid "There are unsaved changes. Do you really want to to discard these?" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Setting_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Setting_Failure" +msgid "Unable to open the shared folder. Please ensure you have permission to open the shared folder." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Setting_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Setting_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelName.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelName.Text" +msgid "Share as" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelSendAs.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelSendAs.Text" +msgid "Send as owner" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelPermissions.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelPermissions.Text" +msgid "Permissions" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\labelPermissionsValue.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\labelPermissionsValue.Text" +msgid "Permissions" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Label" +msgid "Manage shared folder" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Screentip" +msgid "Manage this folder in the Shared Folders dialog" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Supertip" +msgid "Open the \"Shared Folders\" dialog for the currently selected folder." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Label" +msgid "Applying changes to shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Failure" +msgid "Unable to apply the changes to the shared folders. Please try again later." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_None +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_None" +msgid "None" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_Read +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_Read" +msgid "Read" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_Write +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_Write" +msgid "Write" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Success +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Success" +msgid "The changes to the shared folders have been applied successfully." +msgstr "" + diff --git a/translations/en.po b/translations/en.po new file mode 100644 index 0000000..273de21 --- /dev/null +++ b/translations/en.po @@ -0,0 +1,774 @@ +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonGC.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonGC.Text" +msgid "Run GC" +msgstr "Run GC" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonRefresh.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonRefresh.Text" +msgid "Refresh" +msgstr "Refresh" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonClose.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonClose.Text" +msgid "Close" +msgstr "Close" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonLog.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonLog.Text" +msgid "Log" +msgstr "Log" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\$this.Text" +msgid "Debug" +msgstr "Debug" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugSupportSettings\labelLogLevel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugSupportSettings\\labelLogLevel.Text" +msgid "Log level:" +msgstr "Log level:" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugSupportSettings\buttonShowLog.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugSupportSettings\\buttonShowLog.Text" +msgid "Open log file location" +msgstr "Open log file location" + +#: AcaciaZPushPlugin\Features\FreeBusy\FreeBusySettings\checkGABLookup.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\FreeBusy\\FreeBusySettings\\checkGABLookup.Text" +msgid "Look up contacts in Global Address Book" +msgstr "Look up contacts in Global Address Book" + +#: AcaciaZPushPlugin\Features\FreeBusy\FreeBusySettings\labelUseAccount.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\FreeBusy\\FreeBusySettings\\labelUseAccount.Text" +msgid "Use account: " +msgstr "Use account: " + +#: AcaciaZPushPlugin\Features\GAB\GABSettings\buttonGABResync.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\GAB\\GABSettings\\buttonGABResync.Text" +msgid "Resynchronise Global Address Books" +msgstr "Resynchronise Global Address Books" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\chkEnable.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\chkEnable.Text" +msgid "Enable out-of-office auto-responding" +msgstr "Enable out-of-office auto-responding" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\radioNoTime.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\radioNoTime.Text" +msgid "until further notice" +msgstr "until further notice" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\radioTime.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\radioTime.Text" +msgid "from" +msgstr "from" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\timeFrom.CustomFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\timeFrom.CustomFormat" +msgid "HH:mm" +msgstr "HH:mm" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\labelTill.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\labelTill.Text" +msgid "until" +msgstr "until" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\timeTill.CustomFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\timeTill.CustomFormat" +msgid "HH:mm" +msgstr "HH:mm" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\labelBody.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\labelBody.Text" +msgid "AutoReply only once to each sender with the following text:" +msgstr "AutoReply only once to each sender with the following text:" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\btnCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\btnCancel.Text" +msgid "Cancel" +msgstr "Cancel" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\btnSave.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\btnSave.Text" +msgid "Save" +msgstr "Save" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\$this.Text" +msgid "Out of Office Assistant for {0}" +msgstr "Out of Office Assistant for {0}" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\labelSelectUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\labelSelectUser.Text" +msgid "Open folders for user" +msgstr "Open folders for user" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonOpenUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonOpenUser.Text" +msgid "Open" +msgstr "Open" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelName.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelName.Text" +msgid "Share as" +msgstr "Share as" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelSendAs.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelSendAs.Text" +msgid "Send as owner" +msgstr "Send as owner" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelPermissions.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelPermissions.Text" +msgid "Permissions" +msgstr "Permissions" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\labelPermissionsValue.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\labelPermissionsValue.Text" +msgid "Permissions" +msgstr "Permissions" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\$this.Text" +msgid "Shared Folders - {0}" +msgstr "Shared Folders - {0}" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\labelIntro.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\labelIntro.Text" +msgid "Please select any folders you wish to close and click \"Close\"" +msgstr "Please select any folders you wish to close and click \"Close\"" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\buttonRemove.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\buttonRemove.Text" +msgid "Close" +msgstr "Close" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\buttonCancel.Text" +msgid "Done" +msgstr "Done" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\labelNoFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\labelNoFolders.Text" +msgid "You currently have no shared folders open" +msgstr "You currently have no shared folders open" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\label1.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\label1.Text" +msgid "Folders are being loaded" +msgstr "Folders are being loaded" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\$this.Text" +msgid "Manage Shared Folders - {0}" +msgstr "Manage Shared Folders - {0}" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\radioPublicFolder.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\radioPublicFolder.Text" +msgid "Open public folder" +msgstr "Open public folder" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\radioUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\radioUser.Text" +msgid "Open folder from user:" +msgstr "Open folder from user:" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonUpdateFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonUpdateFolders.Text" +msgid "Update" +msgstr "Update" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelName.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelName.Text" +msgid "Name:" +msgstr "Name:" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelWarningRecursive.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelWarningRecursive.Text" +msgid "Please note that the subfolders of the selected folder will not be shared." +msgstr "Please note that the subfolders of the selected folder will not be shared." + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelNoUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelNoUser.Text" +msgid "Please select a user to see the available shared folders" +msgstr "Please select a user to see the available shared folders" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelFoldersLoading.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelFoldersLoading.Text" +msgid "Folders are being loaded" +msgstr "Folders are being loaded" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelNoFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelNoFolders.Text" +msgid "No shared folders were found" +msgstr "No shared folders were found" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "Cancel" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonOpen.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonOpen.Text" +msgid "Open" +msgstr "Open" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\$this.Text" +msgid "Add Shared Folder - {0}" +msgstr "Add Shared Folder - {0}" + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Failed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Failed" +msgid "Unable to retrieve Out of Office settings. You can still enable or disable Out of Office, but applying the settings might fail." +msgstr "Unable to retrieve Out of Office settings. You can still enable or disable Out of Office, but applying the settings might fail." + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Label" +msgid "Retrieving current Out of Office settings" +msgstr "Retrieving current Out of Office settings" + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Title" +msgid "Out of Office Assistant" +msgstr "Out of Office Assistant" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_DifferentState +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_DifferentState" +msgid "" +"Out of office has been enabled, but the server could not handle your full request.\n" +"\n" +msgstr "" +"Out of office has been enabled, but the server could not handle your full request.\n" +"\n" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Disabled +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Disabled" +msgid "Out of Office has been disabled." +msgstr "Out of Office has been disabled." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_DisableFailed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_DisableFailed" +msgid "Unable to disable Out of Office." +msgstr "Unable to disable Out of Office." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Enabled +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Enabled" +msgid "Out of Office has been enabled until further notice." +msgstr "Out of Office has been enabled until further notice." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_EnabledTimeBased +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_EnabledTimeBased" +msgid "Out of Office has been enabled from {0} till {1}." +msgstr "Out of Office has been enabled from {0} till {1}." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_EnableFailed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_EnableFailed" +msgid "Unable to enable Out of Office." +msgstr "Unable to enable Out of Office." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Failed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Failed" +msgid "Unable to apply Out of Office settings" +msgstr "Unable to apply Out of Office settings" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Label" +msgid "Applying Out of Office settings" +msgstr "Applying Out of Office settings" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Title" +msgid "Out of Office Assistant" +msgstr "Out of Office Assistant" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Label" +msgid "Debug" +msgstr "Debug" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Screentip" +msgid "Debug dialog" +msgstr "Debug dialog" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Supertip" +msgid "Opens the debug dialog, which shows information on the Kopano Outlook Extension." +msgstr "Opens the debug dialog, which shows information on the Kopano Outlook Extension." + +#. The group label for the ribbon +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_GroupMain_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_GroupMain_Label" +msgid "Kopano" +msgstr "Kopano" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Label" +msgid "Out-of-Office" +msgstr "Out-of-Office" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Screentip" +msgid "Change Out-of-Office settings" +msgstr "Change Out-of-Office settings" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Supertip" +msgid "Opens a dialog which allows Out-of-Office settings to be viewed or modified." +msgstr "Opens a dialog which allows Out-of-Office settings to be viewed or modified." + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Label" +msgid "Open shared folder" +msgstr "Open shared folder" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Screentip" +msgid "Open another user\'s shared folders" +msgstr "Open another user\'s shared folders" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Supertip" +msgid "Open another user\'s shared folders" +msgstr "Open another user\'s shared folders" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Label" +msgid "Settings" +msgstr "Settings" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Screentip" +msgid "Settings dialog" +msgstr "Settings dialog" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Supertip" +msgid "Opens the settings dialog, which allows configuration of the plugin and access to support functions." +msgstr "Opens the settings dialog, which allows configuration of the plugin and access to support functions." + +#: AcaciaZPushPlugin\Properties\Resources\OOFStartup_Message +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFStartup_Message" +msgid "Out of Office is currently enabled on account \'{0}\'. Would you like to change the settings?" +msgstr "Out of Office is currently enabled on account \'{0}\'. Would you like to change the settings?" + +#: AcaciaZPushPlugin\Properties\Resources\OOFStartup_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFStartup_Title" +msgid "Out of Office Assistant" +msgstr "Out of Office Assistant" + +#: AcaciaZPushPlugin\Properties\Resources\GABEvent_Body +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GABEvent_Body" +msgid "Modifications to the Global Address Book are not allowed. Please contact your administrator if you think changes are required." +msgstr "Modifications to the Global Address Book are not allowed. Please contact your administrator if you think changes are required." + +#: AcaciaZPushPlugin\Properties\Resources\GABEvent_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GABEvent_Title" +msgid "Global Address Book" +msgstr "Global Address Book" + +#: AcaciaZPushPlugin\Properties\Resources\GAB_FolderFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GAB_FolderFormat" +msgid "Address Book for {0}" +msgstr "Address Book for {0}" + +#: AcaciaZPushPlugin\Properties\Resources\LocalStore_DisplayName +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\LocalStore_DisplayName" +msgid "Kopano Folders" +msgstr "Kopano Folders" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_DebugSupport +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_DebugSupport" +msgid "Support" +msgstr "Support" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_FreeBusy +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_FreeBusy" +msgid "Free/Busy" +msgstr "Free/Busy" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_GAB +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_GAB" +msgid "Global Address Book" +msgstr "Global Address Book" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_Notes +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_Notes" +msgid "Notes" +msgstr "Notes" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_OutOfOffice +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_OutOfOffice" +msgid "Out of office" +msgstr "Out of office" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_ReplyFlags +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_ReplyFlags" +msgid "Reply flags" +msgstr "Reply flags" + +#: AcaciaZPushPlugin\Properties\Resources\ThisAddIn_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\ThisAddIn_Title" +msgid "Kopano" +msgstr "Kopano" + +#: AcaciaZPushPlugin\Properties\Resources\SSLFailed_Body +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SSLFailed_Body" +msgid "There is an error with the security certificate for server {0}. Do you want to allow the connection anyway?" +msgstr "There is an error with the security certificate for server {0}. Do you want to allow the connection anyway?" + +#: AcaciaZPushPlugin\Properties\Resources\SSLFailed_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SSLFailed_Title" +msgid "Certificate error" +msgstr "Certificate error" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Title" +msgid "Kopano" +msgstr "Kopano" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Label" +msgid "Opening shared folder" +msgstr "Opening shared folder" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Title" +msgid "Shared folders" +msgstr "Shared folders" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Label" +msgid "Shared folders" +msgstr "Shared folders" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Screentip" +msgid "Manage shared folders" +msgstr "Manage shared folders" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Supertip" +msgid "Open the \"Manage Shared Folders\" dialog, which can be used to remove shared folders." +msgstr "Open the \"Manage Shared Folders\" dialog, which can be used to remove shared folders." + +#. {0} will be replaced with the folder name +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Confirm +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Confirm" +msgid "Close shared folder {0}?" +msgstr "Close shared folder {0}?" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Label" +msgid "Closing shared folder" +msgstr "Closing shared folder" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Title" +msgid "Shared folders" +msgstr "Shared folders" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Failure" +msgid "Unable to open the shared folder. Please ensure you have permission to open the shared folder." +msgstr "Unable to open the shared folder. Please ensure you have permission to open the shared folder." + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Failure" +msgid "Unable to close the shared folder." +msgstr "Unable to close the shared folder." + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Label" +msgid "WebApp" +msgstr "WebApp" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Screentip" +msgid "Open WebApp" +msgstr "Open WebApp" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Supertip" +msgid "Open WebApp in the system default browser" +msgstr "Open WebApp in the system default browser" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Label" +msgid "Shared folders" +msgstr "Shared folders" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Screentip" +msgid "Manage shared folders" +msgstr "Manage shared folders" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Supertip" +msgid "Open the \"Shared Folders\" dialog, which can be used to add or remove shared folders." +msgstr "Open the \"Shared Folders\" dialog, which can be used to add or remove shared folders." + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_PublicFolders +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_PublicFolders" +msgid "Public folders" +msgstr "Public folders" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Loading +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Loading" +msgid "Retrieving shared folders" +msgstr "Retrieving shared folders" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Loading_Error +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Loading_Error" +msgid "There was an error retrieving shared folders" +msgstr "There was an error retrieving shared folders" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_None +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_None" +msgid "No shared folders are available" +msgstr "No shared folders are available" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Failure" +msgid "Unable to retrieve shared folders. Please try again later." +msgstr "Unable to retrieve shared folders. Please try again later." + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Label" +msgid "Retrieving shared folders" +msgstr "Retrieving shared folders" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Title" +msgid "Shared folders" +msgstr "Shared folders" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Unsaved_Changes +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Unsaved_Changes" +msgid "There are unsaved changes. Do you really want to to discard these?" +msgstr "There are unsaved changes. Do you really want to to discard these?" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Setting_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Setting_Failure" +msgid "Unable to open the shared folder. Please ensure you have permission to open the shared folder." +msgstr "Unable to open the shared folder. Please ensure you have permission to open the shared folder." + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Setting_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Setting_Title" +msgid "Shared folders" +msgstr "Shared folders" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Label" +msgid "Manage shared folder" +msgstr "Manage shared folder" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Screentip" +msgid "Manage this folder in the Shared Folders dialog" +msgstr "Manage this folder in the Shared Folders dialog" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Supertip" +msgid "Open the \"Shared Folders\" dialog for the currently selected folder." +msgstr "Open the \"Shared Folders\" dialog for the currently selected folder." + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Label" +msgid "Applying changes to shared folders" +msgstr "Applying changes to shared folders" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Failure" +msgid "Unable to apply the changes to the shared folders. Please try again later." +msgstr "Unable to apply the changes to the shared folders. Please try again later." + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Title" +msgid "Shared folders" +msgstr "Shared folders" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_None +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_None" +msgid "None" +msgstr "None" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_Read +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_Read" +msgid "Read" +msgstr "Read" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_Write +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_Write" +msgid "Write" +msgstr "Write" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Success +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Success" +msgid "The changes to the shared folders have been applied successfully." +msgstr "The changes to the shared folders have been applied successfully." + +#: AcaciaZPushPlugin\UI\ProgressDialog\labelMessage.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\labelMessage.Text" +msgid "labelMessage: SET FROM CODE, NO NEED TO TRANSLATE" +msgstr "labelMessage: SET FROM CODE, NO NEED TO TRANSLATE" + +#: AcaciaZPushPlugin\UI\ProgressDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "Cancel" + +#: AcaciaZPushPlugin\UI\ProgressDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\$this.Text" +msgid "ProgressDialog: SET FROM CODE, NO NEED TO TRANSLATE" +msgstr "ProgressDialog: SET FROM CODE, NO NEED TO TRANSLATE" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonApply.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonApply.Text" +msgid "Apply" +msgstr "Apply" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "Cancel" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonOK.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonOK.Text" +msgid "OK" +msgstr "OK" + +#: AcaciaZPushPlugin\UI\SettingsDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\$this.Text" +msgid "Kopano Settings" +msgstr "Kopano Settings" + diff --git a/translations/fr.po b/translations/fr.po new file mode 100644 index 0000000..852387f --- /dev/null +++ b/translations/fr.po @@ -0,0 +1,840 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.8.7\n" +"Last-Translator: \n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"Language: fr\n" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonGC.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonGC.Text" +msgid "Run GC" +msgstr "" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonRefresh.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonRefresh.Text" +msgid "Refresh" +msgstr "" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonClose.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonClose.Text" +msgid "Close" +msgstr "" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonLog.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonLog.Text" +msgid "Log" +msgstr "" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\$this.Text" +msgid "Debug" +msgstr "" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugSupportSettings\labelLogLevel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugSupportSettings\\labelLogLevel.Text" +msgid "Log level:" +msgstr "" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugSupportSettings\buttonShowLog.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugSupportSettings\\buttonShowLog.Text" +msgid "Open log file location" +msgstr "" + +#: AcaciaZPushPlugin\Features\FreeBusy\FreeBusySettings\checkGABLookup.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\FreeBusy\\FreeBusySettings\\checkGABLookup.Text" +msgid "Look up contacts in Global Address Book" +msgstr "" + +#: AcaciaZPushPlugin\Features\FreeBusy\FreeBusySettings\labelUseAccount.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\FreeBusy\\FreeBusySettings\\labelUseAccount.Text" +msgid "Use account: " +msgstr "" + +#: AcaciaZPushPlugin\Features\GAB\GABSettings\buttonGABResync.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\GAB\\GABSettings\\buttonGABResync.Text" +msgid "Resynchronise Global Address Books" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\chkEnable.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\chkEnable.Text" +msgid "Enable out-of-office auto-responding" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\radioNoTime.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\radioNoTime.Text" +msgid "until further notice" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\radioTime.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\radioTime.Text" +msgid "from" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\timeFrom.CustomFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\timeFrom.CustomFormat" +msgid "HH:mm" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\labelTill.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\labelTill.Text" +msgid "until" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\timeTill.CustomFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\timeTill.CustomFormat" +msgid "HH:mm" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\labelBody.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\labelBody.Text" +msgid "AutoReply only once to each sender with the following text:" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\btnCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\btnCancel.Text" +msgid "Cancel" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\btnSave.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\btnSave.Text" +msgid "Save" +msgstr "" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\$this.Text" +msgid "Out of Office Assistant for {0}" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Failed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Failed" +msgid "Unable to retrieve Out of Office settings. You can still enable or disable Out of Office, but applying the settings might fail." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Label" +msgid "Retrieving current Out of Office settings" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Title" +msgid "Out of Office Assistant" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_DifferentState +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_DifferentState" +msgid "" +"Out of office has been enabled, but the server could not handle your full request.\n" +"\n" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Disabled +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Disabled" +msgid "Out of Office has been disabled." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_DisableFailed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_DisableFailed" +msgid "Unable to disable Out of Office." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Enabled +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Enabled" +msgid "Out of Office has been enabled until further notice." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_EnabledTimeBased +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_EnabledTimeBased" +msgid "Out of Office has been enabled from {0} till {1}." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_EnableFailed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_EnableFailed" +msgid "Unable to enable Out of Office." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Failed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Failed" +msgid "Unable to apply Out of Office settings" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Label" +msgid "Applying Out of Office settings" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Title" +msgid "Out of Office Assistant" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Label" +msgid "Debug" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Screentip" +msgid "Debug dialog" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Supertip" +msgid "Opens the debug dialog, which shows information on the Kopano Outlook Extension." +msgstr "" + +#. The group label for the ribbon +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_GroupMain_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_GroupMain_Label" +msgid "Kopano" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Label" +msgid "Out-of-Office" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Screentip" +msgid "Change Out-of-Office settings" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Supertip" +msgid "Opens a dialog which allows Out-of-Office settings to be viewed or modified." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OpenSharedFolders_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OpenSharedFolders_Label" +msgid "Open shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OpenSharedFolders_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OpenSharedFolders_Screentip" +msgid "Open shared folders - Screentip" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OpenSharedFolders_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OpenSharedFolders_Supertip" +msgid "Open shared folders - Supertip" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Label" +msgid "Settings" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Screentip" +msgid "Settings dialog" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Supertip" +msgid "Opens the settings dialog, which allows configuration of the plugin and access to support functions." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFStartup_Message +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFStartup_Message" +msgid "Out of Office is currently enabled on account \'{0}\'. Would you like to change the settings?" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\OOFStartup_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFStartup_Title" +msgid "Out of Office Assistant" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\GABEvent_Body +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GABEvent_Body" +msgid "Modifications to the Global Address Book are not allowed. Please contact your administrator if you think changes are required." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\GABEvent_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GABEvent_Title" +msgid "Global Address Book" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\GAB_FolderFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GAB_FolderFormat" +msgid "Address Book for {0}" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\LocalStore_DisplayName +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\LocalStore_DisplayName" +msgid "Kopano Folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_DebugSupport +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_DebugSupport" +msgid "Support" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_FreeBusy +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_FreeBusy" +msgid "Free/Busy" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_GAB +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_GAB" +msgid "Global Address Book" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_Notes +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_Notes" +msgid "Notes" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_OutOfOffice +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_OutOfOffice" +msgid "Out of office" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_ReplyFlags +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_ReplyFlags" +msgid "Reply flags" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\ThisAddIn_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\ThisAddIn_Title" +msgid "Kopano" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SSLFailed_Body +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SSLFailed_Body" +msgid "There is an error with the security certificate for server {0}. Do you want to allow the connection anyway?" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SSLFailed_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SSLFailed_Title" +msgid "Certificate error" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Title" +msgid "Kopano" +msgstr "" + +#: AcaciaZPushPlugin\UI\ProgressDialog\labelMessage.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\labelMessage.Text" +msgid "labelMessage: SET FROM CODE, NO NEED TO TRANSLATE" +msgstr "" + +#: AcaciaZPushPlugin\UI\ProgressDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "" + +#: AcaciaZPushPlugin\UI\ProgressDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\$this.Text" +msgid "ProgressDialog: SET FROM CODE, NO NEED TO TRANSLATE" +msgstr "" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonApply.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonApply.Text" +msgid "Apply" +msgstr "" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonOK.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonOK.Text" +msgid "OK" +msgstr "" + +#: AcaciaZPushPlugin\UI\SettingsDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\$this.Text" +msgid "Kopano Settings" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\labelIntro.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\labelIntro.Text" +msgid "Please select any folders you wish to close and click \"Close\"" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\buttonRemove.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\buttonRemove.Text" +msgid "Close" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\buttonCancel.Text" +msgid "Done" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\labelNoFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\labelNoFolders.Text" +msgid "You currently have no shared folders open" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\label1.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\label1.Text" +msgid "Folders are being loaded" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\$this.Text" +msgid "Manage Shared Folders - {0}" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelUser.Text" +msgid "User:" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonUpdateFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonUpdateFolders.Text" +msgid "Update" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelName.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelName.Text" +msgid "Name:" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\checkReadOnly.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\checkReadOnly.Text" +msgid "Read only" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelNoUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelNoUser.Text" +msgid "Please select a user to see the available shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\label1.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\label1.Text" +msgid "Folders are being loaded" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelNoFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelNoFolders.Text" +msgid "No shared folders were found" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonOpen.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonOpen.Text" +msgid "Open" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\$this.Text" +msgid "Add Shared Folder - {0}" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Label" +msgid "Open shared folder" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Screentip" +msgid "Open another user\'s shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Supertip" +msgid "Open another user\'s shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Label" +msgid "Opening shared folder" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Label" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Screentip" +msgid "Manage shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Supertip" +msgid "Open the \"Manage Shared Folders\" dialog, which can be used to remove shared folders." +msgstr "" + +#. {0} will be replaced with the folder name +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Confirm +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Confirm" +msgid "Close shared folder {0}?" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Label" +msgid "Closing shared folder" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Failure" +msgid "Unable to open the shared folder. Please ensure you have permission to open the shared folder." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Failure" +msgid "Unable to close the shared folder." +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\radioPublicFolder.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\radioPublicFolder.Text" +msgid "Open public folder" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\radioUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\radioUser.Text" +msgid "Open folder from user:" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelWarningRecursive.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelWarningRecursive.Text" +msgid "Please note that the subfolders of the selected folder will not be shared." +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelFoldersLoading.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelFoldersLoading.Text" +msgid "Folders are being loaded" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Label" +msgid "WebApp" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Screentip" +msgid "Open WebApp" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Supertip" +msgid "Open WebApp in the system default browser" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonApply.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonApply.Text" +msgid "Apply" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonClose.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonClose.Text" +msgid "Close" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\labelSelectUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\labelSelectUser.Text" +msgid "Open folders for user" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonOpenUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonOpenUser.Text" +msgid "Open" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\$this.Text" +msgid "Shared Folders - {0}" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Label" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Screentip" +msgid "Manage shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Supertip" +msgid "Open the \"Shared Folders\" dialog, which can be used to add or remove shared folders." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_PublicFolders +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_PublicFolders" +msgid "Public folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Loading +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Loading" +msgid "Retrieving shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Loading_Error +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Loading_Error" +msgid "There was an error retrieving shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_None +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_None" +msgid "No shared folders are available" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Failure" +msgid "Unable to retrieve shared folders. Please try again later." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Label" +msgid "Retrieving shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Unsaved_Changes +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Unsaved_Changes" +msgid "There are unsaved changes. Do you really want to to discard these?" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Setting_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Setting_Failure" +msgid "Unable to open the shared folder. Please ensure you have permission to open the shared folder." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Setting_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Setting_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelName.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelName.Text" +msgid "Share as" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelSendAs.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelSendAs.Text" +msgid "Send as owner" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelPermissions.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelPermissions.Text" +msgid "Permissions" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\labelPermissionsValue.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\labelPermissionsValue.Text" +msgid "Permissions" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Label" +msgid "Manage shared folder" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Screentip" +msgid "Manage this folder in the Shared Folders dialog" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Supertip" +msgid "Open the \"Shared Folders\" dialog for the currently selected folder." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Label" +msgid "Applying changes to shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Failure" +msgid "Unable to apply the changes to the shared folders. Please try again later." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_None +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_None" +msgid "None" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_Read +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_Read" +msgid "Read" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_Write +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_Write" +msgid "Write" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Success +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Success" +msgid "The changes to the shared folders have been applied successfully." +msgstr "" + diff --git a/translations/hu.po b/translations/hu.po new file mode 100644 index 0000000..8d93b49 --- /dev/null +++ b/translations/hu.po @@ -0,0 +1,843 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-06-06 11:27+0000\n" +"PO-Revision-Date: 2016-10-05 10:18+0000\n" +"Last-Translator: Zoltan \n" +"Language-Team: Hungarian \n" +"Language: hu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 2.4\n" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonGC.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonGC.Text" +msgid "Run GC" +msgstr "GC futtatása" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonRefresh.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonRefresh.Text" +msgid "Refresh" +msgstr "Frissít" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonClose.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonClose.Text" +msgid "Close" +msgstr "Bezár" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonLog.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonLog.Text" +msgid "Log" +msgstr "Napló" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\$this.Text" +msgid "Debug" +msgstr "Hibakeresés" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugSupportSettings\labelLogLevel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugSupportSettings\\labelLogLevel.Text" +msgid "Log level:" +msgstr "Naplózási szint:" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugSupportSettings\buttonShowLog.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugSupportSettings\\buttonShowLog.Text" +msgid "Open log file location" +msgstr "Napló fájl helyének megnyitása" + +#: AcaciaZPushPlugin\Features\FreeBusy\FreeBusySettings\checkGABLookup.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\FreeBusy\\FreeBusySettings\\checkGABLookup.Text" +msgid "Look up contacts in Global Address Book" +msgstr "Kontaktok betöltése a Globális címjegyzékből" + +#: AcaciaZPushPlugin\Features\FreeBusy\FreeBusySettings\labelUseAccount.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\FreeBusy\\FreeBusySettings\\labelUseAccount.Text" +msgid "Use account: " +msgstr "Fiók használata: " + +#: AcaciaZPushPlugin\Features\GAB\GABSettings\buttonGABResync.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\GAB\\GABSettings\\buttonGABResync.Text" +msgid "Resynchronise Global Address Books" +msgstr "Globális címjegyzék újraszinkronizálása" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\chkEnable.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\chkEnable.Text" +msgid "Enable out-of-office auto-responding" +msgstr "Automatikus válaszok küldése" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\radioNoTime.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\radioNoTime.Text" +msgid "until further notice" +msgstr "Amíg ki nem kapcsolom" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\radioTime.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\radioTime.Text" +msgid "from" +msgstr "Kezdő időpont" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\timeFrom.CustomFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\timeFrom.CustomFormat" +msgid "HH:mm" +msgstr "HH:mm" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\labelTill.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\labelTill.Text" +msgid "until" +msgstr "Záró időpont" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\timeTill.CustomFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\timeTill.CustomFormat" +msgid "HH:mm" +msgstr "HH:mm" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\labelBody.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\labelBody.Text" +msgid "AutoReply only once to each sender with the following text:" +msgstr "Automatikus válasz minden címzettnek egyszer a következő üzenettel:" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\btnCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\btnCancel.Text" +msgid "Cancel" +msgstr "Mégse" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\btnSave.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\btnSave.Text" +msgid "Save" +msgstr "Mentés" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\$this.Text" +msgid "Out of Office Assistant for {0}" +msgstr "Házon kívül segéd ({0})" + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Failed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Failed" +msgid "Unable to retrieve Out of Office settings. You can still enable or disable Out of Office, but applying the settings might fail." +msgstr "A Házon kívül beállítások letöltése nem sikerült. Bekapcsolhatod a házon kívül funkciót, de meglehet, hogy nem sikerül alkalmazni." + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Label" +msgid "Retrieving current Out of Office settings" +msgstr "Házon kívül beállítások betöltése" + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Title" +msgid "Out of Office Assistant" +msgstr "Házon kívül segéd" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_DifferentState +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_DifferentState" +msgid "" +"Out of office has been enabled, but the server could not handle your full request.\n" +"\n" +msgstr "" +"Házon kívül automatikus válasz bekapcsolva, de a szerver nem tudta teljesíteni a kérést maradéktalanul.\n" +"\n" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Disabled +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Disabled" +msgid "Out of Office has been disabled." +msgstr "A Házon kívüli automatikus válasz kikapcsolva." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_DisableFailed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_DisableFailed" +msgid "Unable to disable Out of Office." +msgstr "A Házon kívül kikapcsolása sikertelen." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Enabled +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Enabled" +msgid "Out of Office has been enabled until further notice." +msgstr "Házon kívüli automatikus válasz bekapcsolva." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_EnabledTimeBased +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_EnabledTimeBased" +msgid "Out of Office has been enabled from {0} till {1}." +msgstr "Házon kívüli automatikus válasz bekapcsolva erre az időszakra: {0} - {1}." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_EnableFailed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_EnableFailed" +msgid "Unable to enable Out of Office." +msgstr "A Házon kívüli automatikus válasz beállítása sikertelen." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Failed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Failed" +msgid "Unable to apply Out of Office settings" +msgstr "A Házon kívül bekapcsolása sikertelen" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Label" +msgid "Applying Out of Office settings" +msgstr "Házon kívüli automatikus válasz beállítása folyamatban" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Title" +msgid "Out of Office Assistant" +msgstr "Házon kívül segéd" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Label" +msgid "Debug" +msgstr "Hibakeresés" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Screentip" +msgid "Debug dialog" +msgstr "Hibakereső ablak" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Supertip" +msgid "Opens the debug dialog, which shows information on the Kopano Outlook Extension." +msgstr "Hibakereső ablak megnyitása, ami információkat jelenít meg a Kopano Outlook Extension-ről." + +#. The group label for the ribbon +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_GroupMain_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_GroupMain_Label" +msgid "Kopano" +msgstr "Kopano" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Label" +msgid "Out-of-Office" +msgstr "Házon kívül" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Screentip" +msgid "Change Out-of-Office settings" +msgstr "Házon kívül beállítások módosítása" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Supertip" +msgid "Opens a dialog which allows Out-of-Office settings to be viewed or modified." +msgstr "Házon kívüli automatikus értesítések beállításainak megnyitása." + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OpenSharedFolders_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OpenSharedFolders_Label" +msgid "Open shared folders" +msgstr "Megosztott mappák megnyitása" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OpenSharedFolders_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OpenSharedFolders_Screentip" +msgid "Open shared folders - Screentip" +msgstr "Megosztott mappák megnyitása - Screentip" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OpenSharedFolders_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OpenSharedFolders_Supertip" +msgid "Open shared folders - Supertip" +msgstr "Megosztott mappák megnyitása - Supertip" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Label" +msgid "Settings" +msgstr "Beállítások" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Screentip" +msgid "Settings dialog" +msgstr "Beállítások ablak" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Supertip" +msgid "Opens the settings dialog, which allows configuration of the plugin and access to support functions." +msgstr "Beállítások ablak megnyitása, amiben a bővítmény beállításait és hibakeresését lehet elérni." + +#: AcaciaZPushPlugin\Properties\Resources\OOFStartup_Message +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFStartup_Message" +msgid "Out of Office is currently enabled on account \'{0}\'. Would you like to change the settings?" +msgstr "A Házon kívüli automatikus válasz be van kapcsolva erre a fiókra: \\\'{0}\\\'. Meg kívánod változtatni a beállításokat?" + +#: AcaciaZPushPlugin\Properties\Resources\OOFStartup_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFStartup_Title" +msgid "Out of Office Assistant" +msgstr "Házon kívül segéd" + +#: AcaciaZPushPlugin\Properties\Resources\GABEvent_Body +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GABEvent_Body" +msgid "Modifications to the Global Address Book are not allowed. Please contact your administrator if you think changes are required." +msgstr "A közös címjegyzék módosítása nem lehetséges. Fordulj a rendszergazdához, amennyiben változtatást szeretnél kérni." + +#: AcaciaZPushPlugin\Properties\Resources\GABEvent_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GABEvent_Title" +msgid "Global Address Book" +msgstr "Közös címjegyzék" + +#: AcaciaZPushPlugin\Properties\Resources\GAB_FolderFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GAB_FolderFormat" +msgid "Address Book for {0}" +msgstr "{0} címjegyzéke" + +#: AcaciaZPushPlugin\Properties\Resources\LocalStore_DisplayName +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\LocalStore_DisplayName" +msgid "Kopano Folders" +msgstr "Kopano mappák" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_DebugSupport +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_DebugSupport" +msgid "Support" +msgstr "Támogatás" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_FreeBusy +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_FreeBusy" +msgid "Free/Busy" +msgstr "Elfoglaltsági információk" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_GAB +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_GAB" +msgid "Global Address Book" +msgstr "Közös címjegyzék" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_Notes +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_Notes" +msgid "Notes" +msgstr "Jegyzetek" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_OutOfOffice +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_OutOfOffice" +msgid "Out of office" +msgstr "Házon kívül" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_ReplyFlags +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_ReplyFlags" +msgid "Reply flags" +msgstr "Válasz jelölők" + +#: AcaciaZPushPlugin\Properties\Resources\ThisAddIn_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\ThisAddIn_Title" +msgid "Kopano" +msgstr "Kopano" + +#: AcaciaZPushPlugin\Properties\Resources\SSLFailed_Body +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SSLFailed_Body" +msgid "There is an error with the security certificate for server {0}. Do you want to allow the connection anyway?" +msgstr "Szerver tanúsítvány hiba {0}. Engedélyezed a kapcsolódást?" + +#: AcaciaZPushPlugin\Properties\Resources\SSLFailed_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SSLFailed_Title" +msgid "Certificate error" +msgstr "Tanúsítvány hiba" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Title" +msgid "Kopano" +msgstr "Kopano" + +#: AcaciaZPushPlugin\UI\ProgressDialog\labelMessage.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\labelMessage.Text" +msgid "labelMessage: SET FROM CODE, NO NEED TO TRANSLATE" +msgstr "labelMessage: SET FROM CODE, NO NEED TO TRANSLATE" + +#: AcaciaZPushPlugin\UI\ProgressDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "Mégse" + +#: AcaciaZPushPlugin\UI\ProgressDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\$this.Text" +msgid "ProgressDialog: SET FROM CODE, NO NEED TO TRANSLATE" +msgstr "ProgressDialog: SET FROM CODE, NO NEED TO TRANSLATE" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonApply.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonApply.Text" +msgid "Apply" +msgstr "Alkalmaz" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "Mégse" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonOK.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonOK.Text" +msgid "OK" +msgstr "OK" + +#: AcaciaZPushPlugin\UI\SettingsDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\$this.Text" +msgid "Kopano Settings" +msgstr "Kopano beállítások" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\labelIntro.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\labelIntro.Text" +msgid "Please select any folders you wish to close and click \"Close\"" +msgstr "Válassza ki a bezárni kívánt mappákat, majd kattintson a \"Bezár\" gombra" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\buttonRemove.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\buttonRemove.Text" +msgid "Close" +msgstr "Bezár" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\buttonCancel.Text" +msgid "Done" +msgstr "Kész" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\labelNoFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\labelNoFolders.Text" +msgid "You currently have no shared folders open" +msgstr "Jelenleg nincsenek megosztott mappák megnyitva" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\label1.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\label1.Text" +msgid "Folders are being loaded" +msgstr "Mappák betöltése folyamatban" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\$this.Text" +msgid "Manage Shared Folders - {0}" +msgstr "Megosztott mappák kezelése" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelUser.Text" +msgid "User:" +msgstr "Felhasználó:" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonUpdateFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonUpdateFolders.Text" +msgid "Update" +msgstr "Frissít" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelName.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelName.Text" +msgid "Name:" +msgstr "Név:" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\checkReadOnly.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\checkReadOnly.Text" +msgid "Read only" +msgstr "Csak olvasható" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelNoUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelNoUser.Text" +msgid "Please select a user to see the available shared folders" +msgstr "Válasszon egy felhasználót, hogy láthassa az elérhető megosztott mappákat" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\label1.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\label1.Text" +msgid "Folders are being loaded" +msgstr "Mappák betöltése folyamatban" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelNoFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelNoFolders.Text" +msgid "No shared folders were found" +msgstr "Nem található megosztott mappa" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "Mégse" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonOpen.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonOpen.Text" +msgid "Open" +msgstr "Megnyitás" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\$this.Text" +msgid "Add Shared Folder - {0}" +msgstr "Megosztott mappa hozzáadása - {0}" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Label" +msgid "Open shared folder" +msgstr "Megosztott mappa megnyitása" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Screentip" +msgid "Open another user\'s shared folders" +msgstr "Más felhasználó megosztott mappájának megnyitása" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Supertip" +msgid "Open another user\'s shared folders" +msgstr "Más felhasználó megosztott mappájának megnyitása" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Label" +msgid "Opening shared folder" +msgstr "Megosztott mappa megnyitása" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Title" +msgid "Shared folders" +msgstr "Megosztott mappák" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Label" +msgid "Shared folders" +msgstr "Megosztott mappák" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Screentip" +msgid "Manage shared folders" +msgstr "Megosztott mappák kezelése" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Supertip" +msgid "Open the \"Manage Shared Folders\" dialog, which can be used to remove shared folders." +msgstr "\"Megosztott mappák kezelése\" ablak megnyitása, ahol eltávolíthat megosztott mappákat." + +#. {0} will be replaced with the folder name +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Confirm +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Confirm" +msgid "Close shared folder {0}?" +msgstr "Bezárja a megosztott mappát ({0})?" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Label" +msgid "Closing shared folder" +msgstr "Megosztott mappa bezárása" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Title" +msgid "Shared folders" +msgstr "Megosztott mappák" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Failure" +msgid "Unable to open the shared folder. Please ensure you have permission to open the shared folder." +msgstr "Megosztott mappa megnyitása sikertelen. Győződjön meg, hogy rendelkezik jogosultsággal a mappához." + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Failure" +msgid "Unable to close the shared folder." +msgstr "A megosztott mappa bezárása nem sikerült." + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\radioPublicFolder.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\radioPublicFolder.Text" +msgid "Open public folder" +msgstr "Publikus mappa megnyitása" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\radioUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\radioUser.Text" +msgid "Open folder from user:" +msgstr "Más felhasználó mappájának megnyitása:" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelWarningRecursive.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelWarningRecursive.Text" +msgid "Please note that the subfolders of the selected folder will not be shared." +msgstr "Figyelem! A kiválasztott mappa almappái nem lesznek megosztva." + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelFoldersLoading.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelFoldersLoading.Text" +msgid "Folders are being loaded" +msgstr "Mappák betöltése folyamatban" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Label" +msgid "WebApp" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Screentip" +msgid "Open WebApp" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Supertip" +msgid "Open WebApp in the system default browser" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonApply.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonApply.Text" +msgid "Apply" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonClose.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonClose.Text" +msgid "Close" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\labelSelectUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\labelSelectUser.Text" +msgid "Open folders for user" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonOpenUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonOpenUser.Text" +msgid "Open" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\$this.Text" +msgid "Shared Folders - {0}" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Label" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Screentip" +msgid "Manage shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Supertip" +msgid "Open the \"Shared Folders\" dialog, which can be used to add or remove shared folders." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_PublicFolders +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_PublicFolders" +msgid "Public folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Loading +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Loading" +msgid "Retrieving shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Loading_Error +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Loading_Error" +msgid "There was an error retrieving shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_None +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_None" +msgid "No shared folders are available" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Failure" +msgid "Unable to retrieve shared folders. Please try again later." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Label" +msgid "Retrieving shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Unsaved_Changes +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Unsaved_Changes" +msgid "There are unsaved changes. Do you really want to to discard these?" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Setting_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Setting_Failure" +msgid "Unable to open the shared folder. Please ensure you have permission to open the shared folder." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Setting_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Setting_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelName.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelName.Text" +msgid "Share as" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelSendAs.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelSendAs.Text" +msgid "Send as owner" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelPermissions.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelPermissions.Text" +msgid "Permissions" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\labelPermissionsValue.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\labelPermissionsValue.Text" +msgid "Permissions" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Label" +msgid "Manage shared folder" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Screentip" +msgid "Manage this folder in the Shared Folders dialog" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Supertip" +msgid "Open the \"Shared Folders\" dialog for the currently selected folder." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Label" +msgid "Applying changes to shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Failure" +msgid "Unable to apply the changes to the shared folders. Please try again later." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_None +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_None" +msgid "None" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_Read +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_Read" +msgid "Read" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_Write +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_Write" +msgid "Write" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Success +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Success" +msgid "The changes to the shared folders have been applied successfully." +msgstr "" + diff --git a/translations/it.po b/translations/it.po new file mode 100644 index 0000000..8b8e38d --- /dev/null +++ b/translations/it.po @@ -0,0 +1,807 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-04 10:12+0000\n" +"PO-Revision-Date: 2016-11-04 11:28+0000\n" +"Last-Translator: Luca \n" +"Language-Team: Italian \n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 2.4\n" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonGC.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonGC.Text" +msgid "Run GC" +msgstr "Esegui GC" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonRefresh.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonRefresh.Text" +msgid "Refresh" +msgstr "Aggiorna" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonClose.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonClose.Text" +msgid "Close" +msgstr "Chiudi" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonLog.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonLog.Text" +msgid "Log" +msgstr "Log" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\$this.Text" +msgid "Debug" +msgstr "Debug" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugSupportSettings\labelLogLevel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugSupportSettings\\labelLogLevel.Text" +msgid "Log level:" +msgstr "Livello di log:" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugSupportSettings\buttonShowLog.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugSupportSettings\\buttonShowLog.Text" +msgid "Open log file location" +msgstr "Apri percorso file di log" + +#: AcaciaZPushPlugin\Features\FreeBusy\FreeBusySettings\checkGABLookup.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\FreeBusy\\FreeBusySettings\\checkGABLookup.Text" +msgid "Look up contacts in Global Address Book" +msgstr "Cercare contatti nella Global Address Book" + +#: AcaciaZPushPlugin\Features\FreeBusy\FreeBusySettings\labelUseAccount.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\FreeBusy\\FreeBusySettings\\labelUseAccount.Text" +msgid "Use account: " +msgstr "Utilizza l\'account: " + +#: AcaciaZPushPlugin\Features\GAB\GABSettings\buttonGABResync.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\GAB\\GABSettings\\buttonGABResync.Text" +msgid "Resynchronise Global Address Books" +msgstr "Sincronizza Global Address Book" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\chkEnable.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\chkEnable.Text" +msgid "Enable out-of-office auto-responding" +msgstr "Abilita il risponditore automatico Fuori Sede" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\radioNoTime.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\radioNoTime.Text" +msgid "until further notice" +msgstr "fino a nuovo avviso" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\radioTime.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\radioTime.Text" +msgid "from" +msgstr "da" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\timeFrom.CustomFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\timeFrom.CustomFormat" +msgid "HH:mm" +msgstr "HH:mm" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\labelTill.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\labelTill.Text" +msgid "until" +msgstr "finché" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\timeTill.CustomFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\timeTill.CustomFormat" +msgid "HH:mm" +msgstr "HH:mm" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\labelBody.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\labelBody.Text" +msgid "AutoReply only once to each sender with the following text:" +msgstr "Rispondi una sola volta a ciascun mittente con il testo seguente:" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\btnCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\btnCancel.Text" +msgid "Cancel" +msgstr "Annulla" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\btnSave.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\btnSave.Text" +msgid "Save" +msgstr "Salva" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\$this.Text" +msgid "Out of Office Assistant for {0}" +msgstr "Assistente Fuori Sede di {0}" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\labelIntro.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\labelIntro.Text" +msgid "Please select any folders you wish to close and click \"Close\"" +msgstr "Selezionare le cartelle da chiudere e cliccare su \"Chiudi\"" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\buttonRemove.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\buttonRemove.Text" +msgid "Close" +msgstr "Chiudi" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\buttonCancel.Text" +msgid "Done" +msgstr "Fatto" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\labelNoFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\labelNoFolders.Text" +msgid "You currently have no shared folders open" +msgstr "Nessuna cartella condivisa aperta" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\label1.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\label1.Text" +msgid "Folders are being loaded" +msgstr "Le cartelle sono in fase di caricamento" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\$this.Text" +msgid "Manage Shared Folders - {0}" +msgstr "Gestisci le cartelle condivise - {0}" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\radioPublicFolder.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\radioPublicFolder.Text" +msgid "Open public folder" +msgstr "Apri cartella pubblica" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\radioUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\radioUser.Text" +msgid "Open folder from user:" +msgstr "Apri cartella da utente:" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonUpdateFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonUpdateFolders.Text" +msgid "Update" +msgstr "Modifica" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelName.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelName.Text" +msgid "Name:" +msgstr "Nome:" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelWarningRecursive.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelWarningRecursive.Text" +msgid "Please note that the subfolders of the selected folder will not be shared." +msgstr "Attenzione: le sottocartelle della cartella selezionata non saranno condivise." + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelNoUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelNoUser.Text" +msgid "Please select a user to see the available shared folders" +msgstr "Selezionare un utente per visualizzare le sue cartelle condivise" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelFoldersLoading.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelFoldersLoading.Text" +msgid "Folders are being loaded" +msgstr "Le cartelle sono in fase di caricamento" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelNoFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelNoFolders.Text" +msgid "No shared folders were found" +msgstr "Nessuna cartella condivisa trovata" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "Annulla" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonOpen.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonOpen.Text" +msgid "Open" +msgstr "Apri" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\$this.Text" +msgid "Add Shared Folder - {0}" +msgstr "Aggiungi cartella condivisa - {0}" + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Failed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Failed" +msgid "Unable to retrieve Out of Office settings. You can still enable or disable Out of Office, but applying the settings might fail." +msgstr "Impossibile reperire le impostazioni Fuori Sede. È ancora possibile abilitare o disabilitare il Fuori Sede, ma il salvataggio delle impostazioni potrebbe non andare a buon fine." + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Label" +msgid "Retrieving current Out of Office settings" +msgstr "Caricamento delle impostazioni Fuori Sede" + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Title" +msgid "Out of Office Assistant" +msgstr "Assistente Fuori Sede" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_DifferentState +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_DifferentState" +msgid "" +"Out of office has been enabled, but the server could not handle your full request.\n" +"\n" +msgstr "" +"Fuori Sede abilitato, ma il server non è stato in grado di gestire l\'intera richiesta\n" +"\n" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Disabled +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Disabled" +msgid "Out of Office has been disabled." +msgstr "Fuori Sede disabilitato." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_DisableFailed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_DisableFailed" +msgid "Unable to disable Out of Office." +msgstr "Impossibile disabilitare il Fuori Sede." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Enabled +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Enabled" +msgid "Out of Office has been enabled until further notice." +msgstr "Fuori Sede abilitato fino a nuovo avviso." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_EnabledTimeBased +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_EnabledTimeBased" +msgid "Out of Office has been enabled from {0} till {1}." +msgstr "Fuori Sede abilitato dal giorno {0} al giorno {1}." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_EnableFailed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_EnableFailed" +msgid "Unable to enable Out of Office." +msgstr "Impossibile abilitare il Fuori Sede." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Failed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Failed" +msgid "Unable to apply Out of Office settings" +msgstr "Impossibile applicare le impostazioni del Fuori Sede" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Label" +msgid "Applying Out of Office settings" +msgstr "Salvataggio impostazioni Fuori Sede" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Title" +msgid "Out of Office Assistant" +msgstr "Assistente Fuori Sede" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Label" +msgid "Debug" +msgstr "Debug" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Screentip" +msgid "Debug dialog" +msgstr "Finestra di debug" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Supertip" +msgid "Opens the debug dialog, which shows information on the Kopano Outlook Extension." +msgstr "Apre la finestra di debug, che mostra informazioni sulla Kopano Outlook Extension." + +#. The group label for the ribbon +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_GroupMain_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_GroupMain_Label" +msgid "Kopano" +msgstr "Kopano" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Label" +msgid "Out-of-Office" +msgstr "Fuori Sede" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Screentip" +msgid "Change Out-of-Office settings" +msgstr "Modifica le impostazioni Fuori Sede" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Supertip" +msgid "Opens a dialog which allows Out-of-Office settings to be viewed or modified." +msgstr "Apre una finestra da cui è possibile visualizzare o modificare le impostazioni Fuori Sede." + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Label" +msgid "Open shared folder" +msgstr "Apri cartelle condivise" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Screentip" +msgid "Open another user\'s shared folders" +msgstr "Apre le cartelle condivise da altri utenti" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Supertip" +msgid "Open another user\'s shared folders" +msgstr "Apre le cartelle condivise da altri utenti" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Label" +msgid "Settings" +msgstr "Impostazioni" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Screentip" +msgid "Settings dialog" +msgstr "Finestra delle impostazioni" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Supertip" +msgid "Opens the settings dialog, which allows configuration of the plugin and access to support functions." +msgstr "Apre la finestra delle impostazioni, da cui è possibile configurare il plugin e accedere alle funzionalità di supporto." + +#: AcaciaZPushPlugin\Properties\Resources\OOFStartup_Message +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFStartup_Message" +msgid "Out of Office is currently enabled on account \'{0}\'. Would you like to change the settings?" +msgstr "Il Fuori Sede è attualmente abilitato per l\'account \'{0}\'. Si desidera disabilitarlo?" + +#: AcaciaZPushPlugin\Properties\Resources\OOFStartup_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFStartup_Title" +msgid "Out of Office Assistant" +msgstr "Assistente Fuori Sede" + +#: AcaciaZPushPlugin\Properties\Resources\GABEvent_Body +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GABEvent_Body" +msgid "Modifications to the Global Address Book are not allowed. Please contact your administrator if you think changes are required." +msgstr "Non è permesso modificare la Global Address Book. Per qualsiasi modifica contattare il proprio amministratore." + +#: AcaciaZPushPlugin\Properties\Resources\GABEvent_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GABEvent_Title" +msgid "Global Address Book" +msgstr "Global Address Book" + +#: AcaciaZPushPlugin\Properties\Resources\GAB_FolderFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GAB_FolderFormat" +msgid "Address Book for {0}" +msgstr "Rubrica di {0}" + +#: AcaciaZPushPlugin\Properties\Resources\LocalStore_DisplayName +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\LocalStore_DisplayName" +msgid "Kopano Folders" +msgstr "Cartelle Kopano" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_DebugSupport +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_DebugSupport" +msgid "Support" +msgstr "Supporto" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_FreeBusy +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_FreeBusy" +msgid "Free/Busy" +msgstr "Free/Busy" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_GAB +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_GAB" +msgid "Global Address Book" +msgstr "Global Address Book" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_Notes +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_Notes" +msgid "Notes" +msgstr "Note" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_OutOfOffice +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_OutOfOffice" +msgid "Out of office" +msgstr "Fuori Sede" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_ReplyFlags +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_ReplyFlags" +msgid "Reply flags" +msgstr "Flag di risposta" + +#: AcaciaZPushPlugin\Properties\Resources\ThisAddIn_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\ThisAddIn_Title" +msgid "Kopano" +msgstr "Kopano" + +#: AcaciaZPushPlugin\Properties\Resources\SSLFailed_Body +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SSLFailed_Body" +msgid "There is an error with the security certificate for server {0}. Do you want to allow the connection anyway?" +msgstr "Errore con il certificato di sicurezza del server {0}. Connettersi ugualmente?" + +#: AcaciaZPushPlugin\Properties\Resources\SSLFailed_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SSLFailed_Title" +msgid "Certificate error" +msgstr "Errore di certificato" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Title" +msgid "Kopano" +msgstr "Kopano" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Label" +msgid "Opening shared folder" +msgstr "Apertura cartella condivisa" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Title" +msgid "Shared folders" +msgstr "Cartelle condivise" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Label" +msgid "Shared folders" +msgstr "Cartelle condivise" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Screentip" +msgid "Manage shared folders" +msgstr "Gestisci cartelle condivise" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Supertip" +msgid "Open the \"Manage Shared Folders\" dialog, which can be used to remove shared folders." +msgstr "Apre la finestra \"Gestisci cartelle condivise\", da cui è possibile rimuovere le cartelle condivise." + +#. {0} will be replaced with the folder name +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Confirm +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Confirm" +msgid "Close shared folder {0}?" +msgstr "Chiudere la cartella condivisa {0}?" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Label" +msgid "Closing shared folder" +msgstr "Chiusura della cartella condivisa" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Title" +msgid "Shared folders" +msgstr "Cartelle condivise" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Failure" +msgid "Unable to open the shared folder. Please ensure you have permission to open the shared folder." +msgstr "Impossibile aprire la cartella condivisa. Assicurarsi di avere i permessi necessari." + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Failure" +msgid "Unable to close the shared folder." +msgstr "Impossibile chiudere la cartella condivisa." + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Label" +msgid "WebApp" +msgstr "WebApp" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Screentip" +msgid "Open WebApp" +msgstr "Apri WebApp" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Supertip" +msgid "Open WebApp in the system default browser" +msgstr "Apre la WebApp nel browser di default del sistema operativo" + +#: AcaciaZPushPlugin\UI\ProgressDialog\labelMessage.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\labelMessage.Text" +msgid "labelMessage: SET FROM CODE, NO NEED TO TRANSLATE" +msgstr "" + +#: AcaciaZPushPlugin\UI\ProgressDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "Annulla" + +#: AcaciaZPushPlugin\UI\ProgressDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\$this.Text" +msgid "ProgressDialog: SET FROM CODE, NO NEED TO TRANSLATE" +msgstr "" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonApply.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonApply.Text" +msgid "Apply" +msgstr "Applica" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "Annulla" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonOK.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonOK.Text" +msgid "OK" +msgstr "OK" + +#: AcaciaZPushPlugin\UI\SettingsDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\$this.Text" +msgid "Kopano Settings" +msgstr "Impostazioni Kopano" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonApply.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonApply.Text" +msgid "Apply" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonClose.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonClose.Text" +msgid "Close" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\labelSelectUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\labelSelectUser.Text" +msgid "Open folders for user" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonOpenUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonOpenUser.Text" +msgid "Open" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\$this.Text" +msgid "Shared Folders - {0}" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Label" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Screentip" +msgid "Manage shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Supertip" +msgid "Open the \"Shared Folders\" dialog, which can be used to add or remove shared folders." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_PublicFolders +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_PublicFolders" +msgid "Public folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Loading +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Loading" +msgid "Retrieving shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Loading_Error +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Loading_Error" +msgid "There was an error retrieving shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_None +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_None" +msgid "No shared folders are available" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Failure" +msgid "Unable to retrieve shared folders. Please try again later." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Label" +msgid "Retrieving shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Unsaved_Changes +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Unsaved_Changes" +msgid "There are unsaved changes. Do you really want to to discard these?" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Setting_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Setting_Failure" +msgid "Unable to open the shared folder. Please ensure you have permission to open the shared folder." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Setting_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Setting_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelName.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelName.Text" +msgid "Share as" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelSendAs.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelSendAs.Text" +msgid "Send as owner" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelPermissions.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelPermissions.Text" +msgid "Permissions" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\labelPermissionsValue.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\labelPermissionsValue.Text" +msgid "Permissions" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Label" +msgid "Manage shared folder" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Screentip" +msgid "Manage this folder in the Shared Folders dialog" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Supertip" +msgid "Open the \"Shared Folders\" dialog for the currently selected folder." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Label" +msgid "Applying changes to shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Failure" +msgid "Unable to apply the changes to the shared folders. Please try again later." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_None +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_None" +msgid "None" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_Read +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_Read" +msgid "Read" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_Write +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_Write" +msgid "Write" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Success +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Success" +msgid "The changes to the shared folders have been applied successfully." +msgstr "" + diff --git a/translations/nl.po b/translations/nl.po new file mode 100644 index 0000000..d149f05 --- /dev/null +++ b/translations/nl.po @@ -0,0 +1,842 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: 2016-10-27 14:46+0000\n" +"Last-Translator: psimpson \n" +"Language-Team: Dutch \n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=iso-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 2.4\n" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonGC.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonGC.Text" +msgid "Run GC" +msgstr "GC uitvoeren" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonRefresh.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonRefresh.Text" +msgid "Refresh" +msgstr "Vernieuwen" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonClose.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonClose.Text" +msgid "Close" +msgstr "Sluiten" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\buttonLog.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\buttonLog.Text" +msgid "Log" +msgstr "Log" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugDialog\\$this.Text" +msgid "Debug" +msgstr "Debug" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugSupportSettings\labelLogLevel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugSupportSettings\\labelLogLevel.Text" +msgid "Log level:" +msgstr "Log level:" + +#: AcaciaZPushPlugin\Features\DebugSupport\DebugSupportSettings\buttonShowLog.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\DebugSupport\\DebugSupportSettings\\buttonShowLog.Text" +msgid "Open log file location" +msgstr "Open locatie van logfile" + +#: AcaciaZPushPlugin\Features\FreeBusy\FreeBusySettings\checkGABLookup.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\FreeBusy\\FreeBusySettings\\checkGABLookup.Text" +msgid "Look up contacts in Global Address Book" +msgstr "Contactpersonen opzoeken in het adresboek" + +#: AcaciaZPushPlugin\Features\FreeBusy\FreeBusySettings\labelUseAccount.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\FreeBusy\\FreeBusySettings\\labelUseAccount.Text" +msgid "Use account: " +msgstr "Gebruik account: " + +#: AcaciaZPushPlugin\Features\GAB\GABSettings\buttonGABResync.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\GAB\\GABSettings\\buttonGABResync.Text" +msgid "Resynchronise Global Address Books" +msgstr "Adresboek opnieuw synchroniseren" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\chkEnable.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\chkEnable.Text" +msgid "Enable out-of-office auto-responding" +msgstr "Automatische antwoorden aanzetten" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\radioNoTime.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\radioNoTime.Text" +msgid "until further notice" +msgstr "tot nader order" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\radioTime.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\radioTime.Text" +msgid "from" +msgstr "vanaf" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\timeFrom.CustomFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\timeFrom.CustomFormat" +msgid "HH:mm" +msgstr "HH:mm" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\labelTill.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\labelTill.Text" +msgid "until" +msgstr "tot" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\timeTill.CustomFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\timeTill.CustomFormat" +msgid "HH:mm" +msgstr "HH:mm" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\labelBody.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\labelBody.Text" +msgid "AutoReply only once to each sender with the following text:" +msgstr "Antwoord automatisch slechts eenmaal naar iedere afzender met de volgende tekst:" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\btnCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\btnCancel.Text" +msgid "Cancel" +msgstr "Annuleren" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\btnSave.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\btnSave.Text" +msgid "Save" +msgstr "Opslaan" + +#: AcaciaZPushPlugin\Features\OutOfOffice\OutOfOfficeDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\OutOfOffice\\OutOfOfficeDialog\\$this.Text" +msgid "Out of Office Assistant for {0}" +msgstr "Automatische antwoorden voor {0}" + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Failed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Failed" +msgid "Unable to retrieve Out of Office settings. You can still enable or disable Out of Office, but applying the settings might fail." +msgstr "Instellingen voor automatische antwoorden konden niet worden opgehaald. U kunt de instellingen wijzigen, maar het opslaan werkt mogelijk niet." + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Label" +msgid "Retrieving current Out of Office settings" +msgstr "Instellingen voor automatische antwoorden worden opgehaald" + +#: AcaciaZPushPlugin\Properties\Resources\OOFGet_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFGet_Title" +msgid "Out of Office Assistant" +msgstr "Automatische antwoorden" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_DifferentState +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_DifferentState" +msgid "" +"Out of office has been enabled, but the server could not handle your full request.\n" +"\n" +msgstr "" +"Automatische antwoorden zijn ingeschakeld, maar de server ondersteunt automatische antwoorden niet volledig.\n" +"\n" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Disabled +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Disabled" +msgid "Out of Office has been disabled." +msgstr "Automatische antwoorden zijn uitgeschakeld." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_DisableFailed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_DisableFailed" +msgid "Unable to disable Out of Office." +msgstr "Automatische antwoorden konden niet worden uitgeschakeld." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Enabled +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Enabled" +msgid "Out of Office has been enabled until further notice." +msgstr "Automatische antwoorden zijn ingesteld tot nader order." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_EnabledTimeBased +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_EnabledTimeBased" +msgid "Out of Office has been enabled from {0} till {1}." +msgstr "Automatische antwoorden zijn ingesteld van {0} tot {1}." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_EnableFailed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_EnableFailed" +msgid "Unable to enable Out of Office." +msgstr "Automatische antwoorden konden niet worden ingeschakeld." + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Failed +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Failed" +msgid "Unable to apply Out of Office settings" +msgstr "De instellingen voor automatische antwoorden konden niet worden gewijzigd" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Label" +msgid "Applying Out of Office settings" +msgstr "Instellingen voor automatische antwoorden worden gewijzigd" + +#: AcaciaZPushPlugin\Properties\Resources\OOFSet_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFSet_Title" +msgid "Out of Office Assistant" +msgstr "Automatische antwoorden" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Label" +msgid "Debug" +msgstr "Debug" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Screentip" +msgid "Debug dialog" +msgstr "Debugdialoog" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Debug_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Debug_Supertip" +msgid "Opens the debug dialog, which shows information on the Kopano Outlook Extension." +msgstr "Opent het debug dialog, waarin informatie over de Kopano Outlook Extension beschikbaar is." + +#. The group label for the ribbon +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_GroupMain_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_GroupMain_Label" +msgid "Kopano" +msgstr "Kopano" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Label" +msgid "Out-of-Office" +msgstr "Automatische antwoorden" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Screentip" +msgid "Change Out-of-Office settings" +msgstr "Instellingen voor automatische antwoorden" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OOF_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OOF_Supertip" +msgid "Opens a dialog which allows Out-of-Office settings to be viewed or modified." +msgstr "Opent het dialoog waarin automatische antwoorden kunnen worden ingesteld of uitgeschakeld." + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OpenSharedFolders_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OpenSharedFolders_Label" +msgid "Open shared folders" +msgstr "Gedeelde mappen openen" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OpenSharedFolders_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OpenSharedFolders_Screentip" +msgid "Open shared folders - Screentip" +msgstr "Gedeelde mappen openenen" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_OpenSharedFolders_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_OpenSharedFolders_Supertip" +msgid "Open shared folders - Supertip" +msgstr "Gedeelde mappen openen" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Label" +msgid "Settings" +msgstr "Instellingen" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Screentip" +msgid "Settings dialog" +msgstr "Instellingendialoog" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Settings_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Settings_Supertip" +msgid "Opens the settings dialog, which allows configuration of the plugin and access to support functions." +msgstr "Opent het instellingendialoog, waarin de configuratie van de Kopano Outlook Extension kan worden aangepast." + +#: AcaciaZPushPlugin\Properties\Resources\OOFStartup_Message +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFStartup_Message" +msgid "Out of Office is currently enabled on account \'{0}\'. Would you like to change the settings?" +msgstr "Automatische antwoorden zijn ingesteld voor account \'{0}\'. Wilt U deze instellingen wijzigen?" + +#: AcaciaZPushPlugin\Properties\Resources\OOFStartup_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\OOFStartup_Title" +msgid "Out of Office Assistant" +msgstr "Automatische antwoorden" + +#: AcaciaZPushPlugin\Properties\Resources\GABEvent_Body +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GABEvent_Body" +msgid "Modifications to the Global Address Book are not allowed. Please contact your administrator if you think changes are required." +msgstr "Het adresboek kan niet worden gewijzigd. Neem contact op met Uw beheerder om wijzigingen door te voeren." + +#: AcaciaZPushPlugin\Properties\Resources\GABEvent_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GABEvent_Title" +msgid "Global Address Book" +msgstr "Adresboek" + +#: AcaciaZPushPlugin\Properties\Resources\GAB_FolderFormat +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\GAB_FolderFormat" +msgid "Address Book for {0}" +msgstr "Adresboek voor {0}" + +#: AcaciaZPushPlugin\Properties\Resources\LocalStore_DisplayName +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\LocalStore_DisplayName" +msgid "Kopano Folders" +msgstr "Kopano Mappen" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_DebugSupport +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_DebugSupport" +msgid "Support" +msgstr "Ondersteuning" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_FreeBusy +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_FreeBusy" +msgid "Free/Busy" +msgstr "Beschikbaarheidsinfo" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_GAB +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_GAB" +msgid "Global Address Book" +msgstr "Adresboek" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_Notes +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_Notes" +msgid "Notes" +msgstr "Notities" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_OutOfOffice +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_OutOfOffice" +msgid "Out of office" +msgstr "Automatische antwoorden" + +#: AcaciaZPushPlugin\Properties\Resources\Feature_ReplyFlags +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Feature_ReplyFlags" +msgid "Reply flags" +msgstr "Antwoorden" + +#: AcaciaZPushPlugin\Properties\Resources\ThisAddIn_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\ThisAddIn_Title" +msgid "Kopano" +msgstr "Kopano" + +#: AcaciaZPushPlugin\Properties\Resources\SSLFailed_Body +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SSLFailed_Body" +msgid "There is an error with the security certificate for server {0}. Do you want to allow the connection anyway?" +msgstr "Er is een fout in het beveilingscertificaat voor server {0}. Wilt U de verbinding toch maken?" + +#: AcaciaZPushPlugin\Properties\Resources\SSLFailed_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SSLFailed_Title" +msgid "Certificate error" +msgstr "Certificaatfout" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_Title" +msgid "Kopano" +msgstr "Kopano" + +#: AcaciaZPushPlugin\UI\ProgressDialog\labelMessage.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\labelMessage.Text" +msgid "labelMessage: SET FROM CODE, NO NEED TO TRANSLATE" +msgstr "labelMessage" + +#: AcaciaZPushPlugin\UI\ProgressDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "Annuleren" + +#: AcaciaZPushPlugin\UI\ProgressDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\ProgressDialog\\$this.Text" +msgid "ProgressDialog: SET FROM CODE, NO NEED TO TRANSLATE" +msgstr "ProgressDialog" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonApply.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonApply.Text" +msgid "Apply" +msgstr "Toepassen" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "Annuleren" + +#: AcaciaZPushPlugin\UI\SettingsDialog\buttonOK.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\buttonOK.Text" +msgid "OK" +msgstr "OK" + +#: AcaciaZPushPlugin\UI\SettingsDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\UI\\SettingsDialog\\$this.Text" +msgid "Kopano Settings" +msgstr "Kopano Instellingen" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\labelIntro.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\labelIntro.Text" +msgid "Please select any folders you wish to close and click \"Close\"" +msgstr "Selecteer de map die U wilt sluiten en klik op \"Sluit\"" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\buttonRemove.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\buttonRemove.Text" +msgid "Close" +msgstr "Sluit" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\buttonCancel.Text" +msgid "Done" +msgstr "Klaar" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\labelNoFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\labelNoFolders.Text" +msgid "You currently have no shared folders open" +msgstr "U heeft momenteel geen gedeelde mappen geopend" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\label1.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\label1.Text" +msgid "Folders are being loaded" +msgstr "Mapppen worden opgevraagd" + +#: AcaciaZPushPlugin\Features\SharedFolders\ManageSharedFoldersDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\ManageSharedFoldersDialog\\$this.Text" +msgid "Manage Shared Folders - {0}" +msgstr "Beheer Gedeelde Mappen - {0}" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelUser.Text" +msgid "User:" +msgstr "Gebruiker:" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonUpdateFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonUpdateFolders.Text" +msgid "Update" +msgstr "Bijwerken" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelName.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelName.Text" +msgid "Name:" +msgstr "Naam:" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\checkReadOnly.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\checkReadOnly.Text" +msgid "Read only" +msgstr "Alleen lezen" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelNoUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelNoUser.Text" +msgid "Please select a user to see the available shared folders" +msgstr "Selecteer een gebruiker om de beschikbare gedeelde mappen te bekijken" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\label1.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\label1.Text" +msgid "Folders are being loaded" +msgstr "Mappen worden opgevraagd" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelNoFolders.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelNoFolders.Text" +msgid "No shared folders were found" +msgstr "Geen gedeelde mappen gevonden" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "Annuleren" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\buttonOpen.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\buttonOpen.Text" +msgid "Open" +msgstr "Openen" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\$this.Text" +msgid "Add Shared Folder - {0}" +msgstr "Gedeelde Map Openen - {0}" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Label" +msgid "Open shared folder" +msgstr "Gedeelde map openen" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Screentip" +msgid "Open another user\'s shared folders" +msgstr "Open een gedeelde map van een andere gebruiker" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_AddSharedFolder_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_AddSharedFolder_Supertip" +msgid "Open another user\'s shared folders" +msgstr "Open een gedeelde map van een andere gebruiker" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Label" +msgid "Opening shared folder" +msgstr "Gedeelde map wordt geopend" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Title" +msgid "Shared folders" +msgstr "Gedeelde mappen" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Label" +msgid "Shared folders" +msgstr "Gedeelde mappen" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Screentip" +msgid "Manage shared folders" +msgstr "Beheer gedeelde mappen" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_ManageSharedFolders_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_ManageSharedFolders_Supertip" +msgid "Open the \"Manage Shared Folders\" dialog, which can be used to remove shared folders." +msgstr "Opent het dialoog \"Beheer Gedeelde Mappen\", waar gedeelde mappen kunnen worden gesloten." + +#. {0} will be replaced with the folder name +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Confirm +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Confirm" +msgid "Close shared folder {0}?" +msgstr "Gedeelde map {0} sluiten?" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Label" +msgid "Closing shared folder" +msgstr "Gedeelde map wordt gesloten" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Title" +msgid "Shared folders" +msgstr "Gedeelde mappen" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Adding_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Adding_Failure" +msgid "Unable to open the shared folder. Please ensure you have permission to open the shared folder." +msgstr "De gedeelde map kon niet worden geopend. Controleer of U rechten heeft om de gedeelde map te openen." + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Closing_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Closing_Failure" +msgid "Unable to close the shared folder." +msgstr "De gedeelde map kon niet worden gesloten." + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\radioPublicFolder.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\radioPublicFolder.Text" +msgid "Open public folder" +msgstr "Open publieke map" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\radioUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\radioUser.Text" +msgid "Open folder from user:" +msgstr "Open map van gebruiker:" + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelWarningRecursive.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelWarningRecursive.Text" +msgid "Please note that the subfolders of the selected folder will not be shared." +msgstr "Let op: mappen onder de geselecteerde map zullen niet worden gedeeld." + +#: AcaciaZPushPlugin\Features\SharedFolders\AddSharedFolderDialog\labelFoldersLoading.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders\\AddSharedFolderDialog\\labelFoldersLoading.Text" +msgid "Folders are being loaded" +msgstr "De mappen worden geladen" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Label" +msgid "WebApp" +msgstr "WebApp" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Screentip" +msgid "Open WebApp" +msgstr "Open WebApp" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_WebApp_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_WebApp_Supertip" +msgid "Open WebApp in the system default browser" +msgstr "Opent WebApp in de standaard webbrowser" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonApply.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonApply.Text" +msgid "Apply" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonCancel.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonCancel.Text" +msgid "Cancel" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonClose.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonClose.Text" +msgid "Close" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\labelSelectUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\labelSelectUser.Text" +msgid "Open folders for user" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\buttonOpenUser.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\buttonOpenUser.Text" +msgid "Open" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\$this.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\$this.Text" +msgid "Shared Folders - {0}" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Label" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Screentip" +msgid "Manage shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Supertip" +msgid "Open the \"Shared Folders\" dialog, which can be used to add or remove shared folders." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_PublicFolders +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_PublicFolders" +msgid "Public folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Loading +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Loading" +msgid "Retrieving shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Loading_Error +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Loading_Error" +msgid "There was an error retrieving shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_None +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_None" +msgid "No shared folders are available" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Failure" +msgid "Unable to retrieve shared folders. Please try again later." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Label" +msgid "Retrieving shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Fetching_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Fetching_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Unsaved_Changes +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Unsaved_Changes" +msgid "There are unsaved changes. Do you really want to to discard these?" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Setting_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Setting_Failure" +msgid "Unable to open the shared folder. Please ensure you have permission to open the shared folder." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Setting_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Setting_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelName.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelName.Text" +msgid "Share as" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelSendAs.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelSendAs.Text" +msgid "Send as owner" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\_labelPermissions.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\_labelPermissions.Text" +msgid "Permissions" +msgstr "" + +#: AcaciaZPushPlugin\Features\SharedFolders2\SharedFoldersDialog\labelPermissionsValue.Text +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Features\\SharedFolders2\\SharedFoldersDialog\\labelPermissionsValue.Text" +msgid "Permissions" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Label" +msgid "Manage shared folder" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Screentip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Screentip" +msgid "Manage this folder in the Shared Folders dialog" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\Ribbon_SharedFolders_Context_Supertip +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\Ribbon_SharedFolders_Context_Supertip" +msgid "Open the \"Shared Folders\" dialog for the currently selected folder." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Label +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Label" +msgid "Applying changes to shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Failure +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Failure" +msgid "Unable to apply the changes to the shared folders. Please try again later." +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Title +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Title" +msgid "Shared folders" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_None +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_None" +msgid "None" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_Read +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_Read" +msgid "Read" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Permission_Write +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Permission_Write" +msgid "Write" +msgstr "" + +#: AcaciaZPushPlugin\Properties\Resources\SharedFolders_Applying_Success +#, csharp-format +msgctxt "AcaciaZPushPlugin\\Properties\\Resources\\SharedFolders_Applying_Success" +msgid "The changes to the shared folders have been applied successfully." +msgstr "" +