From 20af086273dda804a1c4864a994c9df746cfd41f Mon Sep 17 00:00:00 2001 From: Terry Yiu Date: Tue, 27 May 2025 00:26:21 -0400 Subject: [PATCH 01/16] Add NIP-05 favicon to profile names and NIP-05 web of trust feed Changelog-Added: Added NIP-05 favicon to profile names and NIP-05 web of trust feed Signed-off-by: Terry Yiu --- damus.xcodeproj/project.pbxproj | 77 ++++++++++++ .../xcshareddata/swiftpm/Package.resolved | 20 +++- damus/Components/NIP05Badge.swift | 61 ++++++---- damus/ContentView.swift | 3 +- damus/Models/Contacts.swift | 4 + damus/Models/DamusState.swift | 12 +- damus/Models/NIP05DomainEventsModel.swift | 97 +++++++++++++++ damus/Nostr/Profiles.swift | 1 + damus/TestData.swift | 3 +- damus/Util/Extensions/KFOptionSetter+.swift | 27 +++-- damus/Util/FaviconCache.swift | 41 +++++++ damus/Util/Router.swift | 13 ++ damus/Views/NIP05DomainPubkeysView.swift | 51 ++++++++ .../Views/NIP05DomainTimelineHeaderView.swift | 111 ++++++++++++++++++ damus/Views/NIP05DomainTimelineView.swift | 64 ++++++++++ damus/Views/Profile/ProfileName.swift | 36 +++++- damus/en-US.lproj/Localizable.stringsdict | 16 +++ damusTests/Mocking/MockDamusState.swift | 3 +- .../NIP05DomainTimelineHeaderViewTests.swift | 39 ++++++ 19 files changed, 632 insertions(+), 47 deletions(-) create mode 100644 damus/Models/NIP05DomainEventsModel.swift create mode 100644 damus/Util/FaviconCache.swift create mode 100644 damus/Views/NIP05DomainPubkeysView.swift create mode 100644 damus/Views/NIP05DomainTimelineHeaderView.swift create mode 100644 damus/Views/NIP05DomainTimelineView.swift create mode 100644 damusTests/NIP05DomainTimelineHeaderViewTests.swift diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj index 3e3bb3ad..209478ea 100644 --- a/damus.xcodeproj/project.pbxproj +++ b/damus.xcodeproj/project.pbxproj @@ -14,6 +14,12 @@ 31D2E847295218AF006D67F8 /* Shimmer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D2E846295218AF006D67F8 /* Shimmer.swift */; }; 3A0A30BB2C21397A00F8C9BC /* EmojiPicker in Frameworks */ = {isa = PBXBuildFile; productRef = 3A0A30BA2C21397A00F8C9BC /* EmojiPicker */; }; 3A23838E2A297DD200E5AA2E /* ZapButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A23838D2A297DD200E5AA2E /* ZapButtonModel.swift */; }; + 3A2BAC5A2DD7E4C400EBB4CC /* NIP05DomainTimelineHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A2BAC592DD7E4C400EBB4CC /* NIP05DomainTimelineHeaderView.swift */; }; + 3A2BAC5B2DD7E4C400EBB4CC /* NIP05DomainTimelineHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A2BAC592DD7E4C400EBB4CC /* NIP05DomainTimelineHeaderView.swift */; }; + 3A2BAC5C2DD7E4C400EBB4CC /* NIP05DomainTimelineHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A2BAC592DD7E4C400EBB4CC /* NIP05DomainTimelineHeaderView.swift */; }; + 3A2BAC5E2DE02E8600EBB4CC /* NIP05DomainPubkeysView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A2BAC5D2DE02E8600EBB4CC /* NIP05DomainPubkeysView.swift */; }; + 3A2BAC5F2DE02E8600EBB4CC /* NIP05DomainPubkeysView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A2BAC5D2DE02E8600EBB4CC /* NIP05DomainPubkeysView.swift */; }; + 3A2BAC602DE02E8600EBB4CC /* NIP05DomainPubkeysView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A2BAC5D2DE02E8600EBB4CC /* NIP05DomainPubkeysView.swift */; }; 3A3040ED29A5CB86008A0F29 /* ReplyDescriptionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A3040EC29A5CB86008A0F29 /* ReplyDescriptionTests.swift */; }; 3A3040F129A8FF97008A0F29 /* LocalizationUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A3040F029A8FF97008A0F29 /* LocalizationUtil.swift */; }; 3A3040F329A91366008A0F29 /* ProfileViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A3040F229A91366008A0F29 /* ProfileViewTests.swift */; }; @@ -22,6 +28,10 @@ 3A4647CF2A413ADC00386AD8 /* CondensedProfilePicturesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A4647CE2A413ADC00386AD8 /* CondensedProfilePicturesView.swift */; }; 3A48E7B029DFBE9D006E787E /* MutedThreadsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A48E7AF29DFBE9D006E787E /* MutedThreadsManager.swift */; }; 3A8CC6CC2A2CFEF900940F5F /* StringUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A8CC6CB2A2CFEF900940F5F /* StringUtil.swift */; }; + 3A92C0FE2DE16E9800CEEBAC /* FaviconCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A92C0FD2DE16E9800CEEBAC /* FaviconCache.swift */; }; + 3A92C0FF2DE16E9800CEEBAC /* FaviconCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A92C0FD2DE16E9800CEEBAC /* FaviconCache.swift */; }; + 3A92C1002DE16E9800CEEBAC /* FaviconCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A92C0FD2DE16E9800CEEBAC /* FaviconCache.swift */; }; + 3A92C1022DE17ACA00CEEBAC /* NIP05DomainTimelineHeaderViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A92C1012DE17ACA00CEEBAC /* NIP05DomainTimelineHeaderViewTests.swift */; }; 3A96E3FE2D6BCE3800AE1630 /* RepostedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A96E3FD2D6BCE3800AE1630 /* RepostedTests.swift */; }; 3AA247FF297E3D900090C62D /* RepostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA247FE297E3D900090C62D /* RepostsView.swift */; }; 3AA24802297E3DC20090C62D /* RepostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA24801297E3DC20090C62D /* RepostView.swift */; }; @@ -33,6 +43,15 @@ 3ACB685C297633BC00C46468 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3ACB685A297633BC00C46468 /* InfoPlist.strings */; }; 3ACB685F297633BC00C46468 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3ACB685D297633BC00C46468 /* Localizable.strings */; }; 3ACBCB78295FE5C70037388A /* TimeAgoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */; }; + 3ACF94382DA9A52F00971A4E /* FaviconFinder in Frameworks */ = {isa = PBXBuildFile; productRef = 3ACF94372DA9A52F00971A4E /* FaviconFinder */; }; + 3ACF943E2DA9B10800971A4E /* FaviconFinder in Frameworks */ = {isa = PBXBuildFile; productRef = 3ACF943D2DA9B10800971A4E /* FaviconFinder */; }; + 3ACF94402DA9B11200971A4E /* FaviconFinder in Frameworks */ = {isa = PBXBuildFile; productRef = 3ACF943F2DA9B11200971A4E /* FaviconFinder */; }; + 3ACF94422DA9FCAB00971A4E /* NIP05DomainTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACF94412DA9FCAB00971A4E /* NIP05DomainTimelineView.swift */; }; + 3ACF94432DA9FCAB00971A4E /* NIP05DomainTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACF94412DA9FCAB00971A4E /* NIP05DomainTimelineView.swift */; }; + 3ACF94442DA9FCAB00971A4E /* NIP05DomainTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACF94412DA9FCAB00971A4E /* NIP05DomainTimelineView.swift */; }; + 3ACF94462DAA006500971A4E /* NIP05DomainEventsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACF94452DAA006500971A4E /* NIP05DomainEventsModel.swift */; }; + 3ACF94472DAA006500971A4E /* NIP05DomainEventsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACF94452DAA006500971A4E /* NIP05DomainEventsModel.swift */; }; + 3ACF94482DAA006500971A4E /* NIP05DomainEventsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACF94452DAA006500971A4E /* NIP05DomainEventsModel.swift */; }; 3AE45AF6297BB2E700C1D842 /* LibreTranslateServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE45AF5297BB2E700C1D842 /* LibreTranslateServer.swift */; }; 3CCD1E6A2A874C4E0099A953 /* Nip98HTTPAuth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CCD1E692A874C4E0099A953 /* Nip98HTTPAuth.swift */; }; 4C011B5E2BD0A56A002F2F9B /* ChatEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C011B5C2BD0A56A002F2F9B /* ChatEventView.swift */; }; @@ -1808,6 +1827,8 @@ 3A25EF142992DA5D008ABE69 /* el-GR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "el-GR"; path = "el-GR.lproj/Localizable.strings"; sourceTree = ""; }; 3A25EF152992DA5D008ABE69 /* el-GR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "el-GR"; path = "el-GR.lproj/Localizable.stringsdict"; sourceTree = ""; }; 3A2B8B0A296A8982009CC16D /* en-US */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "en-US"; path = "en-US.lproj/Localizable.stringsdict"; sourceTree = ""; }; + 3A2BAC592DD7E4C400EBB4CC /* NIP05DomainTimelineHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NIP05DomainTimelineHeaderView.swift; sourceTree = ""; }; + 3A2BAC5D2DE02E8600EBB4CC /* NIP05DomainPubkeysView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NIP05DomainPubkeysView.swift; sourceTree = ""; }; 3A3040EC29A5CB86008A0F29 /* ReplyDescriptionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplyDescriptionTests.swift; sourceTree = ""; }; 3A3040F029A8FF97008A0F29 /* LocalizationUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationUtil.swift; sourceTree = ""; }; 3A3040F229A91366008A0F29 /* ProfileViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewTests.swift; sourceTree = ""; }; @@ -1853,6 +1874,8 @@ 3A929C20297F2CF80090925E /* it-IT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "it-IT"; path = "it-IT.lproj/InfoPlist.strings"; sourceTree = ""; }; 3A929C21297F2CF80090925E /* it-IT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "it-IT"; path = "it-IT.lproj/Localizable.strings"; sourceTree = ""; }; 3A929C22297F2CF80090925E /* it-IT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "it-IT"; path = "it-IT.lproj/Localizable.stringsdict"; sourceTree = ""; }; + 3A92C0FD2DE16E9800CEEBAC /* FaviconCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconCache.swift; sourceTree = ""; }; + 3A92C1012DE17ACA00CEEBAC /* NIP05DomainTimelineHeaderViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NIP05DomainTimelineHeaderViewTests.swift; sourceTree = ""; }; 3A93342929884CA600D6A8F3 /* pl-PL */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pl-PL"; path = "pl-PL.lproj/InfoPlist.strings"; sourceTree = ""; }; 3A93342A29884CA600D6A8F3 /* pl-PL */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pl-PL"; path = "pl-PL.lproj/Localizable.strings"; sourceTree = ""; }; 3A93342B29884CA600D6A8F3 /* pl-PL */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "pl-PL"; path = "pl-PL.lproj/Localizable.stringsdict"; sourceTree = ""; }; @@ -1891,6 +1914,8 @@ 3ACB685B297633BC00C46468 /* es-419 */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-419"; path = "es-419.lproj/InfoPlist.strings"; sourceTree = ""; }; 3ACB685E297633BC00C46468 /* es-419 */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-419"; path = "es-419.lproj/Localizable.strings"; sourceTree = ""; }; 3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeAgoTests.swift; sourceTree = ""; }; + 3ACF94412DA9FCAB00971A4E /* NIP05DomainTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NIP05DomainTimelineView.swift; sourceTree = ""; }; + 3ACF94452DAA006500971A4E /* NIP05DomainEventsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NIP05DomainEventsModel.swift; sourceTree = ""; }; 3AD14EB529C40F38009D2D9C /* hu-HU */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "hu-HU"; path = "hu-HU.lproj/Localizable.stringsdict"; sourceTree = ""; }; 3AD14EB629C40F38009D2D9C /* hu-HU */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "hu-HU"; path = "hu-HU.lproj/InfoPlist.strings"; sourceTree = ""; }; 3AD14EB729C40F38009D2D9C /* hu-HU */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "hu-HU"; path = "hu-HU.lproj/Localizable.strings"; sourceTree = ""; }; @@ -2617,6 +2642,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 3ACF94382DA9A52F00971A4E /* FaviconFinder in Frameworks */, 4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */, D7DB1FE42D5A9AC900CF06DA /* CryptoSwift in Frameworks */, 3A0A30BB2C21397A00F8C9BC /* EmojiPicker in Frameworks */, @@ -2648,6 +2674,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 3ACF94402DA9B11200971A4E /* FaviconFinder in Frameworks */, 82D6FC862CD9A4A600C925F4 /* MarkdownUI in Frameworks */, D7DB1FEC2D5A9F6500CF06DA /* CryptoSwift in Frameworks */, 82D6FC8A2CD9A54600C925F4 /* SwipeActions in Frameworks */, @@ -2664,6 +2691,7 @@ buildActionMask = 2147483647; files = ( D703D7AF2C670FB700A400EA /* MarkdownUI in Frameworks */, + 3ACF943E2DA9B10800971A4E /* FaviconFinder in Frameworks */, D73E5F9D2C6AA8E3007EB227 /* SwipeActions in Frameworks */, D7DB1FE82D5A9F5300CF06DA /* CryptoSwift in Frameworks */, D73E5F762C6A997E007EB227 /* EmojiPicker in Frameworks */, @@ -2841,6 +2869,7 @@ 5CC8529C2BD741CD0039FFC5 /* HighlightEvent.swift */, D773BC5E2C6D538500349F0A /* CommentItem.swift */, D767066E2C8BB3CE00F09726 /* URLHandler.swift */, + 3ACF94452DAA006500971A4E /* NIP05DomainEventsModel.swift */, ); path = Models; sourceTree = ""; @@ -3255,6 +3284,9 @@ D77BFA0A2AE3051200621634 /* ProfileActionSheetView.swift */, D71AD8FC2CEC176A002E2C3C /* AppAccessibilityIdentifiers.swift */, D74EA0922D2E77B9002290DD /* LoadableNostrEventView.swift */, + 3ACF94412DA9FCAB00971A4E /* NIP05DomainTimelineView.swift */, + 3A2BAC592DD7E4C400EBB4CC /* NIP05DomainTimelineHeaderView.swift */, + 3A2BAC5D2DE02E8600EBB4CC /* NIP05DomainPubkeysView.swift */, ); path = Views; sourceTree = ""; @@ -3377,6 +3409,7 @@ D74AAFCE2B155D8C006CF0F4 /* ZapDataModel.swift */, D74AAFD32B155ECB006CF0F4 /* Zaps+.swift */, D7D09AB42DADCA5600AB170D /* CoinosDeterministicAccountClient.swift */, + 3A92C0FD2DE16E9800CEEBAC /* FaviconCache.swift */, ); path = Util; sourceTree = ""; @@ -3772,6 +3805,7 @@ 4C2D34402BDAF1B300F9FB44 /* NIP10Tests.swift */, D72E12792BEEEED000F4F781 /* NostrFilterTests.swift */, 3A96E3FD2D6BCE3800AE1630 /* RepostedTests.swift */, + 3A92C1012DE17ACA00CEEBAC /* NIP05DomainTimelineHeaderViewTests.swift */, ); path = damusTests; sourceTree = ""; @@ -4173,6 +4207,7 @@ D70D90972CDED61800CD0534 /* CodeScanner */, D7C48C0A2D12DE0C00A3BACF /* SwiftyCrop */, D7DB1FE32D5A9AC900CF06DA /* CryptoSwift */, + 3ACF94372DA9A52F00971A4E /* FaviconFinder */, ); productName = damus; productReference = 4CE6DEE327F7A08100C66700 /* damus.app */; @@ -4240,6 +4275,7 @@ D7F360282CEBBE34009D34DA /* CodeScanner */, D7C48C0C2D12E34900A3BACF /* SwiftyCrop */, D7DB1FEB2D5A9F6500CF06DA /* CryptoSwift */, + 3ACF943F2DA9B11200971A4E /* FaviconFinder */, ); productName = "share extension"; productReference = 82D6FA972CD9820500C925F4 /* ShareExtension.appex */; @@ -4269,6 +4305,7 @@ D70D909B2CDED7B200CD0534 /* CodeScanner */, D7C48C0E2D12E35600A3BACF /* SwiftyCrop */, D7DB1FE72D5A9F5300CF06DA /* CryptoSwift */, + 3ACF943D2DA9B10800971A4E /* FaviconFinder */, ); productName = "highlighter action extension"; productReference = D703D7172C66E47100A400EA /* HighlighterActionExtension.appex */; @@ -4381,6 +4418,7 @@ D70D90962CDED61800CD0534 /* XCRemoteSwiftPackageReference "CodeScanner" */, D7C48C092D12DE0C00A3BACF /* XCRemoteSwiftPackageReference "SwiftyCrop" */, D7DB1FE22D5A9AC900CF06DA /* XCRemoteSwiftPackageReference "CryptoSwift" */, + 3ACF94362DA9A52F00971A4E /* XCRemoteSwiftPackageReference "FaviconFinder" */, ); productRefGroup = 4CE6DEE427F7A08100C66700 /* Products */; projectDirPath = ""; @@ -4523,6 +4561,7 @@ 4C3EA64428FF558100C48A62 /* sha256.c in Sources */, 5C8498032D5D150000F74FEB /* ZapExplainer.swift in Sources */, 504323A72A34915F006AE6DC /* RelayModel.swift in Sources */, + 3A2BAC5C2DD7E4C400EBB4CC /* NIP05DomainTimelineHeaderView.swift in Sources */, 4CF0ABF62985CD5500D66079 /* UserSearch.swift in Sources */, 4C32B9542A9AD44700DC3548 /* FlatBuffersUtils.swift in Sources */, D7EDED1C2B1178FE0018B19C /* NoteContent.swift in Sources */, @@ -4561,6 +4600,7 @@ 4CB55EF5295E679D007FD187 /* UserRelaysView.swift in Sources */, 4C363AA228296A7E006E126D /* SearchView.swift in Sources */, D798D2282B085CDA00234419 /* NdbNote+.swift in Sources */, + 3ACF94422DA9FCAB00971A4E /* NIP05DomainTimelineView.swift in Sources */, 4CC7AAED297F0B9E00430951 /* Highlight.swift in Sources */, 4C1253662A76D0FF0004F4B8 /* OnlyZapsNotify.swift in Sources */, 4CA927652A290F1A0098A105 /* TimeDot.swift in Sources */, @@ -4757,6 +4797,7 @@ 4C12535E2A76CA870004F4B8 /* SwitchedTimelineNotify.swift in Sources */, D74F430A2B23F0BE00425B75 /* DamusPurple.swift in Sources */, 9CA876E229A00CEA0003B9A3 /* AttachMediaUtility.swift in Sources */, + 3ACF94462DAA006500971A4E /* NIP05DomainEventsModel.swift in Sources */, D734B1452CCC19B1000B5C97 /* DamusFullScreenCover.swift in Sources */, 4C4E137D2A76D63600BDD832 /* UnmuteThreadNotify.swift in Sources */, D706C5B72D602A110027C627 /* QueueableNotify.swift in Sources */, @@ -4916,6 +4957,7 @@ 4CE4F0F229D4FCFA005914DB /* DebouncedOnChange.swift in Sources */, 4C32B9592A9AD44700DC3548 /* Table.swift in Sources */, 4C5D5C9D2A6B2CB40024563C /* AsciiCharacter.swift in Sources */, + 3A2BAC5E2DE02E8600EBB4CC /* NIP05DomainPubkeysView.swift in Sources */, 4CF0ABEC29844B4700D66079 /* AnyDecodable.swift in Sources */, 4C9146FE2A2A87C200DDEA40 /* nostrscript.c in Sources */, 4C5F9118283D88E40052CD1C /* FollowingModel.swift in Sources */, @@ -4963,6 +5005,7 @@ 4C32B95A2A9AD44700DC3548 /* Verifiable.swift in Sources */, 4C73C5142A4437C10062CAC0 /* ZapUserView.swift in Sources */, 501F8C802A0220E1001AFC1D /* KeychainStorage.swift in Sources */, + 3A92C0FE2DE16E9800CEEBAC /* FaviconCache.swift in Sources */, 4C1A9A1D29DDCF9B00516EAC /* NotificationSettingsView.swift in Sources */, 5CC868DD2AA29B3200FB22BA /* NeutralButtonStyle.swift in Sources */, 4C75EFB528049D790006080F /* Relay.swift in Sources */, @@ -5045,6 +5088,7 @@ 4CF0ABDC2981A19E00D66079 /* ListTests.swift in Sources */, 4C684A552A7E91FE005E6031 /* LargeEventTests.swift in Sources */, E02B54182B4DFADA0077FF42 /* Bech32ObjectTests.swift in Sources */, + 3A92C1022DE17ACA00CEEBAC /* NIP05DomainTimelineHeaderViewTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5130,6 +5174,7 @@ 82D6FAE72CD99F7900C925F4 /* LoginNotify.swift in Sources */, 82D6FAE82CD99F7900C925F4 /* LogoutNotify.swift in Sources */, D706C5B12D5D31C20027C627 /* AutoSaveIndicatorView.swift in Sources */, + 3ACF94482DAA006500971A4E /* NIP05DomainEventsModel.swift in Sources */, 82D6FAE92CD99F7900C925F4 /* NewMutesNotify.swift in Sources */, 82D6FAEA2CD99F7900C925F4 /* NewUnmutesNotify.swift in Sources */, 82D6FAEB2CD99F7900C925F4 /* Notify.swift in Sources */, @@ -5148,9 +5193,11 @@ 82D6FAF62CD99F7900C925F4 /* ZappingNotify.swift in Sources */, 82D6FAF72CD99F7900C925F4 /* MuteNotify.swift in Sources */, 82D6FAF82CD99F7900C925F4 /* RelaysChangedNotify.swift in Sources */, + 3A2BAC5B2DD7E4C400EBB4CC /* NIP05DomainTimelineHeaderView.swift in Sources */, 82D6FAF92CD99F7900C925F4 /* MuteThreadNotify.swift in Sources */, 82D6FAFA2CD99F7900C925F4 /* UnmuteThreadNotify.swift in Sources */, 82D6FAFB2CD99F7900C925F4 /* ReconnectRelaysNotify.swift in Sources */, + 3ACF94432DA9FCAB00971A4E /* NIP05DomainTimelineView.swift in Sources */, 82D6FAFC2CD99F7900C925F4 /* PurpleAccountUpdateNotify.swift in Sources */, 82D6FAFD2CD99F7900C925F4 /* IdType.swift in Sources */, 82D6FAFE2CD99F7900C925F4 /* Pubkey.swift in Sources */, @@ -5403,6 +5450,7 @@ 82D6FBED2CD99F7900C925F4 /* MediaView.swift in Sources */, 82D6FBEE2CD99F7900C925F4 /* PurpleViewPrimitives.swift in Sources */, 82D6FBEF2CD99F7900C925F4 /* MarketingContentView.swift in Sources */, + 3A2BAC602DE02E8600EBB4CC /* NIP05DomainPubkeysView.swift in Sources */, 82D6FBF02CD99F7900C925F4 /* LogoView.swift in Sources */, 82D6FBF12CD99F7900C925F4 /* IAPProductStateView.swift in Sources */, 82D6FBF22CD99F7900C925F4 /* PurpleBackdrop.swift in Sources */, @@ -5421,6 +5469,7 @@ 82D6FBFF2CD99F7900C925F4 /* NotificationItemView.swift in Sources */, 82D6FC002CD99F7900C925F4 /* ProfilePicturesView.swift in Sources */, 82D6FC012CD99F7900C925F4 /* DamusAppNotificationView.swift in Sources */, + 3A92C1002DE16E9800CEEBAC /* FaviconCache.swift in Sources */, 82D6FC022CD99F7900C925F4 /* InnerTimelineView.swift in Sources */, 82D6FC032CD99F7900C925F4 /* PostingTimelineView.swift in Sources */, 82D6FC042CD99F7900C925F4 /* ZapsView.swift in Sources */, @@ -5636,11 +5685,13 @@ D73E5E682C6A97F4007EB227 /* VectorMath.swift in Sources */, D73E5E692C6A97F4007EB227 /* RelayBootstrap.swift in Sources */, D73E5E6A2C6A97F4007EB227 /* RelayModel.swift in Sources */, + 3A2BAC5A2DD7E4C400EBB4CC /* NIP05DomainTimelineHeaderView.swift in Sources */, D73E5E6B2C6A97F4007EB227 /* AnyCodable.swift in Sources */, D73E5E6C2C6A97F4007EB227 /* AnyDecodable.swift in Sources */, D73E5E6D2C6A97F4007EB227 /* AnyEncodable.swift in Sources */, D73E5F782C6A9A5C007EB227 /* NdbNote+.swift in Sources */, D73E5E6E2C6A97F4007EB227 /* NIPURLBuilder.swift in Sources */, + 3ACF94472DAA006500971A4E /* NIP05DomainEventsModel.swift in Sources */, D73E5E6F2C6A97F4007EB227 /* TimeAgo.swift in Sources */, D73E5E702C6A97F4007EB227 /* Parser.swift in Sources */, D73E5E722C6A97F4007EB227 /* LinkView.swift in Sources */, @@ -5727,6 +5778,7 @@ D73E5EB92C6A97F4007EB227 /* RelayLog.swift in Sources */, D73E5EBA2C6A97F4007EB227 /* NostrFilter.swift in Sources */, D73E5EBB2C6A97F4007EB227 /* Nip98HTTPAuth.swift in Sources */, + 3A92C0FF2DE16E9800CEEBAC /* FaviconCache.swift in Sources */, D73E5EBC2C6A97F4007EB227 /* Relay.swift in Sources */, D73E5EBD2C6A97F4007EB227 /* NostrRequest.swift in Sources */, 5CB017222D2D985E00A9ED05 /* CoinosButton.swift in Sources */, @@ -5825,6 +5877,7 @@ D73E5F192C6A97F4007EB227 /* RelayToggle.swift in Sources */, D73E5F1A2C6A97F4007EB227 /* RelayStatusView.swift in Sources */, D73E5F1B2C6A97F4007EB227 /* RelayType.swift in Sources */, + 3A2BAC5F2DE02E8600EBB4CC /* NIP05DomainPubkeysView.swift in Sources */, D73E5F1C2C6A97F4007EB227 /* SignalView.swift in Sources */, D73E5F1D2C6A97F4007EB227 /* RelayPicView.swift in Sources */, D73E5F1E2C6A97F4007EB227 /* UserSearch.swift in Sources */, @@ -5957,6 +6010,7 @@ D73E5E1B2C6A9672007EB227 /* LikeCounter.swift in Sources */, D703D7A92C670E5A00A400EA /* refmap.c in Sources */, D703D77B2C670BF000A400EA /* TableVerifier.swift in Sources */, + 3ACF94442DA9FCAB00971A4E /* NIP05DomainTimelineView.swift in Sources */, D703D76D2C670B4500A400EA /* ZapDataModel.swift in Sources */, D703D79D2C670E0700A400EA /* node_id.c in Sources */, D703D79B2C670E0000A400EA /* bech32_util.c in Sources */, @@ -6939,6 +6993,14 @@ minimumVersion = 0.2.0; }; }; + 3ACF94362DA9A52F00971A4E /* XCRemoteSwiftPackageReference "FaviconFinder" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/will-lumley/FaviconFinder.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 5.1.4; + }; + }; 4C06670228FC7EC500038D2A /* XCRemoteSwiftPackageReference "Kingfisher" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/onevcat/Kingfisher"; @@ -7019,6 +7081,21 @@ package = 3A0A30B92C21397A00F8C9BC /* XCRemoteSwiftPackageReference "EmojiPicker" */; productName = EmojiPicker; }; + 3ACF94372DA9A52F00971A4E /* FaviconFinder */ = { + isa = XCSwiftPackageProductDependency; + package = 3ACF94362DA9A52F00971A4E /* XCRemoteSwiftPackageReference "FaviconFinder" */; + productName = FaviconFinder; + }; + 3ACF943D2DA9B10800971A4E /* FaviconFinder */ = { + isa = XCSwiftPackageProductDependency; + package = 3ACF94362DA9A52F00971A4E /* XCRemoteSwiftPackageReference "FaviconFinder" */; + productName = FaviconFinder; + }; + 3ACF943F2DA9B11200971A4E /* FaviconFinder */ = { + isa = XCSwiftPackageProductDependency; + package = 3ACF94362DA9A52F00971A4E /* XCRemoteSwiftPackageReference "FaviconFinder" */; + productName = FaviconFinder; + }; 4C06670328FC7EC500038D2A /* Kingfisher */ = { isa = XCSwiftPackageProductDependency; package = 4C06670228FC7EC500038D2A /* XCRemoteSwiftPackageReference "Kingfisher" */; diff --git a/damus.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/damus.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index fe7714bb..6de7b688 100644 --- a/damus.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/damus.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "06318d35ee2e6bd681b95591e67da33a9461b48a3c652e58bd9d1a6f0d82bdac", + "originHash" : "1fc7e0b44329ba72cd285eeb022b5b92582cd01586b920d243cb0485c2e69dcc", "pins" : [ { "identity" : "codescanner", @@ -35,6 +35,15 @@ "version" : "0.2.0" } }, + { + "identity" : "faviconfinder", + "kind" : "remoteSourceControl", + "location" : "https://github.com/will-lumley/FaviconFinder.git", + "state" : { + "revision" : "9279f4371f4877ca302ba3bf1015f3f58ae4a56c", + "version" : "5.1.4" + } + }, { "identity" : "gsplayer", "kind" : "remoteSourceControl", @@ -105,6 +114,15 @@ "version" : "0.1.2" } }, + { + "identity" : "swiftsoup", + "kind" : "remoteSourceControl", + "location" : "https://github.com/scinfu/SwiftSoup.git", + "state" : { + "revision" : "bba848db50462894e7fc0891d018dfecad4ef11e", + "version" : "2.8.7" + } + }, { "identity" : "swiftycrop", "kind" : "remoteSourceControl", diff --git a/damus/Components/NIP05Badge.swift b/damus/Components/NIP05Badge.swift index 9d8d9280..e5eb62f4 100644 --- a/damus/Components/NIP05Badge.swift +++ b/damus/Components/NIP05Badge.swift @@ -5,27 +5,27 @@ // Created by William Casarin on 2023-01-11. // +import FaviconFinder +import Kingfisher import SwiftUI struct NIP05Badge: View { let nip05: NIP05 let pubkey: Pubkey - let contacts: Contacts + let damus_state: DamusState let show_domain: Bool - let profiles: Profiles + let nip05_domain_favicon: FaviconURL? - @Environment(\.openURL) var openURL - - init(nip05: NIP05, pubkey: Pubkey, contacts: Contacts, show_domain: Bool, profiles: Profiles) { + init(nip05: NIP05, pubkey: Pubkey, damus_state: DamusState, show_domain: Bool, nip05_domain_favicon: FaviconURL?) { self.nip05 = nip05 self.pubkey = pubkey - self.contacts = contacts + self.damus_state = damus_state self.show_domain = show_domain - self.profiles = profiles + self.nip05_domain_favicon = nip05_domain_favicon } var nip05_color: Bool { - return use_nip05_color(pubkey: pubkey, contacts: contacts) + return use_nip05_color(pubkey: pubkey, contacts: damus_state.contacts) } var Seal: some View { @@ -44,8 +44,23 @@ struct NIP05Badge: View { } } + var domainBadge: some View { + Group { + if let nip05_domain_favicon { + KFImage(nip05_domain_favicon.source) + .imageContext(.favicon, disable_animation: true) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 18, height: 18) + .clipped() + } else { + EmptyView() + } + } + } + var username_matches_nip05: Bool { - guard let name = profiles.lookup(id: pubkey)?.map({ p in p?.name }).value + guard let name = damus_state.profiles.lookup(id: pubkey)?.map({ p in p?.name }).value else { return false } @@ -65,14 +80,18 @@ struct NIP05Badge: View { HStack(spacing: 2) { Seal - if show_domain { - Text(nip05_string) - .nip05_colorized(gradient: nip05_color) - .onTapGesture { - if let nip5url = nip05.siteUrl { - openURL(nip5url) - } - } + Group { + if show_domain { + Text(nip05_string) + .nip05_colorized(gradient: nip05_color) + } + + if nip05_domain_favicon != nil { + domainBadge + } + } + .onTapGesture { + damus_state.nav.push(route: Route.NIP05DomainEvents(events: NIP05DomainEventsModel(state: damus_state, domain: nip05.host), nip05_domain_favicon: nip05_domain_favicon)) } } @@ -98,13 +117,9 @@ struct NIP05Badge_Previews: PreviewProvider { static var previews: some View { let test_state = test_damus_state VStack { - NIP05Badge(nip05: NIP05(username: "jb55", host: "jb55.com"), pubkey: test_state.pubkey, contacts: test_state.contacts, show_domain: true, profiles: test_state.profiles) + NIP05Badge(nip05: NIP05(username: "jb55", host: "jb55.com"), pubkey: test_state.pubkey, damus_state: test_state, show_domain: true, nip05_domain_favicon: nil) - NIP05Badge(nip05: NIP05(username: "_", host: "jb55.com"), pubkey: test_state.pubkey, contacts: test_state.contacts, show_domain: true, profiles: test_state.profiles) - - NIP05Badge(nip05: NIP05(username: "jb55", host: "jb55.com"), pubkey: test_state.pubkey, contacts: test_state.contacts, show_domain: true, profiles: test_state.profiles) - - NIP05Badge(nip05: NIP05(username: "jb55", host: "jb55.com"), pubkey: test_state.pubkey, contacts: Contacts(our_pubkey: test_pubkey), show_domain: true, profiles: test_state.profiles) + NIP05Badge(nip05: NIP05(username: "_", host: "jb55.com"), pubkey: test_state.pubkey, damus_state: test_state, show_domain: true, nip05_domain_favicon: nil) } } } diff --git a/damus/ContentView.swift b/damus/ContentView.swift index 83f98a09..9323fb41 100644 --- a/damus/ContentView.swift +++ b/damus/ContentView.swift @@ -686,7 +686,8 @@ struct ContentView: View { video: DamusVideoCoordinator(), ndb: ndb, quote_reposts: .init(our_pubkey: pubkey), - emoji_provider: DefaultEmojiProvider(showAllVariations: true) + emoji_provider: DefaultEmojiProvider(showAllVariations: true), + favicon_cache: FaviconCache() ) home.damus_state = self.damus_state! diff --git a/damus/Models/Contacts.swift b/damus/Models/Contacts.swift index 6abda61b..6989bed4 100644 --- a/damus/Models/Contacts.swift +++ b/damus/Models/Contacts.swift @@ -38,6 +38,10 @@ class Contacts { return friends } + func get_friend_of_friends_list() -> Set { + return friend_of_friends + } + func get_followed_hashtags() -> Set { guard let ev = self.event else { return Set() } return Set(ev.referenced_hashtags.map({ $0.hashtag })) diff --git a/damus/Models/DamusState.swift b/damus/Models/DamusState.swift index 26b8b693..dbabdf3f 100644 --- a/damus/Models/DamusState.swift +++ b/damus/Models/DamusState.swift @@ -36,9 +36,10 @@ class DamusState: HeadlessDamusState { var purple: DamusPurple var push_notification_client: PushNotificationClient let emoji_provider: EmojiProvider + let favicon_cache: FaviconCache private(set) var nostrNetwork: NostrNetworkManager - init(keypair: Keypair, likes: EventCounter, boosts: EventCounter, contacts: Contacts, mutelist_manager: MutelistManager, profiles: Profiles, dms: DirectMessagesModel, previews: PreviewCache, zaps: Zaps, lnurls: LNUrls, settings: UserSettingsStore, relay_filters: RelayFilters, relay_model_cache: RelayModelCache, drafts: Drafts, events: EventCache, bookmarks: BookmarksManager, replies: ReplyCounter, wallet: WalletModel, nav: NavigationCoordinator, music: MusicController?, video: DamusVideoCoordinator, ndb: Ndb, purple: DamusPurple? = nil, quote_reposts: EventCounter, emoji_provider: EmojiProvider) { + init(keypair: Keypair, likes: EventCounter, boosts: EventCounter, contacts: Contacts, mutelist_manager: MutelistManager, profiles: Profiles, dms: DirectMessagesModel, previews: PreviewCache, zaps: Zaps, lnurls: LNUrls, settings: UserSettingsStore, relay_filters: RelayFilters, relay_model_cache: RelayModelCache, drafts: Drafts, events: EventCache, bookmarks: BookmarksManager, replies: ReplyCounter, wallet: WalletModel, nav: NavigationCoordinator, music: MusicController?, video: DamusVideoCoordinator, ndb: Ndb, purple: DamusPurple? = nil, quote_reposts: EventCounter, emoji_provider: EmojiProvider, favicon_cache: FaviconCache) { self.keypair = keypair self.likes = likes self.boosts = boosts @@ -68,7 +69,8 @@ class DamusState: HeadlessDamusState { self.quote_reposts = quote_reposts self.push_notification_client = PushNotificationClient(keypair: keypair, settings: settings) self.emoji_provider = emoji_provider - + self.favicon_cache = FaviconCache() + let networkManagerDelegate = NostrNetworkManagerDelegate(settings: settings, contacts: contacts, ndb: ndb, keypair: keypair, relayModelCache: relay_model_cache, relayFilters: relay_filters) self.nostrNetwork = NostrNetworkManager(delegate: networkManagerDelegate) } @@ -126,7 +128,8 @@ class DamusState: HeadlessDamusState { video: DamusVideoCoordinator(), ndb: ndb, quote_reposts: .init(our_pubkey: pubkey), - emoji_provider: DefaultEmojiProvider(showAllVariations: true) + emoji_provider: DefaultEmojiProvider(showAllVariations: true), + favicon_cache: FaviconCache() ) } @@ -194,7 +197,8 @@ class DamusState: HeadlessDamusState { video: DamusVideoCoordinator(), ndb: .empty, quote_reposts: .init(our_pubkey: empty_pub), - emoji_provider: DefaultEmojiProvider(showAllVariations: true) + emoji_provider: DefaultEmojiProvider(showAllVariations: true), + favicon_cache: FaviconCache() ) } } diff --git a/damus/Models/NIP05DomainEventsModel.swift b/damus/Models/NIP05DomainEventsModel.swift new file mode 100644 index 00000000..55ab6f07 --- /dev/null +++ b/damus/Models/NIP05DomainEventsModel.swift @@ -0,0 +1,97 @@ +// +// NIP05DomainEventsModel.swift +// damus +// +// Created by Terry Yiu on 4/11/25. +// + +import FaviconFinder +import Foundation + +class NIP05DomainEventsModel: ObservableObject { + let state: DamusState + var events: EventHolder + @Published var loading: Bool = false + + let domain: String + var filter: NostrFilter + let sub_id = UUID().description + let profiles_subid = UUID().description + let limit: UInt32 = 500 + + init(state: DamusState, domain: String) { + self.state = state + self.domain = domain + self.events = EventHolder(on_queue: { ev in + preload_events(state: state, events: [ev]) + }) + self.filter = NostrFilter() + } + + @MainActor func subscribe() { + filter.limit = self.limit + filter.kinds = [.text, .longform, .highlight] + + var authors = Set() + for pubkey in state.contacts.get_friend_of_friends_list() { + let profile_txn = state.profiles.lookup(id: pubkey) + + guard let profile = profile_txn?.unsafeUnownedValue, + let nip05_str = profile.nip05, + let nip05 = NIP05.parse(nip05_str), + nip05.host.caseInsensitiveCompare(domain) == .orderedSame else { + continue + } + + authors.insert(pubkey) + } + if authors.isEmpty { + return + } + filter.authors = Array(authors) + + print("subscribing to notes from friends of friends with '\(domain)' NIP-05 domain with sub_id \(sub_id)") + state.nostrNetwork.pool.register_handler(sub_id: sub_id, handler: handle_event) + loading = true + state.nostrNetwork.pool.send(.subscribe(.init(filters: [filter], sub_id: sub_id))) + } + + func unsubscribe() { + state.nostrNetwork.pool.unsubscribe(sub_id: sub_id) + loading = false + print("unsubscribing from notes from friends of friends with '\(domain)' NIP-05 domain with sub_id \(sub_id)") + } + + func add_event(_ ev: NostrEvent) { + if !event_matches_filter(ev, filter: filter) { + return + } + + guard should_show_event(state: state, ev: ev) else { + return + } + + if self.events.insert(ev) { + objectWillChange.send() + } + } + + func handle_event(relay_id: RelayURL, ev: NostrConnectionEvent) { + let (sub_id, done) = handle_subid_event(pool: state.nostrNetwork.pool, relay_id: relay_id, ev: ev) { sub_id, ev in + if sub_id == self.sub_id && ev.is_textlike && ev.should_show_event { + self.add_event(ev) + } + } + + guard done else { + return + } + + self.loading = false + + if sub_id == self.sub_id { + guard let txn = NdbTxn(ndb: state.ndb) else { return } + load_profiles(context: "search", profiles_subid: self.profiles_subid, relay_id: relay_id, load: .from_events(self.events.all_events), damus_state: state, txn: txn) + } + } +} diff --git a/damus/Nostr/Profiles.swift b/damus/Nostr/Profiles.swift index 2413f31d..37273f56 100644 --- a/damus/Nostr/Profiles.swift +++ b/damus/Nostr/Profiles.swift @@ -35,6 +35,7 @@ class Profiles { @MainActor private var profiles: [Pubkey: ProfileData] = [:] + // Map of validated NIP-05 address to pubkey. @MainActor var nip05_pubkey: [String: Pubkey] = [:] diff --git a/damus/TestData.swift b/damus/TestData.swift index 93c13ba6..4c6446b3 100644 --- a/damus/TestData.swift +++ b/damus/TestData.swift @@ -106,7 +106,8 @@ var test_damus_state: DamusState = ({ video: .init(), ndb: ndb, quote_reposts: .init(our_pubkey: our_pubkey), - emoji_provider: DefaultEmojiProvider(showAllVariations: true) + emoji_provider: DefaultEmojiProvider(showAllVariations: true), + favicon_cache: .init() ) /* diff --git a/damus/Util/Extensions/KFOptionSetter+.swift b/damus/Util/Extensions/KFOptionSetter+.swift index c3597a5f..b072569f 100644 --- a/damus/Util/Extensions/KFOptionSetter+.swift +++ b/damus/Util/Extensions/KFOptionSetter+.swift @@ -29,15 +29,15 @@ extension KFOptionSetter { options.onlyLoadFirstFrame = disable_animation switch imageContext { - case .pfp: - options.diskCacheExpiration = .days(60) - break - case .banner: - options.diskCacheExpiration = .days(5) - break - case .note: - options.diskCacheExpiration = .days(1) - break + case .pfp, .favicon: + options.diskCacheExpiration = .days(60) + break + case .banner: + options.diskCacheExpiration = .days(5) + break + case .note: + options.diskCacheExpiration = .days(1) + break } return self @@ -82,11 +82,14 @@ enum ImageContext { case pfp case banner case note - + case favicon + func maxMebibyteSize() -> Int { switch self { + case .favicon: + return 512_000 // 500KiB case .pfp: - return 5_242_880 // 5Mib + return 5_242_880 // 5MiB case .banner, .note: return 20_971_520 // 20MiB } @@ -94,6 +97,8 @@ enum ImageContext { func downsampleSize() -> CGSize { switch self { + case .favicon: + return CGSize(width: 18, height: 18) case .pfp: return CGSize(width: 200, height: 200) case .banner: diff --git a/damus/Util/FaviconCache.swift b/damus/Util/FaviconCache.swift new file mode 100644 index 00000000..acd23fc1 --- /dev/null +++ b/damus/Util/FaviconCache.swift @@ -0,0 +1,41 @@ +// +// FaviconCache.swift +// damus +// +// Created by Terry Yiu on 5/23/25. +// + +import Foundation +import FaviconFinder + +class FaviconCache { + private var nip05DomainFavicons: [String: [FaviconURL]] = [:] + + @MainActor + func lookup(_ domain: String) async -> [FaviconURL] { + let lowercasedDomain = domain.lowercased() + if let faviconURLs = nip05DomainFavicons[lowercasedDomain] { + return faviconURLs + } + + guard let siteURL = URL(string: "https://\(lowercasedDomain)"), + let faviconURLs = try? await FaviconFinder( + url: siteURL, + configuration: .init( + preferredSource: .ico, // Prefer using common favicon .ico filenames at root level to avoid scraping HTML when possible. + preferences: [ + .html: FaviconFormatType.appleTouchIcon.rawValue, + .ico: "favicon.ico", + .webApplicationManifestFile: FaviconFormatType.launcherIcon4x.rawValue + ] + ) + ).fetchFaviconURLs() + else { + return [] + } + + nip05DomainFavicons[lowercasedDomain] = faviconURLs + + return faviconURLs + } +} diff --git a/damus/Util/Router.swift b/damus/Util/Router.swift index 86bb34f2..4edff182 100644 --- a/damus/Util/Router.swift +++ b/damus/Util/Router.swift @@ -5,6 +5,7 @@ // Created by Scott Penrose on 5/7/23. // +import FaviconFinder import SwiftUI enum Route: Hashable { @@ -46,6 +47,8 @@ enum Route: Hashable { case Wallet(wallet: WalletModel) case WalletScanner(result: Binding) case FollowersYouKnow(friendedFollowers: [Pubkey], followers: FollowersModel) + case NIP05DomainEvents(events: NIP05DomainEventsModel, nip05_domain_favicon: FaviconURL?) + case NIP05DomainPubkeys(domain: String, nip05_domain_favicon: FaviconURL?, pubkeys: [Pubkey]) @ViewBuilder func view(navigationCoordinator: NavigationCoordinator, damusState: DamusState) -> some View { @@ -127,6 +130,10 @@ enum Route: Hashable { FollowersYouKnowView(damus_state: damusState, friended_followers: friendedFollowers, followers: followers) case .Script(let load_model): LoadScript(pool: damusState.nostrNetwork.pool, model: load_model) + case .NIP05DomainEvents(let events, let nip05_domain_favicon): + NIP05DomainTimelineView(damus_state: damusState, model: events, nip05_domain_favicon: nip05_domain_favicon) + case .NIP05DomainPubkeys(let domain, let nip05_domain_favicon, let pubkeys): + NIP05DomainPubkeysView(damus_state: damusState, domain: domain, nip05_domain_favicon: nip05_domain_favicon, pubkeys: pubkeys) } } @@ -231,6 +238,12 @@ enum Route: Hashable { case .Script(let model): hasher.combine("script") hasher.combine(model.data.count) + case .NIP05DomainEvents(let events, _): + hasher.combine("nip05DomainEvents") + hasher.combine(events.domain) + case .NIP05DomainPubkeys(let domain, _, _): + hasher.combine("nip05DomainPubkeys") + hasher.combine(domain) } } } diff --git a/damus/Views/NIP05DomainPubkeysView.swift b/damus/Views/NIP05DomainPubkeysView.swift new file mode 100644 index 00000000..0a863e54 --- /dev/null +++ b/damus/Views/NIP05DomainPubkeysView.swift @@ -0,0 +1,51 @@ +// +// NIP05DomainPubkeysView.swift +// damus +// +// Created by Terry Yiu on 5/23/25. +// + +import FaviconFinder +import Kingfisher +import SwiftUI + +struct NIP05DomainPubkeysView: View { + let damus_state: DamusState + let domain: String + let nip05_domain_favicon: FaviconURL? + let pubkeys: [Pubkey] + + var body: some View { + ScrollView { + LazyVStack(alignment: .leading) { + ForEach(pubkeys, id: \.self) { pk in + FollowUserView(target: .pubkey(pk), damus_state: damus_state) + } + } + .padding(.horizontal) + } + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .principal) { + HStack { + if let nip05_domain_favicon { + KFImage(nip05_domain_favicon.source) + .imageContext(.favicon, disable_animation: true) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 18, height: 18) + .clipped() + } + Text(domain) + .font(.headline) + } + } + } + } +} + +#Preview { + let nip05_domain_favicon = FaviconURL(source: URL(string: "https://damus.io/favicon.ico")!, format: .ico, sourceType: .ico) + let pubkeys = [test_pubkey, test_pubkey_2] + NIP05DomainPubkeysView(damus_state: test_damus_state, domain: "damus.io", nip05_domain_favicon: nip05_domain_favicon, pubkeys: pubkeys) +} diff --git a/damus/Views/NIP05DomainTimelineHeaderView.swift b/damus/Views/NIP05DomainTimelineHeaderView.swift new file mode 100644 index 00000000..7e8b7e6b --- /dev/null +++ b/damus/Views/NIP05DomainTimelineHeaderView.swift @@ -0,0 +1,111 @@ +// +// NIP05DomainTimelineHeaderView.swift +// damus +// +// Created by Terry Yiu on 5/16/25. +// + +import FaviconFinder +import Kingfisher +import SwiftUI + +struct NIP05DomainTimelineHeaderView: View { + let damus_state: DamusState + @ObservedObject var model: NIP05DomainEventsModel + let nip05_domain_favicon: FaviconURL? + + @Environment(\.openURL) var openURL + + var Icon: some View { + ZStack { + if let nip05_domain_favicon { + KFImage(nip05_domain_favicon.source) + .imageContext(.favicon, disable_animation: true) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 18, height: 18) + .clipped() + } else { + EmptyView() + } + } + } + + var friendsOfFriends: [Pubkey] { + // Order it such that the pubkeys that have events come first in the array so that their profile pictures + // show first. + let pubkeys = model.events.all_events.map { $0.pubkey } + (model.filter.authors ?? []) + + // Filter out duplicates but retain order, and filter out any that do not have a validated NIP-05. + return (NSMutableOrderedSet(array: pubkeys).array as? [Pubkey] ?? []) + .filter { + damus_state.contacts.is_in_friendosphere($0) && damus_state.profiles.is_validated($0) != nil + } + } + + var body: some View { + VStack(alignment: .leading) { + HStack { + if nip05_domain_favicon != nil { + Icon + } + + Text(model.domain) + .foregroundStyle(DamusLogoGradient.gradient) + .font(.title.bold()) + .onTapGesture { + if let url = URL(string: "https://\(model.domain)") { + openURL(url) + } + } + } + + let friendsOfFriends = friendsOfFriends + + HStack { + CondensedProfilePicturesView(state: damus_state, pubkeys: friendsOfFriends, maxPictures: 3) + let friendsOfFriendsString = friendsOfFriendsString(friendsOfFriends, ndb: damus_state.ndb) + Text(friendsOfFriendsString) + .font(.subheadline) + .foregroundColor(.gray) + .multilineTextAlignment(.leading) + } + .onTapGesture { + if !friendsOfFriends.isEmpty { + damus_state.nav.push(route: Route.NIP05DomainPubkeys(domain: model.domain, nip05_domain_favicon: nip05_domain_favicon, pubkeys: friendsOfFriends)) + } + } + } + } +} + +func friendsOfFriendsString(_ friendsOfFriends: [Pubkey], ndb: Ndb, locale: Locale = Locale.current) -> String { + let bundle = bundleForLocale(locale: locale) + let names: [String] = friendsOfFriends.prefix(3).map { pk in + let profile = ndb.lookup_profile(pk)?.unsafeUnownedValue?.profile + return Profile.displayName(profile: profile, pubkey: pk).username.truncate(maxLength: 20) + } + + switch friendsOfFriends.count { + case 0: + return "No one in your trusted network is associated with this domain." + case 1: + let format = NSLocalizedString("Notes from %@", bundle: bundle, comment: "Text to indicate that notes from one pubkey in our trusted network are shown below.") + return String(format: format, locale: locale, names[0]) + case 2: + let format = NSLocalizedString("Notes from %@ & %@", bundle: bundle, comment: "Text to indicate that notes from two pubkeys in our trusted network are shown below.") + return String(format: format, locale: locale, names[0], names[1]) + case 3: + let format = NSLocalizedString("Notes from %@, %@ & %@", bundle: bundle, comment: "Text to indicate that notes from three pubkeys in our trusted network are shown below.") + return String(format: format, locale: locale, names[0], names[1], names[2]) + default: + let format = localizedStringFormat(key: "notes_from_three_and_others", locale: locale) + return String(format: format, locale: locale, friendsOfFriends.count - 3, names[0], names[1], names[2]) + } +} + +#Preview { + let model = NIP05DomainEventsModel(state: test_damus_state, domain: "damus.io") + let nip05_domain_favicon = FaviconURL(source: URL(string: "https://damus.io/favicon.ico")!, format: .ico, sourceType: .ico) + NIP05DomainTimelineHeaderView(damus_state: test_damus_state, model: model, nip05_domain_favicon: nip05_domain_favicon) +} diff --git a/damus/Views/NIP05DomainTimelineView.swift b/damus/Views/NIP05DomainTimelineView.swift new file mode 100644 index 00000000..20369bb7 --- /dev/null +++ b/damus/Views/NIP05DomainTimelineView.swift @@ -0,0 +1,64 @@ +// +// NIP05DomainTimelineView.swift +// damus +// +// Created by Terry Yiu on 4/11/25. +// + +import FaviconFinder +import Kingfisher +import SwiftUI + +struct NIP05DomainTimelineView: View { + let damus_state: DamusState + @ObservedObject var model: NIP05DomainEventsModel + let nip05_domain_favicon: FaviconURL? + + func nip05_filter(ev: NostrEvent) -> Bool { + damus_state.contacts.is_in_friendosphere(ev.pubkey) && damus_state.profiles.is_validated(ev.pubkey) != nil + } + + var contentFilters: ContentFilters { + var filters = Array<(NostrEvent) -> Bool>() + filters.append(contentsOf: ContentFilters.defaults(damus_state: damus_state)) + filters.append(nip05_filter) + return ContentFilters(filters: filters) + } + + var body: some View { + let height: CGFloat = 250.0 + + TimelineView(events: model.events, loading: $model.loading, damus: damus_state, show_friend_icon: true, filter: contentFilters.filter(ev:)) { + ZStack(alignment: .leading) { + DamusBackground(maxHeight: height) + .mask(LinearGradient(gradient: Gradient(colors: [.black, .black, .black, .clear]), startPoint: .top, endPoint: .bottom)) + NIP05DomainTimelineHeaderView(damus_state: damus_state, model: model, nip05_domain_favicon: nip05_domain_favicon) + .padding(.leading, 30) + .padding(.top, 30) + } + } + .ignoresSafeArea() + .padding(.bottom, tabHeight) + .onAppear { + guard model.events.all_events.isEmpty else { return } + + model.subscribe() + + if let pubkeys = model.filter.authors { + for pubkey in pubkeys { + check_nip05_validity(pubkey: pubkey, profiles: damus_state.profiles) + } + } + } + .onDisappear { + model.unsubscribe() + } + } +} + +#Preview { + let damus_state = test_damus_state + let model = NIP05DomainEventsModel(state: damus_state, domain: "damus.io") + let nip05_domain_favicon = FaviconURL(source: URL(string: "https://damus.io/favicon.ico")!, format: .ico, sourceType: .ico) + NIP05DomainTimelineView(damus_state: test_damus_state, model: model, nip05_domain_favicon: nip05_domain_favicon) +} diff --git a/damus/Views/Profile/ProfileName.swift b/damus/Views/Profile/ProfileName.swift index ff0e2f09..9d420bd9 100644 --- a/damus/Views/Profile/ProfileName.swift +++ b/damus/Views/Profile/ProfileName.swift @@ -5,6 +5,7 @@ // Created by William Casarin on 2022-04-16. // +import FaviconFinder import SwiftUI enum FriendType { @@ -43,6 +44,7 @@ struct ProfileName: View { @State var nip05: NIP05? @State var donation: Int? @State var purple_account: DamusPurple.Account? + @State var nip05_domain_favicon: FaviconURL? init(pubkey: Pubkey, prefix: String = "", damus: DamusState, show_nip5_domain: Bool = true, supporterBadgeStyle: SupporterBadge.Style = .compact) { self.pubkey = pubkey @@ -61,7 +63,7 @@ struct ProfileName: View { var current_nip05: NIP05? { nip05 ?? damus_state.profiles.is_validated(pubkey) } - + func current_display_name(profile: Profile?) -> DisplayName { return display_name ?? Profile.displayName(profile: profile, pubkey: pubkey) } @@ -101,7 +103,7 @@ struct ProfileName: View { .fontWeight(prefix == "@" ? .none : .bold) if let nip05 = current_nip05 { - NIP05Badge(nip05: nip05, pubkey: pubkey, contacts: damus_state.contacts, show_domain: show_nip5_domain, profiles: damus_state.profiles) + NIP05Badge(nip05: nip05, pubkey: pubkey, damus_state: damus_state, show_domain: show_nip5_domain, nip05_domain_favicon: nip05_domain_favicon) } if let friend = friend_type, current_nip05 == nil { @@ -118,9 +120,15 @@ struct ProfileName: View { } .task { - if damus_state.purple.enable_purple { - self.purple_account = try? await damus_state.purple.get_maybe_cached_account(pubkey: pubkey) - } + if damus_state.purple.enable_purple { + self.purple_account = try? await damus_state.purple.get_maybe_cached_account(pubkey: pubkey) + } + } + .task { + if let domain = current_nip05?.host { + self.nip05_domain_favicon = try? await damus_state.favicon_cache.lookup(domain) + .largest() + } } .onReceive(handle_notify(.profile_updated)) { update in if update.pubkey != pubkey { @@ -151,6 +159,24 @@ struct ProfileName: View { let nip05 = damus_state.profiles.is_validated(pubkey) if nip05 != self.nip05 { self.nip05 = nip05 + + if let domain = nip05?.host { + Task { + let favicon = try? await damus_state.favicon_cache.lookup(domain) + .filter { + if let size = $0.size { + return size.width <= 128 && size.height <= 128 + } else { + return true + } + } + .largest() + + await MainActor.run { + self.nip05_domain_favicon = favicon + } + } + } } if donation != profile.damus_donation { diff --git a/damus/en-US.lproj/Localizable.stringsdict b/damus/en-US.lproj/Localizable.stringsdict index a389dea0..e67be1f5 100644 --- a/damus/en-US.lproj/Localizable.stringsdict +++ b/damus/en-US.lproj/Localizable.stringsdict @@ -82,6 +82,22 @@ Imports + notes_from_three_and_others + + NSStringLocalizedFormatKey + %#@OTHERS@ + OTHERS + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + d + one + Notes from %2$@, %3$@, %4$@ & %1$d other in your trusted network + other + Notes from %2$@, %3$@, %4$@ & %1$d others in your trusted network + + people_reposted_count NSStringLocalizedFormatKey diff --git a/damusTests/Mocking/MockDamusState.swift b/damusTests/Mocking/MockDamusState.swift index 99959ec0..fa8c1323 100644 --- a/damusTests/Mocking/MockDamusState.swift +++ b/damusTests/Mocking/MockDamusState.swift @@ -49,7 +49,8 @@ func generate_test_damus_state( video: .init(), ndb: ndb, quote_reposts: .init(our_pubkey: our_pubkey), - emoji_provider: DefaultEmojiProvider(showAllVariations: false) + emoji_provider: DefaultEmojiProvider(showAllVariations: false), + favicon_cache: .init() ) return damus diff --git a/damusTests/NIP05DomainTimelineHeaderViewTests.swift b/damusTests/NIP05DomainTimelineHeaderViewTests.swift new file mode 100644 index 00000000..cd2b1e1d --- /dev/null +++ b/damusTests/NIP05DomainTimelineHeaderViewTests.swift @@ -0,0 +1,39 @@ +// +// NIP05DomainTimelineHeaderViewTests.swift +// damusTests +// +// Created by Terry Yiu on 5/23/25. +// + +import XCTest +@testable import damus + +final class NIP05DomainTimelineHeaderViewTests: XCTestCase { + + let enUsLocale = Locale(identifier: "en-US") + + func testFriendsOfFriendsString() throws { + let pk1 = test_pubkey + let pk2 = test_pubkey_2 + let pk3 = Pubkey(hex: "b42e44b555013239a0d5dcdb09ebde0857cd8a5a57efbba5a2b6ac78833cb9f0")! + let pk4 = Pubkey(hex: "cc590e46363d0fa66bb27081368d01f169b8ffc7c614629d4e9eef6c88b38670")! + let pk5 = Pubkey(hex: "f2aa579bb998627e04a8f553842a09446360c9d708c6141dd119c479f6ab9d29")! + + let ndb = Ndb(path: Ndb.db_path)! + + let damus_name = "17ldvg64:nq5mhr77" + XCTAssertEqual(friendsOfFriendsString([pk1], ndb: ndb, locale: enUsLocale), "Notes from \(damus_name)") + XCTAssertEqual(friendsOfFriendsString([pk1, pk2], ndb: ndb, locale: enUsLocale), "Notes from \(damus_name) & 1rppft3m:4qxhsgnj") + XCTAssertEqual(friendsOfFriendsString([pk1, pk2, pk3], ndb: ndb, locale: enUsLocale), "Notes from \(damus_name), 1rppft3m:4qxhsgnj & 1kshyfd2:cq04aze0") + XCTAssertEqual(friendsOfFriendsString([pk1, pk2, pk3, pk4,], ndb: ndb, locale: enUsLocale), "Notes from \(damus_name), 1rppft3m:4qxhsgnj, 1kshyfd2:cq04aze0 & 1 other in your trusted network") + XCTAssertEqual(friendsOfFriendsString([pk1, pk2, pk3, pk4, pk5], ndb: ndb, locale: enUsLocale), "Notes from \(damus_name), 1rppft3m:4qxhsgnj, 1kshyfd2:cq04aze0 & 2 others in your trusted network") + + let pubkeys = [pk1, pk2, pk3, pk4, pk5, pk1, pk2, pk3, pk4, pk5] + Bundle.main.localizations.map { Locale(identifier: $0) }.forEach { + for count in 1...10 { + XCTAssertNoThrow(friendsOfFriendsString(pubkeys.prefix(count).map { $0 }, ndb: ndb, locale: $0)) + } + } + } + +} From 612abfd86268f6f181e6d0ce20f007c97930f1ee Mon Sep 17 00:00:00 2001 From: Terry Yiu Date: Tue, 27 May 2025 17:40:07 -0400 Subject: [PATCH 02/16] Fix quotes view header alignment Changelog-Fixed: Fixed quotes view header alignment Signed-off-by: Terry Yiu --- damus/Views/Reposts/QuoteRepostsView.swift | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/damus/Views/Reposts/QuoteRepostsView.swift b/damus/Views/Reposts/QuoteRepostsView.swift index 54c55b2e..95ce7e60 100644 --- a/damus/Views/Reposts/QuoteRepostsView.swift +++ b/damus/Views/Reposts/QuoteRepostsView.swift @@ -12,9 +12,19 @@ struct QuoteRepostsView: View { @ObservedObject var model: EventsModel var body: some View { - TimelineView(events: model.events, loading: $model.loading, damus: damus_state, show_friend_icon: true, filter: ContentFilters.default_filters(damus_state: damus_state).filter(ev:)) + TimelineView(events: model.events, loading: $model.loading, damus: damus_state, show_friend_icon: true, filter: ContentFilters.default_filters(damus_state: damus_state).filter(ev:)) { + ZStack(alignment: .leading) { + DamusBackground(maxHeight: 250) + .mask(LinearGradient(gradient: Gradient(colors: [.black, .black, .black, .clear]), startPoint: .top, endPoint: .bottom)) + Text("Quotes", comment: "Navigation bar title for Quote Reposts view.") + .foregroundStyle(DamusLogoGradient.gradient) + .font(.title.bold()) + .padding(.leading, 30) + .padding(.top, 30) + } + } + .ignoresSafeArea() .padding(.bottom, tabHeight) - .navigationBarTitle(NSLocalizedString("Quotes", comment: "Navigation bar title for Quote Reposts view.")) .onAppear { model.subscribe() } From 44cf47faa4c90e22d25a58b4aa6fe459eed62c6e Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Thu, 8 May 2025 02:30:00 +0000 Subject: [PATCH 03/16] Translate Localizable.strings in th 100% translated source file: 'Localizable.strings' on 'th'. --- damus/th.lproj/Localizable.strings | Bin 198996 -> 205452 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/damus/th.lproj/Localizable.strings b/damus/th.lproj/Localizable.strings index 3244da628e3aeae745fd186e8f1dc3ad7a920712..de3dfbb612be3134ea4d716d9cff917a19fba932 100644 GIT binary patch delta 4087 zcmcInYiwLc6}~gxc-Py_#P;sm-t{AE8^?_uKa$uqy?3PL=*{#QV}XtA*TdW9x9LT%KMY*DaZqQ!smSxRDDVzA$D9#oQkUjd>i2eK7xp-# zPRvQ*Gm7z`99zGp0-LY;No}mnUFSFRq?6 zeyrj*_F7>m$7$4=pliLN@FBK;3Mw)9kiZs)g`e3U8@_%V$^jfV!HXrY;^2)qwYvFi zK0W(m;n(%=b+6*D(SO75c%|u#LC!WQC7^^tqN7S3hDiy z*iMff7K*xxq)&I83(V!|H$1DRlcL2kyZIzc;EcK+PQ$FDF!-49ycRoEPMzaN@LSzn zV=X1Cg)^+45(NC3GT9u5HwkCh1TcYT&i)uyCh#|HqS5nTWw#W`^Q)c6e2pqnA6D%) z(|Ib6vZ#mq)oQD%!d4ry8__#27Sr>86VbVMX=q)}0T_~i2SYHT8&6{-zAeIZ`nvRN z?t!-xrj|KfY%nK^Bf|NQIeYLu%uZ3_moogwD6AjBvdt$8olN@JjYE2kf2_`6Nsr4k zWZ49+^a(m~NCdrnGm1jjJyWP}za9;zE4aItM}m=21dlDVHOav|>YPgIMk+W{j~g>q z4C0#Pf?GC=E-%SoXZjVXHl<=MU8)83^#~9bMVJ|Z+wg5rs9$(En7JFkDpR`tndrw_ zu(3_;0m9nwX+%C6AXtF^9e}4q(zdBQwL^JvNI9~`2S19n7OXVjf_p=zW9y^38D=;xU=8Nq^DmIMW)u*nOfI$zEU^6 z7%2Y0%GZe(i+#yT0+_xpOK4$1dT8+_(L-IgWF|fEa}k(( zgj+VW;Wb&V-+nWfvJZ*O?UevR1tM30)P(;nauU1VBr(t9lJ5Cu*SH4{70oTw&CG-2Cs8EP$rTJxeBt5J_T@w*jhPOs3^ie#Q>FdV@w z;Zxg;PXdCoqe&;q)rVdA5M&*W)t2Bn$yAbC+6Laa1LQ3vj4mDSECz zmS(^fx^PqGQ`eaE&6GgE2Q-vpWMJkghj1D0DK||eZY;@Xw1As7KsJgC!}zvi2hR}p zsR~0!2>K<-rql}G+tH08u+pE ztIj+6){~na`#+=><)phVG|@t*{K$M>lknH*Tc-jUqs|B=ga~hC5*RYY8UyCILE#6(oCo!Ps$1XM=cCv+MQ#q0!wOmeQ@RYP40K;gEP*TPyD-7kp3Kyr+#dj+ z`e^rQnY*!XnOr`YM0?Xo)LzsNWo8==v?WE$Hpj5WVRw0psliRmfixpO4%d@J&yd#f zcrX|?K#CX~*x|}cUn!6ky8dUL`F%n8M5EsK#{zxkPl)@Syb2!u{wISlkGpm_Tw@%j zM3W4TS|N7Sb(%+1%k-Z!E-`Z%rsW@d_Y_I7zI%7mdY(?I zK_<3u;&meb!T)4nS)+#3{CC=9D5&dyw?jYpsE_V{Nn~fS`vx_7wjfx}Z9cV?xIK&0 zn#7)gB3>}u>>h*)k3P1Y4I!cl9Junr6bEndjO8-aZf0ki?GVNDSC7cOpQFhsnM)`4 zifo>!*70CGqGw;t7YVv{Pz334w+J-HFyE%XB&-(0)c3b($aB2W)AgsnjM?V84AA-G zB9lrs%1keJJ@i$YU6jEM%qDg+V20_XfBpjCF$%976(KtPS5c6~qc6A5Q5_!$dy||` zvk?&bKduR1AchFpRvmMwt3>35%{w5R---nCfW*B*&|6=_$p7qh;iGR{5xMl2r^JWO zEePNIXKu@;EYO{DLt&`JAGVFyZP2!YhDqF&k@l4f?YP3THh238xXo$g#PZ~317U|# zTf~fC`y#|c%PEdRzCKr-t(R`(R`b}f_8}>C>eN#Fw<3b^IIzWs99zoFLkAP+Kz>z@ cd0W8!=sj~GUHYD^rSo^>tMi8!<@?cp0rKHa4FCWD delta 176 zcmV;h08jsn#SGMv46xKxmk{3q1e0*?FtdbK>^+z2X8{hEE-wNIv)q>21eahf0Z5ZD zo*=WFoe%|=C From ea04ebe95c56a8989e02b4bdc984be5744f1ff69 Mon Sep 17 00:00:00 2001 From: Terry Yiu Date: Thu, 15 May 2025 20:13:20 -0400 Subject: [PATCH 04/16] Export strings for translation Signed-off-by: Terry Yiu --- .../Localized Contents/en-US.xliff | 288 +++++++++++++++++- .../damus/Localizable.xcstrings | 85 +++++- .../damus/en-US.lproj/Localizable.strings | Bin 206110 -> 215550 bytes 3 files changed, 363 insertions(+), 10 deletions(-) diff --git a/damus/en-US.xcloc/Localized Contents/en-US.xliff b/damus/en-US.xcloc/Localized Contents/en-US.xliff index 969ca9b6..03183ce2 100644 --- a/damus/en-US.xcloc/Localized Contents/en-US.xliff +++ b/damus/en-US.xcloc/Localized Contents/en-US.xliff @@ -308,6 +308,11 @@ Label for filter for all notifications. An additional percentage of each zap will be sent to support Damus development Text indicating that they can contribute zaps to support Damus development. + + An internal error occurred in your wallet. + An internal error occurred in your wallet. + Error description for an internal error + An unexpected error happened while trying to perform this action. Please contact support. An unexpected error happened while trying to perform this action. Please contact support. @@ -323,6 +328,11 @@ Label for filter for all notifications. An unknown error occurred while adding a relay. Title of an unknown relay error message. + + An unspecified error occurred in your wallet. + An unspecified error occurred in your wallet. + Error description for an unspecified error + Animations Animations @@ -511,6 +521,11 @@ Text for button to cancel out of connecting Nostr Wallet Connect lightning walle Check the address and/or the relay list. Human readable tip for error + + Check your account permissions or contact support. + Check your account permissions or contact support. + Tip for restricted operation + Check your internet connection and try again. If the error persists, contact support. Check your internet connection and try again. If the error persists, contact support. @@ -557,9 +572,9 @@ Text for button to cancel out of connecting Nostr Wallet Connect lightning walle Button label giving the user the option to close the sheet from which they posted a highlight Button label giving the user the option to close the sheet from which they were trying to post a highlight - - Coinos is a service operated by a third-party. We have no access to your Coinos wallet. - Coinos is a service operated by a third-party. We have no access to your Coinos wallet. + + Coinos is a service operated by a third-party. The Damus team has no access to your wallet. + Coinos is a service operated by a third-party. The Damus team has no access to your wallet. Small caption with a disclaimer that Damus does not own or have access to Coinos wallets, Coinos is a third-party service. @@ -652,6 +667,11 @@ Prompt to user to continue Copied Label indicating that a user's key was copied. + + Copied! + Copied! + Label indicating that the error technical information was successfully copied to the clipboard, which shows up as soon as the user clicks the copy button. + Copy Copy @@ -709,6 +729,11 @@ Context menu option for copying the version of damus. Copy note JSON Context menu option for copying the JSON text from the note. + + Copy technical information + Copy technical information + Button label to allow user to copy technical information from an error screen (usually to provide our support team for further troubleshooting) + Copy text Copy text @@ -855,6 +880,11 @@ Section header for developer settings Developer Mode enables features and options that may help developers diagnose issues and improve this app. Most users will not need Developer Mode. Section header for Developer Settings view + + Disable high balance warning + Disable high balance warning + Setting to disable high balance warnings on the user's wallet + Discard changes? Discard changes? @@ -874,7 +904,8 @@ Button to disconnect from the relay. Dismiss Dismiss - Button to dismiss alert + Button label to dismiss the safety reminder that the user's wallet has a high balance +Button to dismiss alert Button to dismiss error @@ -926,6 +957,11 @@ Edit Button for editing profile Edit profile picture Accessibility label for a button that edits a profile picture + + Empty error message + Empty error message + A human readable placeholder to indicate that the error message is empty + Enable Purple auto-translations Enable Purple auto-translations @@ -1620,6 +1656,11 @@ Text label indicating that there is no NIP-11 relay description information foun Text label indicating that there is no NIP-11 relay software information found. In English, N/A stands for not applicable. Text label indicating that there is no NIP-11 relay software version information found. In English, N/A stands for not applicable. + + NWC wallet + NWC wallet + Title for section in zap settings that controls general NWC wallet settings. + Name Name @@ -1942,6 +1983,11 @@ Section title for deleting the user Plan Prompt selection of DeepL subscription plan to perform machine translations on notes + + Please check for updates or contact your wallet provider. + Please check for updates or contact your wallet provider. + Tip for not implemented error + Please check the address and try again Please check the address and try again @@ -1962,11 +2008,26 @@ Section title for deleting the user Please contact support. Tip for an unknown relay error message. + + Please contact the developer of your wallet provider for help. + Please contact the developer of your wallet provider for help. + Human readable error description for an unknown error raised by a wallet provider. + Please contact the person who provided the link, and ask for another link. Please contact the person who provided the link, and ask for another link. User-visible tip on what to do if a link contains a deprecated "nrelay" reference. + + Please copy the technical info and send it to our support team. + Please copy the technical info and send it to our support team. + Tip on how to resolve issue when wallet returns an invalid response + + + Please deposit more funds and try again. + Please deposit more funds and try again. + Tip for insufficient balance errors + Please double-check the checkout web page, or go to the Side Menu → "Purple" to check your account status. If you have already paid, but still don't see your account active, please save the URL of the checkout page where you came from, contact our support, and give us the URL to help you with this issue. Please double-check the checkout web page, or go to the Side Menu → "Purple" to check your account status. If you have already paid, but still don't see your account active, please save the URL of the checkout page where you came from, contact our support, and give us the URL to help you with this issue. @@ -1987,6 +2048,11 @@ Section title for deleting the user Please try again later or contact support if the issue persists. Human readable tip for error + + Please try again or contact your wallet provider for further assistance. + Please try again or contact your wallet provider for further assistance. + Tip for unspecified error + Please try again, check the URL for typos, or contact support for further help. Please try again, check the URL for typos, or contact support for further help. @@ -1997,6 +2063,11 @@ Section title for deleting the user Please try opening this content on another Nostr app that supports this type of content. User-visible advice on what to do if they see the error indicating a note has an unknown kind or is unsupported for viewing. + + Please verify your credentials or permissions. + Please verify your credentials or permissions. + Tip for unauthorized access + Point your camera to a QR code… Point your camera to a QR code… @@ -2810,6 +2881,11 @@ Enjoy! This device's in-app purchase is registered to a different Nostr account. Unable to manage this Purple account. If you believe this was a mistake, please contact us via support@damus.io. Notice label that user cannot manage their In-App purchases + + This feature is not implemented by your wallet. + This feature is not implemented by your wallet. + Error description for not implemented feature + This is a public key, you will not be able to make notes or interact in any way. This is used for viewing accounts from their perspective. This is a public key, you will not be able to make notes or interact in any way. This is used for viewing accounts from their perspective. @@ -2839,6 +2915,11 @@ Nice to meet you all! #introductions #plebchain This note contains too many items and cannot be rendered Error message indicating that a note is too big and cannot be rendered + + This operation is restricted by your wallet. + This operation is restricted by your wallet. + Error description for restricted operation + This relay is already in your list. This relay is already in your list. @@ -2915,6 +2996,11 @@ Section header for text and appearance settings Try checking the link again, your internet connection, or contact the person who provided you the link for help. Tips on what to do if a note cannot be found. + + Try restarting your wallet or contacting support if the problem persists. + Try restarting your wallet or contacting support if the problem persists. + Tip for internal error + Type %@ to delete Type %@ to delete @@ -3107,6 +3193,16 @@ This will reset your contact list, including the list of everyone you follow and This will reset your contact list, including the list of everyone you follow and potentially the list of all relays you usually connect to. ONLY PROCEED IF YOU ARE SURE YOU HAVE LOST YOUR CONTACT LIST BEYOND RECOVERABILITY. Alert for resetting the user's contact list. + + Wait a few moments, and then try again. + Wait a few moments, and then try again. + Tip for rate limit error + + + Wait for the quota to reset, or configure your wallet provider to allow a higher limit. + Wait for the quota to reset, or configure your wallet provider to allow a higher limit. + Tip for quota exceeded + Wallet Wallet @@ -3115,6 +3211,21 @@ Navigation title for attaching Nostr Wallet Connect lightning wallet. Sidebar menu label for Wallet view. Title for section in zap settings that controls the Lightning wallet selection. + + Wallet provider returned a response that we could not decrypt. + Wallet provider returned a response that we could not decrypt. + Error description shown to the user when a response from the wallet provider contains data the app could not decrypt. + + + Wallet provider returned a response that we do not understand. + Wallet provider returned a response that we do not understand. + Error description shown to the user when a response from the wallet provider contains data the app does not understand + + + Wallet provider returned an invalid response. + Wallet provider returned an invalid response. + Error description shown to the user when a response from the wallet provider is invalid + We did not detect any issues that we can automatically fix for you. If you are having issues, please contact Damus support: [support@damus.io](mailto:support@damus.io) We did not detect any issues that we can automatically fix for you. If you are having issues, please contact Damus support: [support@damus.io](mailto:support@damus.io) @@ -3206,6 +3317,11 @@ User confirm Yes Yes, Overwrite Text of button that confirms to overwrite the existing mutelist. + + You are not authorized to perform this action with your wallet. + You are not authorized to perform this action with your wallet. + Error description for unauthorized access + You cannot post a highlight because you are not logged in with a private key! Please close this, login with a private key (or nsec), and try again. You cannot post a highlight because you are not logged in with a private key! Please close this, login with a private key (or nsec), and try again. @@ -3276,6 +3392,11 @@ User confirm Yes Your Purple subscription has expired. Renew? A notification message explaining to the user that their Damus Purple Subscription has expired, prompting them to renew. + + Your connected wallet raised an unknown error. Message: %s + Your connected wallet raised an unknown error. Message: %s + Human readable error description for unknown error + Your draft has been saved to storage. Your draft has been saved to storage. @@ -3301,6 +3422,21 @@ User confirm Yes Your report will be sent to the relays you are connected to Footer text to inform user what will happen when the report is submitted. + + Your transaction quota has been exceeded. + Your transaction quota has been exceeded. + Error description for quota exceeded + + + Your wallet does not have sufficient balance for this transaction. + Your wallet does not have sufficient balance for this transaction. + Error description for insufficient balance + + + Your wallet is temporarily being rate limited. + Your wallet is temporarily being rate limited. + Error description for rate limit error + Zap Zap @@ -4287,6 +4423,11 @@ Label for filter for all notifications. An additional percentage of each zap will be sent to support Damus development Text indicating that they can contribute zaps to support Damus development. + + An internal error occurred in your wallet. + An internal error occurred in your wallet. + Error description for an internal error + An unexpected error happened while trying to perform this action. Please contact support. An unexpected error happened while trying to perform this action. Please contact support. @@ -4302,6 +4443,11 @@ Label for filter for all notifications. An unknown error occurred while adding a relay. Title of an unknown relay error message. + + An unspecified error occurred in your wallet. + An unspecified error occurred in your wallet. + Error description for an unspecified error + Animations Animations @@ -4490,6 +4636,11 @@ Text for button to cancel out of connecting Nostr Wallet Connect lightning walle Check the address and/or the relay list. Human readable tip for error + + Check your account permissions or contact support. + Check your account permissions or contact support. + Tip for restricted operation + Check your internet connection and try again. If the error persists, contact support. Check your internet connection and try again. If the error persists, contact support. @@ -4539,9 +4690,9 @@ Button label giving the user the option to close the sheet from which they were Button label giving the user the option to close the sheet from which they were trying to share. Button label giving the user the option to close the view when no content is available to share - - Coinos is a service operated by a third-party. We have no access to your Coinos wallet. - Coinos is a service operated by a third-party. We have no access to your Coinos wallet. + + Coinos is a service operated by a third-party. The Damus team has no access to your wallet. + Coinos is a service operated by a third-party. The Damus team has no access to your wallet. Small caption with a disclaimer that Damus does not own or have access to Coinos wallets, Coinos is a third-party service. @@ -4634,6 +4785,11 @@ Prompt to user to continue Copied Label indicating that a user's key was copied. + + Copied! + Copied! + Label indicating that the error technical information was successfully copied to the clipboard, which shows up as soon as the user clicks the copy button. + Copy Copy @@ -4691,6 +4847,11 @@ Context menu option for copying the version of damus. Copy note JSON Context menu option for copying the JSON text from the note. + + Copy technical information + Copy technical information + Button label to allow user to copy technical information from an error screen (usually to provide our support team for further troubleshooting) + Copy text Copy text @@ -4837,6 +4998,11 @@ Section header for developer settings Developer Mode enables features and options that may help developers diagnose issues and improve this app. Most users will not need Developer Mode. Section header for Developer Settings view + + Disable high balance warning + Disable high balance warning + Setting to disable high balance warnings on the user's wallet + Discard changes? Discard changes? @@ -4856,7 +5022,8 @@ Button to disconnect from the relay. Dismiss Dismiss - Button to dismiss alert + Button label to dismiss the safety reminder that the user's wallet has a high balance +Button to dismiss alert Button to dismiss error @@ -4908,6 +5075,11 @@ Edit Button for editing profile Edit profile picture Accessibility label for a button that edits a profile picture + + Empty error message + Empty error message + A human readable placeholder to indicate that the error message is empty + Enable Purple auto-translations Enable Purple auto-translations @@ -5597,6 +5769,11 @@ Text label indicating that there is no NIP-11 relay description information foun Text label indicating that there is no NIP-11 relay software information found. In English, N/A stands for not applicable. Text label indicating that there is no NIP-11 relay software version information found. In English, N/A stands for not applicable. + + NWC wallet + NWC wallet + Title for section in zap settings that controls general NWC wallet settings. + Name Name @@ -5919,6 +6096,11 @@ Section title for deleting the user Plan Prompt selection of DeepL subscription plan to perform machine translations on notes + + Please check for updates or contact your wallet provider. + Please check for updates or contact your wallet provider. + Tip for not implemented error + Please check the address and try again Please check the address and try again @@ -5939,11 +6121,26 @@ Section title for deleting the user Please contact support. Tip for an unknown relay error message. + + Please contact the developer of your wallet provider for help. + Please contact the developer of your wallet provider for help. + Human readable error description for an unknown error raised by a wallet provider. + Please contact the person who provided the link, and ask for another link. Please contact the person who provided the link, and ask for another link. User-visible tip on what to do if a link contains a deprecated "nrelay" reference. + + Please copy the technical info and send it to our support team. + Please copy the technical info and send it to our support team. + Tip on how to resolve issue when wallet returns an invalid response + + + Please deposit more funds and try again. + Please deposit more funds and try again. + Tip for insufficient balance errors + Please double-check the checkout web page, or go to the Side Menu → "Purple" to check your account status. If you have already paid, but still don't see your account active, please save the URL of the checkout page where you came from, contact our support, and give us the URL to help you with this issue. Please double-check the checkout web page, or go to the Side Menu → "Purple" to check your account status. If you have already paid, but still don't see your account active, please save the URL of the checkout page where you came from, contact our support, and give us the URL to help you with this issue. @@ -5964,6 +6161,11 @@ Section title for deleting the user Please try again later or contact support if the issue persists. Human readable tip for error + + Please try again or contact your wallet provider for further assistance. + Please try again or contact your wallet provider for further assistance. + Tip for unspecified error + Please try again, check the URL for typos, or contact support for further help. Please try again, check the URL for typos, or contact support for further help. @@ -5974,6 +6176,11 @@ Section title for deleting the user Please try opening this content on another Nostr app that supports this type of content. User-visible advice on what to do if they see the error indicating a note has an unknown kind or is unsupported for viewing. + + Please verify your credentials or permissions. + Please verify your credentials or permissions. + Tip for unauthorized access + Point your camera to a QR code… Point your camera to a QR code… @@ -6792,6 +6999,11 @@ Enjoy! This device's in-app purchase is registered to a different Nostr account. Unable to manage this Purple account. If you believe this was a mistake, please contact us via support@damus.io. Notice label that user cannot manage their In-App purchases + + This feature is not implemented by your wallet. + This feature is not implemented by your wallet. + Error description for not implemented feature + This is a public key, you will not be able to make notes or interact in any way. This is used for viewing accounts from their perspective. This is a public key, you will not be able to make notes or interact in any way. This is used for viewing accounts from their perspective. @@ -6816,6 +7028,11 @@ Nice to meet you all! #introductions #plebchain This note contains too many items and cannot be rendered Error message indicating that a note is too big and cannot be rendered + + This operation is restricted by your wallet. + This operation is restricted by your wallet. + Error description for restricted operation + This relay is already in your list. This relay is already in your list. @@ -6892,6 +7109,11 @@ Section header for text and appearance settings Try checking the link again, your internet connection, or contact the person who provided you the link for help. Tips on what to do if a note cannot be found. + + Try restarting your wallet or contacting support if the problem persists. + Try restarting your wallet or contacting support if the problem persists. + Tip for internal error + Type %@ to delete Type %@ to delete @@ -7084,6 +7306,16 @@ This will reset your contact list, including the list of everyone you follow and This will reset your contact list, including the list of everyone you follow and potentially the list of all relays you usually connect to. ONLY PROCEED IF YOU ARE SURE YOU HAVE LOST YOUR CONTACT LIST BEYOND RECOVERABILITY. Alert for resetting the user's contact list. + + Wait a few moments, and then try again. + Wait a few moments, and then try again. + Tip for rate limit error + + + Wait for the quota to reset, or configure your wallet provider to allow a higher limit. + Wait for the quota to reset, or configure your wallet provider to allow a higher limit. + Tip for quota exceeded + Wallet Wallet @@ -7092,6 +7324,21 @@ Navigation title for attaching Nostr Wallet Connect lightning wallet. Sidebar menu label for Wallet view. Title for section in zap settings that controls the Lightning wallet selection. + + Wallet provider returned a response that we could not decrypt. + Wallet provider returned a response that we could not decrypt. + Error description shown to the user when a response from the wallet provider contains data the app could not decrypt. + + + Wallet provider returned a response that we do not understand. + Wallet provider returned a response that we do not understand. + Error description shown to the user when a response from the wallet provider contains data the app does not understand + + + Wallet provider returned an invalid response. + Wallet provider returned an invalid response. + Error description shown to the user when a response from the wallet provider is invalid + We did not detect any issues that we can automatically fix for you. If you are having issues, please contact Damus support: [support@damus.io](mailto:support@damus.io) We did not detect any issues that we can automatically fix for you. If you are having issues, please contact Damus support: [support@damus.io](mailto:support@damus.io) @@ -7183,6 +7430,11 @@ User confirm Yes Yes, Overwrite Text of button that confirms to overwrite the existing mutelist. + + You are not authorized to perform this action with your wallet. + You are not authorized to perform this action with your wallet. + Error description for unauthorized access + You cannot share content because you are not logged in. Please close this view, log in to your account, and try again. You cannot share content because you are not logged in. Please close this view, log in to your account, and try again. @@ -7248,6 +7500,11 @@ User confirm Yes Your Purple subscription has expired. Renew? A notification message explaining to the user that their Damus Purple Subscription has expired, prompting them to renew. + + Your connected wallet raised an unknown error. Message: %s + Your connected wallet raised an unknown error. Message: %s + Human readable error description for unknown error + Your content is being broadcasted to the network. Please wait. Your content is being broadcasted to the network. Please wait. @@ -7273,6 +7530,21 @@ User confirm Yes Your report will be sent to the relays you are connected to Footer text to inform user what will happen when the report is submitted. + + Your transaction quota has been exceeded. + Your transaction quota has been exceeded. + Error description for quota exceeded + + + Your wallet does not have sufficient balance for this transaction. + Your wallet does not have sufficient balance for this transaction. + Error description for insufficient balance + + + Your wallet is temporarily being rate limited. + Your wallet is temporarily being rate limited. + Error description for rate limit error + Zap Zap diff --git a/damus/en-US.xcloc/Source Contents/damus/Localizable.xcstrings b/damus/en-US.xcloc/Source Contents/damus/Localizable.xcstrings index cdf3391d..24729795 100644 --- a/damus/en-US.xcloc/Source Contents/damus/Localizable.xcstrings +++ b/damus/en-US.xcloc/Source Contents/damus/Localizable.xcstrings @@ -177,6 +177,9 @@ "An additional percentage of each zap will be sent to support Damus development" : { "comment" : "Text indicating that they can contribute zaps to support Damus development." }, + "An internal error occurred in your wallet." : { + "comment" : "Error description for an internal error" + }, "An unexpected error happened while trying to perform this action. Please contact support." : { "comment" : "Error message for a failed reset/repair operation" }, @@ -186,6 +189,9 @@ "An unknown error occurred while adding a relay." : { "comment" : "Title of an unknown relay error message." }, + "An unspecified error occurred in your wallet." : { + "comment" : "Error description for an unspecified error" + }, "Animations" : { "comment" : "Toggle to enable or disable image animation" }, @@ -303,6 +309,9 @@ "Check the address and/or the relay list." : { "comment" : "Human readable tip for error" }, + "Check your account permissions or contact support." : { + "comment" : "Tip for restricted operation" + }, "Check your internet connection and try again. If the error persists, contact support." : { "comment" : "Error tip when user tries to create the one-click Coinos wallet setup but fails for a generic reason." }, @@ -330,7 +339,7 @@ "Close" : { "comment" : "Button label giving the user the option to close the sheet due to not being logged in.\nButton label giving the user the option to close the sheet from which they shared content\nButton label giving the user the option to close the sheet from which they were trying share.\nButton label giving the user the option to close the sheet from which they were trying to share.\nButton label giving the user the option to close the view when no content is available to share" }, - "Coinos is a service operated by a third-party. We have no access to your Coinos wallet." : { + "Coinos is a service operated by a third-party. The Damus team has no access to your wallet." : { "comment" : "Small caption with a disclaimer that Damus does not own or have access to Coinos wallets, Coinos is a third-party service." }, "Coming soon" : { @@ -387,6 +396,9 @@ "Copied" : { "comment" : "Label indicating that a user's key was copied." }, + "Copied!" : { + "comment" : "Label indicating that the error technical information was successfully copied to the clipboard, which shows up as soon as the user clicks the copy button." + }, "Copy" : { "comment" : "Button to copy a relay server address.\nButton to copy the value found.\nContext menu option for copying the version of damus." }, @@ -417,6 +429,9 @@ "Copy Report ID" : { "comment" : "Button to copy report ID." }, + "Copy technical information" : { + "comment" : "Button label to allow user to copy technical information from an error screen (usually to provide our support team for further troubleshooting)" + }, "Copy text" : { "comment" : "Context menu option for copying the text from an note." }, @@ -501,6 +516,9 @@ "Developer Mode enables features and options that may help developers diagnose issues and improve this app. Most users will not need Developer Mode." : { "comment" : "Section header for Developer Settings view" }, + "Disable high balance warning" : { + "comment" : "Setting to disable high balance warnings on the user's wallet" + }, "Discard changes?" : { "comment" : "Alert user that changes have been made." }, @@ -511,7 +529,7 @@ "comment" : "Text for button to disconnect from Nostr Wallet Connect lightning wallet." }, "Dismiss" : { - "comment" : "Button to dismiss alert\nButton to dismiss error" + "comment" : "Button label to dismiss the safety reminder that the user's wallet has a high balance\nButton to dismiss alert\nButton to dismiss error" }, "DMs" : { "comment" : "Navigation title for DMs view, where DM is the English abbreviation for Direct Message.\nNavigation title for view of DMs, where DM is an English abbreviation for Direct Message.\nPicker option for DM selector for seeing only DMs that have been responded to. DM is the English abbreviation for Direct Message.\nSetting to enable DM Local Notification\nToolbar label for DMs view, where DM is the English abbreviation for Direct Message." @@ -540,6 +558,9 @@ "Edit profile picture" : { "comment" : "Accessibility label for a button that edits a profile picture" }, + "Empty error message" : { + "comment" : "A human readable placeholder to indicate that the error message is empty" + }, "Enable experimental Purple API support" : { "comment" : "Developer mode setting to enable experimental Purple API support." }, @@ -1099,6 +1120,9 @@ "Nudity" : { "comment" : "Description of report type for nudity." }, + "NWC wallet" : { + "comment" : "Title for section in zap settings that controls general NWC wallet settings." + }, "Ok" : { "comment" : "Button to dismiss the alert." }, @@ -1171,6 +1195,9 @@ "Plan" : { "comment" : "Prompt selection of DeepL subscription plan to perform machine translations on notes" }, + "Please check for updates or contact your wallet provider." : { + "comment" : "Tip for not implemented error" + }, "Please check the address and try again" : { "comment" : "Tip for an error where the relay address being added is invalid" }, @@ -1183,9 +1210,18 @@ "Please contact support." : { "comment" : "Tip for an unknown relay error message." }, + "Please contact the developer of your wallet provider for help." : { + "comment" : "Human readable error description for an unknown error raised by a wallet provider." + }, "Please contact the person who provided the link, and ask for another link." : { "comment" : "User-visible tip on what to do if a link contains a deprecated \"nrelay\" reference." }, + "Please copy the technical info and send it to our support team." : { + "comment" : "Tip on how to resolve issue when wallet returns an invalid response" + }, + "Please deposit more funds and try again." : { + "comment" : "Tip for insufficient balance errors" + }, "Please double-check the checkout web page, or go to the Side Menu → \"Purple\" to check your account status. If you have already paid, but still don't see your account active, please save the URL of the checkout page where you came from, contact our support, and give us the URL to help you with this issue." : { "comment" : "User-facing tips on what to do if a Purple welcome link doesn't work" }, @@ -1198,12 +1234,18 @@ "Please try again later or contact support if the issue persists." : { "comment" : "Human readable tip for error" }, + "Please try again or contact your wallet provider for further assistance." : { + "comment" : "Tip for unspecified error" + }, "Please try again, check the URL for typos, or contact support for further help." : { "comment" : "User visible error tips" }, "Please try opening this content on another Nostr app that supports this type of content." : { "comment" : "User-visible advice on what to do if they see the error indicating a note has an unknown kind or is unsupported for viewing." }, + "Please verify your credentials or permissions." : { + "comment" : "Tip for unauthorized access" + }, "Point your camera to a QR code…" : { "comment" : "Text on QR code camera view instructing user to point to QR code" }, @@ -1701,6 +1743,9 @@ "This device's in-app purchase is registered to a different Nostr account. Unable to manage this Purple account. If you believe this was a mistake, please contact us via support@damus.io." : { "comment" : "Notice label that user cannot manage their In-App purchases" }, + "This feature is not implemented by your wallet." : { + "comment" : "Error description for not implemented feature" + }, "This is a public key, you will not be able to make notes or interact in any way. This is used for viewing accounts from their perspective." : { "comment" : "Warning that the inputted account key is a public key and the result of what happens because of it." }, @@ -1713,6 +1758,9 @@ "This note contains too many items and cannot be rendered" : { "comment" : "Error message indicating that a note is too big and cannot be rendered" }, + "This operation is restricted by your wallet." : { + "comment" : "Error description for restricted operation" + }, "This relay is already in your list." : { "comment" : "Human readable tip for error" }, @@ -1761,6 +1809,9 @@ "Try checking the link again, your internet connection, or contact the person who provided you the link for help." : { "comment" : "Tips on what to do if a note cannot be found." }, + "Try restarting your wallet or contacting support if the problem persists." : { + "comment" : "Tip for internal error" + }, "Type %@ to delete" : { "comment" : "Text field prompt asking user to type DELETE in all caps to confirm that they want to proceed with deleting their account." }, @@ -1854,9 +1905,24 @@ "Visit the Damus website on a web browser to manage billing" : { "comment" : "Instruction on how to manage billing externally" }, + "Wait a few moments, and then try again." : { + "comment" : "Tip for rate limit error" + }, + "Wait for the quota to reset, or configure your wallet provider to allow a higher limit." : { + "comment" : "Tip for quota exceeded" + }, "Wallet" : { "comment" : "Navigation title for Wallet view\nNavigation title for attaching Nostr Wallet Connect lightning wallet.\nSidebar menu label for Wallet view.\nTitle for section in zap settings that controls the Lightning wallet selection." }, + "Wallet provider returned a response that we could not decrypt." : { + "comment" : "Error description shown to the user when a response from the wallet provider contains data the app could not decrypt." + }, + "Wallet provider returned a response that we do not understand." : { + "comment" : "Error description shown to the user when a response from the wallet provider contains data the app does not understand" + }, + "Wallet provider returned an invalid response." : { + "comment" : "Error description shown to the user when a response from the wallet provider is invalid" + }, "WARNING:\n\nThis will attempt to repair your relay list based on other information we have. You may lose any relays you have added manually. Only proceed if you have lost your relay list beyond recoverability or if you are ok with losing any manually added relays." : { "comment" : "Alert for repairing the user's relay list." }, @@ -1926,6 +1992,9 @@ "you" : { "comment" : "You, in this context, is the person who controls their own social network. You is used in the context of a larger sentence that welcomes the reader to the social network that they control themself." }, + "You are not authorized to perform this action with your wallet." : { + "comment" : "Error description for unauthorized access" + }, "You cannot share content because you are not logged in. Please close this view, log in to your account, and try again." : { "comment" : "Label explaining that sharing cannot proceed because the user is not logged in." }, @@ -1953,6 +2022,9 @@ "You unlocked" : { "comment" : "Part 1 of 2 in message 'You unlocked automatic translations' the user gets when they sign up for Damus Purple" }, + "Your connected wallet raised an unknown error. Message: %s" : { + "comment" : "Human readable error description for unknown error" + }, "Your content is being broadcasted to the network. Please wait." : { "comment" : "Label explaining that their content sharing action is in progress" }, @@ -1980,6 +2052,15 @@ "Your report will be sent to the relays you are connected to" : { "comment" : "Footer text to inform user what will happen when the report is submitted." }, + "Your transaction quota has been exceeded." : { + "comment" : "Error description for quota exceeded" + }, + "Your wallet does not have sufficient balance for this transaction." : { + "comment" : "Error description for insufficient balance" + }, + "Your wallet is temporarily being rate limited." : { + "comment" : "Error description for rate limit error" + }, "Zap" : { "comment" : "Accessibility label for zap button\nButton label that allows the user to zap (i.e. send a Bitcoin tip via the lightning network) the user shown on-screen\nText underneath the number of sats indicating that it's the amount used for zaps.\nTitle of notification when a non-private zap is received." }, diff --git a/damus/en-US.xcloc/Source Contents/damus/en-US.lproj/Localizable.strings b/damus/en-US.xcloc/Source Contents/damus/en-US.lproj/Localizable.strings index 7fbd2e73fe410a1a5489ed6324494609d44a2dc5..655ec870202d9df42768d81aec98e040a497c5b7 100644 GIT binary patch delta 4567 zcmcIndvH|c6~E`(WwTjsmYaPhY#y6LD*`crrk!buNMa}*MU52dAP8Bq8qA#jaYzOu`}!mTT#3dS4DK~F{P)7kV+O% zXKG$ho{1HuR&r)qCR3qJ*^(-?dWN+I>y!LgbkInd&T2ft^lYbAO_Tlr-qg5mO-xvC zVjZFx&w!V@z7E!VYfZu*n%XxrTZGx;Tdw7&73{ZW{t4e*{61AH&>UK>c5hrLQ-`%2 zeBo_BB;iRgqt4jg+R8rvYt6tFrT=#n&0Y~gacMvsojY=-QH2q zWn=ko+2Mz6qrObTwu4j9_+5~mx(1HuvF^LFaK||xzIN519c7T_7feGeQoJAn#MulA zmfW9C|K15s?*KAoOwh!nre5@mG6>u;k~f!m@8&C48%@k+_6wrU9OcCwb$ZnPL5HH& zAAysu9Rd#-iFJz|i z(Tq@|UGTWQCGKh??A3N6%Sfuh)&r(r`b2JKebwhI>EoEC$EbCtd0GE~LZ z?Su@#hLy8oQ+^E#{F1dEn%bl0Q%kPJpcOgFhkLf#Xk(G`$(sl3jyuc;db3zLw``w` z4dp)CV+RLa%>@^p+2V|yIt2H5{dHzc1lcEIq(sUpzUt_FD`VTxZl}W^vK8h3(Y;kn z*~oCLX1Xx@PlC;?2I*8b57O|BQWtqH@xzT0?+k+xGfu*s31lFYN};9a_p&L=mh0X| zmLTv;{z#TdEQx;`i;vg{2vKFI0`Y_{N zJyw1OJ_obxvCAJj1%8_Ku`&uol%$y?x6}rPz>DV=%=0$Y|^|6kj` z8U`+@C&8I2+6fX>W((q0gp*GACrTDH@{dD+;35R_xax2m)H7*ZD*MiI@oh;0; zG2M?-p(Bzxmq*?vsK~p6C%`6Qvc1$u-(KHe0+HVhJpR z4HtxH_I8yPs5C(lu|Q5ONL9ZN9Zl$TF~>p zbDG4i*~D3Y$%qj}Bf-w;YR*K|-l7bs!S46nH_eMOr`Wz!F4Vtm#PZVsNaJ{;3g9_5D3!vWud(Q=)B-)~mSnliU zX!>B@xTTPaTZ0^V;xA5D87i|M;q`dxhWMK}{0Y8G8k-FO@5%5354{(`+wm`D#p5;h zn`1Esb;y6514$xABt^6*%`A~XiwE04Pwm%;Iu|H+`cRhm#1n@!LZJ`9jqAQ};PKto zM8@OH-JSy3UdFnWW&xL8l`xrSv%xNXtAf(U6+|WLm76NQsiwx#{-{pFK*Z9VYMyha z&+<{lY|t}>KW zdsI5U#;y1BB=B&_8?`Y#eNuU8_7}<(7{)mq5&UIo<_&ByamW^?t^Z>K$@3!Dxc0f= zOHM?^byah-R?nV^ZL Yci+-pCafJVK?WW#^Tf8fEzhR@7sC72kN^Mx delta 484 zcmZ{gUr1AN6vyv5_jar6&-Ke}mDF~b%Yr2LAYu?>L`3XCWJrJZbQ1&_M3+58L{NbQ z8$Arq*zqCc5=0idhFAPm4`m@55_<~@N(LcPKJ^fkpmbNyy&OJp_4mT`J@}(-Q zlD*5|^bBM;ISQv${uyKr1TrB?JrZhR8H)QWU%^zRRp{P9a=b&8*We=rWU1J9DDGDF zPY4>^JofQI3mAN_jP0B~0fG`+hN^7B+s?mgETj0I@6<8GFOLMH8b!(F2;OL(t{PDk zw|VKX-p0we9wJ#cRocVN7M4HYjGCUot~O45080(L!IeXgYhMtXpW((g6zakn4s?>7 u6w0>r`v;rE0fqTw87*=PCc8bl$$dw4$>BMWDj(OoB&9wj)Xjc Date: Fri, 16 May 2025 06:21:03 +0000 Subject: [PATCH 05/16] Translate Localizable.strings in th 100% translated source file: 'Localizable.strings' on 'th'. --- damus/th.lproj/Localizable.strings | Bin 205452 -> 214676 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/damus/th.lproj/Localizable.strings b/damus/th.lproj/Localizable.strings index de3dfbb612be3134ea4d716d9cff917a19fba932..086b447b592ede4b6da21af5d19f031240e5c5c9 100644 GIT binary patch delta 5059 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 DbvSwy delta 478 zcmYL_K}ZyF7{%xN)~0Ei9mm>o8DyMR(bZNNM5KenU{Dqw_E2P!qKRg()DjULDi-Rr znUG)Y2NklXGzA-)jekUiL1FG8w9`@%i^w8&NC@)Kr4@p1@4@5od++|;;P?m4>ptW6 z^v%nh9LA6zJ2%=+ZlC7Awpx+;y(`RPVpKL#dwLmEAqcIogVQ+D+_ zy-la^Og*<>Px!Q2)Tgx^4E4|1lH`bzZhGMcLU9r*43mIe;A^VdJaoqIU|@yEDI_OSp5G zsiMK>is*ccUFP<_X3_8!3&5Kt42y|X%ty%ksgZGZzxX5va@GHwDJ(mXH`r)FN4#zi H6srCLEEBPn From 16b19d3a9667142286725f37bef4eeb0d58b9c3b Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Sat, 17 May 2025 08:53:44 +0000 Subject: [PATCH 06/16] Translate Localizable.strings in nl 100% translated source file: 'Localizable.strings' on 'nl'. --- damus/nl.lproj/Localizable.strings | Bin 210644 -> 220062 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/damus/nl.lproj/Localizable.strings b/damus/nl.lproj/Localizable.strings index 4ae621c5f9050a29377166d581f027ba76b20a32..f66cc1cd01417539d745c82166640b04e74e9a3c 100644 GIT binary patch delta 4865 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 delta 455 zcmW-d!E4iC7{>Fy$!ZMWMpk1ep=5Pd1(`934iOo}lQIl{4}%+L4uswE!%c%6T-xPFoDgq$a}SyAjHn?n?p+;i>v-3@` z-&DYB^f;eZ8<3N??;F%Uhk~McxJ8r4FiplH3b|j?<@-R;Mgsyld1siiHl!)JhZosg1e+2E4EgzPTDGeuU)YA|Fi-4&)Ax1{ z5Eu5q;P?+@4)&7HB^7_D6z9RE)>+6 Date: Fri, 23 May 2025 06:34:55 +0000 Subject: [PATCH 07/16] Translate Localizable.strings in de 100% translated source file: 'Localizable.strings' on 'de'. --- damus/de.lproj/Localizable.strings | Bin 200030 -> 225658 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/damus/de.lproj/Localizable.strings b/damus/de.lproj/Localizable.strings index 9d1e54696d255b111a1aed0d36e794e47025d070..555608af469ce0c0114448215c3a9d01702ed78a 100644 GIT binary patch delta 15770 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%0Dc8cNDfCx)ziXVEC6fO5`wR- zRXZKHEZhmrozpDw_0&DuMg$BiQS^26&7FL7W}J{n)wffCV8Z3nqx_%g*)M?#KTUSB z9ktnd)vAs1-q$5LDIRaOyb&z>8jfWixv;D_#hrLhPS{(M*}TZNWoY+v%4;tf#LHa1 zWDugN!z#lRj?1P;5Apd?^a))^gJOL7|DR84-;5-{B`f1(j)AHwD z{+Al0-CkF#7SqEdLY0A$Ss81qkGwu=Uy2=d2?Jx_*vXK*kS(dcO- zgF#$@{6<>%ln&Ija(IeUVbfp|(q)wdZTG`ZdrOaBxsilcUVpj-l9tS$D3gE!5CdUGDU7X z*nqFUrXL(z{&>bgDx_9;FLqQR3vIb4NJ_e`fPzt&|JPUerU;$P?RwT(&qK@I=A ziktA$_;;D$YWs8=hhvR>5nXdkIh(dTr>=?BKcS;ViM+*URwc+SkQxyK)Awq1(my`r zdVcTgI)7~6qXec>+aHp`1%BCS>?Q1$BzCPzC?~aCoy1}|1PeIf&cdj~;g|40aPDRN zzl0n@>6Ajo-Uu_#PR`AP)E)NlEB=Qvl2Z7RMeOivS`X~20xxzzF*QfVVUv5hp)s;; z7}-gDP@rrXa`wVzy8oyyp5wlw5byE2HUvv7J7rTfiOEtAIpjDG2mkey$J{Q~^GCfr zjks9NH?Q5{OI*f23zwB~mq4h5^s1f80Q}3xYfkE6oXJ6eF?qfDt_hV1njwB9p5c;c zD}xM-W0A_a54-0R?N<$Vt?L)`_on#lS(Nt|9hd_*kN>fhbu2*YrTlC;I~3NCEa0v% zumawaEHItdM2JYg0HI=6ry~#P;@IsU>ILbz#gd!w5L~Rt<<1tQb!sKp5|@9re5gZH z;%erF#kU);4(q;Lu#*E>7{YC@zkcK|1g{pAz=tUV9ybq~oJJc3=gZWdVC z9H7Il#j8Y7eXS`ada#Po)QF(2!|cly8zUK@>5K&q_ev`|Gyi+Ozz9he;6 zE_q6boh#PO&VTh+OKdssCnIe-&wy+OheDQi%AqFKZlD)8NQE8eG#%L;u?)I`P90iE z4n=XtBDjK-s7YD^$sOxq2C20YR;2V%I?q)7HElpr%t|`;vG(^Djqofl6qten0k2@G^DzQj`v4XovBIoF+& zZB9OuH9oaoIrWMFJS|z(A{oN^ag?MDcd4SBgb83w^Tl~wp?Fo6^9PvRjCArwLNDkj z*}ct3-J5^~0?xUT3|9tm2Wf{R!+~%_(#NFyDc{k4CeR8%dx>Og5hOM8LN7HfP^7`y%N`as@)1FH&%=l}o! delta 1840 zcmZ`(eN5D49DiPZ2j_Vn$8nsBgg=4IDV~Sa$?$>0EOM1PEVd9(NkiNgcUIwh^VmN6PSCMr!b1i}xy2T0=_l z)sK{Iqy+DNqGZa*c6`@SqMX#gxfq`EqCP6%$9)GbrOt^g*~se0rP%A>mtmR$6((kZ za5S?D*M2jEzGMk-7<3^&J2BO^>(Bc9KI^kO~{8um~tv{c|P zaFywz1&l$6+L(-eBS_-KhTU|#jO@cP=9=! ziO}zkVB?c5sAm~9L)gipptqJ9V^t|C(b4T#gc6lQF|%}TY|ekE=_|&M%fXN;ajES4 zq5A=y92^|BL`T}@G^ec|@V?42rDqjg%V6UidQ0A4OEWa}J^@-<*i_lLnI>w_Z>sUK zXA7-}dd9y8?bIZbd^9&%xEdU=@J(it^#`cmAWZL=r5EUK9*G(H4rAAuj^J^wuyMu|XPlI*)k>!}#z8u%{KRp8B}3+3Uj z=^GP7Urz!SgFB!(37v7?rW#ds7Tz;u&{xVeF>u-}oA1(wIF)b>yib?|I%jjc3_qbC zQ_w9eK?eSyPa{WDcN05hP(-7++M6UB%xn&(XFSc6MjNvxLDqhjCISm>(3OqBI%YFw zh=kad!A^;;JPXX5&yHik!P-m{pyM@elD!#BV=(Au^W^yj?6)|vuiq*&Rx%cYkvl}w zq$C-&neC>c{&gpKy)0L@ma#ER zIuk;IPLzp)iBn~Cr(jVq713-R}9-Dg3qwRq9HU=f07MFsx33WV8fc+*Ug5aW#~LxA1!^~ zv2Qd{a9xwW9+qi?EGsoZ?%)3MN$;I>{gPR)rQx4NSCh_uT(|9u+IZ zeFqAtP?fQrc=AKKmB&N#b(#pNrQGKJCl@M1xulmYA%(<^=Nz&W_agi}cq<}{BQHzI zDqK3!RwJKI7U5n57nIVec5WGyjZ#I(kp}5@9tSt9Ji(nmN>f@rcvhN}jx`YrIcT8} zDeA8z-578FsMS2w@45b(FG0`Ki?~pA{{?H=A#U>egg>Td%6DfLoQz7dT scANe(Gs?YgKEVH$P>>rX=j8DWgB)1NFB_z`j-RAprPL)mHt}%mU&_BH(*OVf From dbc7d79ecdead0e497ee6a29c92ba3dced9f5715 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Fri, 23 May 2025 06:37:29 +0000 Subject: [PATCH 08/16] Translate Localizable.stringsdict in de 100% translated source file: 'Localizable.stringsdict' on 'de'. --- damus/de.lproj/Localizable.stringsdict | 48 +++++++++++++++++--------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/damus/de.lproj/Localizable.stringsdict b/damus/de.lproj/Localizable.stringsdict index 8d9ad0a2..3adc2434 100644 --- a/damus/de.lproj/Localizable.stringsdict +++ b/damus/de.lproj/Localizable.stringsdict @@ -50,6 +50,22 @@ Folge ich + hellthread_notifications_disabled + + NSStringLocalizedFormatKey + %#@HELLTHREAD_PROFILES@ + HELLTHREAD_PROFILES + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + d + one + Benachrichtigungen ausblenden, die mehr als %d Profil markieren + other + Hide notifications that tag more than %d profiles + + imports_count NSStringLocalizedFormatKey @@ -82,6 +98,22 @@ %2$@ und %1$d weitere teilten + quoted_reposts_count + + NSStringLocalizedFormatKey + %#@QUOTE_REPOSTS@ + QUOTE_REPOSTS + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + d + one + Zitate + other + Zitat + + reacted_tagged_in_3 NSStringLocalizedFormatKey @@ -242,22 +274,6 @@ geteilte Beiträge - quoted_reposts_count - - NSStringLocalizedFormatKey - %#@QUOTE_REPOSTS@ - QUOTE_REPOSTS - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - d - one - Zitate - other - Zitat - - sats NSStringLocalizedFormatKey From e6a03522c684c324b512710e908b0151efb8d630 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Fri, 23 May 2025 06:38:29 +0000 Subject: [PATCH 09/16] Translate Localizable.stringsdict in de 100% translated source file: 'Localizable.stringsdict' on 'de'. --- damus/de.lproj/Localizable.stringsdict | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/damus/de.lproj/Localizable.stringsdict b/damus/de.lproj/Localizable.stringsdict index 3adc2434..ff47921d 100644 --- a/damus/de.lproj/Localizable.stringsdict +++ b/damus/de.lproj/Localizable.stringsdict @@ -63,7 +63,7 @@ one Benachrichtigungen ausblenden, die mehr als %d Profil markieren other - Hide notifications that tag more than %d profiles + Benachrichtigungen ausblenden, die mehr als %d Profile markieren. imports_count From e74c45ad39691e9191e6bbf1647a4453ada4ec15 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Wed, 28 May 2025 03:10:21 +0000 Subject: [PATCH 10/16] Translate Localizable.strings in th 100% translated source file: 'Localizable.strings' on 'th'. --- damus/th.lproj/Localizable.strings | Bin 214676 -> 214674 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/damus/th.lproj/Localizable.strings b/damus/th.lproj/Localizable.strings index 086b447b592ede4b6da21af5d19f031240e5c5c9..57de5de3998aebe9d52a9be1bbdf679332efc95f 100644 GIT binary patch delta 35 qcmbQz%R8x;x1oixg=q`3o;a^EpDCXcpB$eSpD3Ttc3W}gaD4!)W(XPp delta 37 scmbQ#%R8l)x1oixg=q`3o;be~pB$eSpD3RXA2**TpYe8UaprJ+0J=*ER{#J2 From b8f846ded8a9438964b75e3722b2eae2169af084 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Wed, 28 May 2025 03:11:09 +0000 Subject: [PATCH 11/16] Translate Localizable.strings in th 100% translated source file: 'Localizable.strings' on 'th'. --- damus/th.lproj/Localizable.strings | Bin 214674 -> 214670 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/damus/th.lproj/Localizable.strings b/damus/th.lproj/Localizable.strings index 57de5de3998aebe9d52a9be1bbdf679332efc95f..0ec64911fca02dac92939681885fea2bde280472 100644 GIT binary patch delta 25 fcmbQ#%iGt>+pvW(%cMQegb|3Dw&$5Js|W!AcT@-u delta 29 jcmeC{<(<^a+pvW(%Y<2rPozE5gb|3Dwr83!s|o=CjBf}~ From 3da0ff7eccb96742e8b62659560ac94798254c10 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Wed, 28 May 2025 03:12:19 +0000 Subject: [PATCH 12/16] Translate Localizable.strings in th 100% translated source file: 'Localizable.strings' on 'th'. --- damus/th.lproj/Localizable.strings | Bin 214670 -> 214664 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/damus/th.lproj/Localizable.strings b/damus/th.lproj/Localizable.strings index 0ec64911fca02dac92939681885fea2bde280472..d3b470d5df28991c3b98c8e6ee353b9fc3e7cc28 100644 GIT binary patch delta 29 kcmeC{ Date: Wed, 28 May 2025 03:13:58 +0000 Subject: [PATCH 13/16] Translate Localizable.strings in th 100% translated source file: 'Localizable.strings' on 'th'. --- damus/th.lproj/Localizable.strings | Bin 214664 -> 214664 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/damus/th.lproj/Localizable.strings b/damus/th.lproj/Localizable.strings index d3b470d5df28991c3b98c8e6ee353b9fc3e7cc28..6ed726a2436f3b32ef0d39c3e91bc84ed275db3f 100644 GIT binary patch delta 49 zcmeC^_tnZED Date: Wed, 28 May 2025 03:14:03 +0000 Subject: [PATCH 14/16] Translate Localizable.strings in th 100% translated source file: 'Localizable.strings' on 'th'. --- damus/th.lproj/Localizable.strings | Bin 214664 -> 214664 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/damus/th.lproj/Localizable.strings b/damus/th.lproj/Localizable.strings index 6ed726a2436f3b32ef0d39c3e91bc84ed275db3f..04d59229fda8c6a92a583750795c3209d627309c 100644 GIT binary patch delta 35 rcmeC^4;1&@T9wd&io>KV6d)icE%2LRCx3}gTR From b6dad349c9024b2a4a831c152cda3b489b85ed20 Mon Sep 17 00:00:00 2001 From: Terry Yiu Date: Fri, 30 May 2025 12:36:25 -0400 Subject: [PATCH 15/16] Rename Bitcoin Beach wallet to Blink Changelog-Changed: Renamed Bitcoin Beach wallet to Blink Closes: https://github.com/damus-io/damus/issues/3056 --- .../Assets.xcassets/Logos/bbw.imageset/bbw.jpg | Bin 14355 -> 0 bytes .../Contents.json | 2 +- .../Logos/blink.imageset/blink.png | Bin 0 -> 117314 bytes damus/Models/Wallet.swift | 6 ++++-- 4 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 damus/Assets.xcassets/Logos/bbw.imageset/bbw.jpg rename damus/Assets.xcassets/Logos/{bbw.imageset => blink.imageset}/Contents.json (79%) create mode 100644 damus/Assets.xcassets/Logos/blink.imageset/blink.png diff --git a/damus/Assets.xcassets/Logos/bbw.imageset/bbw.jpg b/damus/Assets.xcassets/Logos/bbw.imageset/bbw.jpg deleted file mode 100644 index 969ef582f2a1e19930191ed84331aaf719a0a82d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14355 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 Q|A{vIe&&DI|L+X_4_ee6G5`Po diff --git a/damus/Assets.xcassets/Logos/bbw.imageset/Contents.json b/damus/Assets.xcassets/Logos/blink.imageset/Contents.json similarity index 79% rename from damus/Assets.xcassets/Logos/bbw.imageset/Contents.json rename to damus/Assets.xcassets/Logos/blink.imageset/Contents.json index 0c0ac3a2..5ca2354d 100644 --- a/damus/Assets.xcassets/Logos/bbw.imageset/Contents.json +++ b/damus/Assets.xcassets/Logos/blink.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "bbw.jpg", + "filename" : "blink.png", "idiom" : "universal" } ], diff --git a/damus/Assets.xcassets/Logos/blink.imageset/blink.png b/damus/Assets.xcassets/Logos/blink.imageset/blink.png new file mode 100644 index 0000000000000000000000000000000000000000..fd20c2f1e13fdceb68214e8617ea933849702b65 GIT binary patch literal 117314 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%0D;@ty~|Y%97!Y2R=@NkC`ve zaX*IuHgXT9GyraY=vP6gpTwR-K8oWqUV8k_FuL8iOi~6rJfBs1a^EvDN;cOYd4i=) zgsR6E5NI+W7$8jdb^LbNA5Kv4c=u9C=^U{MiffX<_UfCOulCADcF4n{kc`YJ?E1$v zPX=zD5Hd6&Q2ET*fCDx1@}bcu;C5K8b3ONh)FdgmJD5e#6HfwUGQ`wlMAG6B?v@y> zBt*1?k&@!>0Q-GB_odOc!vvNeH*oR*RlD^g3QOi4dO_|8hDg(UUW~X>@z#U<5hpz1 zIx_u&Geud13KX(;`G3_6CBTx6p$j2yP>9%7_6bUdZNOyzyqSK;AsfCxv`NkFe{OYg zPPZ@Sfnq9`Tro3IoFjYFqotU^x5A1ZKqCX)xju*>jrq7mTuuoUAfT~Y)l#xYI?%() za!%~!nontG>?u<5OnQQ}hBMMr{8D(WXv-z_zyxQMG|Ml$!ePF~JPIg#q(x zdeRv^VSTN9$Z*DC$25^3;!nB=TxAAGZ=BYB?$5J9y|C z!x(p{9ob8T?ut0h2D++Sw2?yN{~og6=UPjox3WGF&WTYtj@|qip^HO1$U0X+G!moQ z7v~Nx`$)$?q^tM;D_b_N7Q$CJKtcbHSP2Lc?T+lJ505=Q)u?`^o(+bE*V%y6p<;ocp%y5YNqa$90pAJimv=q^hU3bKOA#SI^7S z(r3Pj5+)ud@#ag&MD{8&{`b3vm8XK5m10Ji-@k0WU1C17Ao;bXdn*K;~=eiT^Lm%~<=p{sPKSEoZYv6n=oC;A2 zT@^9(f#0<*!NMssRAS-$xvI9;-0{+xn&*2X|0D&Vny>xG{hF*D{5c^S(W3Ve7ZEhs zO697aaU^pw%=Ka;oIvQY9by)Sp!4KTldywy1C<}?!V^mKM zayDU6Kxt%fl>n*Dg%|LFVr3>&1$y&t#94|I*+VzS2+dsmp~rHEzRl}a17iPjO@Lkv zoZARzOpg9cq>Xsr)DH4|skzW|`#E`Fn&^@59w(Xg&AL?%=+gXyWg1 zUgR`MG2=b8#R5`OD2-Yg4C7l`LEm7=J97#&NQwYl#m6t-xBYU(;qM=_jxcvJkrEM! zBRODEk+^p$n656AZ*<+v)(goj_wR}couIG0mhP(<4gWm)Fz1fUV05El|MdzjhZ&if4v7UCk3c|slh^z{^u+73+JOAJ(2?V} z?*tt$uh)pbpX2{br`fg8+CNZuL62*Zg2H~@~-^n!Xgn=@x?*TYuIxMrigq*q1)rv6-AC2fn1#Taj0>dToYQL zvzFSw@r%H)KW{WB+Pa1)#Kt-rUb5LjT91Av2GFcT4w9*cY&js&s?dKU$dhYVM*Y+l zpyq~bGeUsU$BG|`Ryxo_Z5?IkFG1d_mK5(Gu-zG|Z==58m)>~8Oq7yeZLTZbV5scG z`Z8Y2`1QI|u$lGJpE#Qz)=6k9iRMS1eR(X6*ci55m-pLf87spV1P-UtwRTCbSZ|PI zBv}<^&VrrbK>lK~(?M?lj@BUp5A}@3SXA3SzeHv6{rny&*^A7igcbmXN+hWW0{$$FeDRJxm`wvv|~Q*iL(?h8yY@Bh(O zM;>&7W-Rk{dAYRm?trX<@18K{^Cen*4YN)M2lEg1>z?8?_3iW(3P)2K+V}B^@iA&M zYzJm_!S#)&HB9iB^$LOd>+sXO!Fv=sFEEEzPVnpp!#hptx-A?WG6GRVzxSw3%7?&A z`EpRlEX$%00kYb7{d(!~vfM353Wn@C#&5N!K>l)Q`hU(ckZ0pr)If{_2i05(B|{jP zO+4M40a5p1(b}x2i>eU-R_bE_L3&N}K}N@{Qm^V9WqZlv2&hGuvrwT`L>g)FLNi=* zVPt7WYB-LwCOsc!vkb<_>dNx_T1yz#nDaZ#ZzCiOKL!xlQ)}LgSwEz{>2p24f-0nn z=^kD&Z3fEzH<| zGOPRNRCreB{qpX+_7M8sCoz5UAXqPr!e-5}{t4af5F^}Bm{tz000lqK7O({yKR>@- zdN|$Loq&c%llV&;a{DZ*RqpKeg-8)(3+SH{NeIS=MO>_9l=aLYwNcmR4PCtJ!Tch^ ztj6mLi?YEnO5hza@+CmX+6Ht;dwvow>%kbm3AzNuKPNYnU*9FtlGt-~ywC6a{!g|< zz(es*lO3Q$h{R6~CnqO^YSKb5_-)tV99qqzz^5%Jn=U+E;sXBBt zW3_T_;RVw@jYm^4A0c6CDF@i|!ZmhPDvRle$`SN5O4n9BnkT8-W;A8a0mri~xz%D2we7Q~tF**{MeuE)wGxe6eqBq3pNZb5UoXx@Xy+3-$$N zUn;9z^C)p$G@~88;!}S^auYv6#48W3$8lO3spCh=VN@5|_~Mk?kokZK(}J^Upy0`U zU07N;UqLCF+?utW5|BPe5W11KQ8la+P2*V$sZ${MJY>>X%6gj}7Sg|;ta3Gf!_xCd zg>piSi*>8=+_1)5=O>r%57@$3P_*sFy9o_F4=>j=6GoF>RsBGZv2DD8so6H2^Qwku z675}Gi<51T%7}xFDFP^<4+BbRK(%g)xSKPwB~Aq9-K{`v6O5GuSrHpNK?A;9t!sNE z&5}?j#;}uG-=@M`7@@VS$wK~_t_D{|JNG)FsgQf)`Nat7gTvZ`o$Yx2K}e=NNE&ZLwjOcXM2y$!B_VW>k}5DH$JzDoij~MTBuROA>%b}# zl{dmhz?K}@nXZ&r1$FpeZq1aGr^L8CIeS?|sbcfvGMj^Hxv!AL;51}d-E`tn;{5$N z?dTssa=1;Vn+~mLth^pkRDj3FA9ycoO>~KV!ttKRQM5XE`r)#Q0%N!sY~04!ArF=O zL?WeBlI^HY^6UCFxFzj-AZ*wHsCT}uNdEjKi|)B={0hOA8{CRMn^GxApL<~Y^R2j+ z{q;Vld3f4B=(V+NRB~|I9-#2RYD_->{&|nZ{HfX#S&sz;-o1m5r>JGcRKj!5a%qpf z`)z$?eY(SLJZ^oERW{7V5tv|*vg(B;nbnuf(F!F=%ci+$f;ODCTHj;Y|j-jW4iTQ=nBWl6v~_G z#nwjwv*+{cf0V>Woj_9J9@1-KRXqR572sJSI91b;A-nR3#tGiRT<-9@n2VUC7hZcf z5MbedQ3yr@H!3*HN+w^%op;~XJzp^aYUkW@kcwVPZsnCUGua|)sdj>iO-lYW_1TPmB;iBhKzxclJc9 zIn1j2rvRH-q1QRVD_Vhgr4lsmjA&9c)*i4V@KR7bD{gwoaXn2V^VFv?9y?Grb6CpA z-!*lhH65fkwiB0I$Wp^x*cd1cz!51>+{gdUx9HLpf*HldL<~SnwQIMlVewceAD`r_7_ec+pNtWDWAEgYk1t7o*Lp49U=fy8$)gwy z&R`f)-X)AA;EtLoqlgUc2CQ#0;}>o&=Vx^qN)%%{0L zQ`jlPh!L;xb@lOyNa$M-34dO=wHRB$BCJg(RXTXFIKk81wwuLR6IPH_`kn@Cg_6x!BCXP& ze2st*(#Tiay9OGe26w*_p{;o4QZ1!FH^$t*ru`I*PP;}>2nf8!p4bal@cPqG04YrO z8~Q__`wSUDeXx_f)4Jd}Hy`+n0MUy|MTFB6yyDHl#It0d0i8R{@YdVcet^z(Uw36_ zyMtAMU0_dl3npbNmd(aDSNYi1Axwr)Q}DRX&lv*qf&1zw^s!hzpa?uC1_%02dD;*9 zCGNze$r>}Na8HM)t2z}g3`@VDwZkZ zJ!bzw$`2{!{7GjJE+l!XA7{2-vF~7=Zxd3=jnrktE{|nT>EhoJ6>g&uJhINX$M`i$CB)9MSEaK4_wX=yE*8 zmzfJ5E%JBPJF}#m@hu|DPG$+gE46Lj4c>r9E}gg9(0j)%4u@uaQ>8ve$M=%Ifhh&j zP%?Hj%z_OYtCEwaH!tC{DtOG>qM{;vkN9>0q_p?x7~jVp!W`!E`9q>1DZkSWAQB=} zg|WG*X1cJ`c)kAft)K0sPdAixUVu>ArhFykhI55z6=UR?;V9bqP5hLK)m+6KZV`IX}k90*nLLa zqfJTaK+fg+xep{g18-A@+_hh9g8MPbd{@3rt^K0B3e1g&K){oF4?)?v=dDYs^icXU z&Ft#6foclT)8Bs!ju2WRoWFmO3bO`wo}!!_PxYhY$=XLyn)npC@V5b=UNk3gfHJyB znz&o6MxKbo%d3&nERc+I7gMx%ez8u3-TiP%QjXHxQ2x6Zx@upUu5#e?TR-_TA#l)v zu>`Y$%uzWkm2t1Zsb72tPH+?}DpuhTICzq`nX?2-^RQ?x^agnXP(+=DahqIVB0q_( z)C9$`_KV}G7||Sz)eD&Od(&nonoO83gT%8tp36)`h*?!Lr*U#3@bj3!&r>is=LS;S zy0LqqMV+JA%ym?2=jKG!gA13b`2C2q<%Z|XMIdc1DJ7-IgoFezy)q&ZgieA%s6D_+ z(gOM$2TWU=z0PYQJxu-lWi|(rqd3>+B;q^LT~ARx zSe!cu&XK!ghi|CSoAZh$XfEHw$ITM=zg=8+o=5Y;&b}WTz{fxregef}dBIAFLu!0O zaSxRmem~2<8XsH>YF&fxtP0xAi%niBFnY`lFj<|>poaH~H$92O*rOqQ48r6i*#3@QkV*;AXB4OW42Yu+6* z>)7H@DEt*-ThrF+g&%-m!(#W&$NAGO`W)4oo<#zG?Lv z_n~yi2vTP5J2)V~ZdU_<1DoJk&<9@2SB!9~M$u4*28PZWUE84QDk+YAS7ALTyLiczzUI=*K@h4(7c`@$ttS^? zh9QGWtofhs(BmFvH)HF07z zM7ZVcm7KU#JPg4A+?3UQCg%vV9!l#6Q>V!O9;qQ(ej5>uq z{^zu}@d856mEm{5k$iX-7Z?9WUAOdm~hY71+@W)Poe1Sb)`upq0Z(SIOK3Y!w_SL*QK)VjuG; zTqHX(d5ocdOIPLRlAe~{5l zfls|JtO=KU=MozwUK$PL|MGa{F~?P3hB)ON63{ON|BH;J9(X}8pd+@=wZQ-L;^WYi z@HTJuNYpn%?6kbthqa+{i?g=RI@#OTG!~~xH7OykuwkgIA)6SP26o@HTVo|XlDf{0 zu8nsuN=^s0Oex|j{wQKuHT{u92Iq5^W?r1$B)`h2F478)WEqot>9e{G*s3xQ5RQSQ_IF!Q6d$XkW1M9G9m{L^YPsOS?I|*tb>MMj1QPom9_9N{9^gz!v*ep zs)G_%`-97crA4;C96r7&(C$eDw$nG4l^iOJ$R)&2TJ7w3AFu*?avrC>{HXIKd^E*N zs2iI_5n!d)=d`S!wYObfSk5*x5ai`C{}p&RZrP-Fn+RFr^rNI1?B0vCn<|ha-;;nz zV2}P%U&L+7fnJOkl#%o%4G82XD~~fY6$9bl?fMa?0Nrf2DF@pVruoIi=`5?4#97L9 zW%N9`a6_!Y2Tjnua>92!yn%3Ah;T{zq7$fo!0?LzBukbflXyT~_|Nqx&X!(n1UBEV zk=U#GcF*5Yys;Hw_=RHk2KsKl@2aZ#yB1Y?hTka=w*32)JWg~m&^=fjvg|NU`-G{% z_4*dtp*RNkGU(zNc4DNRt6Y@?FS%nqhpv4~`T&dGg&nOW32jG!HGcj=*L&!AD}R!% z%4uG}12cO~AAJFX6o023*am&$Ty$`5j+;?DD9IZfJqzjoSowYX2~Lf0Q*LmF z@fdDOe&?fO3huoDti`>#)ET^D58P4Q^b_|GF#!NP*kO>qaF+}CXf!sKjQa7hH5G9V zm|HegEjOP5uwBvZWxSl%^6(AilXnBmVihO)zUQ*8t<)go%?Q&x_@ZDW<(_MEhP_J% z|F&=?%({Cp4EMpZKr5A`8uFn9`{SO0R?fnIm8|DlhGj9)H&g33#2qjO9!462^W7ZC zo3-_9oSNH1q{97i%p#;?BBQK4FqgGQQU4gpr-QcArU2YRJVpY(68@-yu@b>M_^feR zwXQ4eP%lui)}2`Y0=AN?>c@GDUVzqi@LiVEn*O(yxRxuRMh4f5OImf0Z(1Z6FWpIM z>Bw#`diEn~zV3?vyndW?9*eol2<*GD!YH$K$y__yc#D5WB zi`yHOLx3nj2Wp;x=NTXxfQG>yByK!30=^RgmJ|K2ExN2))ulSv*f<_@m8`(GAJOuR zA^UrmD9p&lh9X%V6PcDRDp&nOiO7KK*HMdm2(Y5iBM74FdC{UD7f7`ebs8`j!9q~q zp_a<+{M-YA(gThuBz|g4QLl0W{_plelw>NT76TbGt{XSG!I z0a^PXjvXkaci3Zyz@o|}f%A&YJtjc2!T`?nzhyc^tT^JMg+`Mz_=lh@unu&B{9BAw z7#rO$tMY0_qplC*&whRGoIU!}EBE$-nMfhDBJ=hH>vGA!e9WYMe-k=Zj`cpHFy}hI zkqjFsf+aFGJr7@JPBfq*2!3}n)fVue(tV#-p9|dp+9fU#p8MC~Uh31ZZg6F<)y!$q z$6K-)4@}%=&fS`oRio&TPsv%vsl>_yW9f?@N=xPcs{Ue?P}L&q|AFtfwvs`~1_Af( z@A4J}M#qC($?N@x*D4mv6U*tDhZN?hBM_~H1#-np*MlA6W^pwp)w^RPtHS>qY?JW# zgCpTz2C*jNA@&!WN%EbNmad~(OuE9xp+4aIrl{)6Y+S%PTDxCeq$Bv|0b{mzm|pZa zHvx48P$t*M7X)l+&3lR3U&;QWywt8{i4oa~Qx#sg3p;<65Q1Eyvcua+)fPRE11aDy z=X9h4y-oPP86RkH>DCk4bKmW=-XCn_bk$nL0SW zL)QE-w6fxCqLdA`{>fK(%r^h)s(8to?!Sp8nRB{83F?PYHPjKy$$*&KC$51IWVrm#&e*!X1dEF4Nx*9r>+sq^Z5E z5%40(zm{c|JGnPT#dmz|Ad8>J%?Z#W{-=Aui@N|jU6uz)!gB#Y%xA^F;sIlRcP7g` zxUT7Y3D@`g#{HiT|K4V7Ka#K>Ka6o_3Y|`ixJO{K^~U8ct^oiM^~nXzPn8gho(~Pw zR8h5!8cYT*$9lyGZBg7wP|c^8nDqGjez>7BO0*9(sF!MgzkPwH@(CgULPnsxg(3L2 zjHEk7LsSF#mTzn)C+*HDN|G>@vG|an>|6euHZyfh2Dy2NCXit@ydG0|>qBZ{Sr4D} zT7+O7-dD1Joc=5xBw6NIOMxCFcnV-E^{I`xkRW2!`V3jygY!X|umAZ}@j-HD4P*k@Z}pdx+gwOJt@ENhD_xs5 zmDo4#^B!jhMhylDVmwBW&qV`&+$AtpO3v**AC}0Xn-dCote$H4o1pmWi!Be`cn%g8 zP+vY0{{rd6;l~N!UU6bT!f68uqT2muB)dl=Eucf^s-pp06!rp47E~wB#?~s+pEWSe zZqWLPmQl8%s$rzo1cv}@y|S;$yZ|Zo}exXK;@4$4)ItTIPI#3);_0M;^BW+ zWXI|=<|Y`(NY4JCXb4Za+q5JdS_zkNKdI><%K>}THXHvO^Yhpz2V*MPYSY%b^F6BJ zY{;mWZC+ne^_U;AL967Eba1@95%Ba~e6NwLJ_K4T%#a#b9R(g#Uam4X?K>arDbN$6 zGY-?AmP`q7+qoZogY4PkQd2UbJKHu&?%O}xFF_kmR=_VBn;6>)MxE0amdd>=;j%iT z$Ck4BMSK4x9^6jz5RWb*6dLiyib@|XnOJoO8@zRG&!8P`!oOb-%Kw*MK$z`U;RkCJ z=l~yk0DwSlznTwAx*w;NJa(Ev>iISM*|(%(+pe#B@|8VUh;zf{99Dd*qA#3NOM_*- z4Y+UxJ6EdY`O1ORwzoPeL-GHJdh>XwzxRE7#=b^mOWBv~ThYcK%9@>!r6OftlV!}1 zB}GI?$|TB8lzq=0AzSu+U&lIQn3?YxulMKo`@&%T3**iZ&u{@es$2|c_H!UnPF zahj@O_a|6gRAoL{e{E|)yb^)f(M%8RY(zfK-kEw+_jsp=oA7D?0$ff&Hwxg^gG8zv zX1?%!GT;%|A5wI|D&kIYkju{Nu@a)>S(~jxTYBg_n#OaktkVQ*fEIaYBX}E1kP7@H z;(&BEKpnjJvOx4wpcvj2UO&94VzZARo*6ud>(yy%i;C%6y(Y+BUGIm9a*UC{&k4p~x z&&bS3Y7K#E5H)rfW)qh`U8T+ixh{-!6XRC>*Ph85VWh#E26^>U3wD?*4+L|TK)WB`gYFhpdiV%Fvmqfyjou)rXzV`CkRH<; z!U@Pgh2kc=nCd*qP1jgJt7>!joa@>1p`NBFbq^t{|##7i^t3@b}W zPCBu}w6E?pl=L6KMjWA1?H~g^_7>n+;R#+BVyS+*%>aiKoLb{+0AXl3RW4d|ji)Ad#7j6eowmK!$z28NO{D$7EApu3BZC zg=3<;9&kbU%&uj4l@Vrt7mY5lbj8yx66?saA^RkP&`jqx>e;+n!3VmTkE)XgMK5rd z*G1bhs{bK+HsTXGxjg7U6pGaZ6Ag-;L0+rA3lhUQz*yx3QXas1F8NOxLeF#)4e|H| z+%13C!;i65x3s8%LTk1TRwj=1T~*~dI`%2@i!)?c;H&D^qZW|Q z`GBHGchGS8Vl55--mRMy{}aTJBx?T)X25Q`OXa4zR^0dhyP_9wrP!_L*S&37x$RK- zSNZwGT$-3q;+*Yy8a^SWeciGTv~*+;g=}jELJ)9X41DQ!VT5qtx<(u(CSM4MEPplOIg)FFl>PO^2Hj8V&8@w3YLP7FGLdI^BK8 zTxu^OBI4PrjIjrtTh0p?T7X2d#A8|opoJ9plkj-ySs?O1HEXp5!DiKCXuxQqx_H`P ztA8Pj%o)CV=-<`LbyDNkaA0TfXBn-{(I|&hZUM`ZdIaI5JsRRu1@%daUH29gAy}5G zoUQv-R;h5~7dUXtcfl|sz8O2I>@$*lzAmk%RrIXFG{4=jWCU?|sS z%eUf9>`0z@Yof1mQN3?OBC)-yP7B8xi|JUNz(M|^3EGmcs}RTMrJKk^yPgD5@qaReYm+i@ zgK*8F5_27Okk^g-(UBpGRUhBIx>8DyssZmo_bQy8&9jJVmKJXEOG25 z9{L21$#sN~iZMCGvoHnqz}QbW{7G4Ryf8`h9)#Hfj)63*Pm7My@=HqU8FoHZ)f-jR zQ;F&z`^aZ3I$?@0C0^uSR;`P0C&%_&enGU2cx%bDJA!Ih;{B&5RZR%hFki6kP|+$d zpwrooo07&g8ny{q)_UM|`2~S76{f&ufeXyKZv(f-Z$QiHU?I8Sv@-GQHbzO?adY{R z>-esxe>Dr?bm}eK`jgpd6LK_>>@j@1;y^{~`3mK4Vi3qE0^_Ms-EDsNL>Fa@A){Xy z_+vciAIM1V2Q8jK;p+1nqeN9+RHbsVWP{iDnV(VHEF^C(y-#d>=MdYQsm|X&v zT<`;pVZ7|+wd~%TBAwx~a*b4Mp>KyFuMJEnfyZhifK+w8;3=aRgANw2fg0{na>RDQ z1fk4}cwwBH79qJ)rs}{NFGBumjsk-HjrfqdEfy~gpa#!kljz+COYahhccyrEhGcl9 zch%+0RXk!3GyT)1l0FyTZOfDw$6@kJe zYJ65A81`hi59Ne;WcsRo)QD#k`1@9erb9&~@ZdxFCvN_%3&8uPzXn)%06F?6V6r25 z_Es$PzJF_kS5RSnz#EVG2R3}gc<7e}=;z~SNh~AXXR%#fv$5&vA)Ase3AUgW!?TpT zjk>*ON{`InxFblIGgL_?H1}RC8Lr;Q&}DmX^-iPjctD%n?Vi9fuayB{a94xcJI$&- zcyQ_dlRX&sF(+92lBVXbH(B8ZqtZrOe%L3Aia2VX zz}e>@(K2NQJM&{ZVXkbjjaStb`p{a@={#9hQHBTwW>@VT7&-M5`hJFyS^J%&C)*#u z4tB2Ahmw-5$r}Gh!NDJu|Acpk-WLQO%=43J<_~gIn749mcBGn>pCJT>3ah8@E)qI7 zLu?N{ela%aq2;N*Q(Zm8aRu)+e01KkOc4L2RnQ*bzN>%p2tQELiE`kKm8UN0XNiZK zYBkE-!)OZzvB(U$ zsLiJ2AN90Ijr9sGeVmi;FvU{O^Vvsqzsm zcN>qKot+hisi^-}4T$8AnfVG2uzFnM#ZxnZDQ=g znC!eB1W&vA&7?;dR+l49(O3AP%q-9jw-o&4PGA5FDPyX;tC%rU*AS3plYNKAlFT*mj*(Ye zdwU7+`J?oJfyNH7r65@(01N===9@RJs_T$6SMJ2{cijr80BXfy8FYl)QHcHv>}R?T z%pu1iZX9bS$VJIIUE!1;!F}ATLXfY&O{qGq%7j#zErB7V&L2@X-at_OtN$L7LwNm@ zm*%1lW##4%xlltjL~TT{kPWD|-fw*izz5@``4Ke|&>|lijT`9c&5)c_NJr}G)t5kr zMRHrp%HUhI0+LVCze(*KjiQ=|Qs6gvMvi72m{Sw2mOUn!Ro8hb7XpT#rXhwrGU*As zr5~8l`}-~zubLQ}k-ky-$<))Eu!C=itv{-B&j=LSY;6jJeQND}u0;`w@ZX3DR8|Uk zV5`?s|})<0}R%WMhW$V1=Ye4nzQ=&NY~+>nwfCr=s_*DC!V#h6r{=j6hYn zPa@1>_BL4rJ?68$p+05o4oe79WKovt*ZfZTIj(Z?#d^8Dj1r|5yCol`8LLsUz z437nF?8Y&m%Ms|5%j7~?^eYD>8;8?Y_StRz#$>25Wy>lmQHDkg`Om4CW?5*n!W%hhSzI}-ABJVn^38?KoIwNRq6udta!SbLeUZonCEz=cr`xln(^i_5;LSk+qXc}XouNSnZvGK`Jp@6l46Sdx@-&KXp%E}->h>rP(Wx0U#zxVmtarVw2=B}vjP`kRC zN+Tyxj>3f1=j{e%T0#1zV2pHh?48fukk+a}+)j9SymRTPIN`yRsTANwWIq@JE`#!e zoQ+oyK8z4-(28lS%a`^ds8Yg)bwi|d%jkEx0yewCnf0Vx@&s*Ls^=?5^OuQWBpzS` z*6%DA=Vm>+d;gs&+O0z`Z~1Sd5i5oRnz0O%q?dwBarc!03k#d(I~9dbx3yW+$8J}M zLGsR>kT;%Erzra8Ne0R!+lG8Xxam6pu)fqAPwL)cfkNz0&LR7Fn5mq*e2kzScpuMW z|L2-WzgJ|~ho7d*KTC&ihL&&LBhjz9Ly@P1SM%+w0lqFm>^6 zeG4V#t+>P>4}TXM`ioFYPo~Azh?X*43*zLSte5UKtROpuN97rnfk8w4O9g>R2382X zqq~zm#N))&lfkG?&FcO+GE8MQ412=$)3x?%vJ6{Q#KAOMZAfWI%XPTDk2 zsV4zPB7qDjwz60|-qHWY)8?xDvngS}bwK~c@u{rL+*rYuN8LCAJ^89)FXD=p8SLCx zf%D{_ujKc20ZO{)wk(z)4S4D*izN-urMwsZB_qw1UnRcVy(z?~@zC_L$M}1z5wU&j zSt)%wofp@F(%uU|KvqL zGRF+=crB}#x4%699l4P_q+S>~L?i%NyUJqj_NO-gdg65lb}ii5gtuncTb{hSDGRqQ zs#PiQ|753T|Flw1V@f3?&! zqwA*lvJoo4cYTc_^sZrK#EwCy&h2W53A!men34f$olC}-B~L;Rrp3etZbVepd602G zny!b}w<8`t1VbtW!n+d}X^_Uzp$_v$(sm6w*(jbx3PNdfDJHMh7wM>(D47$1 z9N(7V%o!3uCj~$+^o*K$`i&T^lM0XNH%(1yBng8t@eM6M{rtE5^P}Wf)Ff(%LrUX1 zTr+MEsD#qsR>(Cig790ubr*%k&!t0;$nY9aa==%F&^0Uf8=O|3kEdSY&L`0)=w)~e z#KC-f=!fPIhlMd7_WgNCUD)xz_t$?h2=hC7@2?o0mT2Z{&%XGXN3uExzS2M^us7$b zyd?jZR4N3`#htj$6Vh!#@)!f>mg+cspD(4s?^+u%s)C~-$MHvmOm|7DMBAs$kefMV z7rqF{QVsk8)x5dcy{m!!>)?9qC8dJ!>6@X5lO{i%1CNvU@f*3OCuRGvj+p&k8uIu1 z&3|%E)VuWA;uSBI;g?~a{3=JnhnLP8vjf0l!*)VGv`*Y^o58vc5r7Fe(6r2eQs3X* z%W}ZC0n}6b{fHsgJ6l>b&Y_jk{**F-l9QUsPQ^d9umk%JQB1X^E>bi8XuZ#_qIYS# zeKwKWd~^DeFvJ@(Ke|^_Kd>>lN;=Yzu;MqUmO|cI*6djN~EexTuUaNYS|W1NISaj*@lt)a}iGDv&m*a{fw=Okl5H?f9Ysp+%LW5hg$S zApp;io*r1}BdT9bnq~Oy&BrE_X+(4Ei~`{nrK*<%l92~ezszeTHp4>k+gIrQr$~IS zn7y}5FrlG=8Fd2epu^vh%!lq&P!b_%@Egkg5Pu%;6(B?tXyPfFzUimcK7BaEcurJQ z6jTUFe#W`EVx*)Ia1>-j!}nz}Fkr5b&zhBuL)Z83!U#>JLzMnMb@kfbR!^fbhUs4<8ps^IkOa-MUSwo<(>NA@7b9-v(f3JjAuOoNut4Dg{*C~ky+QzU%l|x>?@QtYy!vh^j;-!y(!Ljo zoXle?9~9&ZA`>RwanNGXAiKTG5Xed@|6*HGY&Tb`Sk)f_N&53@sZg?ycB=J*T1lUP zSR*v8$UR)!(yD%&EC6QOb#IZDna;_ah4Qa2QguW`ta|h^HYJM6E@%soPlUoAL86!6 zM8&nzvmAwp=*ox0L|aodeo5ZnyJGUy|tCz52SIUP*ex?VAt0yP8 zGuY;5K~}N>ot%cB>%TPH%CDGyrQ}}yLln*_72Te*IQ!diG7T$SIDEj9dwe;}o7?NnSG8w@yL6$!!vkYigT$KP=KFDs`dVZ|7O=bFi>1EzpusAL;;DeB&LZ@3a(0d?}khc7yrSZ#AR*6 z&a366k@x@6*K*AxAnJPVlox&hM@u+soNPp#lBhbY{?|>?52WGY`z+v5$3NdHiQ~3yWWldcrQaR%9N#J}tgN7#^L3TXUcL*`{$VGAbST=o^FOKFb6Sc6Tm2 z;LG@L5kzQrq2Z53xGck-Si7-su0mW#ZrcvVJrHn%fRiJ67TnY~|Et?9F&=Nw@;l6~ zOd+=Y7t@D=7hw~ycKAt%*u#qj2lGD)*V6R2^Muh#yM(Ru!0KzdM=-H)S_lgXARqI< zX46v_UeNO2;$jcC6``nV$U#|6jb2{0+^y5gNY!?dS`_Rf%Sk=2QtjsFYN$oCN;7GW zr_TEdiNA)KB>B05Co^23@|;XA)1g>DPbk#i$}Ft@7kl&gg_SDXgwS`6dAF+ZyNMJc z7I5-U#7@fxWXJ{5CzkceOL|YNiTm_HtlKkB7|L4n-r3)n7@8w&@Fhk^g~|Hvum&51 z{}a$Uzs}@dBm#@%@c0OyX&D!%V!L{`2mz{AyglbR?sLB!H3AN4*+l0hCnZH{_FzA8I;udav%Ah6SkhmtX;7q3!b`0H*cMdte81QXKxSfWO#E_xcLZnRS*brV9W804+m=xYBr+)12G`K@s4<$6~-FWZZ3w@DK z0y~dM$>vaYnSxWrH|+J((l;2|J~wiH>!+>2GzK`~H0P3i zOv~MfB)uB>|AqF`Es`HZV!tdG(DYpZp*8-1@PJVu?;N8Fpr~&`Z!PWz~G| zN!#qSAJ11T&550(V4HMz0_@Cl0Y<5c(0W>-(wG;M$%r!L%42Ipc&h!Rc<>9^dY=n| z;_mLyQn@}He#Z!{MJ6Sn>@vL9FZ z#pA$1D&Ou!gMacfvh_l!>%PFn zg;nEZHopgCEyKLFQp6juPg3pYIJn6phpitm#7L(eJ%a?i-r)H#gz#384HIy3T6>L_iPLlIRc(#+1c-F^mGC`e>Pd)8~DRHC$nx;uOU?^Y>uU#w)E>07UXsi z9n}l-TpHgrwMT#CCvc(k}XdsXK=ShOv#hdLp=jS`edHAPml zniTd$=7&Cs3noKksDSN=k)I*$?Ag&6hhLC-@s_ z|50k?nN`Kj>g+S?=a-`#^(qm`8tQ*I!N;uyLgSAdq{ea6EzzWFcH*nlKU=gBeC*dU zaoP|h@p~e>I5&J|^a*!>y_wa%1nT_#?%cEenA78%{=efp{&EMUR6LBSTg%pKef6$1 zJ}g-}!Lcbw!#hqY$enG&U}_HoLeU-w^4?PuJATWQ5OU6S@@Ej^Jf`A1tvGw0_x=6j zN4(W@yef;%w?)szq`>Nq`xh&5{cNwVDyZZBHz{)On+`3~ot^*%{@3aq!Oy3stzy^9 z3;rn8h^N;3@B7QuUvhNwjoVQ4jzk#!)wMl1LlnuPJE<$35O(sApZwTrW5DBfe3UQ+ zgizj7dKXh$L80er76&W=eW&Lu|4531)6F@d83oi^7#LVMm0iHnZSpH>GX(}WvhH~s zAM$^fD+W)1{PzTODJifMt%VWqo+R3sJk$z}0J5RX`pij~ zd3E3q*kY99+g#hiGfRaoP_&NaW|-6sDhG#WzHx30^@o!AM282mRswrV1dnt8CeTeO za6XYlgV!I46VxA#cwdfP>Jv%TpS;5Cks!>ye}nUpk)26%AplYDO$4*HSK8M6l2{;< z>?h=>*X^D#_puUl-hniq(sfR1Q+2-T8xdAbxzwgRdJT{LT09c}n00m)DoqBn+8xEU zk9obyVj{)uwEx|=6ruxUM+wOXf}V>k5p?AwGV)QOi@D%$_{ZhfsUl!Z!CIcP-P?U9ZpYE}$qdL3M&vTy3d)r$Eu?=xUn9QT!A_(WlP_ z4sQKfO(t8A&zUtDF6K~zz6}07lc#GjlbPwl?)3~b5=meRIIT#Yer_M1$quXggyF@% z^0dQ0WbaRB=LP+9$V)2A(^_I9pMv(?IB|hV!8Yjv;S~tZi35ipa8Vr`3)p61RisTG zxT=rQQ<<8$lbNzly~nCm^G=sRBQI2FMu}#VJmiFyxm_;??n z`)UPUfH6Nhy3^Mm%>~SprN6g*Q^ak9OU&#Hq1Yf>4_4-i_TQzR+uT+Tjz581G$DlR zt=nYU)7JIbB`_~FQL~vQTJk+<)prhD1ymiJA4=)zs|aMqb)vgprRt2)**6mx$^R-R z>*X1o8M#yk>7?Uqs_KQ`Gn&1>lN;5aaT>VXW_Rl_#^!R}vi@j9q^LZhX13Z^GVh`pfW z8r~fngJ<2VubjNh$6wW8FvNQDN}keCfo$#@k$I)Y0oh_S$P^v!;@=F(k4Uc0$kV2F{kieT(}<+1W57GRVxR`f+GAtx3U8xzFzOvKjh(u1*;r zf7~3lXnA$C!CODEH6RS9BR&1*LEXUfwV-S>!|j;6wa2-~VgtG?FHF{#Q99og#-nJ>m0%k=DPFwS(~}%N^xWCxropYaI0wmkSSeiLqdpf@J^E>yY9xBzbG=&ht=eaG3CKj0v(PtVR4r(h1uvSs*i>-@ zuWMe+!NhhB;NTk*m&Y0n;i_C)O+-o8RVDA~^WRLL-hiM);urJoQHCFz*XeCr6RXxc zMe>PRg&@F;wOwT5y|w4iB>^Q<8}q>5d8m?unF_fc&Ak3)@VCzS2=r`zHUoBEwy_Km z#Ks7v_42jezHV4IQwCo6^o&28Qm$p;<*{5>&Q^c=8_QzGi4n!5_xR;4sf!hB#O~PS zj}2TmF8oG!Z&W%cr1Dx<2_kFr^vM7WZy`=Ju=aY7Kd%Mn8BkC-om&ice)0CzbkCAE zM0HBGwSt2}42c+*K{&@3Lc$>=f+Wc+m(&FXUb(=ZUt=`N_io-h$mg&yW-ue-_?ZnE zUwO_hf8fF`#}@`k9s7&fiI`)g$_K<(I=gBq$QZSRWv^R+D0qEx+4BN!i}mdW_G@1) zJEAg`Af}y=PmA3ulA-pTe9{Cf^Q7Jwy4EgzPxmAnasZVe72e_yeh3m+P?DHc|GCh+ zd}Sp&U3d~sJzaRV%291%S?J}@36R^j_q07xb#^jWuHGI$U!+|%RE zW=L1x%4@HS^}&FZF~FM5D(wE~I?IaTWrQ}IoAHq*sxE}h-Jz&#&&w9?DiT;t?7wKK zsOTj3MViKgKVYQy{ttEwyWi#zb>qB`%sEyEA5L>2JSlnIJG>o#vaUMWVZVyLGtWr) zH2c$>iEs4wmRg-tQm9OV=Is$e;g92GYvRh#vvg_xbh34Ab@tv0KzB9UwmJjb5W-n} z6F%0mz4ehES$g&-&hq(CFE}jf#AFaUL;~Y-1%FiT;~H$Soo7!a)Fed&@W^Zd2}1JV z9TNL1iO$|Gct;bcB~sv=%YRy0C;)reie&ky_4WP8-Wl*SA$-*y6uX+o8!Dz_(6Cy& za=GiYpP#+k>ZQ8j>QDU8z@!KXA&#g_2*3+3YU}{z_gOZ2G%+g<~EVpx)a&|c+$<+l^1N5_3Aq_=aEB?ZA zb}RjDLl1DO$pV~J7}+4AcDp@2WR<434okI#xQ|P|FYDfNiE`?)a0jln(jf4Q>)VT~MZaiDj55$NUn z<=hci&d0X&b+}#rY?$E>(b4wL!R1uZW_{#83leZQG*v;FE{JOGO}?ZyA1x)8=^^=y z1d3;)JDRmW3eaQ$t^Jh234Blg(uU?85VuE4GB<9$S0Y)XXw5MBH(YV=|EC$`VX)|- z^P{y&4sNvCnP%V;B|cyNuM@eyScGj8% zup2gA|EQr8i}CTQNwBu$=+K=hPNdxm)y5PG*|vRllq%x1ePgZCkqZo|!${}ss;52a zr%)DywhE9bsgg#$0}tOUmf+p(!aX<<@`^h{%1}Z3r4Z(G-WT32Rk!!dpXDJ{H*6+1 zWCVWG!Iy+h)0cAiY@2o2>$^oUz3mzOJ2K&v$^EZN^QQ z_)eRF!&qrXUtJ}M#<&yYfcDJCXjzLUmG?i!bSvOl0;Ypvb}kP{h^a|%TIf-Z98wg9 ze^y}qwt?fLgn;)m`0r{1Yn`fRW-S%jo^=G{KKZr!vJO{6_eXZvb*1l{5-{iHR2J`N zz#Qu0@?lh5vuax|=d=W+R`EM|-5mwf1s?fv zhu&r98%>*7Bdqb(4wm}}FSr^)Rg=SOo+*KbaUm^zZ7#x78iu^8DZFd zYa=_G*Rci@Fg2;f1SZ3$^fa4Loh6w8ir_KDr;Nxz#ype8L<7l_4SiVK4_8VsU!Vz0 zC%NjBug*rAe+MYYBnBIeSQ0owA_UlWNBYQ@AaxC6xI~0drn}7Y%Vcjis1^%_W<_>s zY|w-1Yp?CDqb+<1qPkSpkd6ddP(i%Gqq4PzH$OVQLEAtu?WV*VuD_Z^Mccg&h9WC1 z8rufQhkX9rYVeXKM2yW6}xmmWk^>`6oI{5Dw7~e%?xsIp(?XMzjGF=}j){wPvbvPhZx& z6SF@ahU)iNEUiclZ@lp%@=u|Gc*_*oD8q>UI<@CIwe&_~Dl3Q;fB*h1WqL3Lgs05? z+Y_~Qp&4q+IGMlI{#Y65_3>mzGsKHazyFDcx-zkAF6QlfvG3P7Zlw=$zGx>FCt}B1 zq9agz{Pdv6SDF<(N3fU`{hB9GznxqPDTu}ul`>iWHH_A_rc>;ZHrHbRPtXO35~*J^}DNTz!+IwpxTX$G@$1X5s1EY;f{<5?7By*Wo%aFaDShORro;M z<2W1DZA4^$@`kuO?Ilhp7s$l5sjPj}JF?6Rr3(`nEUg~zHF7?}y`EQCDz&>`^-r>% ziWj8q(R^pYHcOD%7g(^ozhvT)(4sc7-G_so^kh@r@B*_hrAhvS>nx}6XI}x_8TL7H zpC$2=^v-li4T8R#ndXJ>-_Y*Ul8>4n>~@)}fC)nevzx8=`^etAr#F3?|5J`q0`pA( z&g~?1=-Rh$(D5D19)LETCAWOG&h^Ff*@M-2YPtueojM{}zLQyMn^Mf@Ykm<*{X>Y; zmeK3Qmg7AGB7j~@%4^?&S_Up#m`%Hl!jTe=eqw z7{g8e{sSX!)f}RN>x*0Vy9!HO><$iH>a<&!qyp%O>4{y$tx+< zN|T7+%LV9}l{oD7nTCkLd*+8T$xKDf-x$f=RD6J%15CwzL)w2}5ouQMl-3iggUn|R znX+ZehNlk$jtJMnLZX*nOuySnTZkp9L&crRWgGvA+?|PN2zjIeat&*cUcYPG{11b2 zXFv>_>ak=wC871j(^R8LWzpWMezw|4cA_*Il6+ERqbtx$n<;h`z$hw;@K^KG2^+XB zkzk$($xc@WP|ts>yxSw?9q}QHga!nyqM|eqQj%35=&SGwO}t}m6|as0jlZLRbhhMn z1dScj-LvbUtLd=4Hu3Q**cZUWB?~CC%F(p{==jtEM5yBV?1J)tA%5NF%>@Q9kMIu_ z)U>I>U5f`o#4M9L8h=&e5{a*7={^75%d8W^KxjDF{#!3gw6SS362x)=SG(+eFap}LI*r-7 z5hmK;U#;(?N3+TX2IvA>F^LujxG-kFWJptNzPXniB|8!CE={%>QoUd^h84=B9K?bOSm?Of^9sykrhtfj(&tW|H6Sip1NFMe z7J>4f*MlTPrIV6n3B*~2YX(<0@h%i=a=-3z8MRvF&2MoZn}QDOVsca7mk9#~1{(_* z_&C5BGJKyA6h=;FiyPQ(y&%^%yHk86%Ho~b(%;Ufw-rSYkBQ3)Q1`ZY#1m zqz%{4Mv806R-!qK58s-PpgOf1-Bmo#0qTMSbx%5TKa=lueosJ2cnGxdZj++?;igGx zh@#N6+w0EzJaf-&U2yszIbUwk@>j(E))=#D9IOqUzVI{*ZJw9Du*b~){K*`JiVu3R zHC>$F4Rp|rxfI>*MZ)kL+Md^BfqML zL%-i&W}W)6O_TnG7mNgD{CR_)RHV{skiC2r=|s%-4?onmiH-Z>^-*~2+MOrG?i_oz zMm`=A?eg$<{Rm@aa9bzM;V{LmpC0*PQa`=V%~Goxzs*e%c_eMvhIl~qvQ`_Bc9)U; z+a9KbrV0Tz-sDVEZhNsXv1Ue5Cu8hN*#!HMVH2q_|v1f0R8 z^H0lis_(>DX=J$5&F>~6iUu>iw{ey_L~TkCDNNtMa8B!9LpA2u<=o5$IW>!{zROigh<*Cbp2{!k|L=<=9Pn1sX<`6IcAD>r9CbC;v$X-gjOtixJ-+C zFSFCg>Jar~3x)|gN2RS<5v5og;Vyy2JKdcL{Qn;L-(DZG?z`s}p9djpCHiI(;G2gi zS7&>B>!+xcjakWQw!E4d0OMv4i+QaVMp@K5PTouW_gP_{d%agk`B>@Y;<@hhug#EM z9s}E(A54!j@mYf3=m)=A$;yJ#vdm`oKFX97l7*`Xco(nbt?HDev`ZIKY-IvIW;mX_ z%|i4bW{*U|ax@#^3A$tg3E@@k+mrqj2K`KcZ6}bxOqx7#Iw=y&yu3KSi@NtlR0Yr4 z5hXjDE^Q3G^y)UjvFo*Y&k510kSqm(NPAzGB4eC;tD3;~m6%lx0=Re=FaC$FC+X{= zr$vlIRH<=26taK%$hPdBdwQhSu<>mSc!4UK3=Osn9lyBT*`?q@d`iZSH`a4#H?EY zE7~33;m9b7Okw%&;m^^{+}}&&K5re&b=c%zeNn|*imIA3oZ@Z71sYs9=^D6-tyoi3 zC_p@a%ILVl%0`Z&uG zbero6R8H^&hg%gX8#mfF$=R(VQ|7@PxV|Ctf*CLZvJ9$@md{sih)Sz2Ydc ziG9mARry(Y;zz{!w_{O11J9S;;2m%}PAWG+IOSGgj-gvO2V3@y^3=7{~N&=R6_zG@xM(#*&K!MV&t@HknHLauV8brR_O||9Uya^TW}tf z=i8q9Qm_B;Yv?$a-p^xH-D>;uXS;tCiBvSC1;E8+G(q)F47Sm|uM3F3@M+cw+h<&|T1o+O5b<7+A*zH-8@>Oq(}d6( zYr6}Smc0%qojnX;QAqia5>5PrEw=fJ7tWf7I9Xwd<1vr>G5Xw8W1hpLm*>ZK_02%) zcVM+_YSqQt10Of+cxs0AWhe|W2*n+SmyDn1mD`HPpR=7ke@>63@)^-i4l8N{&{viO zslwR(5D{SG3A7NH(to0#Gr0D};1_zYqUSSVKCAB=a5aE!(Y(L@f*G~Xhw z2n;@@(;~fgsXfn02NkGe2vB~*fXR*NJ9X)0ipBxXod_-FaJkTo><0F&OLf=mA5y&} zlTqWGxYARP=(my8;kRklZy0Yek@@(BZrhyjqY!&*`YarsPoy?zj5mxIRuN;~UX|>< zzy01tt@7cX_XMtqp2Pdq>D$74FK%=DenTM7J(gEcsrpAB8GL*4ELFv0tVJCM(p9GT zW!OMn)XELKvh9AOTk#g8unfC3xQ_jWx;*}D3Wy{@akFTS6{7?u;ptTG$0mkQS|(%3 zTEgQF;yKWU&%G9{F;ytws}<2_mK?qm|m?>`q$`qB>R6DNC&!D~+Izeh$JIq5S^ z-)Ergo)TKWj*fX!Uvh?iMaOJY>Yp1t)-S#CD`*Adb0PiOi{6{N-qt;-@n1pvuHTGw z;DAti#IhCt;N0g}l^nm@_kh7e&vp&Y1Od&&u=-MbQ9-9dJnqDA&h(T}6@~nJ6#?!! z@bX%AUPt4}^FFYDG?Vz~DpdMd79&A@8sWN>BC{aWR3EByIp@l|1isqru?dL3*8=Y< ziG^a*4v+iP2>vLT9qd$Bj+ypsThUC>oQ)cV&_InCKVt|=Bi>d{!g9t`ggq!(H;ai6)db(x6rtCt`@tsAVbn1;%isLE^d zfp%I3bNL^hkRyY*SV9S*q)Y70&*+s&mgDeswyT`Zc>GS$>kwTRvMrD@F~xzbxcIPHR`S$9Cby z*S39OwK~&<*u)jx8R@2=yXTUxwyw#fnaa(u(t3JGizA;zjb2Y1W}0CNnV-`{DV%Gs_NewT_B2D{P7WXrFKDC@5rRWL@h1 zaSfs_$45BJmGu3)d}QjQ$B8rV^G`%0gZuv#tBf>rM0EU~x$~k0kcf z{&+gzrap|#^Dk`t^yuL5)6LW8Gl2_K$#ZcjsVDIo{fMw<+l&Hw+o*jAX|FHUx8I%NChnAJeEgcXCvta-%11TF zOP(;K(ZlN$=x^% z=@V4+u0XMe!40XVu7eAr+iYyp^G{noPw9?-x-q3Zbdgp@UlNJYDH;_A4Hj zpCq#VN*nq&{GNhzuWH%J0Z8m|(p+JmQ=*qD2E1rHOt1NZG#9STp!FJ}ULq3YoaBK# z_ox(es6&SEd9UXYCeP;^d{onp7Cyu$@&Ih!Z!+-{K^0}!a{>{{ba7)T2s(nzEm}$0 z$0THcfsDU+vZVMbd$Zt<{ItmDkJ`U6cA@(`?uWOXw~ah~akn)I7wj51fsX_wLMTjB zN>*QclxKw%r^%OTHLk#O1Pn%8j5lcW5LqIj0>H!&Nhu5WWk(U0@;9#qsEbnwGWDB~ z+6o-R&a>SgU)5oguIjZP5!fCryw>cE@+-Y8%$O)6`jj4R>7;$>k_04Ci1Fuyp6y6! zz%@{5X(}i3oZj$xEqLBqij+FHfULKJjx1Hn{U5qKsi|ewdnwYIm<`>W!QMvxw1%W9Z_umaC*+**i${qA`P3+g`J1j|Ex98|DlFzJHXDGOG zO$mWw&{`m>v?&#}Ha75nH2NG&E_N-=UGzKqHt|M2$gk_*4PcxNe|S8d*Iw_xoqAo1 zT5Fh2Dz<;|>EFEY+hwXQ4 z!hT=nz9LA~biYmJjj;2Bkis=xg$$WLd{cMnXST37xe0>opU0#H>Bl=XHJD$kKIUU#*EwKoYEl=5>#o9-F*E;Fpp)CZfb>JOR!5!w#|1MaK<<8ev1DM zyn|Pto`xp)LQLXed$HrRaITr&!!f6~$LgiS0)One{{^u#KwdnEt&Od<6W3JGu?0oP zf3p@9#g-$TETp9{4POrlEMy`y*S&easVz)7E7I8ltx5_Kp(UK1R%p6()bLlIaBOHb|8uQK9N zvD{wugbYi64M>3k)0b_7S^b||*7@1diSt_mr^7I=AV@zI9A&{<=%dPt!cHdTcSGmD9g*U;cuZAA;!d6kb z=!>@rVkse*o8I59T$i&CZoBq!NH0qOEuyHiyW~eHE%9mFmtJ?xg`vLAUs=(O^WI

dm8HtJvd4F{rwHV+6LINh-L>VZDu|tYg5=;jwh{1}km9 z3)24P6XPS~G&P@ulQvTKf6;T1iObt{*4P*6Xk=_z@%G5} zipKQC5(fsg4@)-0#ByX`JNq~Kdva8=IC@F^?(3Sl|LRTkpx*TVn0oJcs{i+Y{MaiQ zk)rI8WQPdn*ktc)imdEx&M}iDBr7v}gzU_N$jly@$KD)!9L_o4=Xt$9x7+Xcm;ao{ z^V-+_dR+I%BTWum96yWi$Brm53@&d}^4lS=gj%U~ye26W!O~fs10&#K8cPH)H zrS_z~4PmT!9!)j~!bj5yTwfe0{$Kv!O6bQH#t0sIVkLDio^4a)cHMFs{8cBC)kz4q zym_y;;HwPNMan&^|E*&0h*Ck}@-za7kxyjbZI;DX3C=zuc9$1U60R?m;5VzN>1A__ zFBf3OI|_6%Hiet$f=zAAAjyQ6Q!c=Rr+~uqrEXE)UaE?N6Qv6@wGSKz|AzAgT&|Gl zP+v0%u2NkXX#HeaxMNZmlMMU1Vo0bwm>zxtUj%|eKtv%d-wo(QPr0<)+!-bIvpuYY zz8^C)+gq8-(k!jp3V2?aIIUAG5%^7V125a@g~GE*mn?6QkrwZVms(%)6BzvO0JOLR zFlGDkiQn#@$gMqPaXgq5U7fD`S$d2F0%_Hy$kpu^1o!mS&npZ_N+TgR>8EX=rIR?8 z?i1MApO)d2c*{`0@EYbXV(>(d7>Dc;V;bKwCKnQdHX%74Il$>Q`Ryv?oOJ59myuX^I-qJ3rXCv>`p6pm7uTF6BA)M`jOfjz2;R3? zxbT~ViS!SDunHM?)rWji*|P7SV}B2} z3?;=|=Kp)27%wZ&O<+5QTG|q{QY_Jhy%k$EB{AhsHT`>0zFqdB6ot9gF?Z2$FQsgC zn*u-m(6ip#@a@;Eti%=fVvX@FN-|t9lERHe5SN!`?m*v^ZAJGz|9ac=D&gdohBB85 z0B>fR4c`k-ZoVSF(0WCaDg(u+xUKA5L*FfKs;LV8re)s_v=wPTO&Gkzt*Lj7WMe{| zk3*q;Gp0hPqAw2KeE;Omnd0JdT(HT3%^_F)OKkY(1^~kk_gi;M{%8L^ePLM2UpM;$ zhOl6b)K7F1vEO^Z3T`Rnm%&UBU5bJL#)G1e*h%!p#*sP~ zp&Qb%^#==QO^uWBC@;QQV92c{bNKz>=qF_@eyFq?r7b|!)LJPWMkOFcaSXDW?iNpOo z9kBSM_6tq*8CM~(D;|oFfqvE#37^)qMIn9>`jF0ZeWn`2Ze927YfG*d&f@XO!4YQh z(^nTyM^koj6jl4dyJ`O^zc=@OlPVE5deDl)J7JIPSVH^ni<2!gLdf&EhCq{;-yas=KW9SF|QolK{$*5xt+TQWiOo#MC9Qcm_agl zbm)Wf$T^@M#h!}k_xH;=cj@W0TPj1kGqEL_|B_7 z`>{#{9Syw;bE^TW2o)UJ*b#jEd5t$z7dANeRBysc(!D{LWnNBdo98KkT5rV_f3 zmF`>0j`zwLcZi6O_%G#Qo0)-D{E;^1u$vzL>hQ_4RYsn5s?>Ro2ElZw?)zZ819kBu zy56>s%$ZnCGxCrU4*SE!R>9XhT;C8l^Iw~{mBBIra-ax0+*i4lM6x@dEGq<1(Jmk8 zw)}?KTqYQudr8Q6wPnvM$Y6~D&xfJ&{4@C3&;Z|9L`EcV`LSg)yXDh1hrRs6MZ0`M z3C6X77qI&#Ouk1<2+^D=&3We*8|!6vi%UUkur35H6UNK>siW|0<^$w09$<&mo&o}} zYftI(z6R^9T#DSCmZU|cUuw#aA2Y0@%{$=YPX!+MXSf>GGT9T~lO|lT4Hs@d9Toj` z?u$VMX(z?Ey$7iKhr<6q_?<&ilp&-{^4E-SZlv(z%8f+O?M?kVZTOSMubpzrINbwa zg+?bcuFgpUa?E^Ic&~5aMtLy}4?Xs8;aVv+;S_kVB=dEb*-uxy^7c5=5IAr@;7#15 zOw<<ELzqt!mRyhB04;uA1c z9&fY4ok_mwo3=&W?F;O2x9nxy4x^f!Y&ZM4V0C%&?8KVJ&02Sk-d9@%^}cK8#D}H>2is`o>%skb!Z$n3bA}{cC zOkDe*f&Q5qv>%!X45nCzG%kG`y?hB8Fvm?w=-dAZ1|4*OU1)bhkFiedE3v5wv< z*;p1c;C+(x65cepI=-qh!~g^hcKF>M1S>RljrIm?fE)`z7e0COv=LLGix` zhDseq%M)Z@M>d(h%0&ePVeydX_6kYt#dm3D@KJ#e>Nx#hZTivtbf6cAyM3ED8+u8a zg&k$`%4B9+don^8A5Y}D8#T2&Wz{D1#N9YC!(S1L-`dxU4c$XydOoif5{SlJQvO%c&0Vfknt!6g4w|m>e&yGuI19UdH>@LD z@Q+FxC}hr_qLFnGL1jXbYO3>O$Ee3kk^9fRAk=co(KU9vt7RySnijY-7q0|R*w)@| zP^E3}IiqcB&cgH(84Ddr6nWN0n(a{%;=!}unL?lku1C}FbeOi@$i(2*G+9s#mAU@a zb-%0#aW?T-GuV*Q3jHs@{7S;ewy?|b%;Jh{9iI?JL36-$gO0s@v+y{Y zh3gL9@hV=>Zhqae!@ailA$?9bveG#%3Gn{Kw_T6qZXQ8XgcO{=G zt82N1ljfK?+>|XRnCK>@%xCOOjWq8(sa(R__Aat<-wqfy$w~o!oX>E-$pI7>yu%MX zO%-xZOq*+o*&-^?`Ffo;znI7jWg@5JPPnHiEUWPb^s=m@{_8C{K76`c7~l;yAiItc zw;j*O-OLV`lLezdr|U_jbFVZe)EU}%Vi=cBQ{LWaGBz;wu0D#)@g?xsA_@WG-(gnk z|6+UVpAjXXqvAn?eebX%y0{x!%f;$X@39VF$48syr;gITX6&CA(%!4u5laY)+rKlF zOwoc_5}y?>Yv-p5Q)S5XVxb{NKm#oKHr|!aP(mkMNpn zL0x!384u&=iBLsBG@GL5rbIai3Bv#o+8E=$k1$!!RzZ~M3S~)WZkaFyPu$aXF1xQyErn~GZ2`A3`hH!?r19%?* z#i}vcm@j6ZWZ~Vdigtf#b)c{DRan)O_Utro?Vo2kzE?dzPWIzC*+=z$0i{?EY*2Lm zdjRX^O38{AJqj6`=&?$-si@FB3M}5bP9Qk&(7EXO>$j{9#?D_XnZ)2K2}>gMJL($23TIfSZngzsV?^@Al;c_m6-y;vKMO%|5l z44B{(TDmlCA92+X~0tUM%4Mp>^X_9m5G9E3CoApNO>W*2}($l#k;syt4lHm z>v1*Y9-|6%_e!VrvtJou$V?bxjrgijO`RbF?&3tm6X^kV#sGdNym(Pz zD2qScioUPbb=x<^T2t#iOBMqks6|ER@2@_*DL%5N9_;K#vSCAF5!7oGfUTL}23@vf zSN--RN2B{?uSqPhPQM-~aWmXM^P>;J`xGm>HKUvm1FKcpCs_LVQ)p3zwNX;XZ1-^( zCrzQ{x9-3#3S9I0L{fo)a;ZwYm57NXrP~D>Jsl_gA{-^DW(d+NRy8H$45fBqtb6c2 zb2~62cS8v$>HypiNB{T3Wpl>%+OM83WbkRt@-fWfcakeH{N(Mu-2D+)jB>t{y%wvv z#{+^$;+bi{gNOl;;kzKPokCr$*mBKdyi)dh7w|KJc+~ZlBHVy+MNdK3EF?fUXq7Lz zEs%GIF5XVgF2@f2XP*!1CU?LOu+Zt<1{_Qe|NBEoz|q=(2nJu1hrppowvzM%9sVCK zqA$_-+jy6P-gl5a!D$0i-%D7fNMQ;#xBl-_@v^VGiDfS+&RROM>t1||3(LZ+K!UW$ zZ$PK&s^`gqMszMr2;KQBq~oQEstL}Q)NWR(%7632J-?fNd4XO%tJAdd7!e5cFbtd) zutvv*w%L$wgfYTnU6oWf@CYCSJWSPR%t0%3uCw6q`>6i_5|{3aYpZ%jCAMFJckeyC z+U*PxSTAFVX8YMTh$+3}tLFcVMPcxEgBuwz0JVdp?BjXN|Gu#{<$DbA;lCnWwhEP; zR)Y_pdFGeEGN~SYA(2P0^g=%#NGS?B(B`$b0Q-srAlZ{c;O-0jnFq5yaF>k^CtZ;S zsKY~7!xtgFy+vE(f4KcMXSUC%=F z;qb@&cx{VdHrb09%4sA^mHu^(`lc~8BV!6psMw-8_J%J}YYeQQP<4i&~z%DMHRrJ2UAd`jKC4RgHSu(nCF(J$hAPQ|5E)Eq3iJu zKU*ehW2BfrK<;59Pe)WGkS|Bv5K)Y2HVE?vOq~^Xzr~f&9PN*6ji&qq7$gjzm$})dI^iRLJ1efRZ~M$lW^zw=+V7Fai{`s z1ZewAln^AVkWj%8&pqR7Rd`!D>R6)iZW$q~#O-Q^lASVaS*g6aT?klNU-W1BNK}rS zsVmHn*jG9zC=^bEGZf#F%F^W%_{$!i%C?cZMS3EP5&#oVkNbo?mCW9kNCEXuQ%VPX zfSj8jJpY79@%~7t%cudDiovNV6`BO}9l#UDAo<6=xak@0ObWXez)rm|9}7tCKB$Yl z;}?p>myoj+UFs${2SHjHUVEY6LuMI@RS32(HooFe6V5kVxp+Zm)6=Wuf>$KRp)F_q zt<=$Fc8_S6HecXj{B1-a`}P9Etl1et+iePNp^@Db;D9?U{!64l)A1PCSp!(TaGmNL z+@B19;2{FPEAc&IYJCx$X#rT(vy)9Xs_(S zv_SODM_x@#GOU~+9jzB0=Y?I3lv&+aRHV!(_8H&&J?J60w&OPW>qu!J4;B#5&%&R9 zt|WBckAu6DXG6E>arbF11>aMT>Ecpfr>$DZ**)k0$dv!gjso(-H%5x^^tCR*+QZQB zB8VzxQ-(-H63*Xp6~8(DDJ`$E9N~&{x+cS9Wyi!6B~bH6L4&FfY+>~t#^29Agy0%qTA z^tgT(arG7$)GQeG@$DP~^xqO5KeIWnYWRbb5iY6Ycyz7Wvg4I*q_s_~vc)%VtqJN0 z0pr{TFQOCqj=HHVBEH9veEq?Kxz6(qf{rd=O~ZmWNYTqq z>|zEYkXrr)fF8>?MKnWOLw74J@?2@(hBCRO?ov3ggybWKX-dd`{0+Xhc1>pYykUam zX8G(?L8*-D?IZq6G35VMoRMffTrL(^);G5LfS46al_4_;L`X645Pm|*|K-~c`vKM( z>3J-7CM&Lq|3Ow~QJ&$}M1Wdwd+C1ls?e`>Dy#04tlUvSwguoJ%ZPV0|HV&q5=CNx zzgOF{YnFJWk~KkbkVslb9K~K_V>(y%V*xzJFYJLDVnDcvx3t5V<55%0 z(LuI(=u=>1a(KIej$0U`p9Pvl_6(h&S(@?76g#Eq@Jb&-J{!V?PMW$^&fyWrn}%ry zR2i^|0IZKjyt_Yb1-uA=4v-1VeN1}1&Rl)sk;+_(_22?eV|kiSJK$}GkA(0}k=cvw z5k}#cnBS!f5fa%zD1T@Let*qeB*zLIW^qY>Zff}iS(4XQN(^d5_HOZwezyS0FSixj z307=f2d7=8&zZ)2<0SU%1JN&~hvh@Qsk*0YwMxar$+{B`W7nBB(ao$82Ee0yq}%cp zO>c>qG4tKUl?j4wCATVNo>5B=@}V zAjmeIq{r$vu&kKJ2%x*F)Bh`$f`k`+XC7ZH+%w*b#e1vHGZxOsdQAA?4|4k>n7WAk zsmF6`osH<*+Quh#U^dS9^RVK-Bdu?530?IAkj`d6PkS3m07G%)gwV(jUGbs*&5a#Wo~bAy`lT{?;gN;O8n7U zIK!#-N353}cJB%(2cL=b(mh0mCtf=}x%APTypHC~`S;1VZY7do!N-HW1Nrnyc5064 zLfY`YEE)@rr9y(k(x#tvN5#ATccN5WIH8jDC9C)+P0cWwh{QHZp~s};XT_<9iIe+7 zB8BVRITHPdh?GJ!lS|KXyTazVK82e}X(EXf6m$>srt6jm$Ysh|99kAOOyc_WTA`GI|xRIE?q|22k!Op@M0ab29d-wFt^Jh+V`gnmIdFIyH-!3?nWhF)BVzroy z?Y4d2?eK%{1!0zSgSL6K_JC#|mu{HZzESI(qA59DF1)-ii_oyc4u7dPs)1ChBZB;R zP%}xwnEc~PD!y9Qdx@MR@h%qtfV}d#@_#ar`kxFYj!Ik@l%vn$T?JY9JJnr#3hV?q z56+lZeevGifKzxN9RrQYAuId#mTt=&@W2QyfEW9}9!|j=wr@Ir%(px8lEZ4TkLw_Y zM(a=I29e4}sMox-Vl{f}P4|ADosARsJtnqd()_3qKI)smKgc8_jnm-2rwJzWn6p&_ zoGf@V%b-qN2k-;-TNY2_{g%7PjyR9spD&EQ4s1pJZ8%*QA=+scKD+aQ3H55_;?xrI z*ak@-U>bU{^JEdL^bJij=8UUEu?mCZ=CO%9%y zQet6Tlt;UBAB7nrM(a1JCYhG++rL4(sNP9GYz z+19iwoMzi~35%KM8aDxYM@`B8}&>Np8OUFjp);7MOj zhG))-U8Ua*!$@z=UN|x35q%Yxl74*)M_UUlJmvkTm+gBB3{*?%ERFYYwwloYmlKh2 zA2lbmk5qZd96K{$yzf0`!9(-|b^IC8*ENpL<%Ia{-MLg_x869r+jh8rKWJMGcanks zv~%(w+V(**C*Ja`vAFFS&C+l8f(M`YZa;QpouqK!GX+#rn^L@kY};MA+jywSkhabZuBkJ`U(83;(GEtrwPb9=VS>NTXwG$W zrk>BKT1qlg#BAr;A0{AV!ZxwTvErBwQZ_@Jf>0r4f@YzJt3B5D;V%P+9CE~hnj8;BdP?{f|uOCqWub7)f81y5Pn~+TtF+8Osd?)a&=X&r=q7}ivdsP_h17exS zF(E%&Yd7%xFoKA7m2;NwGc0VuxV(5umM;F}Hw*gY40qkQNJ;|@S|e5(xE(%GMSpg< znY%dsA;krdM15*S7q2VZUq3c^h*C$G<0~!- zc;Z%1NaBW0Bos-vfmhC1^M`+(Oz&Rq)j2QJ+^9fw=xhbR2I@P#3`c=C z&)DB6J_`Fcp~AYKeT!Djx9gBw)d~Io%LFx;|B#Di4wx@MS%{A8fqfV|2tn>Ql+bJaBbo3m!b&}bW*gn^b@AWxjzPSFga0>_ zI%WI6M7{tvZVQoINl%Z!2hImto4>&#&lh?ARO}9&TrV0c-8Fe?lJVh(=8pgoYPD#) zvGd%8gOGLMx))|+Pu|#&i?nWQvepGYtec5pjddhz{ai2zA|P}aCCI1I043Hlsm^`* zIGzQG)lL5-`DGu^pg<$!sal%d$8K1+Z_TfZjFan3FIRdyG{==}HjxRkEpSNYqV3{9 z2987y>%Nfqa2-MXf<%p%O!xCKp}Fs(J9Z*I>A^T zQ>b4B>aF_aQ;C|oCO5w!rBO)VhX!y`ly5K0I8r)S|T^MzCG zdAjB?8n5skAt;2`uH{)7{OW|j)HEZ(R)*e_8Q9<`4LPYJxn9^azbo@t=B}oaQ8B&x zv0li4Pi@|Zs-)QMfkKg+N$tuVK@5sq9s~j@>ixnl?p&9=(K1f|!*eosgW@EA`i16q zv%{}Hyo4ndmJdeGmdzeXTkVfOBPT{zH}hIl{Gb?l8mpB#H{yle_%coeSTB*v56iMxmbhPui9rU1dcXz31LX-~~QNA-FHY;xa#NB=Y&M zlR6h~Io;1BW83}C!Zu%2FnYKMfn`l01Az_{vaV5a{-(w~jcj&ujrS_c3z1?Mk4p z<6bO=)?)-8;pGMh8MA4qm)S5nU0v#AcNac>h97cGK?nlHPw>-U3S!r?9fI8d6h12? zi}PAc*XbR+q)I}mXy)~CDv_L0o*V}!MH|wRcOE$>KEz6C^ZXQTG|)Y{|tB z0$H2h0}GXHV%@W|uF%8z@feNyFLPgom=y)`j#_V`A5r#aoi3R{-U`?i*lRTa0KJZM3$C-8a=TC^m}(nNL6oB4 zj`8dWjg-cFtZILlvU4e`(bcLA%U_#MGn{R+?7pb`ngzNg#=}7O2=PFm(kCz*E$oi= zxpRy)!Z`<2<@pM(rd z!saKeZo~k7I?#b#GRtDYCcG+#13Ni{Y1Gd?7N0qJEV-4qlo@q0CymK%g6sB-bMy$r zq?2uy!<5AiE_rv#k%e>iUn`Tx|7?YbVz=M7omC3zt+RlL<#1u-PmCyP06dE{CX3I$ zb!DwAN|TWGQq8IQ951~rbyI3%oSzAQrcSIRRWr|LEJ|^<-stCtg|v|{p|(_`kt$SN zI*J7|J%H+9^3wqhNdMmfvF>sz%vtJ8F61WMk9j;A&8jQamfr%;&Qtg5<9%cgt`mo< zLSHM7;lHH|ov#tupWC{EsVBie|Cj--{YwT124rJS(*q5?+oKqK*bR?ruRrzNP>%nJ zkWTgn=3(i5+Na5vdEIB}c^6#wG2e6aq=J&EXJ7Dby6wPW+Y%EbAkeRv`#7@(L}lMr z-2>L2kYVB8=PXQ{Nps6nPOP8o{SlJL%vSJnZ!sD6u5sd-celIQo$txFt|Imq3kD-M zb7HL3wUyF8{ya~gLruZka=frt8%V!1ko7l!E;i)(tCnYZEZ8f&Y}%2#+%@^OpRP?o zHY-W~XR$?`?{A_Uder)>PRnQ?RftpHA9GbUy7*!=Y|=i*s`yO&)+xKe zS9N>=M?Jd{04@5%aKP_;2RpM8v>wbAA*Jhz=B!&dT~2d~8S$unj2%`wg#f$*+PPK; z_R;&g>DWKbC{+Hn(EdBsbF$qA2_scibz;=3P)+!&b~hS)5J*<(?uJUh`EKA@kIID; z;vhk^G<vl4BZUwMETXzU3;Qd{_LOi!Qf zT?jhv%VdE;haEWMM?@d3d;$W5c2C?8pWlN1*(>^!ETJ?qrQ{5i-T+~jrA!#aA&QaoLCR;2`iE;-%bV{dx%(+X0nzunJrZuJ$}tz)}B zduX8h;IVvt;5g~Zq{oB|=G?y?+Bz8nZqoP;23_i~0vRD{<+=9$q;K5*WM_~_J6GfL zm@`{H&kK#e3+!G+FRlw1K}K}F(p=TAAo`4_bFm%VH2>JO?g%ozE5RcL?1x3{dJ|C9 zmL<-HW+f1TH#Kv=D(P$fPSnGLi#lOu$gGC_2az()}Ge zoj|VMAg1$~xaQql!_wzVD*HzCLJ9vnPFCk?bPX6lo8;9E}} zK(YwdL?+XrXxnXW{lJD9ZbSZ3@e47zb5$o@>V1RCuQ;BOXZ^t1G zQSM4;+fQhAlUnCJ4$xbdkiAPSk}dAY%9i?2!03NcvQ1!TDv^^InLH6HaC5gQhiq%T zqgm2sl*LSUVcJ=yPua|;n-`)9LE)MNqLn1>dYMY%tJA8;8^l4bK91|%-{u9LXhodz^6dW@<`~F6Jal`Gx z8^2TZ#}|Q(7{r@Mvccblr-$|=dsy>8H~rzPAgW3*DCjLtRXxhaOiMY*w} z#;4&Dsq=X4ry@{mqhWBBw)TUpX^j8t%K;VFMtjA{G8U}IsOk2im2#}1aKqjsKDWvI zQqivjgL!wGyhJ@i{B2uK0Wz`=(<~s_H@GnKdb4Xh@NB{Dz*{n1{AN^Zi8hVY`qs5H zOm8Rl3aV!~McgYRQ9djFf~ebXb*&~rc#r;CyL2tkJ)I5lRIwgGQ|QT%mlV%I2Dv^)3WOL2CS zx%TwxcxyV%bmhV!CU@_V(g%Z>oIaH5e((Vdk)6I^$3Z6AZ$3c!G}Z{~p)Z&TwE|yW z?@o{bHA(WiiqG~H&$;8(vW3%iF)wfA{`E@P0{Dvji6cEjqJ-NnXpJiD(@uVa8_V09 z3Z&XyG3rUs<}y{MSC;pZKEaN^z0E)j*mQcJ(z0Wh3Y2{hD83J)k28y8^N`GQ)0+W| zZjEb5RWk#lioJ~PD-uy@CBmn5STn0T?b8enD_u{|nIazOJKK{x6E zA^(6!-Ue>pCRJHL;*+{^RUe@KB9FXle`sTfFqC!i+v<7(sL_Gx)3u0G*>hBWl5(v7 zSXXgnfK*5smqR$n3C|_iN^VQ`WS1!b1H;A+p*Pd#ELA`uakMz^>;k-V2hgwnO+c|Jx95@}oZa)byZ1?rp^Kw6gL1=y6;=|xtMskNML=?gjv+YxGWM`!Pe;GLerlP~M}D2;_4BqM z=rY>kkUi4kq#y|ewcGTpk2};NKhs|1ZkU3AY2l~VX=UHeZv_`Hx%$kxoap-eu>1#< zduR0J8E`oRpc+1V0XDY` zOFx_X*kzjWX#P!QjqGgDjoRkE5v@*{C>$u#t^Bo}kse@@5N#@)2o3%dVO6UX=CXwW zFSq+ZuQHt=7c2h-DS;l+sHxcBirr?Y1$kC(tnJ2<;~hr zn9L*QMd!7Hn#o5(&zoLGOsz&xY+j`RD;trzRf29Br}KU4Qo-l5;;}#|hvFQ%!ur1| zOPfTjUI{Zsf-$Y`S_w%a>1$VH*Dr3v7h(~iOUOSItrSVJ4?KK~wb+FOBLvf+b&9cEdPed<$( zNGl=&_+2HPJNh-vfu=)-8;hoHq91}UQ^5^Sv^ii@t`a0=t_u8R zP9|l7b-_&B2%`gaHNQGGjF?`8;jcs#I#V`cH!q=l0)!!3{Sv${>krgv z>~vOK|DxM=r%hWg^9BO8i|DQhLYnX3j_T|WwEw$;SO>Y)ZW9(B#v{v`hA4iLnudP*twxGo!TecruV(DTHHN!q_Y`;I#se z)!fJ~{8v?X5)tU%x21j9@xTcn;f$)Z#0HBmalS~asN&Lh>CUlL=8MK$_mOZod=me{ z#UfNXDQCCr*rE4%w5YY2RbjnG&bILk|G%^8t@Uh-k>HJk#V!+R70CSp*8=;>z|K!) zWiGmy_YtC=l9~0#(D6r+;{zHGHAx-rqDyr6XJ@B;%p_o%iIdNk_nvzZ!w~g#_>jb+ zyQws%ca(S0al4vPq96Wx{zj~xhC&aT0&MgV*UN^P0jrF>_#pS5C*UUaVc9n00V?D~ zXV!fteefel@~GZ2aoU0Z_mY84Z5i7Y2&47_-Eh94zI&ZRHbQIv{#t_J#$Ahwr-?-@ z`ILM>L|}kjnsuV_ma;%NJ0^Q&+CF*(Revr2Y~1$mkl~%F5i0gjtEpk6z;zcg)>WfHK#D$J%M$Awly>H*RIbCBZtF4bfI9Y9qZU%fy%|}7L6v-4 zJiLnrEjRxVZj7&k2K>&v1mX0GeA}SLhBl96A7*;%75qUSs3kVW3|P5THN}{0Nll(3?#XG1=70yYa5}-ry_9-Ox`I^7>DiJjJ*c!oPIcVNa_O=GY&7&m*%@y>hb;h*TR z66W_t5JlwP5OG@8J%o#Db8X|1W&HX=kJ-xtC}c~tr1nkA@2hKzuLeplH8m};bsxgo z2f(fJzrdjRL{^{*lIc6@**vrFId^pQC?rMhVYYr_=ZrK(_2@_f;-DOkuS$_rS}w00 z9EJAma`Bs9Of?$!E8V55Z;e$sOSI2!aJqH~YFAj^FkW{(APVtoLpM7!xbB{vNE9=G zgp~HOS+>)_TcwwRV3DFH#TI&`h=%1O@&3nq=?#1wDM3;pt%8LPq1DWgRhN^00^Ig# z%%8Sqk-O?NUprlVdiDcJFZ!E0ka|B%w+AaLcW2-M+RiDe<@h0i|GAgF$v@FC->lg@ zB-AUL)6FW-6KUY-8A-W+_f<%Gz_)@jJxx%y26ZmzW1oxU^Z}Jyi*vcgDdbxrca^-_ zt>SY-D%d{Bmk62?3P%^Sa?4-kNhcEC$8}{N@IV*$ajnUUdh^*J%iien@WDi95cPwo zWD&zAsxxB0CN440DIYFc-bMRsrljD7g`~l;vVNqV|5Ld;$X%lcbu@Ttcm76_3znkH zG0No{Rq))QP_dil-C7?<{o%G_W`7LGeHd3!T}aoWA?gHEGW^V>5-BLi2WE z`<*W3)b~N|+T-`p&8Owy%TKpuQa@qdQ zDww`Wp8-#7yGzF`wf4#Tl&-;4E!&T!v)8Zbj5Dj94t|R(wUfqU3AJIYXb+BDBJG>j>U9 z4PCV#}JhC#n_zx938H8pfzPOTGh^(G@=^&1dWyn%f9eUd`s3!W^n z68TGCJE)OwrQv2vfQ8Fe=2ApHuhXKvOM#L+vR>)4F3BtHb4$^A@yePn?08L3G;O(F zQ_V(a0SySHplw`eWuHrh5IZQ1Yd_n*EJtC6^H5kZTfrO?=~quCH|1_lkl&av5X); zlOGdmi4O%*r1EF;Ex!!4d8q?<*%pbL`FOuS_YjDM3vgMf)1})oSL+L?KMcOkLDu4} zCRga`&V|f|mZXn?ADjJMM8yW>*RKi6TN_a(&&sdFks{=2=v0Q$JPkl>woi z0Fq5bXqv=sE-F#ceJ`DgA65z*NjG3b3QM=gioGYL@|!&P$Nb@sa#>xB1x-hi)%-~R zRk|Vx=;rn(s=*zgrkhH%%9{Q@JOnIzbE@_KUPL3Sb;oPN<*izfT_83Noo^6!rt;c4 zQiq7&)C&d+J#TAh49_ihTd-$a98C1oMz6`-I291eW(AMJsqH4I*y=4>YfCmUJ2K@r zU-~g1AsL+f4TLQ-MghQPydiF=>=W_UZ`0R!WuG72iWr%EW|BlTGu(1%kx0j@BQ{eL zU0ID;sSek>;h{>}SK(zjpSw(}h<@zui2wNsEvpInwqF`U#ctCVf%Di)rYDDxB-TccfJRhQgVND1V7JkDk7C2tW2N*mpJ;BEp zXU}15wMEj1dFXAMYtBt&#ZhcaY<`)9sI3&|rfzr5Lq9kp7p7vs=F@%ItyVJjfDhjX z%B$2DonxU0DJiRO9dEQU4%w=w!daY&YV|~&T2!23)Vz)T=OWO)ncZq`kMB7U)3@#~ zXPW*4n#=c`m%UKYA3^<@doU)kc%Rzk+DSX&{eho#**9=Z46xaMG3|YjX%_HM4pjJ+ zdJ48SYGDd}r=`L?Q?k^UETYh?33s;&sqI;)d{NnC8@sIWww6|Y>d!d?iZs`DkI(o8 z7YresoA;HRaP~U668xnhuE^oQef@cNq37k7{DEoifTPnUOB9(p3cwCa$L_2V?s5Wr;eiJnd+S>@vqzE!RK!6oRHkPc=NeLo-0(qk8R=%neiXXd{i zn{OT)b@X}+;$K-)W$LrfVvWGC%|b0Sy6)vm>LttklSAZ0g34y?jTLeX=P$7A9+qe@ zUHZqb&=rM*tMEGwvq;#8-jEc>!fI=3Bt@ z`+3(b`+fEA>_Ed|5r(pzRUxQ#1%vyB`6G|L8%sm|7y754_d4DEMN>C6GnpQ6v9hmq z?`6SfP|z{X-ABf>0HcZmvWJ2SbLRME`yOPUn)e1%UsWD+u_9ZJ;2`y}>(Y4`n10Xn z+XRcy{@g=wX+&Y%&)3Y+wg=!sizefZ>)SV&>yuh<)mh9lLz`OUYh3DvdIDxe7Y7El zQ{yyZMy*Hi`J#;2fTxl^Z*F!I+Q=s%=+otrR-nT-nDWVew?jKtkGYCMEZ)L`6@@h? zghdtEEn2U%g_CcBwrxyZK`D@qO6eVE&IAO0U79TYq03@67f6 z{26?vB0~HD*?ja^N%qRehL~VtaVVVX{kLyV@!@Xh)ZdGf6P#}(Ri&B()XNye>pa_H z=$Y+O-3j@jJ{yIE$L2Ql;xC7&fQd;6@Lh*^K(D^zY?V45{W|b$DfGSsO#{}>19imD#IIxac!cTP zW!~r{l_4wGOX4DdI7zKeRP~GZL+-=+1sxX6alzg7KmVQ~i#cPftCaEz5YzVwG#M3K zepU203O}9iSrWS+$;B`&@YZR6MbX~4`B7+HOgc)Ek4ocVrZG%8D%of2F#P#7+}G)* z{YU=TTn5w0QF9j4nU8Ya{@!CWB>07{1H)&R){8b0=XQn?wHGcoBdBJT2kHJr*v#T1 zN8*L;`=euuXBxA|7f6o#oP6%Hy%8e~ za{kxr-AMs_FD;^=gE3MJE~?P>!BVx3c+VW1N+!H+ZT;@5`nB56pSch_^t%(xFru*p zh>4p@Q#uU>za0S(y6s)_OP$0Us28%Obh1ST(0dM@LzwRvM=Ki?wi3Wn+?xJ-lMqHdGlQE9KTQ^#+wG`A|Kb&3|Lpchhr+IdFHb zYYX)M+WYFSsJ^IgkQ9*kB2r2!A(DbfgM>&UN;fFY(1^f*C?PFMNF$-dfC59q5Yk=4 zz`zVSbi)kIbI0fXC*HN5`_q}V?wWhfjJE zCkCQ1h((xZ?|cne{bBs7 zC~vtMB3>d@;c||>6^)L&WX8g3#~8EKwqsUL|EMR$Oxz6YLgz~1KKy9_&Q4p3uRM%_ zf!H&?QAS6#^}6rpG`vUDrlD;_l-}EA`5O(DY3G@c4(3kJq`@&)xO<5ZZaN?4kP%tDFAn(XUsY zy-R3mUiHB-ftHObY|uaDKp}&!9fDNXwgYiP0NsQW(E#%B2cHMoyZQS9kr}TbUjYgU zM(KXeC_nJyi5Grd7%wNkbe_f1>%cI336DGnUS;6OW(2gtp zDpS^Lk~PUyI=%&m#IsV}yqTKGU&Dj!GlF1Jpuj|IKkt0M_IC76+;YBd(?U*&>V~bc zcIe(08o%$YkhhW0s62hUofm2%tR;tZJ5s3?(D$dHinZn8a_8-_Bb9anf}nH`fE+<# zv5XFQBye(y4Ov{+X%fC(eLQ4B6NuEg%`+omHz8E$aO--R_(;<=U@2rocwLZmm0A2s zZRvENwwq$U-qAW+`dD_;KJh`MEe|meUneyQDOUU2;o68xs*gJ!HT4C2|Kw5ceD25E zkhSII{`!lxqV?xGm(+~P@Bm9u=S{MxY%6cB7Fx4_feGKoCsI5KmCZUB8Mc8DwaWu< zr!D>JzDK9B3_J?M@7@kQM5&4OaTESf)Ynz2|JpLPD|%V;JUCs^?R!5*uKFo%AV}BZ zRqXpVC;Rg7#)p4~(>ZdxSXXy6&D*Z8;vDU|_zvYfNM3A}USL^P<+mwy=an$^hisJ$_m}mdHrqEH?v*khqtK@6o_C|% zkk>0zVX>&XgVkh8LP&wWaL_0D$Aqn!_93se)}Uum(do}8GoO_Xke4JfpRZpWT%K*Z z#PdH8p_PMVwOMxg~h^y5vDaLFEr{H5bU2~uMcnTUg3Y&Ah+)xpK zHI=7cVWWp=F@UZVf57Vs|6?GE2T;1|i&H5A7NwVU4;BuH4}$hE%N+~?$o?!>TEa5k8P-#jI<}Y> zp1*?=9yD$&F#nIgDL2U?3Ovx84H}f-Ckchbo)*yz`hOv;2Xh@ZFqU61{?T4ymR5W4 zutPO94OfP1!3GpG_s@d;%@6&x_4Y!jn9t>(b%)&1shn6TgEkR!%mU810s>NQjc2k3~Q4O>U0jl{oKCQ)n(*_cqzM% zW{;~J79bZ@`~4!)X;z?=!Yc4hFo`6pvjd~DOy8AIbUqDLWV9CB#+x^;Lw97{}zAq-{KSZ7qzSetjjAH zXk+hx|6VUCR;pV2qiwXIw`uMUF1hk%a7gCz#$&R_=eM~Oc?gbnyZJ&#BDJRW(S-ZC zpz-uSGb0D-bg7YXKMx0*A<)DF>(d9^l5CQn;#j?ws=g`5jymcF2{@-tuy|Y&dUu4J zP(&#CE$VL>T@CZN7^sl^9WJ+owNoQpWP4jd9a2=}FOb3h+qs9Ju|y8Ltrf)XuY>0G z*j1rhJUhsA(fZ-M^T*^w%A+Exd#d#@uFDz-;h@^XiZ@I@-CT@F_5%xc-`nYMS-pLg zguY|i5HqbV=KEp*ndE~>m8?F%`Zgcc?k;VU5!7ia0YYEbA8;Vhc)Sh370bKZCGS-Z z3r~ZnTlPz^8LpG>8jsRz&AnW@FW7J0*pw6U7mUjr6Zee>_){@^r9IBb=+pPy?|pzm zTtiQoK8t@eST|d%xS~tm+4eqw1`p5=>vY`ZJ)Sy|Jl6)}qLUrvHr-ZiF{vK?y#8W8 zHZ4&?X!LgvxQvxl=wr6+;y3FY;KT))na?C*=;3tS)51F^lOkhNkAp4uO(QFwxpQRf zR?|l|X}h-Ih!zd5zTZYy3_MI2Bu(k{k$F==HbEpT&&1j5o{&G>nFhzv=}0r$O#G6F z2wocrwoE>x>VKJiF?}w5Ni(&FB_fz5!rOycZonQuFAzGH`}Bdwox{EYcT>WhL{Lp^&DAlZqk}<#DAmU!Hz~gN;tsb zQ{>jkq_W!wE3inAZa)h-cx^xCj>1MIwQ&ddTy1jsz!{j|-JsR|djckfl{V-R|z z7uHx}aP4sm1O&%SY0Rjvo09c!uA?N1nV0`PSBBMDx9X2S3Kn3UB@HYMm#?h9k0 z>d$UTHulmFp`V5bvW+{6(J(<)Du#_lJCJiF)ga=qO$tf zjx+WSc1f6RFE#Zgo`NiRSo2aNrcUEAzQP2{n())>M!%Y0nY*QaLT<?fJftx}JD^a{`yN1P9Z zXMhI`HN@ECF45psIZWh;h6C7F*#Xs(w|kj$`-q63&gh?ncbfn?05mwrvOgzh{GI0$ z<|2qhL6Ythy~7mhaEES~cTC%k&Ft4vN@se3iaoij~Qv?*qkVOkCDZ*tmx*BBu%votDFPwBYn86I{Wji|1ju`_=t z6x5xC3a=zOa^P&A`CF8cHC#b7Egd_bz~AX2$6ri8i;HgNDTSI3wu7@*c+u*j3|tq_ z4mK?rWHYhWux_H%vO$$HaN^{%AR=LJ(bnsrfz>pq_UdlP^^OKpXP=r6G2pdlT};2u z0(*a?4FR&Z|F-h;C|+2lnQri#)RthMgo4>z90p=lqFpZoXA&`EO@g0zgCe3n%+I+Z zThfE&H#8Wo;4A{ZI0rW7#6X8jj!XV!p5pCcqxVMQDb3d~+ssZ_@Pe%7abDw!0fJ>_ zLA}cu6x(C)=e1^S`4=&YU4Pi~+m^2Wg$`2g(Y$O_2NwliRpM@%Q^oW;V@{_d-Y$u& znpD!8h)msp%U}wvnXL)#>ttc91oin9JI+lswb(BRXTl;NUpRe&ZZ~{YU3cI1m}~Yg zRz_r{R5im#?HbTno&X>NietqG060z{=r~$7@>}n%*n%sZH_sjLfO6f{r9W1RW-G5+ zq$Cyd)P^Y85P!Fm3Fo+Un2G@vIzzE;PG5@|WeeEL>i0E}GDaDMlukUmDlQI zuP+|i%dVISPaCg~Fn^lsGF7O#)=zn+*UZ!RhW0%E;t4m;^WZ_SKZ~fqN{+*uY6X%`DNM|H&U* zRZ-rG1e-884Vfn&nOtB^OASEoYs+Yh$!UKO-69QvM-D#x^~f3jOlV=>YQP}c%6tX6 zof@^-+$|s0T3ZIcp$>`Ted6B>Z$5iHlg_;47Zu?otCCR@E?3e?%HSrMs+`06+-X?s zo{fOP(-sH6nj6nK`;BA#Vt9{o`Se&{nfZN-tea};?XdgBuz$GQ$aL%xT0(5Qy;c_b z=2{7{MhOeaQPlrz+S?iN?Z2;Cwyab~9zn@*bH@kw7Ye|Th|UaGk3NNueW9h@6;AF& zkV}y)zR}AnFl2H)1ToSZ5;;mkAR>t0R<-Cj#pa6v1|8UWo2G&61ukSH{aab?WB%wD z+#y~X+Zy^#%#(e^r5n9{Dv)goak>9l^1w6DS3DYyUF+-Js8?^(rQYhT`SJ$op6zN?BB zyDqm!m-0O==9eIs#tQhEof`k3 zp14&>j!xheZj80vG1DcYaUy?0!EN=O>&PbjlWlQN%k?Yz)?f6^&`ns*Y3Ct(kUkB^ zb$r92Bsy%dY5)dX_c#?xg}nT$NUQACR$|OjrLRHeIN<9K$&7vFaq3*Ud%YE$bw;xc z?15S`c(vguHq)NZ34T)>FZ<-DuzWRlm5le&uRn$*!#KnG`NHyr+XNw@&L0K496G-bsIyBeu&bd?B+s^sMeN-3OqGhz zC=5C*=z0R=$;J#WjL`7x=eYlO)1B&a>s$|PiV^>q@>nz{Tq;IJV|@5;_O=Jw#bqmU z^A}u&Tzu!y@jj#}SotTasc0NzIlj?3xJ?7_!GH`fyacYjS909<*7J$*`5hojfU#(d zHE(ebc5jAr5fscmI#Mf;whQVZPbfc#4w&Y9+@LA!6<0Et#r&lPSu|F}#%aCXgPPZR zji&gJE8>y=V2ztHnlJL*2-wOc%TW2QbOQKM7-Q`IVr5`LkjS2eV0hV~`P~u~1S?Go zqgMN$XXo$UOW5$Ly>O*F9?c0$*x(aNmoo6CGes*cp~QYD`jJG`1Sft^jp^!>w0mb^RcQo3dN{Z2v!bW-h0NKCX5~6(L)tzJ;mmB6S(xdhMp!JE2DIW}k zRr-8q@I5cEihn*}Yb4hsHKMp<>6?(==ez#I9bKwMrEgU*JZ~Nd2kCuOcgJzf%FVnh zT1%f`FlUvR^hE?0C_9Of6TYNAEDizej=v20N?!Y{@U`jnvpkmv0?T z@HkVv&74CV(&7@QGabv{BL*0|C%fj6{}2zB8Z}K~M2| zG0zQLc65Ofx_34^RGwy?(O&+M5zW#kKhXep0rgF1dM)Kaw___{l46iki^HS0Ab#J? zz#}`T1nt(|653?*#GkwP*a7yM>AiflkMsI_pY5-N?2NvyZn_LoZEh6zPJ>G|FIG}T zH=S=&A`26WXz3>`B8_`=yNqj|CG!6=E+gg`AJVwDaQ3N6l$JOmh+kb zTi!zz`;H3c4B)t$$w%bb>XzrK^2?VW{{LJMO$OrTL^z z;ck&3tyn_q-s=3LlSdc#Eds{05IokS3`4fl`d*%ba|4K}#(?-At21qfn@5 zkpL=WlO*0&Oc*nY^L04@{mi(h`{%_w zA(a-{91o#&k$_i`P3g80G-e^K<}p4&2GF)_O_x#%gh3S@vDfZ0-Azl{-;IX1Gbglx zOW|BnpZIP7*#0z>Rr(OFO$7$ZdsY6au5R3Apc+7E>fr4^Qi37ipVT4lKe59J_kANw z#L#1~dtEuZO=I85V3i?TeK#qKLl|#zT-QLP6|76&Mz~Z)HmAxo?;hQpYP%zUiW-UM zCyv|SLUKmhIXnwJHjXqU#ipx{aRc}?=AY7p z3~bhBA@Yy8^i5Sc6sEd%enB;Bp$G6=Sr(0xuh*^eHGrwjTKw&ql!M7@Qi6}Ww?F_?>Yr^=~cYh zZHm}$HWxa%9-Nf*OnSOz3UZ93Ch@eEEqz1|JNJ&^oljigOSar9pYqcq z?J;8HbDo^C)M*-SVNR9s|vwa4ZUK<#I90}aNkJ4>H03VM+5Xl5@=#L0qgPwE1L}4=@M6y&5Yj==BUQg%2^8@UH5Z zbKs&Z;l8i#Vw^wXqzIFT%-@B4WuBJz=Tf^pakdd2(WGZX%Q3T8JE+^!{?wJO$LIB! zsKx7R@cB%qc9t1(0&oR}N?~{uS#p1a2&ns`!Mg-nf|2YSW2Dpx1`m~R4fJF$g&L3V z;No`o)|t00m*Q$j!7Vw#ZV4Ha8Rynyskk6AI~nF-A~!e5qMW)g#VvnFJrmB*8rfm% zvZ?&6-F9;lW23*(94UJNvu0m9MnIS=58!7cn(6~jAdwnqSTV(H^! zQ?bQX0Pq4DchY2!O|bz*4ApNs&xV+&>$i$D6d$Z8Hvh4-C>oOP+zz}Xh^7kTtN_ANJc!1n*^z0&R*d2u2Qb>8JFnANSj)on>m@;}3-k*7cqY*5gl(Z#jUE6@!)w|+ z!F+47M+S|sPwhj6(#HtDCOBvlqkU6<$Qs~rzX!2wDy zMiVPYZ@3=b7iPm2v3-bRQD?i(i$3wfHrc0ae2w;VLplR>6vr;~63)`Xm*L2y_uSXc zrTtUxxCn6VF2G`lF3^fk0CvDjKEV!Gm?JGQ(Tl97BiGG79#7=!yJMef$z~o)D~=%aWHLhIs?^}W3M|wg#Z|xD(T(`hD-98!e)HKL;=2e_{SRH((#!w= literal 0 HcmV?d00001 diff --git a/damus/Models/Wallet.swift b/damus/Models/Wallet.swift index 1c2552c4..936198a8 100644 --- a/damus/Models/Wallet.swift +++ b/damus/Models/Wallet.swift @@ -83,8 +83,10 @@ enum Wallet: String, CaseIterable, Identifiable, StringCodable { return .init(index: 9, tag: "breez", displayName: "Breez", link: "breez:", appStoreLink: "https://apps.apple.com/us/app/breez-lightning-client-pos/id1463604142", image: "breez") case .bitcoinbeach: - return .init(index: 10, tag: "bitcoinbeach", displayName: "Bitcoin Beach", link: "bitcoinbeach://", - appStoreLink: "https://apps.apple.com/sv/app/bitcoin-beach-wallet/id1531383905", image: "bbw") + // Blink used to be called Bitcoin Beach. + // We have to keep the tag called "bitcoinbeach" for backwards compatibility. + return .init(index: 10, tag: "bitcoinbeach", displayName: "Blink", link: "blink://", + appStoreLink: "https://apps.apple.com/app/blink-bitcoin-wallet/id1531383905", image: "blink") case .blixtwallet: return .init(index: 11, tag: "blixtwallet", displayName: "Blixt Wallet", link: "blixtwallet:lightning:", appStoreLink: "https://testflight.apple.com/join/EXvGhRzS", image: "blixt-wallet") From c996e5f8b3b827eb1091aaa2954eea3fab968172 Mon Sep 17 00:00:00 2001 From: William Casarin Date: Thu, 6 Mar 2025 10:42:10 -0800 Subject: [PATCH 16/16] perf: don't use regex in trim_{prefix,suffix} regex is overkill for this, and performance is quite bad Fixes: b131c74ee367 ("Add prefix and suffix string trimming functions") Signed-off-by: William Casarin --- damus.xcodeproj/project.pbxproj | 4 ++ damus/Models/NoteContent.swift | 12 +++++- damusTests/Benchmarking.swift | 72 +++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 damusTests/Benchmarking.swift diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj index 3e3bb3ad..a085c88c 100644 --- a/damus.xcodeproj/project.pbxproj +++ b/damus.xcodeproj/project.pbxproj @@ -47,6 +47,7 @@ 4C0A3F93280F66F5000448DE /* ReplyMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C0A3F92280F66F5000448DE /* ReplyMap.swift */; }; 4C0C03992A61E27B0098B3B8 /* primal.wasm in Resources */ = {isa = PBXBuildFile; fileRef = 4C0C03972A61E27B0098B3B8 /* primal.wasm */; }; 4C0C039A2A61E27B0098B3B8 /* bool_setting.wasm in Resources */ = {isa = PBXBuildFile; fileRef = 4C0C03982A61E27B0098B3B8 /* bool_setting.wasm */; }; + 4C0ED07F2D7A1E260020D8A2 /* Benchmarking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C0ED07E2D7A1E260020D8A2 /* Benchmarking.swift */; }; 4C1253502A76C5B20004F4B8 /* UnfollowedNotify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C12534F2A76C5B20004F4B8 /* UnfollowedNotify.swift */; }; 4C1253522A76C6130004F4B8 /* ComposeNotify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C1253512A76C6130004F4B8 /* ComposeNotify.swift */; }; 4C1253542A76C7D60004F4B8 /* LogoutNotify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C1253532A76C7D60004F4B8 /* LogoutNotify.swift */; }; @@ -1925,6 +1926,7 @@ 4C0A3F92280F66F5000448DE /* ReplyMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplyMap.swift; sourceTree = ""; }; 4C0C03972A61E27B0098B3B8 /* primal.wasm */ = {isa = PBXFileReference; lastKnownFileType = file; name = primal.wasm; path = nostrscript/primal.wasm; sourceTree = SOURCE_ROOT; }; 4C0C03982A61E27B0098B3B8 /* bool_setting.wasm */ = {isa = PBXFileReference; lastKnownFileType = file; name = bool_setting.wasm; path = nostrscript/bool_setting.wasm; sourceTree = SOURCE_ROOT; }; + 4C0ED07E2D7A1E260020D8A2 /* Benchmarking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Benchmarking.swift; sourceTree = ""; }; 4C12534F2A76C5B20004F4B8 /* UnfollowedNotify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnfollowedNotify.swift; sourceTree = ""; }; 4C1253512A76C6130004F4B8 /* ComposeNotify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeNotify.swift; sourceTree = ""; }; 4C1253532A76C7D60004F4B8 /* LogoutNotify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoutNotify.swift; sourceTree = ""; }; @@ -3772,6 +3774,7 @@ 4C2D34402BDAF1B300F9FB44 /* NIP10Tests.swift */, D72E12792BEEEED000F4F781 /* NostrFilterTests.swift */, 3A96E3FD2D6BCE3800AE1630 /* RepostedTests.swift */, + 4C0ED07E2D7A1E260020D8A2 /* Benchmarking.swift */, ); path = damusTests; sourceTree = ""; @@ -5002,6 +5005,7 @@ 4C9B0DEE2A65A75F00CBDA21 /* AttrStringTestExtensions.swift in Sources */, 4C19AE552A5D977400C90DB7 /* HashtagTests.swift in Sources */, D72927AD2BAB515C00F93E90 /* RelayURLTests.swift in Sources */, + 4C0ED07F2D7A1E260020D8A2 /* Benchmarking.swift in Sources */, 3A3040ED29A5CB86008A0F29 /* ReplyDescriptionTests.swift in Sources */, D71DC1EC2A9129C3006E207C /* PostViewTests.swift in Sources */, 3AAC7A022A60FE72002B50DF /* LocalizationUtilTests.swift in Sources */, diff --git a/damus/Models/NoteContent.swift b/damus/Models/NoteContent.swift index ea3ed120..70aac84d 100644 --- a/damus/Models/NoteContent.swift +++ b/damus/Models/NoteContent.swift @@ -257,12 +257,20 @@ func mention_str(_ m: Mention, profiles: Profiles) -> CompatibleText // trim suffix whitespace and newlines func trim_suffix(_ str: String) -> String { - return str.replacingOccurrences(of: "\\s+$", with: "", options: .regularExpression) + var result = str + while result.last?.isWhitespace == true { + result.removeLast() + } + return result } // trim prefix whitespace and newlines func trim_prefix(_ str: String) -> String { - return str.replacingOccurrences(of: "^\\s+", with: "", options: .regularExpression) + var result = str + while result.first?.isWhitespace == true { + result.removeFirst() + } + return result } struct LongformContent { diff --git a/damusTests/Benchmarking.swift b/damusTests/Benchmarking.swift new file mode 100644 index 00000000..9dc8942c --- /dev/null +++ b/damusTests/Benchmarking.swift @@ -0,0 +1,72 @@ +// +// Benchmarking.swift +// damusTests +// +// Created by William Casarin on 3/6/25. +// + +import Testing +import XCTest +@testable import damus + +class BenchmarkingTests: XCTestCase { + + // Old regex-based implementations for comparison + func trim_suffix_regex(_ str: String) -> String { + return str.replacingOccurrences(of: "\\s+$", with: "", options: .regularExpression) + } + + func trim_prefix_regex(_ str: String) -> String { + return str.replacingOccurrences(of: "^\\s+", with: "", options: .regularExpression) + } + + // Test strings with different characteristics + lazy var testStrings: [String] = [ + " Hello World ", // Simple whitespace + " \n\t Hello World \n\t ", // Mixed whitespace + String(repeating: " ", count: 1000) + "Hello", // Large prefix + "Hello" + String(repeating: " ", count: 1000), // Large suffix + String(repeating: " ", count: 500) + "Hello" + String(repeating: " ", count: 500) // Both + ] + + func testTrimSuffixRegexPerformance() throws { + measure { + for str in testStrings { + _ = trim_suffix_regex(str) + } + } + } + + func testTrimSuffixNewPerformance() throws { + measure { + for str in testStrings { + _ = trim_suffix(str) + } + } + } + + func testTrimPrefixRegexPerformance() throws { + measure { + for str in testStrings { + _ = trim_prefix_regex(str) + } + } + } + + func testTrimPrefixNewPerformance() throws { + measure { + for str in testStrings { + _ = trim_prefix(str) + } + } + } + + func testTrimFunctionCorrectness() throws { + // Verify that both implementations produce the same results + for str in testStrings { + XCTAssertEqual(trim_suffix(str), trim_suffix_regex(str), "New trim_suffix implementation produces different results") + XCTAssertEqual(trim_prefix(str), trim_prefix_regex(str), "New trim_prefix implementation produces different results") + } + } +} +