From fbccdd47dfebdaaba8121564cfb3c13edd53aea5 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 11 Jun 2022 09:10:01 +0400 Subject: [PATCH] Various improvements --- .../Telegram-iOS/en.lproj/Localizable.strings | 1 + .../Sources/Node/ChatListItem.swift | 6 +- .../Sources/InAppPurchaseManager.swift | 48 +++-- .../Sources/StoredTransactionState.swift | 57 +++++ submodules/PremiumUI/BUILD | 43 ++++ submodules/PremiumUI/MetalResources/chars.png | Bin 0 -> 11102 bytes .../PremiumUI/MetalResources/matrix.metal | 79 +++++++ .../PremiumUI/MetalResources/random.jpg | Bin 0 -> 37539 bytes submodules/PremiumUI/Resources/badge.scn | Bin 20239 -> 27968 bytes submodules/PremiumUI/Resources/lightspeed.scn | Bin 14641 -> 14629 bytes submodules/PremiumUI/Resources/swirl.scn | Bin 0 -> 84910 bytes .../PremiumUI/Sources/BadgeStarsView.swift | 59 +++++ .../PremiumUI/Sources/DataRainView.swift | 198 +++++++++++++++++ .../PremiumUI/Sources/FasterStarsView.swift | 107 +++++++++ .../Sources/PhoneDemoComponent.swift | 199 +++++------------ .../PremiumUI/Sources/PremiumDemoScreen.swift | 15 +- .../Sources/PremiumIntroScreen.swift | 25 ++- .../PremiumUI/Sources/SwirlStarsView.swift | 204 ++++++++++++++++++ .../Sources/ReactionSelectionNode.swift | 146 +++++++++---- .../TelegramEngine/Payments/AppStore.swift | 1 + .../ReactionsStar.imageset/Contents.json | 21 ++ .../ReactionsStar.imageset/ministar@3x.png | Bin 0 -> 341 bytes 22 files changed, 992 insertions(+), 217 deletions(-) create mode 100644 submodules/InAppPurchaseManager/Sources/StoredTransactionState.swift create mode 100644 submodules/PremiumUI/MetalResources/chars.png create mode 100644 submodules/PremiumUI/MetalResources/matrix.metal create mode 100644 submodules/PremiumUI/MetalResources/random.jpg create mode 100644 submodules/PremiumUI/Resources/swirl.scn create mode 100644 submodules/PremiumUI/Sources/BadgeStarsView.swift create mode 100644 submodules/PremiumUI/Sources/DataRainView.swift create mode 100644 submodules/PremiumUI/Sources/FasterStarsView.swift create mode 100644 submodules/PremiumUI/Sources/SwirlStarsView.swift create mode 100644 submodules/TelegramUI/Images.xcassets/Premium/ReactionsStar.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Premium/ReactionsStar.imageset/ministar@3x.png diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 0f820d369f..cc0aa1e301 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -7711,5 +7711,6 @@ Sorry for the inconvenience."; "Premium.Purchase.ErrorUnknown" = "An error occurred. Please try again."; "Premium.Purchase.ErrorNetwork" = "Please check your internet connection and try again."; "Premium.Purchase.ErrorNotAllowed" = "The device is not not allowed to make the payment."; +"Premium.Purchase.ErrorCantMakePayments" = "In-app purchases are not allowed on this device."; "Settings.Premium" = "Telegram Premium"; diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index 2c2f9345b2..7aff6992c1 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -2241,7 +2241,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { transition.updateFrameAdditive(node: self.titleNode, frame: CGRect(origin: CGPoint(x: contentRect.origin.x + titleOffset, y: titleFrame.origin.y), size: titleFrame.size)) let authorFrame = self.authorNode.frame - transition.updateFrame(node: self.authorNode, frame: CGRect(origin: CGPoint(x: contentRect.origin.x, y: authorFrame.origin.y), size: authorFrame.size)) + transition.updateFrame(node: self.authorNode, frame: CGRect(origin: CGPoint(x: contentRect.origin.x - 1.0, y: authorFrame.origin.y), size: authorFrame.size)) transition.updateFrame(node: self.inputActivitiesNode, frame: CGRect(origin: CGPoint(x: contentRect.origin.x, y: self.inputActivitiesNode.frame.minY), size: self.inputActivitiesNode.bounds.size)) @@ -2253,7 +2253,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { transition.updateFrameAdditive(node: dustNode, frame: textFrame.insetBy(dx: -3.0, dy: -3.0).offsetBy(dx: 0.0, dy: 3.0)) } - var mediaPreviewOffsetX = textFrame.origin.x + 1.0 + var mediaPreviewOffsetX = textFrame.origin.x let contentImageSpacing: CGFloat = 2.0 for (_, media, mediaSize) in self.currentMediaPreviewSpecs { guard let mediaId = media.id else { @@ -2279,7 +2279,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } let mutedIconFrame = self.mutedIconNode.frame - transition.updateFrame(node: self.mutedIconNode, frame: CGRect(origin: CGPoint(x: nextTitleIconOrigin - 4.0, y: contentRect.origin.y - 2.0), size: mutedIconFrame.size)) + transition.updateFrame(node: self.mutedIconNode, frame: CGRect(origin: CGPoint(x: nextTitleIconOrigin - 5.0, y: mutedIconFrame.minY), size: mutedIconFrame.size)) nextTitleIconOrigin += mutedIconFrame.size.width + 3.0 let badgeFrame = self.badgeNode.frame diff --git a/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift b/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift index 08bda86473..b1df3d7b7a 100644 --- a/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift +++ b/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift @@ -30,6 +30,8 @@ public final class InAppPurchaseManager: NSObject { case cancelled case network case notAllowed + case cantMakePayments + case assignFailed } public enum RestoreState { @@ -51,6 +53,7 @@ public final class InAppPurchaseManager: NSObject { case restored(transactionId: String?) case purchasing case failed(error: SKError?) + case assignFailed case deferred } @@ -63,7 +66,7 @@ public final class InAppPurchaseManager: NSObject { private let stateQueue = Queue() private var paymentContexts: [String: PaymentTransactionContext] = [:] - + private var onRestoreCompletion: ((RestoreState) -> Void)? private let disposableSet = DisposableDict() @@ -82,6 +85,10 @@ public final class InAppPurchaseManager: NSObject { SKPaymentQueue.default().remove(self) } + var canMakePayments: Bool { + return SKPaymentQueue.canMakePayments() + } + private func requestProducts() { guard !self.premiumProductId.isEmpty else { return @@ -119,10 +126,16 @@ public final class InAppPurchaseManager: NSObject { } } - public func buyProduct(_ product: Product, account: Account) -> Signal { - Logger.shared.log("InAppPurchaseManager", "Buying product: \(product.skProduct.productIdentifier), price \(product.price)") + public func buyProduct(_ product: Product) -> Signal { + if !self.canMakePayments { + return .fail(.cantMakePayments) + } + let accountPeerId = "\(self.engine.account.peerId.toInt64())" - let payment = SKPayment(product: product.skProduct) + Logger.shared.log("InAppPurchaseManager", "Buying: account \(accountPeerId), product \(product.skProduct.productIdentifier), price \(product.price)") + + let payment = SKMutablePayment(product: product.skProduct) + payment.applicationUsername = accountPeerId SKPaymentQueue.default().add(payment) let productIdentifier = payment.productIdentifier @@ -156,6 +169,8 @@ public final class InAppPurchaseManager: NSObject { } else { subscriber.putError(.generic) } + case .assignFailed: + subscriber.putError(.assignFailed) case .deferred, .purchasing: break } @@ -205,39 +220,48 @@ private func getReceiptData() -> Data? { extension InAppPurchaseManager: SKPaymentTransactionObserver { public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { for transaction in transactions { + let accountPeerId = "\(self.engine.account.peerId.toInt64())" + if let applicationUsername = transaction.payment.applicationUsername, applicationUsername != accountPeerId { + continue + } + let productIdentifier = transaction.payment.productIdentifier self.stateQueue.async { let transactionState: TransactionState? switch transaction.transactionState { case .purchased: - Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? ""), original transaction \(transaction.original?.transactionIdentifier ?? "none") purchased") + Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? ""), original transaction \(transaction.original?.transactionIdentifier ?? "none") purchased") let transactionIdentifier = transaction.transactionIdentifier transactionState = .purchased(transactionId: transactionIdentifier) if let transactionIdentifier = transactionIdentifier { self.disposableSet.set( - self.engine.payments.sendAppStoreReceipt(receipt: getReceiptData() ?? Data(), restore: false).start(error: { _ in - Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? "") failed to assign AppStore transaction") + self.engine.payments.sendAppStoreReceipt(receipt: getReceiptData() ?? Data(), restore: false).start(error: { [weak self] _ in + Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? "") failed to assign AppStore transaction") queue.finishTransaction(transaction) + + if let strongSelf = self, let context = strongSelf.paymentContexts[productIdentifier] { + context.subscriber(.assignFailed) + } }, completed: { - Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? "") successfully assigned AppStore transaction") + Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? "") successfully assigned AppStore transaction") queue.finishTransaction(transaction) }), forKey: transactionIdentifier ) } case .restored: - Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? ""), original transaction \(transaction.original?.transactionIdentifier ?? "") restroring") + Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? ""), original transaction \(transaction.original?.transactionIdentifier ?? "") restroring") let transactionIdentifier = transaction.transactionIdentifier transactionState = .restored(transactionId: transactionIdentifier) case .failed: - Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? "") failed \((transaction.error as? SKError)?.localizedDescription ?? "")") + Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? "") failed \((transaction.error as? SKError)?.localizedDescription ?? "")") transactionState = .failed(error: transaction.error as? SKError) queue.finishTransaction(transaction) case .purchasing: - Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? "") purchasing") + Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? "") purchasing") transactionState = .purchasing case .deferred: - Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? "") deferred") + Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? "") deferred") transactionState = .deferred default: transactionState = nil diff --git a/submodules/InAppPurchaseManager/Sources/StoredTransactionState.swift b/submodules/InAppPurchaseManager/Sources/StoredTransactionState.swift new file mode 100644 index 0000000000..3f0f328d81 --- /dev/null +++ b/submodules/InAppPurchaseManager/Sources/StoredTransactionState.swift @@ -0,0 +1,57 @@ +//import Foundation +//import UIKit +//import SwiftSignalKit +//import Postbox +//import TelegramCore +//import TelegramUIPreferences +// +//final class StoredTransactionState: Codable { +// let timestamp: Double +// let playbackRate: AudioPlaybackRate +// +// init(timestamp: Double, playbackRate: AudioPlaybackRate) { +// self.timestamp = timestamp +// self.playbackRate = playbackRate +// } +// +// public init(from decoder: Decoder) throws { +// let container = try decoder.container(keyedBy: StringCodingKey.self) +// +// self.timestamp = try container.decode(Double.self, forKey: "timestamp") +// self.playbackRate = AudioPlaybackRate(rawValue: try container.decode(Int32.self, forKey: "playbackRate")) ?? .x1 +// } +// +// public func encode(to encoder: Encoder) throws { +// var container = encoder.container(keyedBy: StringCodingKey.self) +// +// try container.encode(self.timestamp, forKey: "timestamp") +// try container.encode(self.playbackRate.rawValue, forKey: "playbackRate") +// } +//} +// +//public func storedState(engine: TelegramEngine, : MessageId) -> Signal { +// let key = ValueBoxKey(length: 20) +// key.setInt32(0, value: messageId.namespace) +// key.setInt32(4, value: messageId.peerId.namespace._internalGetInt32Value()) +// key.setInt64(8, value: messageId.peerId.id._internalGetInt64Value()) +// key.setInt32(16, value: messageId.id) +// +// return engine.data.get(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: ApplicationSpecificItemCacheCollectionId.mediaPlaybackStoredState, id: key)) +// |> map { entry -> MediaPlaybackStoredState? in +// return entry?.get(MediaPlaybackStoredState.self) +// } +//} +// +//public func updateMediaPlaybackStoredStateInteractively(engine: TelegramEngine, messageId: MessageId, state: MediaPlaybackStoredState?) -> Signal { +// let key = ValueBoxKey(length: 20) +// key.setInt32(0, value: messageId.namespace) +// key.setInt32(4, value: messageId.peerId.namespace._internalGetInt32Value()) +// key.setInt64(8, value: messageId.peerId.id._internalGetInt64Value()) +// key.setInt32(16, value: messageId.id) +// +// if let state = state { +// return engine.itemCache.put(collectionId: ApplicationSpecificItemCacheCollectionId.mediaPlaybackStoredState, id: key, item: state) +// } else { +// return engine.itemCache.remove(collectionId: ApplicationSpecificItemCacheCollectionId.mediaPlaybackStoredState, id: key) +// } +//} diff --git a/submodules/PremiumUI/BUILD b/submodules/PremiumUI/BUILD index 7cf7d94251..12c178b056 100644 --- a/submodules/PremiumUI/BUILD +++ b/submodules/PremiumUI/BUILD @@ -1,4 +1,44 @@ load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") +load( + "@build_bazel_rules_apple//apple:resources.bzl", + "apple_resource_bundle", + "apple_resource_group", +) +load("//build-system/bazel-utils:plist_fragment.bzl", + "plist_fragment", +) + +filegroup( + name = "PremiumUIMetalResources", + srcs = glob([ + "MetalResources/**/*.*", + ]), + visibility = ["//visibility:public"], +) + +plist_fragment( + name = "PremiumUIBundleInfoPlist", + extension = "plist", + template = + """ + CFBundleIdentifier + org.telegram.PremiumUI + CFBundleDevelopmentRegion + en + CFBundleName + PremiumUI + """ +) + +apple_resource_bundle( + name = "PremiumUIBundle", + infoplists = [ + ":PremiumUIBundleInfoPlist", + ], + resources = [ + ":PremiumUIMetalResources", + ], +) filegroup( name = "PremiumUIResources", @@ -17,6 +57,9 @@ swift_library( copts = [ "-warnings-as-errors", ], + data = [ + ":PremiumUIBundle", + ], deps = [ "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit", diff --git a/submodules/PremiumUI/MetalResources/chars.png b/submodules/PremiumUI/MetalResources/chars.png new file mode 100644 index 0000000000000000000000000000000000000000..1a00dd5f4e3a451e8ce2c0ae695654da80a4e9b2 GIT binary patch literal 11102 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 b)(bjYA@=wL`OZ_TztP}&rnjnYIz9bAqJ$4x literal 0 HcmV?d00001 diff --git a/submodules/PremiumUI/MetalResources/matrix.metal b/submodules/PremiumUI/MetalResources/matrix.metal new file mode 100644 index 0000000000..9cbfd8e745 --- /dev/null +++ b/submodules/PremiumUI/MetalResources/matrix.metal @@ -0,0 +1,79 @@ +#include + +using namespace metal; + +typedef struct { + packed_float2 position; +} Vertex; + +struct RasterizerData +{ + float4 position [[position]]; +}; + +vertex RasterizerData matrixVertex +( + constant Vertex *vertexArray[[buffer(0)]], + uint vertexID [[ vertex_id ]] +) { + RasterizerData out; + + out.position = vector_float4(vertexArray[vertexID].position[0], vertexArray[vertexID].position[1], 0.0, 1.0); + + return out; +} + +float text(float2 uvIn, + texture2d symbolTexture, + texture2d noiseTexture, + float time) +{ + constexpr sampler textureSampler(min_filter::linear, mag_filter::linear, mip_filter::linear, address::repeat); + + float count = 32.0; + + float2 noiseResolution = float2(256.0, 256.0); + + float2 uv = fmod(uvIn, 1.0 / count) * count; + float2 block = uvIn * count - uv; + uv = uv * 0.8 + 0.1; + uv += floor(noiseTexture.sample(textureSampler, block / noiseResolution + time * .00025).xy * 256.); + uv *= -1.0; + + uv *= 0.25; + + return symbolTexture.sample(textureSampler, uv).g; +} + +float4 rain(float2 uvIn, + uint2 resolution, + float time) +{ + float count = 32.0; + uvIn.x -= fmod(uvIn.x, 1.0 / count); + uvIn.y -= fmod(uvIn.y, 1.0 / count); + + float2 fragCoord = uvIn * float2(resolution); + + float offset = sin(fragCoord.x * 15.0); + float speed = cos(fragCoord.x * 3.0) * 0.3 + 0.7; + + float y = fract(fragCoord.y / resolution.y + time * speed + offset); + + return float4(1.0, 1.0, 1.0, 1.0 / (y * 30.0) - 0.02); +} + +fragment half4 matrixFragment(RasterizerData in[[stage_in]], + texture2d symbolTexture [[ texture(0) ]], + texture2d noiseTexture [[ texture(1) ]], + constant uint2 &resolution[[buffer(0)]], + constant float &time[[buffer(1)]]) +{ + float2 uv = (in.position.xy / float2(resolution.xy) - float2(0.5, 0.5)); + uv.y -= 0.1; + + float2 lookup = float2(0.08 / (uv.x), (0.9 - abs(uv.x)) * uv.y * -1.0) * 2.0; + + float4 out = text(lookup, symbolTexture, noiseTexture, time) * rain(lookup, resolution, time); + return half4(out); +} diff --git a/submodules/PremiumUI/MetalResources/random.jpg b/submodules/PremiumUI/MetalResources/random.jpg new file mode 100644 index 0000000000000000000000000000000000000000..708398ba99f86895dfa8b4d7f819758c382b1f0a GIT binary patch literal 37539 zcma%ibyOTd^WZM-?!nzR8({fbSw-EEIbSh47~po z76)Wd$$p5td%o8sU{uo>qD|jF0m^A{;CNECL)1GTeWj z0K|p?P~lK>fh5G$H7q>Bewe4ZhnBVs9;7bb!9oze|7kw*f$V zpAQT+EcQF`i~qx7BMFwi)FW4;TJf&uNlsC#AxUoTCf5Qkx6#j;{DSuG+R?2adiB!Q zvU)psBV5k~lQH)hhtkOYv2whRb-#$kudA##wGY%8HOLFS=@r!ZW>los)APJ_%Ze75 z=-(!nR2Y`IOD0FpY%kbw3FGUT=Do1GQBUN{YwkC!7g|ja_{CCd>z#?Kv-7PN;1h?3 zv>2CXwZuA*yUyt|1H8K6>p+=A472U^^mWxm>#YjCxrLSX<^E-uMpw0L1dJA&WK7aF zr(0YV1~LX-WIBcAUv=ajl6t2{Z@B&FL+Z4AO65XNE~M#a6vt?7_ZN3~_Lcw8$De2`Jw)(=QO4MzoQ*Jbjl zuy={mrFAuW(`oIa(|pyMzC5)uY;ZW2(NTALb7>?r;jS)q%_q5A`CUdb>JCtw%yMr&kirpc(#+stqFfKfKz$;a* z$4$4hb5IVNMT@svjtcC$SQMGJn37EF@Hz?3^AIf*!#u z224X_8i)k=sR!Bs~ylTY#O!HALQy;tck1B)mNshz zHj9+5@*EYrG`jeX**84XXo?4+<>!nt^V229sG0QwGr}@YQcR3rwJCT9MypH1i|UYi z*LBXrzxxRD;)=_!ByDLSRG-$SGAYTg>++4`7ZId)Sq8!b{!StWrG-?%#>{MnlnsX;Zt{;|c^w{g{6I{# z5oIF%OW1;_fP9Dei|q)Nf8w%iHLY5Nmi*Hzd93*=@NVBVDQ5pg^jF3iMnB*>Rn;wRcjzsO_S?N=D}M?giTUAM76atPlq2o4nBcrx?cu;s`912I8UT=SN5+r( zj{l5_OsYQbilzEmlnitkAcGlTyo|s>KEuQwtSkhO$vR;w7=`cJ?gb(+3jxJl_c$rZ z$4#R};2!&ma3B6|k)?bVLDLI_2jGZE`qUwgo2iNf0A+0(xFh$qS#|?2`w?8Ae#oTE zLMU780s+i#w|m%w0eknCr^5iPKs*YvH%5l&{?Mxq2eF4kx39^RTV#IWhjUbW;)ghR zjV=`-rfFg*axTID!vwJZVFL3Xn8Cl!;5imVt2I!54j`SH`ym5L&b%s;zuz_{LFFl7 zFrQp6e-Lg9tIh8Q z_S|51#U2`b_fWBj(r3phu?M#(RwFo&mD}f5o#y184>~ z5&OF-#)!CB-x#+!i%-+i5-PunrUYnU3LSb$QvcxiG$&ga_=deJ9&jD)M1%ndX+lgw z-WNH;+I~i6{h|=MJ0?3-y3L`u@TF^2JOr&Wa&-a~xEk*}M?EP{B~gSU_YZ&~w`VJI z_VicL4fgnNFN*&rj1~so-9hM@Xwh5fKY)h+?vphdURXuIClPXn2=eR+aX=MA<53`n zKgP?dQE-yaK+0!kvA+U!n21))Ri|TVURt9bz3~O$0?W*t={=C5JsXXS%}Qv9Y2{A zI5+@z_M<50X~Zcbm2ffxj0e6 zSWsU&rkhW6ib;It49|weo!7|WS(^6sXH-&AmzEAXZ<5lV2c?#r-c%lTfBPxp<5?Ra zlS~SOc!Ydg&;n<&$jgy()L7Ku%W{64zgD$D z?RH0<{LOV;P|2-2KgY;7!*Si_!4oVlYVOj1zT*w{%90w%ekAr<%u<-}A!w&c%5M~< z5wfrKigz&8veC9$CVsq=@kw&D)y-E@;;1&*ErZx3WCoy=FA1#^D9)(_Mk(nCY&e>N z37EdB_C~io3-Ofl8oca3{R2qFg6hm3(&?&s30>)8#uyA0sUw6O!FrqL5I&&_4(bd} z&4AZKRWSlP#dPJ2rCb(fhgT==AO+T^g$dVR{r)FLApJRZNBd&kR!t$%CHkza^~vlC z6CFn`eK5Ru4Q^d#Ci_A@y&gDO{ztO5Uv3^cU45p~qaTgqRO#i2(cQ7fMIK_|PRhf6 z)fc+f>jr}ueFH(Hsfw3Vl!=X{xyN8JQ13n0oIz}zwY~|&Bi+4t(A7~UH{oG0y?m3G zEo0Es9)6bD$)_`K(u^pb=2OjU-KuuWZ_I^0ADi|@QCOE|kFBs-PwzEJB3+3i9B2MX zkI~SW=vHHy_=Q{|i`qFAM^({Q{AemIOr!4B@=9XMqEI&0R-%s+PdHv0AkziAEm>{_ zul;!)kbVVB5CJMv>1mBxu-`Eq}r&XKl_mu_YdxxCAF=`ISx?@sAtGD&kMAkbz*6MRj3jO5@&Mw1+7Jm%OV|)eu)oS7*7rJcs%|uGATW}z zeiR2aq*uP{jc?W@Tpy8H`gjs`*Ct8r?F$XKzhz!+?57KFih(orn)AQf@nW&G>L5t_ZM{>r+`8bnOj!H4I)Zhn7Wxk$4Vjay%_SoY z(3zkw*VQD`X-soyrA+3;gXbwbVk<7SuKnKH-gS!eGO~tFU|;AthkQ1}tb&GLYpRjX zi#=g=>EXDbitA^vn_qHoP-`^(51?>4Ig4j%U0K+6m2rQ*JkCs&Tk-5U;pt&u{d7R6 zj9!lU4*;42v)UGE#PwdrSH$!bc+ur=cCU|UIlv0q_Zo%xdF z|5R%5W!EJ2tB9t^vye1x=cYtJ+lOkd_`0)xRj1m(3VW^OYPN0xqwrO*di*r`> z#7ZT^iBgl?>I#WM4OfiqN1|(jN6AiHQ;Ir5G84Nh+?sx^A}#u13GNO4nZ2iWhe3;* znVZHz>|Qo0i;tUfl4R9}xB`D2EyBy`)9WgX^DFFt4T+*osU24RmvgpUBaeI$Gs_B! zd4|LB)<(tODMTJmobpiIspyR}X9-R?7s)eFOYE~c7PN!=wwB~kx~%o=TF-;N1U4J3 zMRIA9G1D>3Da>_GY3f`~)CHw}tkyj*z@3jRRnH&oD$g(TEQBZ#OOC5?S9tSUE4ScU zBHA;>E@h)Ev93OTJkr)SuI^-3(0>9qr|z?!!qI7iqq6d=s0P6?S4-B zi5OR=-ll;zdGmX|1m$usKT$b2uRxdR?)V0k)$?b4a=q^n@dMDkwGVnz$(8N?92tW! zsu;P&Y5YW6qI#pmiIrCrR*QVHPe&!`=&W@}mVcJf-anNw`Vbe>)U3x1=8<_$9P;}u ziCaZU{Xt-B9TIsgm=1khD0s0eDp=7UKW*vV@W`_*Q&B9!)FzpYEnU~^v$G7DTb{4n z>8pS8W>I!c7GZ=GHAwsFO3AG7>dd$DKQGZ{g*xP3Ho{&+Jr#btJ{I9=$lJ8yF@2ov zm}Q?TYG2HSRvD;0q8am&m(jC`v@R?AquAXQWq$t5=YLu@l^O2e%M;{Y>eY1arQ@C% z{f%hWD-z(kk!$@ z;OP%*SPZzzW zOAiJcOB5Z#HUSQ7E^>~UhVOEq6B?l!)nGS_L494EF zSCG(6O$H6K)7~!T4eKZ4jFAROi_-h_jF37C7KJ3wb5sp*^nDh9peboh{K# z=g3&qgYbzj6*l?vMRP+O?U>!o=bRmJd((OabgFq`vhF?0ZB@nD zLYd(I2Ut<9*S;>&>^5}t@cyic9h>mI@x$f$_u^WoM8wm$!myaw^T#hi6x1UABwULb zI?e_Z+!bCu+O^IpLfS1$&IDbms}pA{_UdFjj<~HSklB1<`pnp-Dy`K8WOGn|N7@!%UG235RSX8V1e5I@PLsy9VA7Hgx zXKA4@x0r&lrh{?05yO4{f|zJCk)gjgup83HQBOQ{H99xlJ8UJ@cuAK}u5krw{xrc}MEGE5uV{3Xb?#>xDE< zOG$DIwsn?X0qTURZ*6oQ;E-vry38&i{DPo7*j(G=)t(w=VqW~bGf?V|CmFMK06KAO zrn*=CbLkn6KW#;TZV?@n*4Rr|q>c4nHA7O=Z_;1FppiaUnL&ph2hI_!n_S{SS6RFXZELJe&)cZzpwq>@RU(jk!@E0P%!GV zME{vD&swpK`@$Su+Llc#oI>QmQ8?zJeDhH+gqle{{dQIs|OAMOTd{?cg zlr-;WswDr=&nDD_-e(5k*v8#=HvZhd|la{8pQ zPROf$H5o4&fYPVpDB+mOH50Y6=7bpa`}Vrv%fhl3P$F^DvX^q2k8rCiegx# zV%~=_7rO!6$j%}=+60w>TixgZki9*jr~h{;il>ub#p7Do5>Bqr8PuEQLapx-RYq!M zed|4D2xak|PUkm0dw<5u;ShprdGMvSc1cs@1zYZ0_phUw+rmGtI{LDu_|V=h&KB|v zNU3nxn5?Bp17*HiugFZhk8NfFHniq`X*xG8ioe;EIeceJFYMqAb0OOmF=))OU*5?p z7C^DRs3q8TY_X1uY?l*cWAP+Q<^d4Mnr+-Dw2ZUtBt}+0;lW7`BM$2w^b@$biAaH!U&-HJlTK= zGvvp3iK5Y~lO6qQLaDWIRSDlxL&z;|46>tW<6Ll9hJO1U zx>Jb?vsZsDMRkyQy=XIZ#bk4n)N*EF@g$$LD4{1#W_EjQp>u=%VpUUxl+GBmZUig+ zrAikVs#)!I^sCfC>6w3w-cCGbY;(l9%XJ22Ue_e+e&f<2psU^&lH*RFAzk%r>HQDU zg)o?YDvEKxMMY}RmTpw~ zDq$^gx|53RR51q?_VkbEa!ZYjH2nTDt`QkJ9pehFm2}5C!IJs4_@(I^E?GVjeY>sGmq{PNM)VEU~&+J)fmYubc*kX zMpB6;*|iIq0XVDB57!UIxyMfbu+PC!GPw6|3;K0a${A8az&YxiKDex2Qb+01M*Z#? zN%U=KJ0CkY?c^8d{|J6XRzs;eWVU`9Fbr`+S1|r*yoACq?B1SnIy0rZ3a6qVcTlKp z9idHg3AqR|ph2;!kjc6RBg@Ad9pxJirjYU@s+4;MFL~ih@=y&O_$sSm;gRdtJwox( zkPys{=RET(z8#MWfJb{eYLKzb3!AMQYJ@Afjw;{5IoB(X|&Q+rgLp=2Bnd zv)h09HWVv}=duo_-BJNAJvhM=rClVAUa9C&ZZ|{8jOwqgn5WBB>NdW_j35xPB0FVl zE49olD5_9oE2}%Y!QL$`6()udk}eqw_<7+|DZHey_uPh90$o>L>fMt_O*9+ za|p%CdLFvY^-hEWV7zNl()se(;<3A#A`H0WLEUYDkYc%Bw!7^dg0ulY_^mFaC(WaW zSFqmGqJ+VcD;eLk1{vwR-ohNMrH4OI8ThQ3pMT>IGRcF<4Td8&V|v+=5`)nSaI$yus|dF$PoK8xcpwR4f`Tv*AaEhE^Y>KI)k zo3=Fs8A0q74(R5%CBHyzP@x)6Z!qNJxse8~WbUo`=C-tC`) z6fq`#vwF`}YoX#4aoA|d?2Fh)mx<*(d&e*1gNM9!Mq6mVOV?>CZ(ds6CFNOazv+xS z07ziS88q{h!yfN)r~gcLcJHwk;O!N)I`{rSXO!=Wbq43qF;x{8()F?~Z39X0V1`Hj ze)tDChcDhjmS_3?=ex-#*Ey7pg89G)Z~o{JxA(m)w6%M829^+y<|k;w^9j0*td@o< zyFUd}suUugjg;$wQx0ZPh6cwHeI^X<5#=npgTzR=uj%-A^NJ7TYkIZ1i!&=5wk^T$ zMcI#aAP8aI5Lx#i2kcR}xmZqJ*3e5UGvJ>6+C|ViN2WyE4x7IyU{`8j z)8|jxYQiRw%E)SPuJ=XV3k7u|M-?$wLr5fRY4NFVbRgSm7qMy~+iB_W*fz8>(|^svqpz+zf8mwEr86K#A>&M76Y{_A|N7$~ z)l)8`;m7UOK3WH&*$v%IEWk*{sUdZurc)YT>R5Ve2%(V90MfmyYuNjdi4C2~2zh&Q zjUj@gl66~)ST0SODcQsh3G-2Cx=aB|k z&alS1d|&%Xw5Biay~V`obnH8mgZlbEIZ?HxY=ju|8fNor5vM5xuQtH8I=dtO;)ei0 z7m$@fcIem2o;W4|^yTmF{hmO2Hiiiq&-TNk=Z(9;3P)vOl}Z z*9kblXV4z=7JA)FVJf72G|oe@;CI)4kjS7^Mw-Yv`MqzQgp_0R2!*{H_4>P474$Wb zMk_@(YUMjF1H7WPU;fi+B#f1{i|H+;V7=77hbFGT#>u%SK_e9K_b{%Y+F7NeGI8tc zR0uCjqGX4~Ma^byh&--w_UD?|g5owe4wSc)22E|KvxCo1smZLoh+9{;&GK`@DT{}~Xl(@~bU9-RF&oTs!R8Fd-VgRd!Cx}l+%#_T@0 zx5ph|mdP$5%ck#g6oKPGBcTC;HVEX+5gTm^eMRvBsO71{5&&B zjt8vE_f4|3;jCeq>Fes==9$`Qy`Bz%2=oiFGb2Gd18Rt-yx-Q_p#~cTYeZqzJ|dhl zbSNF4+l6j&@VRQ_B(p0Fp%a*5?=C9U7PuSXmL(OVZZmn5Y0{ttok1p8l;X~?))Ybi z;H5BygU)0h{vnkCB=z7wyR_bI-^JzDZoySdyufxkV@?30Z)jGHk0xFxo@B`HATD_~ zF)o*f+Ai@E-qw50gBxvh_93xI67o6L3l9x0qH z97WHD4wWit+7Qv2H1qS2D6gx^F)y50eQBc2s^(o*#xcg_0GXP$U|*#Ap8d=`e*udK zWxjl;ll^eoVFCWxOkGGP10waf!~TyoDs}m8N!y_;xVJx|Y6^Q;S3;iR2n)@d8B1`) zJnaA@-{aVQ%4Nu5QPD5SqP!ZW#OYfrL91fb$kiYbwTL|*k0(>g! zuC|)5${ST-^Xfq&DszV~DdHI^1l!Py{V@D?+JAuhAr3H;QHflNvr1P(&A1ppUK@Yt zhS|81{McR?23%++jDUG%9tpO_73}v=HT|r~n{9*o&u0+=5RZ%Hl_yE9T;^@XZdraF zgp9UgXmYkH9G*@MUZLpqe)YOJiBg!-v`1SGU@??nlLp>(kv5GU%N4+_sP{qzs-V|0ieS6Obpz*r;i-3aP4)cH=bYaX`&T z>9nR%0Emqv&wYCmm#U%dW`A4?Bxr6?_oQ1w^t4WTTRU4ht71Np==`Nh7(h3|ZHc3S?QPI+G+$F*&#qu_JT(Mk z?c=jGRhX57$h^n5Jfmzkvx(uEjTQ<0%9XY0zppOZx$Vq5m`W@~5+MpF0R0JYgo z5voo=e${YDbcFkmNE+=BA?&FfY7qX~3+L(@Q>k=2z6@j5g*dx?W*}Gr< zGP|M~bLpg0jxgSCzj>h+*Oi}UkaylzvzKH_pd0y1;U&kS!s3}L=WX159!jfxw1fK( zVCw{LSEO0tO{;QD6QnWqQk;@TWA41EBrv1Gi;lKFRTBe$2DbU49lRCBz@V*&F3r3n{j8g7h*K8;FvplYMc$mM(N_4z;NuQ z)NqI9PK<-Lhj7PoKi9llrhLr)+gjS}belKl;UN38bGDAx8HzM!HMzlno^JmG@C?1* zc6SluyG7Wywy9V>H}hY+1PFY$OK7+f(nw+^K3~zQ@uW_~^cP!2)+U;QJhG;vJsG5E z3@7sv^fYlnG;SN-u;@=5M=+oJ96R0;F+Rlmu()YZo>(AI1<8Gmoxa-;c|N-f{GvMg z%{=aMOuJcInJpng!Uau}E{;l9Ap_zo;`p;Ix#sYU6$d>RW`RQyS!%#wHwqjZyXpDn zq`5e)AjByp%;OZswQ(m8q*2W4M}ppB0;A*~D?*$x z&guP4BuyOpfrcL>J{SFvk(a+k2{*@_R#HFmu|EXj__R<_Mo*`Ki{pli@G%nd_q#GQ&QRI+wPa{?GoY5#jK;fO zLlzzvfjdL2l(UnEOgD#E$wzd=;&OmG-D&IvAFH7)b4ZQ!D3fP zzsZ3m@Ad8rD&qj4wPS4L=uE3qK?_*YBtL)PgH6`R^Zp35PX{$|lAw z0Vm?6eZQry1Z-NwmnM=;yMDd#HKHA{cQjE~)lFEpqca81%z7s@&YvFT88fOd0G+c(d4GJ14iq_^l%9Q`n>Qg)0^v+h$RnI;w{poocEK zYGRQZ^kfGA0jgZkA-vhY|_F!p+ zjis3U3Z4WsWt^IBxqNYy48%Xqx?5vQWV9W%e^je}Mf;&Z$C23h!9cAPgjxM1=hG#zV{spyT zOA<${EPqmP)BOls3>+isNOZ5c>7d#kac>+m{$cM28rT|T)Td`|d0yLU()4ZhczboAN#H-LfpyW^b+=`0uL(9`cV9hs4kV;W(Fv_Bq zxD=TTvAusiZ_6e-99Lch>cx18;Y>7l*1MH((=&^o5H>FCj7yqMev?Htk|%NqQ?X0q zt6F8DwjRzBMx?2zJ94!1-RSdF63kCvOh|WAf}2_A3fNBZW+5G3xHZskyzPi=YSzm; zP>PVN3Q1#r(D}%bK(ej9)N&D8I?-2I1hmtShqJ8bx&pa+#lS zp-IA00K=Fix(obqOxwfo7RbBIY)#s2N~>eAk;33!hm&xObJ<7_dk@MqiaLp&_^C50 z*z8Q(ni<=9L|ugtOIKaIr{PuQC!p(b94KPIjX$bZ=10PZpV01GU+;`dlAa=SKYD50 zcGRKdqK+36+P63=6;5OKo9VTWzlfM%-4*-#C-w`$T~3)`M=U3@yg288l69LVTtvg` zht-?iqvIO~ALp%tZ>!wRa4o6*`uNK1)SmJ~ z8dttBuk5;}E01~cxv!LXA*mW+EVgPJ@_wPRs?v88VwA`q-zJ=Z|6@f6*J9qHc$h5Z zUPdaqJTbx%Tx2Og5U-oJN54&o3xKU!E{|d} z>iD+gG*ifnK%;it8*xJO`SFvLzjv64+B;lX_DBJiGDa@}BxbWQwpt4P zRdjJ^gvS-KM9S0DH|WqsL>rH3lvP+(%#CP^+-YIxG)YE<2n5ObY2Y2O51#|0@9isd zvWB!Y)QRzxyX9ckwRNOJCqB~sCi^q($UYvLOf`*5Q8N~BAg`6CKt$t6h1?V`c6;4; zFK6ro0#n)2!D`DJ;-)-{B-NU=g@17A0pEHod8a4I=M>gtN);HzCU_l$Yvrx%aN5^I ze=(7GU$m0TMD*_EjscDz%Lt_Av3)XlD+YR)#h-IWZZ^${W_s0$CJ0@4vE_%5lD7F@ za>eH%uPeFMnYqJ*vMd2o{916scnZ=^92c&Q*<*%1wLwRY6MiZD)E1-?WYB4GMzM2P z_al7tx}j9#segdFyIdG($5Pgb1T%KddPkmACN7(9g6z-K)w!y{HrlkD%v6;T95uhG zO-dY^%vDOU;re*gFJ}y5;242*ZpxwXKx~|HWtyk#@S8P_DGX@iH^jpiDP5Hybd*n zJ{BC85h<8$HD2OyTv>coz9ZG)?o}jYdU$HW7Lj^#?_%A)q(@_?E?k57CQyeBLni{{ zGa5%FC2$$SC1B)!Z5(9Ua6M}>({@j#29ik$DA)Tz$(##<^{yRn;d9;X+3Nn$w@|Ea znVsAen~To%;f95i^s|Ha6h8-&r{Ob?oh6+GT^FB~iljdl4hhOndqM~7@F z$$Nu>P&(xmVl-q{+WKuhPOavOIQ8mE-x9yIH@5DUlrS~cXy?DB(rDo+cx?`EKJVck znVA!FDKP9AOzwOmX(+rkC|6KT2M-QVq=#{5*5@oq!^-+iWzV>Y9m)%{4>JA7^02O^ zoBsgxAM>`XHf?oox_C1nRaSiYWh-Nb>e0!L@kgKY2oLiH#N#{q-eo3XQ@%Q62is9R zt^rD#EmG;oM#F|QVR3gLt&R&*Yo4%TSr`ZWo;nQ3%InN_4h)zuOrn5eMPe3j0cjv= z{HeV~Wvyqpb8d~7*w;@BlUw7aRi}i3Rk%lSh$k7oRo`4xxz$HY53IS*!#N&B;hyrnK18;9c|zH)tygUgf`J2 zoaTax8ZvshR^EIuhhVu;1OXg7&cnu;xJ)c9Ae7VykQt-rs<5H4wAeoYMc>eFP(p-d zKRhm$Buz`VW!>nZ|6GK?wqg)?1EDpf$bvJb7@JcAKl_IL5~xJgT~nrS94>|{DVP$&{Dbw*+46T;EwNm-Ds~!1dn&n6fxg! z)r1vJcLF3gO%NDs47b1x72l7c8OM+@P9 z`mCE$s32kO4~N4|$1^ak>@qRzC#xXty+ZiO_avCqXj+wWA{Eu##qNU)K(=pMF8|hR?sg#1Q)35HDBXdOeFWtf-$v2VBhgO)6uTf$4s;r|u>{<03t(ku^qW4@06+?Z9@XSW<2W z>7Ak5B8Y>duL%k|5%rR2kwao3ljHirH)H8%grFKC2U*#V@jO2ha;>364VluLnOw=l zy##gG;eAAxV=fJFc*ulfpm?Sl7Tm2hn%`-!z61@flh<7&Ce$AAP&F?`B@`958a5

&`B?s+?3R{iM|tjY8L;Q;ZjRivoJTWs_A4y}-Qk@S?c?w{_e4fwlFzt;DJ1|O_HEiH~By*!)GP_74tD*V>hZ?>;rKpr|1sUw2aW=c{-)8EPR zAt#GEUM=77KK?0C(+;0t^8fY1YBFJS--S)-pff~^cBl4{>vMf?Ekz&uq#yw!-3(F+ zED?!aX}Yf_`?K-E%g4=2n>@7%T){AV`eNeWoYsZjWM!k)qlKt#MIUzwO1O&T_);>U z1~Xb(kqKDr582|Pe4~SB4!<@xpwm{HR!qmRoSMp#N+|bcG|PHd22w9B9pBRaNKTl| zBgGg@8tP-LY?z^guhWGX4G9B!MBb_vt)(FH$_t^e#Pm%y;6u3DZUm8RuB6DGD@%l| zmDEQ1YM@g*Qis08Icb=+!v$}XK<(kH1z&j-|sh>`Q=HB)Y}pIFu3M^&oj%Gq4WJa#>?k^L$o*^h`)KARk$Ge29QqRc0XEdj@sqYMm#9Ih*t)w*Vbh-o<62afTS3RoV;{b2 z+E>3?_|n}nWt!+B&1(9(0(0@Y(!m6jqy()@+96&x=L4BUHH$3dw&ip5(q%b3ErrU% zJpH6$;VtdugSlJ2asu1syn4#okyslqq1WxGF4Ohk7_HV)=t)BW*Q zF~6=v%t$r}3N2<{7`&ORj6A^MA&_GZSyrRi+&%LnlMxB zJygPjyI6*7Sy4JL;;&*~|G{ljV~S=wJ~L%UzM3OM;2i6g&EX8=i!;JqCrE6cDX&3c z7?NTP$2XNDOtvD5WEcP~9Y%r^Z;lr*M0FmXDq&A6iqOSafo7FSq~g4l@O z@>1<3E|AQcJx)$}n)8*{4npvl#mz-Q41SXtRVY5TycFk*N}Yo@-y)pP^+xltHE+!+ zFR?VvI4wJ6DK!Ri2OdklwHra53*}Vf)2l9gm_=1p16DqbPxrbN`+K5~Ua4=?9|Gu{ z-L-LuLgEZtDd2!1ASyuogt{O1P)!7{;_$Q6;zFW~QtGI=l~TsEi_S_G!dZQ2>dcWl zXqUrMw<&RN#7TplD9)y0Kq|!O+pF)A)0yjNN4a*w`Up&6wz||Gt8-3_;~SO;g1@)+ z1aCUh46KQ>OxPQIrD-k(TQ%#3!D7ByneJQ76{S?uVOG}6XRhc^<8mW|wx$ABWYN_# zH=;V}B~hWg(v%Xdl(9mDHc!MXkfNmdr=CNfd)D?CH7n_Ym{`R`L!@>F;YY}s78<4> zLHy58G-LBG$SKI_*yTSVh5@Q1*SD&v5@GYEf1Ad5E`-L%f94Wkll;w6E=y@2VO7X+ zr7$&o_r!%JS%4U*Dmmd17o9CJ0-n{Gulscy{sCOCH*E?JGYo1kS~@-l*QTa2nuVk7gsH?JtIS0NeDGPqXF}Sh2YyoeYs0N6dPK9xV zF$zh?{moT?y5E-X_c!XisVfGQtG1wU;!}K`TVif(bdB&87T@7|D$o&^WZoSoQpm zi7c!PEG}z#?5=q7jV!iN+e~o}W7Fo*;~caM1*PLjP|SL$iHykPP(+obqr#=031nk+ zu6WE0ySQ`-of{3lkebW744vA%4nSJ&Zqq>xon-?^R9;9yklJ$5&BbC+dV|SJWW-lp zN!R}n_6S)vlXyVHKbT#3@{xx!9Bm?yR4E_p^nY9;+5J$gwj*4G6ur+{jux$KT-ASqdQkgD z6B1DpoubXYqi(V0Wl#YS6}4D(NA1I%07j~vTNy$J$5tf-^6K`c2Q=`A201AuBU^CW zj-9{(7*hf?v_;V86s5L*uC)jy{SLhc?}Vh$W4NZr(cM%ZZq%G6(asP09HSu8o&blIf#dE7UoI~NaC1-Tq`Wmd3I-ZTJEiEOK6 z&}^qk?jqX?`_&MhDilmNY(6%RvL%^I%qkG#oNw7oaExcwZ9vy8>bcRQ{{g5H7i8=T zdhBC#PGqdKw(sE+5g*ySqj;f#vr>0=+$@x0j3jb8YcZi9tESb@c0!T$*eyF3?};@7 z45}j0M0KT76T;IwaeCqIxm*|QvZmU-pL_QMZtc^eQkz5gEtCQVPQImV40gQmv*;+- zHA21~hLwZKFHlfPhh?bTv738OAlwj&6vbcFBf%T(bZ{SyNU5#L`<-C%P3h* zXi2ARuZ1&|Gh)pZssu3sl;AI-f~6WA*h3@Rr&4ujvf31xJ~(j_yZ562K)tELBlI5%yjk4^RQ8J$CJmiYpWlOG#}?|<1+lEE z5;L?We{xg2YPI)3rZ6Q5Um=}2ZEzb#L{0pHQA#1K1>7m1cGPPoS;_j%yQN`b(L*G4 zMfZE6G-Tf2r5NjMR(Lu57o3K{)D8_(ez_XSRoZG@wu9e#$4m_c zUASt(XvewIv4Lo}`qU+v4I@@y%iy9NmV3f+?s89-!`w$4v6F=YB=l zvY!>!N!$rvtESLuti)Oh9DnVux_u*`x%K+}QRsLcMp{!FF9IvvY-KurD^mGX(|kWT zf(Xo(cxcwH_Q0&Sm|~xsFs&%xXN*B20`70O`U35V*UZ*Zf)Jt6$(PeF53$1K=^?P{ zdHJkQ+_Tl})NQ9qBAKEhAysg1HC|G87!bT5TD;=qcj@vBWx-Mlj51QAkK1T^eUBgZ zQPc|mBt6=C-{29IWsdV%`kn2#aatTQ<%J#sz10)}!esqYo);f*Yz71^s)z-(tEuw# z<9>Xj`Ou5__bXkW)wIG8QE@gU7B`&09U$Fong?NTr99_D{d3=LmNhEl#26Sm1y>kf zm}r2p9@K2HVGRBUsCCVBOAql|$G03&N^`?S%<>mZ$f^O79li#3^CU?Yz`?0EFVlLO z2K>|G-lNgt& z217+hMsCZx^O~l+F>Ro0!ecS0BR`E=nPvll4b`I4Urykx!+@x~Ci0%HH#oHmrWpOf=QvFXcyaONKv=qnD_fNsIbsYIHDznslKN*9=Pse66js6@vs zFK?C)chX61gho07RUTPfFpdwIR!Lsn#vyE=FYaxLHG*4IP^hSD{kzqie5CgE?dLf{ zI%_~2d@=5aaN3w2tDzvK{{@3Ue7_Z4WyAK7`ac|2#FLjMfe|R$Bxd87E%3>1$#`Gx zuk>8hgBx)#4TpY$i4B=Zo5_ZoZn_;dmD_J$w}1YhQrQ$x8wr1o%c4jUv13db)Bvw_ zYyG8xFzWNcFv=MtBO^DlfMHZUjp+klCA;caGUFGeE-|4_D1{T5(I#+dxQY^Vy36@3 zcf5Av_LHeWkVu1OTE)q&rm>UbV2lchjr3LB4rbf;v=U^+0j?<}O%Nt!xDj)6QoFw% zz9w^A?&x}Csfag|XK{!k?XEHTI_>ud#`Igfmp01>1k^C66-24n=dNWK^hSb zX$OYiCg+XI{!Jc27Q~8CRE{#wg`K6+U54O4xw#MJyDRd1Bj@k8_3#- z4zFpAQ!W1h-?05-7HkXwoEnXNMF1m3szg{Iu~LPqx;Jg}T=_1uB_;HVYLK+k10j%r zp|V5)*LR5Sfu_aJbqXb9iiAZ`ywB3A)@qZL3@{!2Mhm#Ns@1zUH4&LHR7^vHosRS(&EDew0CLB1c|0ePa#%Ry zEjoo_xQSIv5Cwo;6X(XQ9;Gk4ZsP8%M@;}=bgn>)b%Nl|Hy5ddK+E({(7WVO%D&!% z8bVlk5LbnJnaHZskz6cDRzxA<^eNsrKHZo4G#M$SWI`~x1^^D=A%374b0}4PyIqA` z(6y3I$!hkP+!+Nj>v-m(yDa1|?Y8ILwB=|aaTx14fk;m9B*p<_6M>IA)rnX?x6yp; zcJ!)PEFua7RtGl(q=jlwfTfkW#x&l)kn3z_U;7Mz-STfOj~vv)i3k|6ORTPwD+;FT zg8r8|5mA!}jucQ6F?P)jvk6y>{;peVEn z{_UqTL=6Hd6%8d74D2ajiLTX0<5}gZwTF(7V|qBXlQ~~0p_UXKwq6o_v*Y}HmHcI1*89dxxT0(S0Jb-f7ZpYUN%ANe(dBa8v&gpTB4y$p zF;?jQ}kU*YRy}+tE6sQlYT&SQRE4NJiBcPfAag+FRqXe{SA_7Dp9H zG6G6zws193N08B|+1LK#(Ru9XTLFUtM0XTS6Bz;rg$uv3yj&1{Ls{w%5LO|92-`lta|=Uug+TfG|M1NjEIpf;uO=PsEyVL-fL$Q z9N$C!<<(^A&}^K8GZvhR$}6sX*0q9QEj2Bd4I{?y9RC2gok++U#gRTa#@j#*Yot~w z5%(+geZEAp?wo7bif%e97@6IMv>rh@G~FxZ#c_65_WATe!i6ZSrUGN@GjVDzT#%p$ zlt6Z`+qM4y#?nC*o?}%jWdcPfFf6DL%wnS=;#rRG-0idOy(bw4K;}4>sa%_B87BdQ znMVUk?e?wd_q?t?Jq|ORA`&rNL@k@#5{hxmQF(U+*Hr;$qq?pS9SeIYTUaJy$SFPJ z(na*gaSw|Ak01F;Zwo8(G_<^Jx>pNWt}ROr2pocSVbnZ;7iqco{B*MRq_O;;M$^SAOZX!7n#hzc>#aV8{mUZ|GhCUlZGYFTIUpLw0#E`~}V zh7lXCpgqXwAbYx$B$xL?#_!xljZcTL*0n^jQ_?uwONSWP&OC3EZk~qT>soE}c^B5f zrJ{37#%6ZdiA6%psm2##ite%ZgNpLoi{yDt5=1&gNOuA&a5DrTWoEP=E=QzW-dzcO zu02-(!Co;aNW`XKqGahJ70DhD*j1{!{{SDcjdI?Rl1Z(RyhAPus)*f{ta2kFvjG5F zu9sRZd~1$IgybLqy={1b!MX*xJZ;D!sM>5|)qG$4OU?UZ{{T;%aThWPg*6iGM1bB` zH7dM8k6QT|i_VVMwE_e=7|=2j1-ROUF!ETH?9eJX4z-)Z_1J6q16c6H%D}{!6^t+$ zJG3Nm$Ac={EeDLBC7!=}?;^1=#$+1{9}?(&*2O^ac_HNRr-t#`z3h+}#6rph*aH$wXb|19ZNB=#lD6OEe3r7) z{EL;5Pxy%zz`1D%^W)@-Br=PXO(ERw@c9;6x(^B@0clpub5=WBmJoRhBrl^BT0!Y^ zt9Rqx($+v|NkjuLu1XeB2?m*}m>L$vedptY)%bYo<5>AJN?9suji+j0ODF}F!_aPE zz1bBvk^VzI)|ZY3S&){*3`78g7>Pq=>|q95marA86_2q+&$-8_$}^TOYoZLMRT6O` zqaUp00&U)C&>ypMzb4$Vn=oJ@CyFBz6c}1-s8q%w?093L<$& zP((sxn7oRP*jUA=s9(P2X>h0}yo&S2WTH2wmq9BY1c#Z72C}>TzsGvtp+j0~#{-dW zG_rw%n@oMxHchKP8{F&VxyZFAP_V}&7xewBcQYz6&ZtIaEi*VmQD`#9}$msF*O zAjnvdGF6nUr4p2a(%}x451j0uoDS~;_Ni(mEE+uNT-Ybm@ zGP#17T~4-1B7tr}o<8bz16i1RYP0U!%DOnlBb4A6hC1XBY@w`exW=W5lH;K(w9EeG z%^=05mW0TzVnL!i?2cT4w`bJ+%bvA^Kk?~U`3fa$&6r7&HH5BhWi^UzRI{NbWS7}p zmw#(drRvAI-2MN;L2RaDM87!PT<0^>ONt>wE=bFelUAkiorg1KcTtYwmmi59Jz z*5)mtm2Tg9(4sP0IY)AGWoo5U3?ki%$TC0&mV*JVg=05@_ubSh2w8ll77BwFoKmy2 zV3qorb$()+pgTNmx!Q9XiX#xx62CD?1VG4*u{v&JsV0P)y8i%ansHVVA@yO!Gc0sT zc*(Z2wpG!1n$_L6_R`jB9AiWyYr$Dalt;8BOK$?Ls~YP60Kch(V~eVaPaW&}z=2xF z@#*oDWyD1C;Q1LX_}=cUr>1t969p9vh4B+zd_A+Ky29EIxBf<5a+qz2HZ?HDQv)hCulrcHb>`Xf{IztdKHs)iE$f zSepW+w0efDZVP?;Jr24U#ggXRg4zT&mNsdLAc2Q605PcxUcY5_@wBpGnXydXW{9Vz zN;aSL?p^OB*J(Uu3;;<+HLH%zi** ziwH?%9WAMxmGR^LhiFBT$}Q3iGBN@Y07!vSrq^M>t5(j{w6DV$1kTW$7 z;xf**V^FR;Yy%8#hg)V>X<8JpfQFHc$b=&AprwZqCMd27_a|B`s?Tlug9(FJ5UFHS zNzDd}b)u}cH@nwDxUum9+k1-83XD!fwk8EJAys}p*QsVQQcHJi)y47`?Okc*Ob8@l zZA8d{6ffwM+Zg3#E9>#PEdI6j^bTy33SnxDUWFu?pgAb%w~N@Achh|V;qz}8VAE*n;gahXg?(u z9s7KklP#EK422rRDJg=8Xzr;WLA8!j`wR8|0HUH zzR$Yhm&v&#Q2~q(nIeh?hMKAA1}t%VVRNFx9-NhG5~Y(w*A)`XROEk92kmWu}g#_APuDkZDc-r4x*!tp33wl{Gf<#;Nh4e z8ksDev4-F;ASs+u_1U4yV!W`>wPguqG7_Vz4ww;|$&4!;p(LR@T_2U+;n4%tIBV)r z3t>V#&#ZEsq~qQS6-e5%{H86d{9|Cyv9_^%<1nNY5iBGN_pJ(Z7MTL>@&-e0T=^P> zl_a^4TOA}!n3eFY`1as#C<7|;u3P>++pYzkRzetIj7t++84(GIOIFdTVAvAt8rf)n zBIZ4?SYOE0y9*(mW3yOsB6ABN%sT2N2pucO;Ws^5J?=l_gDEo2Lt}6Ofhc0e=ouMx zsLtBBmw9*n>vk8W8j(u~3}u4J0*$TazmUWMpCQ0@?z@AA_h%zjnl|G4 zR(!WsY_!`y9lv28AxT(C%Lb{)q8S4uG9tQwsp>(Gk615_np_DGnvI*fC9xZfOkKbv%}RTy5nA${-%8ZAY*C`g<@&5pO`u_mqw(DC_LJoH#3g%7@ z-^OrxMwN@0ApZa%$^P2esY+;uWQ|M7*cZ7*)8p4)$E1tL2AdwMmf8OR)4`Oo0ya^K zqGmy5OIFw{rP3>7n9QYPg0cSqLoIgo4o>X3BC=f}8x+H;vbCMY2(zAyb^idmsHLkDKOIdzW>CyuU!iD}*`NOa(v}j`z?s;iX;9O0tcCoR3&z$xZ&ho$ z4nrHIuN|hPnz}Mb4uXOUc|g#uL;3Sm+bGf7IKAz}rPk+Msv zc8=LN@{LRP7I_*E4j4G9XpO0wijrp3WDi>`7`D}cw7ZSFbFWy7#g;ZENzjp*4Wb9- zqTG2GTuTv6{vO{q7vozgkc%R7j8Gf01jtIPis);JjLP{It75G&Olu#j&y0*>4aIDH zKo~F%;(A+2S_NEPcP?N1{ie&-Q%$KCL@6c^Ms%0;3bB~h-Rytp*k+fQPv0>+5tP>; zP$Mrzz);*>H&(TESYhK?VwS5c$ntTvROA&?3x(AoGDx*We8Q3=9~ri;1G_#g8kR^D ztQRs*8V$lD3sD8cR28IYTTJ@;*W_8@w!ml&EEqCvUr9M4$1!sah5c<1R#QQ}9LfGZ zlyViGEELQd%ls>J1FMT#S?ZeouGz#M9Q!!W1M%F?uE6RJdAs5p{ZcN9iiG{eE|++l`L5RVVE|_H;*70 z`1biMBSI#bLl9MxmH;4ewWbMVEN8slD_KZ=n>M_@PD?G!s!~xWO;jo?GMZ_(lwC|> z*2Dh*)8MqcY-dA1>6HshtY83*dv=*cCuqCWp?o};s!GU5Qqu# zebc2*~NR~ju8}+M; z^f>jCB}Iu?Et<^KO2}e^VI{NF}rZ3n7VGrJYA~ z)WfJcTFXYITy{UUw0Nr`c}Fai0~hoTx;C{JF@OjXU#rntQ;}_)TG)tcFt{7;ZLA2I zyCkE&V8+yjevU@I_a9o5Oqx_i<d7~RIf$VxcO7)6L_3!#4<_cHr_Ov2__ zmnQ=3LlYnk=!SUYEEO79wb)?#JVkMP8V@6Uk1j7UN~4fWM!6;RTVg`<7Jc7)O$T)2 z5eV!Yg}Fgw0UqYG9kC`j$l7(E@))amOO`G{Z93Nj5G55EkXy)M&O-7HOPVSqqwX=c zJbx;G>JybS5xW|0o`Qpssi~w@$dhvIo-wl{kK6opxh;#>(qr^90TvWZ3oj(#L_K}# z&lB5s2PUsHq;c^`;N2-1iH+8v1>_A*W3OAc<=aZ`Gqdhu0)%n^mZ%8{td=usi^5G4 zQ>z?HW0J*QwQC)#3wniO3tNqrLTXaxcY>JMfao9!=wR@VJDqJ;{{S6~nNtX+P6S?I zxZ4v`eZ=4|;mOoc8(@>KBc9jN@*j5+cOo%OX)B zBE{`@B{eWBCZNcOvCWwW&Ut+ey>Cpcyi*CL+@LDngL4+SbkwjGGTI*dj^S2DHPg7H zBDr8g09Z^2Tzv(Sv>mxVmDChDly&?@GS^;=u$tCefLSIY+qW3LwObfiTU&U1aCfw? ziNuReFiB&OM#~|NqKPOQ^DBhjru7#Q+`IO>PRS{dCmPVfCQAt721|6B1Z}4J9K@Y$ z{68O?pF~Jus5T~`28yCeUDatT0aE!ERxTsMW`B~anj+p*MKQUYlo1}rU{FjT$2IuZ z0eMe6PFXGJCsnyFg5lQ1G@PsKOBH{|4t$O}-SMX!pn9YY%pqjS4Iw~)tf;q7++Tn0 zSq5p~sax^#R4a*{i+KP7H;bUffnckBhISKc$x{98^L(3nc3-Jr5^RzV=EV>KP@;N+Cb4S{z7P)PrZ9<+s0m7$yxq1-VKQj>R_YSu zZatfp>sx!qyDvUbSrSQ7LtF~j9zxha%Ii?v>*C7CS{HFD)={`vvTXkVg5(MD>}vJA*ypVitEOzwu+daCc91u0ivY(t%EjGCwmiI`?W46XeN1*>Ntgmk8=80%`IkHlj=dR;`@ zAh4Dkj6j$)7A0;95oj8qwcO+GemuBq}yBU^jWVyjORhlYlKHtw#$&s1n{Pa|8*Dvyc}1Ed2m?8I;86 zT`q*1l}y1_3xxH;iB9G_M8Hd2mg8Tw%DZ>3Xjy6vF18UdFdIl!)M+lBl~}Cu3ApBW z)Rx!}hQq@WlYkWLV{{BBW_s=PS71FI*EZ%$bW5-4S!|M$1??*}oSS|+#ZLJgVMWm6 z(X~v-P^v&>$`TeTM{;P+D0Jica&0W1+O*epn|!kw1(Gj0OI4E+LNgK#zBH29@5g7z z@WZ!~wp?we=`50jc;-+xprMDo!2ueG3evtdB3pLuI>NO5y+KkLiVu-_enIt5VD{qf%3n`^=+{RgFYgM6gPL>SLNcD^^ zR%7GrRIR)qm05FqhTpQ=o=Xd_(jijUQUdYg_4Yq!j2n>`a^^mj z5Rekc2P7J%%|}rvg37V%Sg#k}?+P0!-gduSjzz|i5iQ8^`tpsH+qrb?a$D}I>Er<# z&If4&fsPX70wZ0U^tnKND@uAlk&}_B0&L4?c*KOv#LULdp!k~7>JtxII?s=dwXIDD z2wZ@NPUHYCsgQvE+Z;z<R1}jY(3vC#hhnd%myZ`AL2&Y0 zs2462x2{!g2%&4FZldeKj8nzwXLpbGS*Jp`B0a6dLgZp5I+{QvR%u#U?oro!+Oot7 zUq7Z2BXL_#clSskI3QWMofrIOB(|Tk*wyLsf$cGwACf7_{H5{ zny$*5q!CLp(AgM?mF~F_w{>drV8m=0c(&9OJGcH#OT>VnX+|(rR1^gW3rMzHCbF-p z-RJopy&VGtyOEJ0U-(Ml(X%!oDve5TS4zX1+Etw`ZHkn!xhyFo2-tUdDwbm~{zm{S z`>fIV6@g>HuIZoC>(p35+)*M3(;yUH! z^SevNVvixc?wCBNvvGut(28KYi}B^H@x-rf|0n+(00xNa>*)yE#E3K z1PV`)oTu$4MVQE2W@N1-#O7mb2{|jRCUx;#H(mUH9``n=C^CeNqj;Q5gbQzD_>K-F zG+4`b%g8^nw`022rZL$7mK8HhPhR3wWH_2^aIS{>{{WHr=tsMyGX6j{GfMxNjWCq z7DR!>5@TwvTw#!rfn9G29!0hLo#p7|BW^`i2nYm|0QniTDP~+rwEEPeU;LJFR_Y(R z@fJ#hkTEGsgX_ig3wE6KbJmNN{e=?d}J1@MSk3#) zv8A9?U_iKuJ;qJ}b*ZP$3bS;BBPhYk{^upL)HfM;=$vB~ft3*GBDc28WlYE=A6?db zPm#xQZpYLu&hr$4IdY?p4xvzj!G@*eHEgdKA5$;#tAmS`F9ZZQTVhf(63Ag}#9lVm zg(}+G3{8aNo<;5__4uFw0590#`65H~7M4Qzi(&#@1hTv9$MKxy@#`pQqD}x}Hzo;^ zW<+huWQ{>cu{iAi0OS4d8cW1-@(5h~P#7qt1{q42IRZCaG$D*S&8*{MU@9oS3!9I-;ipz+tS2cAVmaM0E=mf8B3H00ymf;`3W@k#ojmvtv7pp z>erGc0g*F7xrZu(QEt4G`ffKwR9Q>tdj9}zxU@NJxj``yAmU^}k?e4+lS|D&+jy)~ zd}{eYhs|%JfIt5LM(L)`?lFXw76f7brG9->qkmcN2G0Mk5yjL{hp)b`{Ak zh=A&-M3sBp{r(+8ayYM%oGwV@3#Lh<4q)YoCiRXcT)o}MwwqdqWXKE%isTBiwqO^3 zucs#{@yIMcg6HwHcJWciYDdpoo>tyrCeIo!2fO zTj7~VxTc|eHaR)}04lo$ILtIGq*y81O++#DYYd*ngM!}?Eq(6KiK$DIumPXY3Ms4w zqRVc^Dh0h@Xb%(D(fTfGA2M>Ng;Xmk+K@Xewly!bmEXI2@=^W!CRpPJY+T$hSu=2$ z9Gff>k)Sc#hRj1KNAQB)L@m=NNQs>ZQ@j(6o1WF(G;8o^3+zuapwn*u?Tf}$#R zjgCSHh8$#|uH9rxWgg=d`+B$oExTMSU?i)CnPXf|LZPI$)&W&ad-6W-wWLeV#lt9j zN=m4hC7j(&U1F3o_@jIF`^;fvWJB zDa(yOMnMx=cN>rt0JoacK1a2}p1maBAP8RVdy{FtM3qFOsuWDOQX?gVZnN)Q`+8ik zA`-X~haT`y1mLCYF{dG0L;@yjkltE_QdKgt>G=)v5^VWAc9gb>xn|Hrk+#fH5+efu z(i7=(?-`qqx&Huj9Xbg+v2g1vhY~FoPfMg601fn?HFhkiU5i>4iv>_oCk*^1; z%K>&JOI;1>^eW5OWtQ~Rpiz*sV|SXSAgS3%A!xKJ0WX)uZC`rji)v9l9y?+oML~$R zqTa+D$u-vi!J(0K_*ATAd~a~1RIozd4o*7CAkJ7uHcF)Ar>Jo2Rn;pV*YUZuky`Dy zCP0mo^jt&<87*W-Z>!Ym?ebjv9I`_ap_wjq*R(1kr&?O64nKe7FZVxcGMvS^u_0XVr`bKb_?XWGfO#rHlgigBQtsF9YW#tIHZ3J+mWE$rkK`xh-SyqMU%;}o(j zk&vld5VkfeZd%MOHk1OfvF&9$`$=Niq>~;dvs@)Yng(T&Km#B3N(nd7U*u4Q*ycwD ziUI<1Q7e`b1|)`>Ec1_&Y--saBP{}Jaojuo%`K{zZd6V=jbSwuFOek2D4fE~yT&8- zdkW(V=N8C$em>$tR17P~kP!e2ab7!D+2^pH;?r!OCPM_E2NxZgjw6LsA&fZe6F(R` z*44nh62pn&B*+9Bf*`~JqG9972?&kOJ|P2pe`2TJA?{)Uk(F%UbCi*gsBeqG)gATRS4}Az(kLbqN>{n zE?H|$t8aSdPyYZRO>IpFOh7G6gQjL!)Pstyih*wGSGUV~O|48?-87XV#*Waqh#8R` z(IR8SB!8F`cz)XLHt1okYR7~Tc+Q>3Wn%OUNK}d`?mF!c@isR z2_`aP7rnV2O4%e8a{PcpZzBHy568c#OH@+mmy8TVENK{3voc|=?aEabDL)|2zZ>#< zbBrS@2NXygjdCDGUPJB_8!VF=n`dt0ErNd`I*X)c$s%wKFjEK01bI)*nyE#OHe2XI zzDOarHH$mYwTwwzQl=*&4Pr_qvn3;I9cuiKkJ`6sXw-|_k}$OHl*r8J1diPscTq&cNQEl&kpGBC>h#`5Wcz#=SmG8VFh3=O+#UrI@g zNi~dPTmXJO&f9LQj}@tp5!Ut{VC;_9T6s9Tep--7a4JqzI}nXB zMP%V7vbS;ncwpG~}XbI?gt}eF8!z7EEol2v(2QtY){EHREB6Zo~n! z1Yo3?p#^l?g1AL)<$wFXA6VHyU?8Z5N??S3t06S>_2U4UA9qFOfUhETCfiuJpV$LnfU@t32@vkZkuNeK0=o%~=14QF0S z5t^>r4%@8vIVTn|)Y$=oRib>CND3Ek9^kOLGFD;3LyqS)uFY`5Tc%=VdkMMORu=gx+lE?83*(-txJL? z2&heF>vTSp*W|g5q3(8K)7%E6asq&oC88n*2XLlj>O{|u;4sGqW8!?4CdyvJ_fr9Z zC>6-WZw`VhVjTz2eD7f)1_q}omk_(HqsY{^9fq4qC5&Rt!4QZ&isIo^i@8l|doMlf zxYk;Kkf15bi6{dZhDE5EIV@YDYq*Xu$F=wUd_1Q!lO#6?%XMsBBLL800~yXZ_iliC zKl?W)O~>3?x5~<3qGN5UlvwmpKuwAZ`aagA6y`Y#1>1v(h#)f%x{%tlu-t%PV%*2B zwf_KVgC#6>M39g?59m!6UNz88FG)D-=>GssUm^Mj%+&)XD^SQKn-!ozKgWSp-N1kjdDGnA3!7Up4U;NE@pJ08#cYi(eWC_t$L0wW;`NkBEM zO7W~0YpGz?a&|k338H0lZXk$;V5EjI&1y3SD;cdQ$o2jsY+U8Uxup#bssv=146I`G zH|a(_>KgL7N~-&xbBUltAV9Jcf&qaT1_Kg{*3u=`pDEG8R>0t`7? zm@&K+M^cqd<)215uOj350RW}m*RNQo3f zvFVn>A|xh-goBP5QQoPrzP02x9j)WUW-{`%$Uxer0tASJOX(7OWK~TzdOFIER(n)d zx}Y3j5iArNHi4D^+?NcthGTv`%b6Ss$NNapV;osqSO9TD0zkwn11Mrks}&8d+DSbh zdgh_!0LBc9JY0F1>Vt)K`iT658!lS2{{X1H3L7mcC>GL1L>iO^NJmiS+gK)7lB0JD z)oFf(`Fax1e1l3BL{f5MQw&~3SvF3k&=psE`2lfOnhn#ktbnna@*iSWT-z_KAWgp8?O zFeEmyBk~`R?1kd;@vlwC$HsI_!DNzah}f6wUeE{7yG|Q<3%|$t7rGgL1}sj~GfB*v z!e+7Ush=CjZEU!|D&o99+jEq;7AL8ZKt!CF1SKphZgE$7h5Uy904e&Bpo~alTR&Pz zO6PHo8>~8uDQA#9l=0)gN{d9+$m~%Y1vC+p2N*H+R=umNLjfxi5nS&gn2TjL)WFR)kE`t;`_8}Uw~dpM@ho-^E>Ogr z#6a9;B~peFJnFk?#pt%np5}-$(r{auOC)JAr|1C+IJPBFy7E!oXjor~-_WOejtJK- zBPf{I*GY9$p<9|vXCf8X=;hEeGZaZ?FmMquGckBaB5Pnh)ZKVi+o%u7Mdmxmu7)mT z#jq=`cm&ofzQS1vIGQ6vazR|J`*w6JmsqHW8`oX9A$ zucI4-xW?bsJ8m0eBuGq5WMF1ZiUqVjwKIs^v|hUBqx(#8gdD>rfE#AH5TqND&V=5% z$fB-=ul?7#p(gHyNnMd#l~nbTaqccjWlKeuo6T*?_SnB0LeQXu5lle{z|HwK2vWv2 z^Obb6F#0^M753U19E#-C*AYw<$eGBS0$#gIsL?_jPDAc{o;NnAAgjbsk;cm{fs+k{ zmeF^pzl!?$`8zFkq7ccMXw^v1R4k@}6^VsN$xx5+$(OiPwQ^~@GVBpLV1?rqHfviY zy<#dHbQ8M6jhFd2vb=pc1Tz^6f|!Sf>Zzkts@&t`w6c9?eSp7xcYO@fKC*=51X@|a z5y*)#s7SdxT~wW%xww3>OD}mG7spfm0`#(kPM^8>Z_Q1K8NG- z+;X(SW2#9_X;j24NLeso5cV0L$MP5CfHLkk$!9QJ)UlGavSMaV3KbwlGyoEV$GpXh z`{m=O$o!5j`W{akZK#b=vsNb*jztD!vAL4i=*L&JZ?A^tl`a8bLPY5iu|+~Iz0%76 z0QnT3C*H*4($LIsk`ORr7ZW93-Y^K?sjD87JGj5B9{z6ThaQ0^L=?%_QesbRR~ZgX zs|-!Nf7NAtZ2ccDSUA#T+8pqjq$EIqd-pkroyN?LJ6Cx5J1V6c0|1(kQwj{1^jNhd z!gU141ABmf`&N$=6_R%5PZ@;;bS8F1VERRfB_|vI0MUxRE+yFVW(4RM5QAaI6i<%1 z5Vd%OnzeQTT;FF)IVuJh5yv#ioJA}W$v;I3A4-AWDvF2LObwLQ zvdA_teHOjOF7Bs(voa)$Hz~OZl;k%el7Spr!hs`QYz{zbdri{~jU1K5!h%}lNJb4} z6pO~%dW6&qMn4jNiD$M)5-r*wQ6&|wVob_mE-lm5Q8uO}TzNcxwPa~Hi9e%6333gt zWT_efC07+^+pD#9$LMaO!%?kmq`+k?I$?lU3mn?=ZAl(dpn1P{{+`CSKuB1a1SrY~ z=GDOod0f24hlVKw{HiiNu1ihDK#Y`-rGQMD1mYw3EfZq0zyJ>@+0Nc&ardk*L>@tt zjwMx-BtS-(18n5C_>6meiz*t!i;xX^Ja-w+L(^XMMQ4KkQ->rd?x|nx7EOTENafk0H z6{m!<35^n97{G{Baa(Q?$y6-HHeE0_-FLd>>LN`r(jFLOi4>Bj8Gy^%ENHrXe%Hpc zkh^%c^r-RB0Lg01nQR7OYKBq;ki{6=xX0c%QE|)cXc{pX_g=)>hEOpZEJUs}`HYOs zmkG>UYElLC1d%OGXWW4eePV&|ssj={&UtTOGV?zLAmBtkH6nXK6qwqioH zG?jTpZkqW^;@Hc!{wq3C@*W8nb?;HZj^bMzYoy3Vs`xQ^l*L&-<-5*H6DFl7SQOg{ z6=K_S7QfPK7O^$m;Cj8zOzbd^b&8nuCa#f)*T^ zOjbcO%wAc;y-%R4$hBX|TD;#OE77H_U;-a7%H$?siUelirUZJJE%GRPeR$k$({n&} zoMMS&kp#>#PDXC7+VXl*hA{sC^JrGFjUY-T6r0RRlOoe1UGZ2Qp(KKOFbS4A!lhUQ~0vX*;4dx?F z$tp!8j#Iae2x&)(34D5wybX5~IO!Iy@!6kCSX<1`Pct8LD< z+R}351d!U^QG-KCiuddg*j;|i=`%Td-cL3UUl=TB6ejB%-7Ldm#EC~Mq zuHOyqDA|)QHiql}01=5RyWMA&7IK8zCr>CH&$VaA&7s+8m@X3}|I zBD%metA@&W`-_rulyQm?dfk9CcMH=tb~V zWGErYNuT=HGBgJpV>H4d+!(Qh*FnYL6w0Vo(6;m{=ZnY0{@$VrP0|xW;ghh721N2! zX?Re^2&Fdz`Wea&?P`WuQHa9fZwQ8T@5XA4)@D|_>|4L0wKt1I`^$-%t-_W@B`pxE zA$dJs>na59yoG)^t?l;N!}3TP*GxHQw7?X&AW4ie@dyUsTX`|v9nbF`Lz1^B ziDoP)I1`Ab(Ur@6KrOO4ZpEy6AI6&y}}%XkQKG zHyw~l0aT@%+7#6LO78aY?4`@m5G{7vxY^`e3Bf?vdX0p}_g77mE-Njx zuOqOip8A>xhxTgC>V*gFmXbJm*jZ~qlxM9*>AS%Sq$P*pI|mI7>b~jBQw7nUecB% z!s6C`g?9e{DNJj!8Z2u}zLHzASOF|D5OT513n$1PpgX*GZSs3sVPu>X-v-LyAWDH7 zMrdV4>kdYATI0K;cGj{EWDVA0kd?u|S!4my zR=7^cT~c|gCmn%z_LOutRYsZ#+;Ue@8vGbI1C-gk+&qf z)j$bM0Eq5oJe4nxyX|CO2ISS2!*uD7r zW+KdD5d!DQ?!}1&EiAnQ(#l7Xi&`AT@%Ec=G&s%5pCOe?C6ZFP8IW++fgXf3s-QA( z?SCWrIM!+g35f`XK+54mR7BZDBP1`Wi>tNR{{U|0YF>zvSSDj8Mqrop-xD6`E^D;9 zRsR4R?WWW1Y3UegOT%>05~0|oqm@3ojbxy+PB-7TW!{5P!dJ!sw5(*#WM-Kl9@~uh zTW{CnF7RWwg?jRW*o#QV9=Vl~uVNMu0*A#6E3~GxwP;@=?)P4%tf6p;DU-Jy5Kv4j z4z>!Z<>K2y7e*z-`9Hs=JOq*n2vM*iRRc)co+ET~8mnI$K1)K+FD|kXie$KkLez!N z8On&-(<2IltEP}|Uox+8CjN>Z*jboNioik%q(v-Q33ZTKWgQfQJYVl?5*pS+Dw1M^ z!Gj<%KDB`X2mmc!gS-C#Pre-=(5B-8Mqs7O zCIXuyEGQDS5)38$cYrS3FzwduAg;N%?0NE@|Y!Jr9fbFN(>9(_B*{|95 z+D5f5WZ>prLvdp>ajtFPIu^vT?;|-|k?|Myn@UVEv4zkl5=-JJH>^iyrt;Z--cC3r zGRUplbF~YG_)W}qOOCe+2}Rf zx%%&4nHYUiVx|aHdw&^#1y$vp(4VS|i9!CA;A7$(YY(9i;|jEjgm za;~D? zt$B)N&i%u?sCHS4@v>!dM^TwcwqWEdF^rZpPpRH8ch|{tO)AZj_De2QS0b=rDLec- zhR)Nv!tI_8G`{E_OhKu^4kW`0q8MWvL{i19R>p_P^4G&kD9@TU4a9c zxB)p4#_nn5wR(cPN~<*8w$C2w?k7uA1{jHtqnHH~vhJKcEaF!vO#^jz7HhR{xW*Jd zE@38S-bk&IVL%y&q_S;;2iM5YzTPzJb=8j#mW_hr7$EC;a?UaVidH&~k9Ezp+f9uL zvQi|~sf4pR-T;|fN&pGMc81>_zr^Q%`-ibE-O7qhkswsTOwuyN{9tp4zB^ic{liN= z%?meeB$yTn9jV$ws7ajw%zUcrUpFt=TH3a0*wQkkyjLnFLd0vEcgU^|FbSH^jmc&; zd^f)OrwuIvFk~QED;3E^M83N68w;o&D!x|!-S;;ix`=T$V`LzcSJdESMPz|#FdV7@ zonMXaub>)@5Q*|!VJ2c?30n;y_A)<9OnD!5inYw<{q-Ij3UXlN@=qorXq2cVL3dB6 zFW$9uD0jzG?OM|~k&SeCm|#lygckw!++wpIcu1ObV!uz2O;{=ad$ zCkPD0goP^_x}aLSrblhcxDn8`eWhe`H5#0lfOD5<1%CPBN=eR1j=H8`elE{Kr-R~041#aWOmY(%(y_RI0b~u8Zt#lT><#Q z<@&2){C0<8&P@jUEk;8o2?H*WrA5Q)_|=l`P!-q5-T3+$Uo(hGRJx8~jX4XfKO7a+ zlS9&=YcHLy?+UI+D8Sgr6@v_-c2>g1yg>s!HFbbo44>{X+Jb^?uxeUYF(guEPON-z zD_Cqx0<_`{w%%&&@@Y2_6|OgKF~I~B0{O?T5kcNgLYin##P#_(e!U0+Ov+-3Tu2p7 zGb%?Nwz508rP0^QY`@IC9bhgwjj1t~62zDd$TPg(j%G|xmIM$B zCeYj}Iorx~TK@odjo9L-qPSggU-&o_5X7jNZ=fr^Z^(LXBPPwqW2L%=%I{JnOC}tc zfYcXy=f)4$eQu!cWgX7FW2K7=c{LtGh9Y*Ya|{=BBw6EQy7hPM1>20};?tj*kfN3Z zNmOwp$=#@=Mhd|lU~eDv?A>3-%6Nb&lA@VYNS6#7e;;S$GT%F`R=j&0zO{BdMVxWO zg|iW&2AL(wIu^L7$+v=}A3MBT-h}ivR1-|HNX%x`FP|bZDgP5^kh5vJ(HYv zi)F&HB0b}HgT58W5vh)^ALJ#zKX12lw!C$qmzuE_ONXfDOX?D=b1{8_#OiAg+5C)a zjk%|R1eWnI%!flOm{|(L9^?}gRFPtzEehrSgsW7xVYnp%ejBM40=BlIRnlX4R-gNf zM~{;3KERt*5fHH=Q3T5%WJN^P--C06m`r~vc&yvI&dS*s>6I>OW*AXUi(woXzZ6#TsH;y%~<)w35=hCtTWT+UGo;e&>8<6l_bC)bBT@Rw|7@tB-RuWaj;M! zB1~XSx_ot!IL(Xd=>ChBbQp$#EO;%V>{BsBFb#zEH8s#VHxLwf&Oc|ncdADo;GKCx zGD~FcMfFkELQJqr;SNJ?EzjREX{r*^B0A22i6Q}AR|ahuev<^_@n8EHTA0ikJ2SgQ zlz}YB=O)WK80zX!UO#T{HyYV^ae>5BHwfWp62y=}gPU0QYTigaC*OsoQgw(pAIz1>NfCB#NKM%iFkmCS+U)$u2Mw z7Qn~Xqblr&Ta;p;aO5B#!>@agCLJ~P`)bmVy~KR5V{ z?i$eYa0HVs5&@MAt8_GxWlk_t*W^2mug1G&tJINNWRXJqrSyhWFaV@dYySWXSHtgi z9cuQj1&fBV$|IsSm6XGi zYDO{2qCY`-EI0En+R-gPC{Jr@f{2ZweR4jrub0tj>BeH!b?ibMohn&Fj8!g~R6%Vs z40{$$d&PBCMfL*R&i11jw56Ek4Y?B)FqamWX4qNy>ps42R$ONz8oO{)AV85Ul?x8( ziI)MAJaWhAYm?Bnc2i{k0K4Ioz!8`(CYXj4t*l&7G@S-YF-R#j+41bPHuOv)c+1B2 zKu=kVK*mQUH}G@z(6ArYyUZQNcv0hQ#`Xc4 z?_k)yV^m%$HtUlex0#r(NXmE=F?|n3=J@Jg50cS`ahZ0YYBE_#y2dPlnEZii z`_y@T&t+PSk(B~lL{2mvxe;HbSog}Vg;3ye{q^b+p@to?f^-j|F$qXHt3B58{+s9?ji_GA6lX%DqOvbLJ&(v$k zqz8(fwN?h&*xgbLYAVug0pkOAtvukC8QThd`9HypVt;AGea zOcszPjA1Kx4%ZR3=c3THTc}o&AUP`M=~%4gsfvT!713w*xj7b=@vkE;Aq9`L%s}?* zs*_zu>&7QIi~6USKbdRQ;#dO*&T_c4Vs3k zS(w6e27v@czep<0+WcQ~QI@DR!yri|v`ESp2un8@CaI}s3FS3x@-F<9vfq!R%&r@l z<&y|RV8eDnLra{=^|-!C-3}|fY4P8ASq`KY5Wt0m5kTD#k}su0Z0uj}qsQfC@9WXW z(U&BaK~)Qqg0k5=mup5rh-Cwo<UVE=}K7m&@m@+dUuu5(GzW^WD(u5SNABf?r23Mvyd2!Rf@z)2&NWY43^_9 zPOq-Jtl+!H?pep$mfEm%%-kTGj8_=DC6wGp50yZEzJAt3L6c)>hs$Kv*36Wv$7B%H zPb`5|b(($OX47>hmCP3FZRk2oCP{ODhvkkRR}V+)MW2zY(E=cugCT;EV2Kj%+CvG9 z2ZlvSXJ2E6?T$?>1SS)(fvO4sj1pG`jAX^su#1@MZN5qt)blM^;Pn|Y0#?7Q69sA_ z00qN~r0$&*IRV#d%DsA+DV>y3M@@-nw=0<)ec{DdkZ~ImsfR%wYcj zkjY?|y2?ywYd@olQVGfA$&VDqVkUm3L)NjI=Zst4wuEHS{)+Uoft9W9fE9^C!1pj^ za+5=H_m(v+wI3=!Uu7=S=vCDOta_ki z>h3rEUXyglefXKXpMeJ(mZI*&n{BzNPNmm6f zhQyRh4klC`0SX7)3dM9E`;g;f{EbZ`X^ff!6)*!E1XZ!oVS~>fuIm{>FIVx}dl2uA zh$bCPsmMq(_1vix(?fxcqf${@jLkw!ID@W2I;+N9HC$>Cs~vax@tD4Ek)Tpa z98eH!o#I#0(h_PIi0!c8LX1xT0N(OAv<4|8;VxudGgCq&2o@NmG?7%K+#<)k+>gn~ z`1fC5S%sJ;87gKakyjCu5Cuj8_ysLL9__c><>0mqfEXcyy&$UO&CxtgS(UyVta}Tr z*LRJJ4{39|;qq|F-9S{bU|Y!sOHBckQv2n9m+`H1DXGROCoZw7xQPN`6;TvETE$V( zU@`@0wyV5)Vy5Oni~s|cFg0vXWp$7pBucU%zV{uzD>_o-VdlvYFc^lgW(LyN>uMLs zoP}Ctf4O_xFvkhBxs`b{K##AFo7n1hA#Z+4~v zXkSWM%h!+p0ItJ>l4F)35@8F5tY+d%juHT|vy5&tYc6pqJ*^XoGR2I^(H~KT$m}E3 z9EcOQ?yk|j8VME~hH5DK#b8@8Rbz-7dH(=UZ{J5B;kQvUPBXEoIM}1Lv+JM^fGUR~ z{dnu;{vC^oy96!>PHfS(HD+jfF{oaK+SF{*_d#G{FCJl)> y7%G=WKUoTwC;!>kv*OGE literal 0 HcmV?d00001 diff --git a/submodules/PremiumUI/Resources/badge.scn b/submodules/PremiumUI/Resources/badge.scn index 48992cda49a4fb56ae3c82a0eb4263f5a4b5f8f7..40aa6f0b0df5b70f4502fed247337c1c3be19814 100644 GIT binary patch delta 10048 zcmb_h2UHZv+U@G@YSJJBjJj)D1SV$~bzNOhC-fvn1p_X_0OBaD2reLIr_6CpW6omE z0Z}pMoO8}OyRKn(pZeE;i1Xe)+4IhS`czkUb#;BWzVCL`?W!@ez>Z5`Y%2I;Tv}CE zSHeY{AWjlzi1WlH;wtfocn0D?OVAo50Xs+rd7wKO4aNXBm;|PQLNE`^2g^VaSPa&I zVxm5{2rhxk;0m}3u7T^|2Dk}sf!p8?xC`!q`-F%n1`oiW;4knm@E&{sA4!4)BuP?a z0LdY_WVnlrAR|dWDIkTUh!m3&QcB8*-K3mUkV>)v*@%oIZDeyoPPQOhk%?pynNAKR zSCA{oRpe@N4Y`&qBG-|{X7THHI2XjiV+~ld0*{3~Dj8oZ3qrppH?;sk78Y>K65gdQ3f` zo>On>nzWo&(DmsbXe%8@x2D_Co#`Apm+nQ+qW92y>7(>X`ZoQTehvX7p+Bqw!(d$~ zhH@ASn?NJ9LI+HNonU9!7Y>HQ;dD3y&P;`KVIeGr+u$C!7aoL1;0bsRUW3=+4TfYW zhGrncFg}bgAOmCYou; z{J{KJ^b`lI)~WEO1VQ+Q>v|CcA|qm7;5$zNI)vW2S5P&p{2tN7R#t{iqSr;|sBkha zXC9G7bRn{lKMF=;P|$U55Wyu_!bto=n23gim9P-ih+HC$$Rlh-bD{-C6i;*`3W)AR z4D*h*}}Pl}1{#14G73)?Kl<-1GI1*PY` z_*{%j;&DnO_7VGu12{j3@A$-F{NzaK^P~8Dj5uD@+vgeWIz^mrm!P$2)4Diw(+Y`G zg#Hxaz}-7bM*>&q92IYj{d86Ia^eH*Gl`oQ3#C|L<

AABHsOhQ?pqO0&SnOF)9X)woaQmb^Ez3D`Kv{ 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 D?n-Tf delta 6540 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 Y)ois|9o7a*)?Y_`fF|K}M0H>IAD|DD{r~^~ diff --git a/submodules/PremiumUI/Resources/swirl.scn b/submodules/PremiumUI/Resources/swirl.scn new file mode 100644 index 0000000000000000000000000000000000000000..f5f50794de53cb6a05ca5d10bd0f79606da704bf GIT binary patch literal 84910 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.size * 2, index: 0) + + var time = Float(CACurrentMediaTime() - self.startTimestamp) * 0.75 + renderEncoder.setFragmentBytes(&time, length: 4, index: 1) + + renderEncoder.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: 6, instanceCount: 1) + + renderEncoder.endEncoding() + + commandBuffer.present(drawable) + commandBuffer.commit() + + } +} diff --git a/submodules/PremiumUI/Sources/FasterStarsView.swift b/submodules/PremiumUI/Sources/FasterStarsView.swift new file mode 100644 index 0000000000..f80b621f70 --- /dev/null +++ b/submodules/PremiumUI/Sources/FasterStarsView.swift @@ -0,0 +1,107 @@ +import Foundation +import UIKit +import SceneKit +import Display +import AppBundle + +final class FasterStarsView: UIView, PhoneDemoDecorationView { + private let sceneView: SCNView + + private var particles: SCNNode? + + override init(frame: CGRect) { + self.sceneView = SCNView(frame: CGRect(origin: .zero, size: frame.size)) + self.sceneView.backgroundColor = .clear + if let url = getAppBundle().url(forResource: "lightspeed", withExtension: "scn") { + self.sceneView.scene = try? SCNScene(url: url, options: nil) + } + self.sceneView.isUserInteractionEnabled = false + self.sceneView.preferredFramesPerSecond = 60 + + super.init(frame: frame) + + self.alpha = 0.0 + + self.addSubview(self.sceneView) + + self.particles = self.sceneView.scene?.rootNode.childNode(withName: "particles", recursively: false) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + deinit { + self.particles = nil + } + + func setVisible(_ visible: Bool) { + if visible, let particles = self.particles, particles.parent == nil { + self.sceneView.scene?.rootNode.addChildNode(particles) + } + + let transition = ContainedViewLayoutTransition.animated(duration: 0.3, curve: .linear) + transition.updateAlpha(layer: self.layer, alpha: visible ? 0.4 : 0.0, completion: { [weak self] finished in + if let strongSelf = self, finished && !visible && strongSelf.particles?.parent != nil { + strongSelf.particles?.removeFromParentNode() + } + }) + } + + private var playing = false + func startAnimation() { + guard !self.playing, let scene = self.sceneView.scene, let node = scene.rootNode.childNode(withName: "particles", recursively: false), let particles = node.particleSystems?.first else { + return + } + self.playing = true + + let speedAnimation = CABasicAnimation(keyPath: "speedFactor") + speedAnimation.fromValue = 1.0 + speedAnimation.toValue = 1.8 + speedAnimation.duration = 0.8 + speedAnimation.fillMode = .forwards + particles.addAnimation(speedAnimation, forKey: "speedFactor") + + particles.speedFactor = 3.0 + + let stretchAnimation = CABasicAnimation(keyPath: "stretchFactor") + stretchAnimation.fromValue = 0.05 + stretchAnimation.toValue = 0.3 + stretchAnimation.duration = 0.8 + stretchAnimation.fillMode = .forwards + particles.addAnimation(stretchAnimation, forKey: "stretchFactor") + + particles.stretchFactor = 0.3 + } + + func resetAnimation() { + guard self.playing, let scene = self.sceneView.scene, let node = scene.rootNode.childNode(withName: "particles", recursively: false), let particles = node.particleSystems?.first else { + return + } + self.playing = false + + let speedAnimation = CABasicAnimation(keyPath: "speedFactor") + speedAnimation.fromValue = 3.0 + speedAnimation.toValue = 1.0 + speedAnimation.duration = 0.35 + speedAnimation.fillMode = .forwards + particles.addAnimation(speedAnimation, forKey: "speedFactor") + + particles.speedFactor = 1.0 + + let stretchAnimation = CABasicAnimation(keyPath: "stretchFactor") + stretchAnimation.fromValue = 0.3 + stretchAnimation.toValue = 0.05 + stretchAnimation.duration = 0.35 + stretchAnimation.fillMode = .forwards + particles.addAnimation(stretchAnimation, forKey: "stretchFactor") + + particles.stretchFactor = 0.05 + } + + override func layoutSubviews() { + super.layoutSubviews() + + self.sceneView.frame = CGRect(origin: .zero, size: frame.size) + } +} diff --git a/submodules/PremiumUI/Sources/PhoneDemoComponent.swift b/submodules/PremiumUI/Sources/PhoneDemoComponent.swift index 9a6515eb8c..e1fb0878cd 100644 --- a/submodules/PremiumUI/Sources/PhoneDemoComponent.swift +++ b/submodules/PremiumUI/Sources/PhoneDemoComponent.swift @@ -280,125 +280,9 @@ private final class PhoneView: UIView { } } -private final class FasterStarsView: UIView { - private let sceneView: SCNView - - override init(frame: CGRect) { - self.sceneView = SCNView(frame: CGRect(origin: .zero, size: frame.size)) - self.sceneView.backgroundColor = .clear - if let url = getAppBundle().url(forResource: "lightspeed", withExtension: "scn") { - self.sceneView.scene = try? SCNScene(url: url, options: nil) - } - self.sceneView.isUserInteractionEnabled = false - self.sceneView.preferredFramesPerSecond = 60 - - super.init(frame: frame) - - self.alpha = 0.0 - - self.addSubview(self.sceneView) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func setVisible(_ visible: Bool) { - let transition = ContainedViewLayoutTransition.animated(duration: 0.3, curve: .linear) - transition.updateAlpha(layer: self.layer, alpha: visible ? 1.0 : 0.0) - } - - private var playing = false - func startAnimation() { - guard !self.playing, let scene = self.sceneView.scene, let node = scene.rootNode.childNode(withName: "particles", recursively: false), let particles = node.particleSystems?.first else { - return - } - self.playing = true - - let speedAnimation = CABasicAnimation(keyPath: "speedFactor") - speedAnimation.fromValue = 1.0 - speedAnimation.toValue = 1.8 - speedAnimation.duration = 0.8 - speedAnimation.fillMode = .forwards - particles.addAnimation(speedAnimation, forKey: "speedFactor") - - particles.speedFactor = 3.0 - - let stretchAnimation = CABasicAnimation(keyPath: "stretchFactor") - stretchAnimation.fromValue = 0.05 - stretchAnimation.toValue = 0.3 - stretchAnimation.duration = 0.8 - stretchAnimation.fillMode = .forwards - particles.addAnimation(stretchAnimation, forKey: "stretchFactor") - - particles.stretchFactor = 0.3 - } - - func stopAnimation() { - guard self.playing, let scene = self.sceneView.scene, let node = scene.rootNode.childNode(withName: "particles", recursively: false), let particles = node.particleSystems?.first else { - return - } - self.playing = false - - let speedAnimation = CABasicAnimation(keyPath: "speedFactor") - speedAnimation.fromValue = 3.0 - speedAnimation.toValue = 1.0 - speedAnimation.duration = 0.35 - speedAnimation.fillMode = .forwards - particles.addAnimation(speedAnimation, forKey: "speedFactor") - - particles.speedFactor = 1.0 - - let stretchAnimation = CABasicAnimation(keyPath: "stretchFactor") - stretchAnimation.fromValue = 0.3 - stretchAnimation.toValue = 0.05 - stretchAnimation.duration = 0.35 - stretchAnimation.fillMode = .forwards - particles.addAnimation(stretchAnimation, forKey: "stretchFactor") - - particles.stretchFactor = 0.05 - } - - override func layoutSubviews() { - super.layoutSubviews() - - self.sceneView.frame = CGRect(origin: .zero, size: frame.size) - } -} - -private final class BadgeStarsView: UIView { - private let sceneView: SCNView - - override init(frame: CGRect) { - self.sceneView = SCNView(frame: CGRect(origin: .zero, size: frame.size)) - self.sceneView.backgroundColor = .clear - if let url = getAppBundle().url(forResource: "badge", withExtension: "scn") { - self.sceneView.scene = try? SCNScene(url: url, options: nil) - } - self.sceneView.isUserInteractionEnabled = false - self.sceneView.preferredFramesPerSecond = 60 - - super.init(frame: frame) - - self.alpha = 0.0 - - self.addSubview(self.sceneView) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func setVisible(_ visible: Bool) { - let transition = ContainedViewLayoutTransition.animated(duration: 0.3, curve: .linear) - transition.updateAlpha(layer: self.layer, alpha: visible ? 0.75 : 0.0) - } - - override func layoutSubviews() { - super.layoutSubviews() - - self.sceneView.frame = CGRect(origin: .zero, size: frame.size) - } +protocol PhoneDemoDecorationView: UIView { + func setVisible(_ visible: Bool) + func resetAnimation() } final class PhoneDemoComponent: Component { @@ -411,6 +295,8 @@ final class PhoneDemoComponent: Component { enum BackgroundDecoration { case none + case dataRain + case swirlStars case fasterStars case badgeStars } @@ -462,14 +348,12 @@ final class PhoneDemoComponent: Component { private var isCentral = false private var component: PhoneDemoComponent? - private let starsContainerView: UIView + private let decorationContainerView: UIView + private var decorationView: PhoneDemoDecorationView? private let containerView: UIView private let phoneView: PhoneView - - private var fasterStarsView: FasterStarsView? - private var badgeStarsView: BadgeStarsView? - - private var starsDisposable: Disposable? + + private var playbackStatusDisposable: Disposable? public var ready: Signal { if let videoNode = self.phoneView.videoNode { @@ -483,8 +367,8 @@ final class PhoneDemoComponent: Component { } public override init(frame: CGRect) { - self.starsContainerView = UIView(frame: frame) - self.starsContainerView.clipsToBounds = true + self.decorationContainerView = UIView(frame: frame) + self.decorationContainerView.clipsToBounds = true self.containerView = UIView(frame: frame) self.containerView.clipsToBounds = true @@ -493,7 +377,7 @@ final class PhoneDemoComponent: Component { super.init(frame: frame) - self.addSubview(self.starsContainerView) + self.addSubview(self.decorationContainerView) self.addSubview(self.containerView) self.containerView.addSubview(self.phoneView) } @@ -502,42 +386,60 @@ final class PhoneDemoComponent: Component { fatalError("init(coder:) has not been implemented") } - deinit { - self.starsDisposable?.dispose() - } +// deinit { +// self.playbackStatusDisposable?.dispose() +// } public func update(component: PhoneDemoComponent, availableSize: CGSize, environment: Environment, transition: Transition) -> CGSize { self.component = component self.containerView.frame = CGRect(origin: .zero, size: availableSize) - self.starsContainerView.frame = CGRect(origin: CGPoint(x: -availableSize.width * 0.5, y: 0.0), size: CGSize(width: availableSize.width * 2.0, height: availableSize.height)) + self.decorationContainerView.frame = CGRect(origin: CGPoint(x: -availableSize.width * 0.5, y: 0.0), size: CGSize(width: availableSize.width * 2.0, height: availableSize.height)) self.phoneView.bounds = CGRect(origin: .zero, size: phoneSize) switch component.decoration { case .none: break + case .dataRain: + if #available(iOS 10.0, *) { + if let _ = self.decorationView as? MatrixView { + } else if let rainView = MatrixView(test: true) { + rainView.frame = self.decorationContainerView.bounds.insetBy(dx: availableSize.width * 0.5, dy: 0.0) + self.decorationView = rainView + self.decorationContainerView.addSubview(rainView) + } + } + case .swirlStars: + if let _ = self.decorationView as? SwirlStarsView { + } else { + let starsView = SwirlStarsView(frame: self.decorationContainerView.bounds) + self.decorationView = starsView + self.decorationContainerView.addSubview(starsView) + } case .fasterStars: - if self.fasterStarsView == nil { - let starsView = FasterStarsView(frame: self.starsContainerView.bounds) - self.fasterStarsView = starsView - self.starsContainerView.addSubview(starsView) + if let _ = self.decorationView as? FasterStarsView { + } else { + let starsView = FasterStarsView(frame: self.decorationContainerView.bounds) + self.decorationView = starsView + self.decorationContainerView.addSubview(starsView) - self.starsDisposable = (self.phoneView.playbackStatus - |> deliverOnMainQueue).start(next: { [weak self] status in - if let strongSelf = self, let status = status { + self.playbackStatusDisposable = (self.phoneView.playbackStatus + |> deliverOnMainQueue).start(next: { [weak starsView] status in + if let starsView = starsView, let status = status { if status.timestamp > 8.0 { - strongSelf.fasterStarsView?.stopAnimation() + starsView.resetAnimation() } else if status.timestamp > 0.85 { - strongSelf.fasterStarsView?.startAnimation() + starsView.startAnimation() } } }) } case .badgeStars: - if self.badgeStarsView == nil { - let starsView = BadgeStarsView(frame: self.starsContainerView.bounds) - self.badgeStarsView = starsView - self.starsContainerView.addSubview(starsView) + if let _ = self.decorationView as? BadgeStarsView { + } else { + let starsView = BadgeStarsView(frame: self.decorationContainerView.bounds) + self.decorationView = starsView + self.decorationContainerView.addSubview(starsView) } } @@ -561,8 +463,9 @@ final class PhoneDemoComponent: Component { let isCentral = environment[DemoPageEnvironment.self].isCentral self.isCentral = isCentral - self.fasterStarsView?.setVisible(isVisible && abs(mappedPosition) < 0.4) - self.badgeStarsView?.setVisible(isVisible && abs(mappedPosition) < 0.4) + if let decorationView = self.decorationView { + decorationView.setVisible(isVisible && abs(mappedPosition) < 0.4) + } self.phoneView.center = CGPoint(x: availableSize.width / 2.0 + phoneX, y: phoneY) self.phoneView.screenRotation = mappedPosition * -0.7 @@ -575,7 +478,7 @@ final class PhoneDemoComponent: Component { self.phoneView.play() } else if !isVisible { self.phoneView.reset() - self.fasterStarsView?.stopAnimation() + self.decorationView?.resetAnimation() } if let _ = transition.userData(DemoAnimateInTransition.self), abs(mappedPosition) < .ulpOfOne { diff --git a/submodules/PremiumUI/Sources/PremiumDemoScreen.swift b/submodules/PremiumUI/Sources/PremiumDemoScreen.swift index 7c2a77decd..327de73c3b 100644 --- a/submodules/PremiumUI/Sources/PremiumDemoScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumDemoScreen.swift @@ -725,7 +725,8 @@ private final class DemoSheetContent: CombinedComponent { content: AnyComponent(PhoneDemoComponent( context: component.context, position: .bottom, - videoFile: configuration.videos["more_upload"] + videoFile: configuration.videos["more_upload"], + decoration: .dataRain )), title: strings.Premium_UploadSize, text: strings.Premium_UploadSizeInfo, @@ -760,7 +761,8 @@ private final class DemoSheetContent: CombinedComponent { content: AnyComponent(PhoneDemoComponent( context: component.context, position: .top, - videoFile: configuration.videos["voice_to_text"] + videoFile: configuration.videos["voice_to_text"], + decoration: .badgeStars )), title: strings.Premium_VoiceToText, text: strings.Premium_VoiceToTextInfo, @@ -777,7 +779,8 @@ private final class DemoSheetContent: CombinedComponent { content: AnyComponent(PhoneDemoComponent( context: component.context, position: .bottom, - videoFile: configuration.videos["no_ads"] + videoFile: configuration.videos["no_ads"], + decoration: .swirlStars )), title: strings.Premium_NoAds, text: isStandalone ? strings.Premium_NoAdsStandaloneInfo : strings.Premium_NoAdsInfo, @@ -831,7 +834,8 @@ private final class DemoSheetContent: CombinedComponent { content: AnyComponent(PhoneDemoComponent( context: component.context, position: .top, - videoFile: configuration.videos["advanced_chat_management"] + videoFile: configuration.videos["advanced_chat_management"], + decoration: .swirlStars )), title: strings.Premium_ChatManagement, text: strings.Premium_ChatManagementInfo, @@ -866,7 +870,8 @@ private final class DemoSheetContent: CombinedComponent { content: AnyComponent(PhoneDemoComponent( context: component.context, position: .top, - videoFile: configuration.videos["animated_userpics"] + videoFile: configuration.videos["animated_userpics"], + decoration: .swirlStars )), title: strings.Premium_Avatar, text: strings.Premium_AvatarInfo, diff --git a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift index 313505e395..cae6c1b59d 100644 --- a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift @@ -1161,13 +1161,10 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { }) let termsString: MultilineTextComponent.TextContent - if context.component.isPremium == true { - if let promoConfiguration = context.state.promoConfiguration { - let attributedString = stringWithAppliedEntities(promoConfiguration.status, entities: promoConfiguration.statusEntities, baseColor: termsTextColor, linkColor: environment.theme.list.itemAccentColor, baseFont: termsFont, linkFont: termsFont, boldFont: boldTermsFont, italicFont: italicTermsFont, boldItalicFont: boldItalicTermsFont, fixedFont: monospaceTermsFont, blockQuoteFont: termsFont) - termsString = .plain(attributedString) - } else { - termsString = .plain(NSAttributedString()) - } +// if context.component.isPremium == true { + if let promoConfiguration = context.state.promoConfiguration { + let attributedString = stringWithAppliedEntities(promoConfiguration.status, entities: promoConfiguration.statusEntities, baseColor: termsTextColor, linkColor: environment.theme.list.itemAccentColor, baseFont: termsFont, linkFont: termsFont, boldFont: boldTermsFont, italicFont: italicTermsFont, boldItalicFont: boldItalicTermsFont, fixedFont: monospaceTermsFont, blockQuoteFont: termsFont) + termsString = .plain(attributedString) } else { termsString = .markdown( text: strings.Premium_Terms, @@ -1403,7 +1400,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent { |> deliverOnMainQueue).start(next: { [weak self] available in if let strongSelf = self { if available { - strongSelf.paymentDisposable.set((inAppPurchaseManager.buyProduct(premiumProduct, account: strongSelf.context.account) + strongSelf.paymentDisposable.set((inAppPurchaseManager.buyProduct(premiumProduct) |> deliverOnMainQueue).start(next: { [weak self] status in if let strongSelf = self, case .purchased = status { strongSelf.activationDisposable.set((strongSelf.context.account.postbox.peerView(id: strongSelf.context.account.peerId) @@ -1418,8 +1415,14 @@ private final class PremiumIntroScreenComponent: CombinedComponent { |> mapToSignal { _ -> Signal in return .never() } + |> timeout(15.0, queue: Queue.mainQueue(), alternate: .fail(.timeout)) |> deliverOnMainQueue).start(error: { _ in - + addAppLogEvent(postbox: strongSelf.context.account.postbox, type: "premium.promo_screen_fail") + + let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } + let errorText = presentationData.strings.Premium_Purchase_ErrorUnknown + let alertController = textAlertController(context: strongSelf.context, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]) + strongSelf.present(alertController) }, completed: { [weak self] in if let strongSelf = self { let _ = updatePremiumPromoConfigurationOnce(account: strongSelf.context.account).start() @@ -1444,6 +1447,10 @@ private final class PremiumIntroScreenComponent: CombinedComponent { errorText = presentationData.strings.Premium_Purchase_ErrorNetwork case .notAllowed: errorText = presentationData.strings.Premium_Purchase_ErrorNotAllowed + case .cantMakePayments: + errorText = presentationData.strings.Premium_Purchase_ErrorCantMakePayments + case .assignFailed: + errorText = presentationData.strings.Premium_Purchase_ErrorUnknown case .cancelled: break } diff --git a/submodules/PremiumUI/Sources/SwirlStarsView.swift b/submodules/PremiumUI/Sources/SwirlStarsView.swift new file mode 100644 index 0000000000..6b80754777 --- /dev/null +++ b/submodules/PremiumUI/Sources/SwirlStarsView.swift @@ -0,0 +1,204 @@ +import Foundation +import UIKit +import SceneKit +import Display +import AppBundle +import SwiftSignalKit + +final class SwirlStarsView: UIView, PhoneDemoDecorationView { + private let sceneView: SCNView + + private var particles: SCNNode? + + override init(frame: CGRect) { + self.sceneView = SCNView(frame: CGRect(origin: .zero, size: frame.size)) + self.sceneView.backgroundColor = .clear + if let url = getAppBundle().url(forResource: "swirl", withExtension: "scn") { + self.sceneView.scene = try? SCNScene(url: url, options: nil) + } + self.sceneView.isUserInteractionEnabled = false + self.sceneView.preferredFramesPerSecond = 60 + + super.init(frame: frame) + + self.alpha = 0.0 + + self.addSubview(self.sceneView) + + self.particles = self.sceneView.scene?.rootNode.childNode(withName: "particles", recursively: false) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + deinit { + self.particles = nil + } + + func setVisible(_ visible: Bool) { + if visible, let particles = self.particles, particles.parent == nil { + self.sceneView.scene?.rootNode.addChildNode(particles) + } + self.setupAnimations() + + let transition = ContainedViewLayoutTransition.animated(duration: 0.3, curve: .linear) + transition.updateAlpha(layer: self.layer, alpha: visible ? 0.6 : 0.0, completion: { [weak self] finished in + if let strongSelf = self, finished && !visible && strongSelf.particles?.parent != nil { + strongSelf.particles?.removeFromParentNode() + + if let node = strongSelf.sceneView.scene?.rootNode.childNode(withName: "star", recursively: false) { + node.removeAllAnimations() + } + } + }) + } + + func setupAnimations() { + guard let node = self.sceneView.scene?.rootNode.childNode(withName: "star", recursively: false), node.animationKeys.isEmpty else { + return + } + + let initial = node.eulerAngles + let target = SCNVector3(x: node.eulerAngles.x + .pi * 2.0, y: node.eulerAngles.y, z: node.eulerAngles.z) + + let animation = CABasicAnimation(keyPath: "eulerAngles") + animation.fromValue = NSValue(scnVector3: initial) + animation.toValue = NSValue(scnVector3: target) + animation.duration = 1.5 + animation.timingFunction = CAMediaTimingFunction(name: .linear) + animation.fillMode = .forwards + animation.repeatCount = .infinity + node.addAnimation(animation, forKey: "rotation") + + self.setupMovementAnimation() + } + + func setupMovementAnimation() { + guard let node = self.sceneView.scene?.rootNode.childNode(withName: "star", recursively: false) else { + return + } + + node.position = SCNVector3(3.5, 0.0, -2.0) + let firstPath = UIBezierPath() + firstPath.move(to: CGPoint(x: 3.5, y: -2.0)) + firstPath.addLine(to: CGPoint(x: -15.5, y: 15.5)) + + let firstAction = SCNAction.moveAlong(path: firstPath, duration: 2.0) + + SCNTransaction.begin() + SCNTransaction.animationDuration = 2.0 + node.runAction(firstAction) + SCNTransaction.completionBlock = { [weak self, weak node] in + Queue.mainQueue().after(2.2, { + node?.position = SCNVector3(0.0, 0.0, -3.0) + let secondPath = UIBezierPath() + secondPath.move(to: CGPoint(x: 0.0, y: -3.0)) + secondPath.addLine(to: CGPoint(x: 15.5, y: 20.0)) + + let secondAction = SCNAction.moveAlong(path: secondPath, duration: 2.0) + SCNTransaction.begin() + SCNTransaction.animationDuration = 2.0 + node?.runAction(secondAction) + SCNTransaction.completionBlock = { [weak self] in + Queue.mainQueue().after(2.2, { + self?.setupMovementAnimation() + }) + } + SCNTransaction.commit() + }) + } + SCNTransaction.commit() + } + + func resetAnimation() { + } + + override func layoutSubviews() { + super.layoutSubviews() + + self.sceneView.frame = CGRect(origin: .zero, size: frame.size) + } +} + +extension UIBezierPath { + var elements: [PathElement] { + var pathElements = [PathElement]() + withUnsafeMutablePointer(to: &pathElements) { elementsPointer in + cgPath.apply(info: elementsPointer) { (userInfo, nextElementPointer) in + let nextElement = PathElement(element: nextElementPointer.pointee) + let elementsPointer = userInfo!.assumingMemoryBound(to: [PathElement].self) + elementsPointer.pointee.append(nextElement) + } + } + return pathElements + } +} + +enum PathElement { + case moveToPoint(CGPoint) + case addLineToPoint(CGPoint) + case addQuadCurveToPoint(CGPoint, CGPoint) + case addCurveToPoint(CGPoint, CGPoint, CGPoint) + case closeSubpath + + init(element: CGPathElement) { + switch element.type { + case .moveToPoint: + self = .moveToPoint(element.points[0]) + case .addLineToPoint: + self = .addLineToPoint(element.points[0]) + case .addQuadCurveToPoint: + self = .addQuadCurveToPoint(element.points[0], element.points[1]) + case .addCurveToPoint: + self = .addCurveToPoint(element.points[0], element.points[1], element.points[2]) + case .closeSubpath: + self = .closeSubpath + @unknown default: + self = .closeSubpath + } + } +} + +public extension SCNAction { + class func moveAlong(path: UIBezierPath, duration animationDuration: Double) -> SCNAction { + let points = path.elements + var actions = [SCNAction]() + + for point in points { + switch point { + case .moveToPoint(let a): + let moveAction = SCNAction.move(to: SCNVector3(a.x, 0, a.y), duration: animationDuration) + actions.append(moveAction) + break + + case .addCurveToPoint(let a, let b, let c): + let moveAction1 = SCNAction.move(to: SCNVector3(a.x, 0, a.y), duration: animationDuration) + let moveAction2 = SCNAction.move(to: SCNVector3(b.x, 0, b.y), duration: animationDuration) + let moveAction3 = SCNAction.move(to: SCNVector3(c.x, 0, c.y), duration: animationDuration) + actions.append(moveAction1) + actions.append(moveAction2) + actions.append(moveAction3) + break + + case .addLineToPoint(let a): + let moveAction = SCNAction.move(to: SCNVector3(a.x, 0, a.y), duration: animationDuration) + actions.append(moveAction) + break + + case .addQuadCurveToPoint(let a, let b): + let moveAction1 = SCNAction.move(to: SCNVector3(a.x, 0, a.y), duration: animationDuration) + let moveAction2 = SCNAction.move(to: SCNVector3(b.x, 0, b.y), duration: animationDuration) + actions.append(moveAction1) + actions.append(moveAction2) + break + + default: + let moveAction = SCNAction.move(to: SCNVector3(0, 0, 0), duration: animationDuration) + actions.append(moveAction) + break + } + } + return SCNAction.sequence(actions) + } +} diff --git a/submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift index 62ef7d5b8b..00956b337e 100644 --- a/submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift +++ b/submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift @@ -321,46 +321,82 @@ public final class ReactionNode: ASDisplayNode, ReactionItemNode { } } -private func generatePremiumReactionIcon() -> UIImage? { - return generateImage(CGSize(width: 32.0, height: 32.0), contextGenerator: { size, context in - context.clear(CGRect(origin: CGPoint(), size: size)) - if let backgroundImage = UIImage(bundleImageName: "Premium/BackgroundIcon"), let foregroundImage = UIImage(bundleImageName: "Premium/ForegroundIcon") { - context.saveGState() - if let cgImage = backgroundImage.cgImage { - context.clip(to: CGRect(origin: .zero, size: size), mask: cgImage) - } - - let colorsArray: [CGColor] = [ - UIColor(rgb: 0x6B93FF).cgColor, - UIColor(rgb: 0x6B93FF).cgColor, - UIColor(rgb: 0x976FFF).cgColor, - UIColor(rgb: 0xE46ACE).cgColor, - UIColor(rgb: 0xE46ACE).cgColor - ] - var locations: [CGFloat] = [0.0, 0.15, 0.5, 0.85, 1.0] - let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)! - - context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions()) - - context.restoreGState() - - if let cgImage = foregroundImage.cgImage { - context.clip(to: CGRect(origin: .zero, size: size), mask: cgImage) - } - context.setFillColor(UIColor.white.cgColor) - context.fill(CGRect(origin: CGPoint(), size: size)) +private let starsCount = 7 +private final class StarsNode: ASDisplayNode { + private let starNodes: [ASImageNode] + private var timer: SwiftSignalKit.Timer? + + override init() { + let image = UIImage(bundleImageName: "Premium/ReactionsStar") + var starNodes: [ASImageNode] = [] + for _ in 0 ..< starsCount { + let node = ASImageNode() + node.alpha = 0.0 + node.image = image + node.displaysAsynchronously = false + starNodes.append(node) } - }) + self.starNodes = starNodes + + super.init() + + for node in starNodes { + self.addSubnode(node) + } + + self.setup(firstTime: true) + + self.timer = SwiftSignalKit.Timer(timeout: 0.5, repeat: true, completion: { [weak self] in + self?.setup() + }, queue: Queue.mainQueue()) + self.timer?.start() + } + + deinit { + self.timer?.invalidate() + } + + func setup(firstTime: Bool = false) { + let size = CGSize(width: 32.0, height: 32.0) + let starSize = CGSize(width: 6.0, height: 8.0) + + for node in self.starNodes { + if node.layer.animation(forKey: "transform.scale") == nil && node.layer.animation(forKey: "opacity") == nil { + let x = CGFloat.random(in: 0 ..< size.width) + let y = CGFloat.random(in: 0 ..< size.width) + + let randomTargetScale = CGFloat.random(in: 0.8 ..< 1.0) + node.bounds = CGRect(origin: .zero, size: starSize) + node.position = CGPoint(x: x, y: y) + + node.alpha = 1.0 + + let duration = CGFloat.random(in: 0.4 ..< 0.65) + let delay = firstTime ? CGFloat.random(in: 0.0 ..< 0.25) : 0.0 + node.layer.animateScale(from: 0.001, to: randomTargetScale, duration: duration, delay: delay, removeOnCompletion: false, completion: { [weak self, weak node] _ in + let duration = CGFloat.random(in: 0.3 ..< 0.35) + node?.alpha = 0.0 + node?.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration, removeOnCompletion: false, completion: { [weak self, weak node] _ in + node?.layer.removeAllAnimations() + self?.setup() + }) + }) + } + } + } } final class PremiumReactionsNode: ASDisplayNode, ReactionItemNode { var isExtracted: Bool = false - var backgroundView: UIVisualEffectView? - let backgroundMaskNode: ASImageNode - let backgroundOverlayNode: ASImageNode - let imageNode: ASImageNode - let maskImageNode: ASImageNode + private var backgroundView: UIVisualEffectView? + private let backgroundMaskNode: ASImageNode + private let backgroundOverlayNode: ASImageNode + private let imageNode: ASImageNode + private var starsNode: StarsNode? + + private let maskContainerNode: ASDisplayNode + private let maskImageNode: ASImageNode init(theme: PresentationTheme) { self.backgroundMaskNode = ASImageNode() @@ -370,7 +406,7 @@ final class PremiumReactionsNode: ASDisplayNode, ReactionItemNode { self.backgroundMaskNode.image = UIImage(bundleImageName: "Premium/ReactionsBackground") self.backgroundOverlayNode = ASImageNode() - self.backgroundOverlayNode.alpha = 0.05 + self.backgroundOverlayNode.alpha = 0.1 self.backgroundOverlayNode.contentMode = .center self.backgroundOverlayNode.displaysAsynchronously = false self.backgroundOverlayNode.isUserInteractionEnabled = false @@ -382,20 +418,24 @@ final class PremiumReactionsNode: ASDisplayNode, ReactionItemNode { self.imageNode.isUserInteractionEnabled = false self.imageNode.image = UIImage(bundleImageName: "Premium/ReactionsForeground") + self.maskContainerNode = ASDisplayNode() + self.maskImageNode = ASImageNode() if let backgroundImage = UIImage(bundleImageName: "Premium/ReactionsBackground") { - self.maskImageNode.image = generateImage(CGSize(width: 40.0, height: 52.0), contextGenerator: { size, context in + self.maskImageNode.image = generateImage(CGSize(width: 40.0 * 4.0, height: 52.0 * 4.0), contextGenerator: { size, context in context.setFillColor(UIColor.black.cgColor) context.fill(CGRect(origin: .zero, size: size)) if let cgImage = backgroundImage.cgImage { - let maskFrame = CGRect(origin: .zero, size: size).insetBy(dx: 4.0, dy: 10.0) + let maskFrame = CGRect(origin: .zero, size: size).insetBy(dx: 4.0 + 40.0 * 2.0 - 16.0, dy: 10.0 + 52.0 * 2.0 - 16.0) context.clip(to: maskFrame, mask: cgImage) } context.setBlendMode(.clear) context.fill(CGRect(origin: .zero, size: size)) }) } + self.maskImageNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((40.0 - 40.0 * 4.0) / 2.0), y: floorToScreenPixels((52.0 - 52.0 * 4.0) / 2.0)), size: CGSize(width: 40.0 * 4.0, height: 52.0 * 4.0)) + self.maskContainerNode.addSubnode(self.maskImageNode) super.init() @@ -416,10 +456,37 @@ final class PremiumReactionsNode: ASDisplayNode, ReactionItemNode { backgroundView.mask = self.backgroundMaskNode.view self.view.insertSubview(backgroundView, at: 0) self.backgroundView = backgroundView + + let starsNode = StarsNode() + starsNode.frame = CGRect(origin: .zero, size: CGSize(width: 32.0, height: 32.0)) + self.backgroundView?.contentView.addSubview(starsNode.view) + self.starsNode = starsNode } func appear(animated: Bool) { - + if animated { + let delay: Double = 0.1 + let duration: Double = 0.85 + let damping: CGFloat = 60.0 + + let initialScale: CGFloat = 0.25 + self.maskImageNode.layer.animateSpring(from: initialScale as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: duration, delay: delay, damping: damping) + self.backgroundView?.layer.animateSpring(from: initialScale as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: duration, delay: delay, damping: damping) + self.backgroundOverlayNode.layer.animateSpring(from: initialScale as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: duration, delay: delay, damping: damping) + self.imageNode.layer.animateSpring(from: initialScale as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: duration, delay: delay, damping: damping) + + Queue.mainQueue().after(0.25, { + let shimmerNode = ASImageNode() + shimmerNode.displaysAsynchronously = false + shimmerNode.image = generateGradientImage(size: CGSize(width: 32.0, height: 32.0), colors: [UIColor(rgb: 0xffffff, alpha: 0.0), UIColor(rgb: 0xffffff, alpha: 0.24), UIColor(rgb: 0xffffff, alpha: 0.0)], locations: [0.0, 0.5, 1.0], direction: .horizontal) + shimmerNode.frame = CGRect(origin: .zero, size: CGSize(width: 32.0, height: 32.0)) + self.backgroundView?.contentView.addSubview(shimmerNode.view) + + shimmerNode.layer.animatePosition(from: CGPoint(x: -60.0, y: 0.0), to: CGPoint(x: 60.0, y: 0.0), duration: 0.75, removeOnCompletion: false, additive: true, completion: { [weak shimmerNode] _ in + shimmerNode?.view.removeFromSuperview() + }) + }) + } } func updateLayout(size: CGSize, isExpanded: Bool, largeExpanded: Bool, isPreviewing: Bool, transition: ContainedViewLayoutTransition) { @@ -430,8 +497,7 @@ final class PremiumReactionsNode: ASDisplayNode, ReactionItemNode { self.imageNode.frame = bounds } - var maskNode: ASDisplayNode? { - return self.maskImageNode + return self.maskContainerNode } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/AppStore.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/AppStore.swift index 8dd0f98cef..4a8b1c68b0 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/AppStore.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/AppStore.swift @@ -6,6 +6,7 @@ import TelegramApi public enum AssignAppStoreTransactionError { case generic + case timeout } func _internal_sendAppStoreReceipt(account: Account, receipt: Data, restore: Bool) -> Signal { diff --git a/submodules/TelegramUI/Images.xcassets/Premium/ReactionsStar.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Premium/ReactionsStar.imageset/Contents.json new file mode 100644 index 0000000000..18355ee5bf --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Premium/ReactionsStar.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "ministar@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Premium/ReactionsStar.imageset/ministar@3x.png b/submodules/TelegramUI/Images.xcassets/Premium/ReactionsStar.imageset/ministar@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..efd6a2ef5a49cd8b74c63a9567b46c26ca097493 GIT binary patch literal 341 zcmV-b0jmCqP)T)S*tpP!xypuL~o~vIPP&cmxv|f}0}X7X%g!JPHqh z1xS#?Sy5wgK$|qc)%; zV5be}1UPI8Z37eFxG8i7^vTB?N0Vx(2kMugHnaX>dnO6R;UWQlVF%R~JfwK7p(*lyXM> n;`!YaDzBQKSSV$*C{We{%t$oU2G