From d9911cc30b04b14a408c0c822a799eee63da33ab Mon Sep 17 00:00:00 2001 From: "seonkyu.kim" Date: Mon, 21 Oct 2024 14:52:12 +0900 Subject: [PATCH] =?UTF-8?q?[=E2=9C=A8]=20IntroVC=20=EC=99=84=EC=84=B1,=20?= =?UTF-8?q?=EB=B2=84=EC=A0=84=20=EC=B2=B4=ED=81=AC,=20=EC=9C=84=EC=B9=98?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EC=88=98=EC=8B=A0=20=EB=93=B1=20=EA=B8=B0?= =?UTF-8?q?=EC=B4=88=EC=A0=81=EC=9D=B8=20=EA=B8=B0=EB=8A=A5=EB=93=A4=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WebAppUIKitBase.xcodeproj/project.pbxproj | 65 +++++- .../xcshareddata/swiftpm/Package.resolved | 24 +++ .../UserInterfaceState.xcuserstate | Bin 14618 -> 62524 bytes .../xcdebugger/Breakpoints_v2.xcbkptlist | 6 + WebAppUIKitBase/AppDelegate.swift | 36 ---- WebAppUIKitBase/Common/AppDelegate.swift | 44 ++-- WebAppUIKitBase/Common/CommonUtils.swift | 126 +++++++++++- WebAppUIKitBase/Common/Prefix.swift | 53 ++--- .../Common/Protocol/LoactionProtocol.swift | 13 +- WebAppUIKitBase/Common/SceneDelegate.swift | 35 +--- WebAppUIKitBase/Info.plist | 2 - WebAppUIKitBase/IntroVC.swift | 8 - WebAppUIKitBase/Scene/AppDelegate.swift | 33 --- WebAppUIKitBase/Scene/IntroVC.swift | 193 ++++++++++++++++++ WebAppUIKitBase/Scene/MainWebVC.swift | 13 +- WebAppUIKitBase/Scene/SceneDelegate.swift | 55 ----- WebAppUIKitBase/SecretCode.swift | 8 - 17 files changed, 484 insertions(+), 230 deletions(-) create mode 100644 WebAppUIKitBase.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved create mode 100644 WebAppUIKitBase.xcodeproj/xcuserdata/seankim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist delete mode 100644 WebAppUIKitBase/AppDelegate.swift delete mode 100644 WebAppUIKitBase/IntroVC.swift delete mode 100644 WebAppUIKitBase/Scene/AppDelegate.swift delete mode 100644 WebAppUIKitBase/Scene/SceneDelegate.swift delete mode 100644 WebAppUIKitBase/SecretCode.swift diff --git a/WebAppUIKitBase.xcodeproj/project.pbxproj b/WebAppUIKitBase.xcodeproj/project.pbxproj index 29fdb8b..39e5df9 100644 --- a/WebAppUIKitBase.xcodeproj/project.pbxproj +++ b/WebAppUIKitBase.xcodeproj/project.pbxproj @@ -6,6 +6,11 @@ objectVersion = 77; objects = { +/* Begin PBXBuildFile section */ + A7D80D4D2CC5DFFF00E93F4D /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = A7D80D4C2CC5DFFF00E93F4D /* SnapKit */; }; + A7D80D502CC5E01D00E93F4D /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = A7D80D4F2CC5E01D00E93F4D /* Alamofire */; }; +/* End PBXBuildFile section */ + /* Begin PBXFileReference section */ A749CDFD2CC5D8CD0038D13D /* WebAppUIKitBase.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WebAppUIKitBase.app; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -36,6 +41,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + A7D80D4D2CC5DFFF00E93F4D /* SnapKit in Frameworks */, + A7D80D502CC5E01D00E93F4D /* Alamofire in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -78,6 +85,8 @@ ); name = WebAppUIKitBase; packageProductDependencies = ( + A7D80D4C2CC5DFFF00E93F4D /* SnapKit */, + A7D80D4F2CC5E01D00E93F4D /* Alamofire */, ); productName = WebAppUIKitBase; productReference = A749CDFD2CC5D8CD0038D13D /* WebAppUIKitBase.app */; @@ -107,6 +116,10 @@ ); mainGroup = A749CDF42CC5D8CD0038D13D; minimizedProjectReferenceProxies = 1; + packageReferences = ( + A7D80D4B2CC5DFFF00E93F4D /* XCRemoteSwiftPackageReference "SnapKit" */, + A7D80D4E2CC5E01D00E93F4D /* XCRemoteSwiftPackageReference "Alamofire" */, + ); preferredProjectObjectVersion = 77; productRefGroup = A749CDFE2CC5D8CD0038D13D /* Products */; projectDirPath = ""; @@ -144,20 +157,20 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2.0.8.1; DEVELOPMENT_TEAM = 45MYH7ZHUQ; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = WebAppUIKitBase/Info.plist; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "검색과 길안내를 위해 사용합니다."; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UIMainStoryboardFile = Main; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 2.0.8; PRODUCT_BUNDLE_IDENTIFIER = "kr.kro.sean-k.WebAppUIKitBase"; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -176,20 +189,20 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2.0.8.1; DEVELOPMENT_TEAM = 45MYH7ZHUQ; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = WebAppUIKitBase/Info.plist; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "검색과 길안내를 위해 사용합니다."; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UIMainStoryboardFile = Main; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 2.0.8; PRODUCT_BUNDLE_IDENTIFIER = "kr.kro.sean-k.WebAppUIKitBase"; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -343,6 +356,38 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + A7D80D4B2CC5DFFF00E93F4D /* XCRemoteSwiftPackageReference "SnapKit" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/SnapKit/SnapKit.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 5.7.1; + }; + }; + A7D80D4E2CC5E01D00E93F4D /* XCRemoteSwiftPackageReference "Alamofire" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/Alamofire/Alamofire.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 5.10.1; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + A7D80D4C2CC5DFFF00E93F4D /* SnapKit */ = { + isa = XCSwiftPackageProductDependency; + package = A7D80D4B2CC5DFFF00E93F4D /* XCRemoteSwiftPackageReference "SnapKit" */; + productName = SnapKit; + }; + A7D80D4F2CC5E01D00E93F4D /* Alamofire */ = { + isa = XCSwiftPackageProductDependency; + package = A7D80D4E2CC5E01D00E93F4D /* XCRemoteSwiftPackageReference "Alamofire" */; + productName = Alamofire; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = A749CDF52CC5D8CD0038D13D /* Project object */; } diff --git a/WebAppUIKitBase.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/WebAppUIKitBase.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..1d89461 --- /dev/null +++ b/WebAppUIKitBase.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,24 @@ +{ + "originHash" : "4d1117f641c000c6545947e4d48e126cc17473ec53f643df82900a33ad4936b2", + "pins" : [ + { + "identity" : "alamofire", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Alamofire/Alamofire.git", + "state" : { + "revision" : "e16d3481f5ed35f0472cb93350085853d754913f", + "version" : "5.10.1" + } + }, + { + "identity" : "snapkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SnapKit/SnapKit.git", + "state" : { + "revision" : "2842e6e84e82eb9a8dac0100ca90d9444b0307f4", + "version" : "5.7.1" + } + } + ], + "version" : 3 +} diff --git a/WebAppUIKitBase.xcodeproj/project.xcworkspace/xcuserdata/seankim.xcuserdatad/UserInterfaceState.xcuserstate b/WebAppUIKitBase.xcodeproj/project.xcworkspace/xcuserdata/seankim.xcuserdatad/UserInterfaceState.xcuserstate index 6c3493550e68c418beae3dd8929f81ba12c7c472..a0b098267bcd4d2b3f7ea8ba60dc9e8de29ef5a5 100644 GIT binary patch literal 62524 zcmeEvcVHAn^#9K6?(N?0-R5T67EuNId>U% zIk%F#mb;F-iCf2Q|Ot2hx#rB{3wK zq>xn7m-Hk3$pA8tj3Ak00+~Xx$@wIY1jt-cLPDgJl#zL4F^ z@;mv1{7L>Ie^ZVUN-0kTDpD62OC>5(H`S<48`0LZ4Q)%?(I^^CV`(=UN0aG5I*1OY zLudvaN{7+mG>eX-7{f9T}iK^tLa*LJzYoF({frtZ>3dq8@-#}M<1rU z=wtM8x|=>vU!eQwi*!FdKo8PG^j-QP{fvG|kJ9hx_w-l#2QTs-z5(BaZ_2miTk+@c z?f7%~4ty8BD<8+l^9g(+Ka3yFkKjl0qxjMM7=A3D$!GE7_(}Zvd=5W@&*kUv1$-f2 z#?RyD^9%T8{Kfnw{H6RA{7QZmznZ_6zm8weZ{Tm{H}bdfck%c05AhH4kMU3P&+>ct z7x;brEBvecm;7P=EBwf=p=L&5`;t{N$4pI5QYjPg;Bz2AxoGjOcJIE(}fvAuCPd0EG!W&5|#?40Kzii zV&M|uQsD|=m9Sd4R#+#j7d8mD3bzTj3tNRdg&o2}!o$KY;Su3!;Thp2;gIl-@PY85 z@Tu^ba9B7Zd@KAQ{3!e?{3aTrUu+;Y6dQ?+#U^4?v6Je2E8ZvGFFqhXDDD!U6rU2G7WauSiZ6+;iLZ-qh#!d`i=T*}ieHM~ zh(C!xi@&%ym*n!f{H_MBCaxB))~+_LXjgkzCs$`zKUaU(0M|g*AlG2m5Lbq4sB4&O zxNEd)f@`Add{>TZhO59;=qhprT_M+e*HV}10@pIvm97=8HLmrp3fHZ!+g#gR+g+`S^_c55*Xyn~TyMJGa=q<($Mvr3J=goL4_u$PzH)u-`o{H>>u1+55|OCH zOM)az9;ux0Sh<^=D5uK3-LdXL?!oRM?hN-(_b~Tx_Xzh$_bB&hcb0pK zJJ+4(4!8^5MeYUeh3*U8i`+}y7rQTUU+TWfeYJb7d%gP>ccuF__wDXG+&kS5xgU1# zazEnU>weDty!!?BKKFk20rwm3kK7--KXD&%f9pP~2#Tn<6iJa4x1uPj;!(Vcp)^vO zDb1DcN)P2crKi$M>8lJlpfX4qtPD{`D^rze%5)`9DN=$;u`*Ygr_5It zD5i3Wa)q)|xlUQ5tW(x2<;oW2R^=Y$UgbXJe&qq>L1m}%i1MWJl=8H)PkB*!NqJd0 zsJx+kpnRfys(h&&RymcZROMAc6;+oisj});eQE=>q1r@kuC`EHs%_M^YCAPb?Vxs4 zd#MA|!Rioom^xe?rH)p|sN>Y}>I8L)I#pe!E>|y8SEwu1RqASWt$Mw>PF=6wqHa<* zt6S8qYL$AIx?SC)?p2>tpI2W{_o*+cFR3r9uc)u8htzk}Pt;G<&(x#pck1`*59%-K z?;hSGcqEVJ(LEhKojjdAT|8YqF`igYH&2`=-jm=-@$~cz^bGP0_Kfk2^<;XoJQF=r zJ$ashXQrpf6ZBl>x!iMw=St5C&q~i#o~u3Acvg8Phac)s=g;5p`{UfwHseO}G0dkt?R zZ!>ROZ#!?4H`?3P8{-}59poMC9pcUK4)qT64)>1mj`WW5W_l-kXLxhHdENqVp?AJ_ zfp?+zLhnW1W!@{jE4-E7&E75ETfMh=Z})EXR(ZF1@9^H~-QnHo-R*tC`=s}I?+e~T z-q*aZd*ATB z*2ZY#v`JcyHbc8mTcj=4mS`7gOEpsiZJBnlc8PYmc8zv}cB6KaR;g{)wrIC%RoY$J z1KNYyONi5 z8|Y2+)_NN~O;6Xm>pk@I^qzVzy|>;+@2mII2k9g9ar$_Df}W$#&~x=XeYRepm+EEu zJpCelseXfgqkfaVPG7HY&~Mf^>bK~d^m2WReusXae!u>JzFU7ne^P%+-=n{vAJ7l# z@96L9Kj}Z~zv#c}zv;*H-}OKAKlQ)#zYX3{48PI9XlR^cv^LrpZH@LuCnMfSFcOU( z#(74TG0qroOfV)IlZ?s66l1C}&6sY?F!GJLMu`zJmKYZqOAXVw#JJp8Wvn)CGS(UQ z821|Y8TT6x7!Mjdjfaefja|kg#%^PevDbLcc-7c%95CKC-Z4HiJ~zHFzBIluzB7I^ zj`=x1@l(Ixm;9>V@Hg_e_P6o3^|$kP^mp>d_~ZO3{#1W=e; z{5ShI`fu@9`fu|;=-=so$p5f^m;bSG(M4qi1qV1U=i@X^=NfR0CydODofB9XnvB20 z_Vf7Y+=84?sDd*%ze!ELf@{b%LK}nrZFbJqqtoICr1u|~o)VLg(l;e0DJ>;ECOthZ zHD*BizyV1~NpUG@1N&#|4KoG|oDeLT6DrQh4Gak8mK6qyN}ZgWb5UH^+qo88ORg1n z4%eD%!?oqwnWE`3B~v!tredn5=XNfdYtNm_b->>(*{A6>eL(**o8liX>oY!EZ^San zFUkwf&j<~|x68~e2?UC=^nnUE72pC8Icp$Yk=vorIHW)%eRPPX0} z1^ecf;y9+dzG@d&Z&s63Fjz1nrzFEkDqC+_bI;1A`j+feb}HAG>$;Uo&^8sHB&bY({DB~8=8&G#%7bPSjqjl0o*`t5I2|`g4I40Yq^=Z!dz+IVBTo1 z!+O8j#5&h8)6Chy`6F}Y<y!>#w zZs+wUa5K2BRop~w5;vKf!cFC-anreM?tCuCY;LwNTbixRbIjIe8?&w1&Wx(!a=AP% zz|G`lakII6?gDNOS71h)31%O2s5#6WZ|0bD%|+&=tQtB`%njxRVp(Mb%Sv(s;Vw2V zBewc|V*Ag|DVh}sW$WEeLwIbUI2dAYfEAXlx2t|)SbphoNoHYpiyeVEmtZ$HG6Mxz znSs3OEOF#JxFlFsY~R3fGA0#Ooz%!+X?|`XWTj~RdE9d?s-gTV zmP^8hX|3{P1`!u1=;X16yPj)Y&aE|L%DEfNSjMyr+I2p&AIWj<)}*@cN?q%(efH z>T~%J>o3`ejy-Q!*0}MLrUr`UUTEJX#Qu%%Qv1J)?ONW%l_QA`Tu@wKQ|qX*(t`Y= z0HX%mqr+Z1++vkn1y{+fK5hAIeMWXx>EQn3<5LEV&#K7-yM01R&DZ0y%vx9+2&IOz z%O0PZofuyuXVqLLa$(V|j6AIV{F(X4TlQ;g;ci6+8<{zxtdteFriWB=TUZ})+W&U$ zPS)qQa#h?m?hZ52Ofr+rl+D~-+;;A6Ziks_o@e$nds%&+5#55~oT9uyp4CiQsPXLX zf;~Af5aZ8ps89v9oP@UmEv$xsVx$!dh3fC3k81Gy- zz`eoh?jU!FdyRYD>}&Qj`hK(+|S%E+^^g-NxiP&i}WsSh@A1t;^ zj8kj;)3X}>tzi>xRN^ImL@n_Vjp)QMCzun>N#^9uqycG28j%L(6mzOM4L|>vv^;4= z&at)pKf{=`Bhd(B5@k*=C+*Gbe}XaT#BCs5{t3qC*E@`J4Q^DAtN#JUMSU#&8`WpU z-PRxfQd>LC8B5~1t`(#ki8E)IxfLVh-^ahQR+IM*_VrdXHQKr4u5GaEJb%PGyB&0w7sSWs#`eUJ8wq9OlZm>8o*}7=uWL{u$W|0{@fRBtMqsVA7hK$WB#q=iPixx7g z!7McA=s4A*kt{NfjGu(#?2x6F&4Tfv**PVFJj+lZ6UiiN&MIsu*s8k{FHg1%N&CAk zI+aX2;SH?Pvtm||>C6tQ^?KDePq<$F+IFfr1P7z%9A7WigS9HLg5?fLTOb;+?l1-^vmMoh2NE{Q}cfxKfyBipo zLc@sza9n^x{Qy4D*svwW&U+K@H#Ih^YP06!`v(gPgGCcZmjp|LxxoUIYZ;cC*meoZ zonus}Dqd~lTy3!&ueLMF*~Mt*VuKNQ@m!W=GrZi9U;z$) zQ6eTRF?QZzl;~!ar3+q3GR9B zWwcA*#kt)t(Q^5Pa5$qYqtQ7>6*E-NQDm>2&e;&9YU{&CcMNxkdQ8DAGZA^-djdbE1f zdqqd9Vg84DbQ9UaTCbc`aNEdcbGdmL4g@dXjGe9nxt(l97hF^G3iC>)1Y03lGdJ9* zqJo7PMW}Gl7PO2z{JRLPLgqkl?vE`iD#CmH3WB+FP(fO^N^^4OAZ(e_fPvo{%GEh6 zi%VXzM5j@Giu+h^=5(}s$o)*^-%IW@uQIQ$AP9C$1=F9WS$=d8^4IomOK>zPv2`7_E&nLS@)R@Yq~Hi)<1^F{K~^lI0E z^}3bhMfSqg#N;%^tKrgE+W_7H4>7Od$*tZ#$||IBq_`=dh6V{eeRSqr{N z-ZIyl8!E7qF(IDL@!^4-Ie|Q<=d_+Uw)ze;V&`J6ua)j%;jeJZ# zA)k`Z$miq>@+CP;z9L_fZ_JJ6E#@Y(+^jGw&CTW(^H%dV^Y(4zTXK|qN4_UNkRQoU z3o#sP8UkCag&|^S<2l}TOKYc{bg8ah#3(+)V3wzKfYr8O5 zx6Uca4+V=X=ifN&jp16bUBtFaPz$@)EX}vDATas(n}*|S&O{GdDXToJlo|)Kb=At0 zHED54J~}uTI=8K5NqM#Xap(p@JPruV%qc4W&h_@V~cQ$hW-fqA$2fO)->Kx5jRYg|d2(5AGRxx>82 zytk6J;5yJ&=6%=??>9S7!{ln*VpG|-n&}H2zp|v}6q zrD-&scBeh)dFC$j5%W>=G4pYA_pP)S?M?gOXFo*86XugZrt}(bOBvRFQkj;VsaE~(3!;?9<)c4(`$OQjlo9MBsex0EM+uqU&kj4bMlL7 z#IcU7HW)S2Nwemjx!-)wJY>FM?lr59pEasgnRbG))%jI>p6pgN$)lANdnk7D=gpVQ zSIkuh=yG})zSRYEEWL7aO>X0?a^Sn~GhdvXQ8Y6cYfTsEyrqEX)$|%1Ya^&?T<-Qj z)Ou`mPJT%RUByO(r<8Frzm^=OSDG&)oxd14B5{Onu!LScna~D&iJR$0dJ7qPd@D~X z%`ZfpcDi*k8==|tXufW~maUJf zmqNxaVAGMs_*!-u@1S>1!4f+Cu#(b6gJu&p zd#z4a(+6rJu!7#pUiq};577IuCLSO|=}!6(TYoSECj_S8?~*_Px@zVH(5LdY`PP|k z!bj+%<3?s8LsZa5SovGz1`A_zictl}E+{OB!FntXl$0)vVKZxJ(AF{{Z31`NK6W&d zv9CG&`~-aleOUBK`V@WIeBb=Q{IHTfOZU*d=11nI=4XtjnHME{^ze+#tn7gUGO|XE z&CVP+d|>~qj8P-AhYdt;P@4#W@fn#J{e}-5i&C~oWEuk}j_x}$Gn|G^2QQIFE9lGg z74u{B6LS?hEXHNvTuedOF=lxJM&uOb&qM&BiG!0|%r}6x-OT)1Ww_V@ts^vXn%J{7 z32AJ$CO#=XrE8m{WE>aRS-eK}Y@x5yH|U%6E&8_kx%q|prFq!=#=PFX{~p;>PG80X zguj2pG_g~p@U_p$o=wjE!)VL1`}7-n#47ez=GV-Yj~bU@FZQs?m}w7O#-gEq+zX9~ zv-A9c?5VWV2&aJg;QTH9jUKbtr_@r-Oh;AF-&s#!YgZ!fMJm2O>0k73o})!P<#}E( ze=z?7!kI_SBS50fKg_>tDHGnsOO7%zkD1>&9B-AC_mW39^FChVb>1+)H-9vLF@LRL z?LRF}{DE=eG#u!a1jqNcy%%B9PuqJUb4b9!I*4bd;6cZ>OYKz9XYp z^LLv}&#zZ9wc4)R2`^I334AvT|9@udXFONr>Ef~(2n4$}V?x$44qWSVO0c6JEL0Y9 zCR*~G8B#up?~N->_+&nXPvz72biO;^gFlb&$@c<+>+UHK9*6)$1mXfB0g-{Yfhbjc zA8Us><5eg1*+tzuTImG%0aVtg6EVR;E*C~@xG|yhZ#76BA5(U;+rP{<|gQ5r-dpQ9b z!KH!N;LMq!0P;;_O27^mriMMU-PcE+ra{DTi$E zjVF(m^Amu0n12C%4g6$=#wq+%{Fx2}>)mI4YUV1vn?6v#DopZx9zTm~T)_wUnLrF6 z{tA9JpAVz~kS1(2(j1+pr8#yB*+aSN>OpcJjWsq47wQz@I5C8Szt9OHP9{bCT$V|Y zF9y;ONTUkAgggMGF}hkhPtOaR+QS1yvr1=AVbx`sW`U5=F4{?9A-@C%PW*-ZA|9>z zra+njXS>h`$OGxH>X{1uHIoXp?)?a}TsV7JaU}Y7-_9)hEv$ z6-M>xYK;y#y}GW}@Hep9Udvw(q#ckb^lI@X<~6LoJCB=*T`F`!o#S{pcXl9m4l1DW z_P(T!og#Dve+&JKFXt;zS8V3D@JIrkn6gL!axT*rqXB2lPEZ%O^IIKt0VEbkhuR8b zJL{r%^E>!^_Kq{rtO(@(=I_`9u6`{OkN1{G0q+ z{M-CHKoWr@0Z9gu0wfhk8jy4#-GTG~a$XhxUYPPf;y)%wk@7!dl;6{#{Jua&U|l2g zj6BQu)|$@P5Gt{HWBeZ(g~mb? z0SSHxkPIM0D~0Al3&!!ofDHfdIbLYTX+l&aMSpuSzxRf|Lz-{f)cL!lug?L-@xr+% z+aXeR#iS-jC&cz&v2tB@fzdo4l~>EC$B)`9?$kvWA=ct>A;#kHQKzWEY4gzeI3Pc7 zcrYig4&D}$>0d&skVcDyWT6M+?Qx8^(I^sVDHZ&`aoD!`qXAWY*$sVIaC@ zgh9e!0h=fb2wEKzt0^1v7|v)GlO4}EyN=1qlXJ8%&gSSzr{rj1vdz&`Y>sB@FY3=p za^l?TaRYrJ$EIgoxNwH^w3%7R6N1RhLO_@)%o1h``N9Rl9HBrc6pDak134c^4v-l@ za)F>t5deZF+$v#>%~$$o&$0a9RpA~iSEeGcZY6L2QELRcfL1%gc+tPpMxZUllh^E^h) z|7dNW(pq;ixmhS@B)d_#ML;`pE|3x+p-Q1bsAMEt3Z(4+0LfM%ac+wwPDPbh7OWUl zdJFgdoK3I4+1Vo5yHIv}r0ie6-E??%!~Tb^i2JJBV*RP#P}Zq}dxZOK?R1}|o#r!c z#aUm#RWm1!MhxDkOU`qT3cGDie%#{ZMW=W!!g>~-MHb#GJclg&g0PRVu*p~$nQ{qZ z;oE^+ej*FMEWA>~!pnhNRGWogV}0s%;SJ$U;VmFbfuPR07|10xRQxR2%Ba}HnRaAi zgH6B$i`ZV1P%Y1k@R7~B%NXm1*T9^DqrbAHFFiF!AGJC9GMl3V^~%xqi*&2weX31q z;TM~$ugKQ_m+}sC_Ayapoc+7-hw!KHm+-g9iA1C#FJg zK&}I_rb=|#oGmJ%DtfqR(Z@J@t;5;K1Dkm&J+6}&x<|9ULp=aelaDPNviyqfzkdCF+jW;RW4ezV zc8TzZAjf>3Zwj+BPbtTNVvernliu{1@tABbjR>&0@^58@5tjp9w>I&rJRbt`Fpyn99s%+wkjH?ap|Kmt6F{D< z5-Y;`;a1z*B33c|@RXw;_EdXY4xCjFXFxsdWa<7p*K%TWf zQ9XEczr#Dvh;>{%h4`HKJP`c<#rjhaFN^ybxfP4ATK4P{>AA3Ek^$z19_d%KN{&DoE6x?~ zN^m8*l3d9^J^}J6kk5d84&)0UUjjJ{O)su^M^=4Fk#G&f% zEceTw%#>$wAkf<%IlFguE|i5L$P0w0hX2)EsA~jrwQD4hZ^K;e8pCijmK`gD?b7`R&Tx+SFQ`^S}R?7u7C?&bw2_5 z8OSe{uGy}9M!CNN`R%`_Tvsutx#mXFXx{AXV_)3Y=i=*r>#_Nrk%ef9w%qS3McJ}Q z+1B?DJGSrp5n~=#fBtsKq_(|kDA%>XwTRX8LN=KBoegGOi`ii2kGcjk-NqOs-)W$W zUCS-5cAsn-HDj+jcFHnNaOuGWE z9j-lf>00Z$zM7e-8z`;K%o|vby4khSb&G2gP#&lV)CE+kW@gt)i%~HnG_%q9f>W!` z_M`t1LEmjBC!d<2@3#n=DreB^Qpbzbu=FDqOHlxRxu05{3uIGSaxE&3s4%7hZ2igE=L!ga-HU`?H%Jo8+s$X`!;(8US`T$Zj zZ5pO(+7f6-pq-GaY3H+4UH@ja>qAD>9|11Aw>{;qPZ_X2bA8T!fHnu(!u~|Fx{Kb& zA%i0>X1KY&bsYuT3g|f%uJ2tx0BsGlef_cZudY8BTmR-d=E98{ZGg4~+OE>|r|U0d zYZ?VK`oCvuN#r!i70JNazkZRmt6`u0H-0AzRaP8Cy#RvNi2c7h8+7qx$G!ze|H~LrKk~mKJMEEf{Ol zF38%Ffvk;5oak!L*8Akttmw3TE@K0;a8+ucWKghVECx_24Y1HZ&TeRo$5c9dKwuum z0?G=`2^7^~l1owaFR8tBE-jKeN}U+-$1~#Z0W_8o{}iCw2{NFuW|6j}9)&SB3iG|3LCQ6f}$Qsx(cSE@eyS zOF2N#1KJa4FQC1F_5s=#Xg{F+fervVuu96cHGnirnoY-Y(b62I0R}l5U^vi;IJiOu zFzKuUsDA|@Ekp$%T?lk=SOG{&7{D%)mP)1sK!*U$06G-tFjN4VF6)i-D2H1vmsT)x zxg(_qU>FfvPsk0ce$kBpa&jIZEY_5^~xlajq1~;)=C!X9?6<*T`Qq`8&$w$rUI^K zDqu_)uFh+V&dZ|V^ z1ORuLg?BmGeX9LX#dI8WmKns8t0xbd>1X^4r{SxND-)-Nr z^f%+cxef=GI=*GP^ehL~KL^UVaiUztVMc=#ewV-InW39Qd@j%hKoL1agCx(B=htxXD!@HM$8)gE><9TGd8us5Xg{m~ zx)LZ_1y@%SF+FZ4QkaI1-+Od&W|mjkR`@liWai^H9XU05le`&;Szafvmp8~a%Nyle zupgisfueQCK9QJH^odS$@0Bs?V}<;j z{5;TdpcNJJKKVtU*w|a^kDB+(uQ6&qARm+u0o@FA3(#9D<=5pm7&YGp6ql6!*CwX? zKGN+6k#xIaYy9w+Kg}q=WWeqQRUKqpb<=Xc{4vUY5-B_8>1lUGqITPMsS`Fr{$BpcrfGEYqhWg2DITwD zgN$YJ$$y|JD*p*|N7xi~bJCMQ@2Sh)q{wt`(e0|ubi07wTQ}3WJ#KFe(_y%W`)Vvy=^pyGOy}?@eWlV}>Mmo< z_$tu<0}C76i#g4`B$DmwVn(-#vJfd-2Qxke2V_o+R?i<}`tGo&HEx;}FPKb`v9qYO`+dT8mDS4)@v99}0 z_dOV5%zc-8yZdhU4xsM?{Q&5PKtI~-zSn&p-`tJ8p$ZV5lYB zP@G?k8&`3waN}AcR_ZJgjZ@Ya-7jM_Bscc^FU#Gp06omC^^?Ryav#JP2JS=d*MNQn z7^T38h~$3L%@zmMiiqUK?S5{o&^PKX$-|^^fg0$A8wobL%gB`!1}-oxsL<=vE4`XbTuyX?XsO5*G5Rh&7fI zev6%wQKxj46Q8BFeCLzNkIop7h4*SD&f=EWnfQo6X$~$h&8aQU0+Q4z&RV>-=t+y6 zSvDiI5NA;eYs+^#S<<+sl7-c0L5ONUaniCoVd!d$`)x#JGvs9jEleFye2Rv9oLiBx zijKV!gM2vQzwF)LxMA$LYZhXF{$Y)h6~EE|Bdk>MQC6*bk=NyP~PAib|4J~5o~VXXEFZpxDXcW z%OY16b_kmq^J07H0}C*y8+$cOrlDQF+NHoKEhiS6^+c<{niE5=x+HPzkPKYIg%NM? z{E(W!ads83DE)a>Y8d4Z1O6bBVy^wL)N_i17*{rA-NRMg7{3@}CMX%W+#0t?^1?pX zwPG&w|Nepda&UDBTe-c;=`Ujx^sQ{BbCpab3qz*73%m{(@#OE#$^>PiGD(>XydU^> zz^4FzJ|o{$I~0fYndr1eSurb4tlf%E4cl=T9hvGU5vg{VMVtzqiDwb@E6ZoGV^4gT z1vXeXBbZa-1TI#xl^hlsuh@LET$urUgX;4Jlz@_tv3-=8$}D9z@C|`)1bpL4n{(k()P=_tz>esnTv-#*N4W|k z`Y;J)6+L1X6ZqDrAJoS#+*%CjV<%FR1V#lqS!^Pw*KJTXVpA$N10Pkc+yZ=iY|EM; zRLW*+=9Q1m*2mZ9yl+iBE~gx~DR*G+S8i9fDpkrh;LimfiLE2>oi;0XDt9T{mAirO z415>hy8@rgx{w`;#_82|kH>YM7@V{$6o!L+vA-SpylX9_)Rxc6DZzEP|0wPdg##>S z;V!a{eXK$4(q!8?GODtZ#`dUHh~w|*Ckor``Vfwwl!t-G0D}jWM=`(~hIvySQyy1# zD^Eh#* z8b1>FQNWKzQyP)1*}9tzOPKZwO`aSK77of`2caRb?7+Ne^ahz$9##~bU(`RRXkJdp zIecjZ3*Hny?F-{PA@=8C03Cd^nS<96fx;Pqk{UY&@!EtX)|Z`-g=R{iCc`QH(TczT z%}kM_6zj!-ysTjH@W8x4K{y>2oLRS*2=&WxqUTz0RTWe>D#n!ueh~0Dvvxp5!&KE( zL-o^@>?FYww1np66tF+pS#S9{s22wVKO|cpw`fsJT6|(`dQxg!a(rr1Qd)XiQX(D$ zl$@Fro0gWGlA4|#mzbKEo@B+DOHNIVO^Zv8OHPVUj!#KSN6Gm3`1IJgM0_wcH9j#V z-VQ>CFjE_;>^MWq@U2iA;n_;zVl`#O0)D7ffUvHJPfWCr9ZK)oCXvOrj_Un&%jg%Y z7B32eNo}Q`_)yB&L@A42V;_EoVxVNQ+BMOO8v$zLJg!MC6s05Sdq6a$;S5BmvKr3cuF~JFiLqt~ZQT zGwt3`yUkP6V^h*n;}fvIrp6^Dq@*NuZIc|A9-EYqmYANN9G{kw5*HsIZu5z(%`x9> zZ1cGIp)m!;F~RX8oc=aV#fTN#bwkWmv(@v}99(n9yRKCO>P$4Nx2XB*1;ReHK>SNB zLW>&s9N=?-53p5ue=sYXp9L)T*i;N91^gV~3z_xJ2Z4MD{9H^{Emr5MC2B}5Rm;?Q z>U?#9x=_7PU8F8nm#7!1OH~tiwCJt|ek<@#0slVmzk$#IFo+7qDiLOYuo#5vLAVEm z7eV+OL<(ZdT1rH{)TVJfMr3lm()h_D1*%ut8RFrD^}A#akCNR%m zGqd&C_4>NuZ8e$fc#3fu*(cf6qpq>D$JpO_^_smMoiTE`c#XbRZ?dz#puX$fS?SsB zl(}!Tb1yhU+nMa@cQzVSug_O2?QAi^Votr*H!}!oR7zyNx7+!m_OIVfW2at@s@`d5 ziw4H@dVSr)%(=@)d$oE)t%}?Dvk?qU|R!$*+E{eubWN^$Yb& z^)T?40Dmd)%P~-o`i+V!6w#Y;8O{r_?EWD%<^Lqw(^IRD{qk1V zUq;Hie&6Q)?ojA{Hp#F4in6~&%3k-&j)_9Mf$JV`y7HNyvOhUkGs&<1q5jS0uZmUN zN{c?KD=R#lco2Aur4qTj*|G>dqIJqjxSc$*N44g^Jm~Og2mDp1dfs`)@U%o2d;FdT zo`#-Ap2nUgo~E8=p5~qwz~hi;74WNp$MN%Zz^?&*EnuKc{s!Q0tn#$7VeDyZ!`RcF z!T2Tz#_OwLeA`(V*Z(B82RCPwdy;@(7lyGX6=5u_l$Np|7IX_2lUtwF&RkC~PhadF zp57iD7jFRm<_b?g4~~pC0>8Q5VC)&<8ICaaWO#;paAb|nyG_8CBaA&GJ)}koTV!AoqKAqU=MFvULF6fz%_O$5}l;ii>b~j7QU`!ZX9eA#xGF5#V*6dB(#c zpYUrv82JRD`{e0B_a)Dp47x9SUh%x@+3z{vIp{g$dCl{>=MCVW2L2h~p9Ovo@Oy!O z4*2JRe*yS?z`t1Kc`FRv_dM^jb+Vq17<6B9p!*8&Y>5ei_}#P6Jp<4^%Aorl@Gm>i z#n{BSw8#F36>tA@CQv=Ud;VhG=?~AJz`qLo{tD0EUhGb2f4^C8u=R>wH^SEI@=9JA zc(fP~0sk86T(9cISSpCw*MWcIv~=!iVdRN*~` z!S?OCU~9zuQGI-97{cE6-i{W8y%@a&A^aXf*ozg1I{WRD!QLC|O-BfOyLsch@!kY) zqBqH#>`n2edeeaa0C;rdeFXf+z<&b#r@(&({O7=b0sNO$-tIPpy}j&xnBIO2!iOCQ z~04^bg+95Vz=&XDo+1+$omMx?!(?) zAV?s{72Zd^kAdI@L9IXRKIMJZ#_lr=yMlt9Q2yG&ZsZ0Hr(pZMuQ2Ss=zYoiG6){P z69fcbrT10D?g0=qhFv^K;J>xDy>B8O--^UzU5mH9@1pE`k+O9x-gc_sL+>Z7+SYnM zX4n<{r&Dc*y*T$@<^9V0wf7tE5%0I&qu%el-+O=X{s=-t5U}_1rz3V*@Ei71 zI{;3&fB2gC@U+?rUsE5pWLps0Rrp%?uq~rNu!7&zi{ACM^+mHx+M(?zV4NEk`2}r9 ziYD1fhkU-yK0LFc($~e;)rS+V=YoJesUw=)zBpgJ1>8;`bY|H7M{o6+Gr4`KoaRf5 z#Nz|=o=Cm*#f-fBo=f@jVA(JIn91$yfwJdC$~I7YWR@NpRdeZg*$YE3jxLxO(U8q)~lN8u>0@ z(47N9x&z&!Q;m9kWxfRrQS*HBLFfU(c@@5ez6(L<2|}NGQ@OsSzGbZc75l(axxKLe z`Ec531qi((hHQp7!0Ccl_^x8ez0$YBw-SWDAoK&Ff2Hqg#O^8(23X)7$V&Ndhq(2J z_5Hr<5sf!QqOokluMO$s!ReJlbLTB;upXm~Aad8C?D|OA8(Tbfm3Q6HeN~eVwA{P+ zr~bzwccZV|M(!pHxr0wtb56D0=EF@$RleJOTYXi&ZN58vclz$~ZTH>n+W|rb2tz>_ z2EuRGZ$PeQbKz_l56E z-(e7@fG`z=X-wgM%zvlb;ijF zcMmN=V`pb*i5i+sXvxm4&{DKi5K2HOtvBdu=V`rJCOw(09AdVz@F3dC1Q+?7)K=C8 zY8eP!ZICut!V zyBq|J0AwxF(XK$~)_qu|)6}c9>lmt5YuAEsB?v1jv^CmV!1L3DYZ)%;LZnq_y|Bhr5y+x}Y_QG8eCugsn+AbTqcwPxYcP)diZb3KlfKMl% zC$xPGx=(6PX-{j{Vs;9%;cxD{xYAlRA2yAVThEo$b)Ws-ECme9C z&kh$&=XD7IuM4`UyFl0m!W|&oS*gpssVgAdWdVNsf2?)h$}W0%(2khI{)KB|=D6>s`<|;A>FQ1O78ZE*<`#H&oT}oS zYHO=^MeyqF^e8=AZ?B)LchEcPo%GIn7ZC0R;XV-V2jKxg{VnVS;UN$n24NQnk5uU~ zHhA@T8@zfl1Mi~_c=3Rvu*v+wS@70Bc=i4WUVQ)vkA=aj4?fjMS0Aa5!LFf?(no`^ z8-yn+^s#y-2v35rx88KFK2e{_AUH{%tmBaNDG;6p;h9Q(8bUA|gl8=X?)k4F7(iIf zjD*#(D|Wp!*WKsi9Xm6g{OYp<2^IwNQTBpJ*+tW@d+z+-MzmV9q1PpzmU|W+2f;$U z*y1i7hm6Qw&mjc$5{tW@kKitYG<8roU%${sE~bTQci*WVbDlBv6%4tcFVip9FVQd6 zm+P15m+M#PXj8oe0#35M0>Y~x><0lS*bahl2n6(Vyk4cR3?p}yeITX2h9UP22f4VQ z1T`-^kW%>cEOgHRbSoHiD?xbEf$pu$WUli-N~f*w)bD2Sy-VK?!rLIcQ=#wB?*ZXm z5I(Ly_&%tk?N_Pq)F0B3)o{?RU1RV2)`IU|lzlEzc5lC|>+=Q-^R2t=gQGvUPLDedzWel- zZTP-q!S@ryp_pQszmdmDI&E`Ef5XP^>lSuDJDq3V)4ycceP91T|4{!(|5*P-|5X1> z|6Kn91pNO?5DtUz6$oF0@C^t@K=>8}G|9fJ(lOi;3x}j1vHi>X_YAw=JJ|iv@h^+q zS?Jb3bPW!nYY-5A2t(Hp5V|a&y&cqkD2B6lg4&0>hoKri>>h^4KtBBmgr6%6&Co&k z1%yBA4Z21nqZvZiXlyhwa3R32Ap8cxF@&zs!f0th_jeHRIHl8o?!QIkX%C?H8|^sF zh>C<`Xv);YvN!v$UzRd)!c~X59bnKk&PCY{k+Qyf-&?G`l<~l2Gsny;dGdkQHPAIW z8!@b&yRgwN+fh_u#NudI_#4q1sd?q`PV*!gsTO*T6oy`rAbO2hOJV;V@tE^WPh$w8 z*XU*RHu@NSjebUdV}LQx7-S3vkq0~wS`=ru<0*7;Mmbt+B>J zZi~}-X1#GML+%FSW@Dpqi?PWl$0n^bHXB<2j|dmBu3LlH2E?`?A{j)17!6{35YMeL zZVMxKo2_?^?F_jc!g^QiQmuDW&I0!g0QXS_+{Zxd=m7T#1g`O<@f7<3u@m4q?batc zs}w!e=_1b?FEaSPVC)02D~K@_#!JS_AjX0i$M94y3#yER2Af32zWbWhce`OfJn6~| zr(o|II44|byl1>`d;nrRhzTGjRvI4}ALEX2F$u(E1U@U`8MCDS(G=Kk;IX?#9mnoI z_4$1<7p@=r;2pnT-)-~CLxU`ReFSB{jf8x|)D6^ar*ju!w%AI zSV6kQ)YGZ9-;F=H#^uHzAf}fae}UND>^u!a=&>+@7)vw1Xch)Cnh=TE1jJz$cVjst zA|=|v3`153#N@gJScIf;80xTgB*lIU?FX&r&aLaY+VU)eaL@Bc`P<{G`H|NKmix~I zagY`L>4Zw#@9&J&*2UiyBNoM$VsO-`zR%7$GV{;S?;sAgYckf~4Qp}$25zeG$6_=i zJ5GW>-jA_?%Kg}#Gs^wgkB8QoJg1Q?GR~iFVwjAMarj?ad_r7ITwHuoa{Pe42^gWM ze_Z^)?EK={!JKpercIPFyISL^5RYQ55|_+v}) zm7Jsp`bTk%xB3V92m6QkGyFsS!~DbjBm5Y{a}6yMJi)`3JU;B_ zr0R$9$dTi7U}2H*Jf=J>&o-OW)Q$$4 zm0!y0xM{?V@qv;MMkuT6)+qZds%$+j;;C>TQhYG8tgsLR3)^&)8JNYQp@zm;aXTl( zr}RxoO32d>+po10<3ajOKlqn{I19u=5KF4#F#9j{Ux8sd{mcEA`7Z}?Hi-EkUQp@3 z(!auA0^%GH(c;Wy@5b<5``v2gJ-Q@6Sb{-N?O4dC5bTF%&SVCPb4qfom~Nd;ovfXQ z6|F3)j~zyg8{-7l^{?^YSXbe1@~`u+2eAl5w2_O=_^94T?MHLDHti|bX1{+E(n`6% zg3$^Ki9E^>)EUJEcoJk>+(ANlL3ByV#OQf;8%>JNDaoCkkKeMQOM}G|qk}V8xZ9AQ zBg;1-(~rzVUc)f3VWC%LcUDO-SZb2(dNbA2pkd2aojS*L?{QvK&%PN$hYcT*Ibq_| z>~YaW$o>bsKAed0PaK&Ue$nV$7NK(L$p2T^cR;0)egA{$vBWN-iLqhFiakm!#DWDC z8$u8)s31|nu4pW%sMsrFC2H(S)Ywq5Zlc*_-6Wgdd#{`RC%gMC=YM|Z_d9dWyqP!m z^*i^zd3WyT`5&f<6bXS&i%b$J1W?Yl5Pv$67#SH68S$HfqLh-d%FnvTMW!YFgpd2D zLhYcO?d{;49XWC$k%$ms;a)tTc2HeIN>fW4qN6K{^N&f76qOZ)Acsf)EaX3^-=bXH z!bLB61da4lF^LqJCLHp2r^ysa=j_^@vol9Y#NbeoP9sP9|AqF9cK=z16O|nCo0Nf} z5!6@&lJ|GH|H=2?ybS*TpZr$?6=idP`P*}L|7@8lOr_Jz+#+XB&fXmHPD?B690`$k zyh4tg2-NZKEPgiP--$(LdT)Q{fS(mXM27za78aopi|~e{lm3eY^e+;$J31*m`ah{J zC`viN+Z}VHa^!!O?c}P`;p~#LFGsoqaU@43NA_o_Dx%!~l`~m1?9~4P4-_@{-%o$y zW&a0OP#Pe;^MbdJFDmr!5ser1Xz<^ck$?4k4DsiNbD}r6!`DwVBtCz!lqf|28t3ir zMW_A53;zjpoYol-=qDQMzph2h_IF!Z8jJgf zH#)F>qFa2pNKF41w}~Lif6iYz2%_ZwLp)$NKn4I7E&S;L%m7vZcK{NA0{8={06HKO zPyi?eGy<9dEr3=)FJKrj2@nF70jq#@z!|^>U<+^?@Cfi4@Ey1ZC=FBwssaxH)qv_i zO`tu{8Hfd@12ciSz&v0HupC$ctOC{m8-Ptf4v-6M1C9g#0KNl$0)7F01O5=(DYi#U zTuf3-T1-|H_6gw|=PwcVS zE3vm?e{Pf9CjB>GivjYvu ze`$&y*&)$hSRxsEQnpXFNOnMW@GnW4l)Hl_5~jI3M0z6m#18RoVA)aGv29=x@-eVW zv}?c)(N}hA&Ii#U60aKnyBz$PMs7@jxo&PJBVH#yE50QHIeH`hPW*%TpW>fI z&^+HoC>~-WlpF;SLJn9$RpNleK?w~BEeVJSSA`)_E-@$ZP;!sRj~Fg_SkhZET#_jA z=Zuz&k&Kh1h}<(1B$FfyC5t3WBuhm;hZQ1!!y3st$p*@>>X=lb6ixIyJxi)giY-+sRV`I3RWH>j)hyK_)hg94 zwJE~$)ZS;a&vReGKK8!ReOvq9ieCFY(&EyRqMbx#q`}gv(g&muifr0i(sm+~CrM-< ztB|ggu9B{iZjtU0nNH@Uh0_gdivfpHX$N}ZH$?cGnl9QH`m6MlKlmp2b%X!F!$Q8-e$~DL}$+gI} z%C*al$<50N<(B2vx6&U<50qXiy;gdw^j_&B2mlfTZ3pcH?FQ`yse@o3Z%_;<8I%G_1*L;(K^-6- zs2g+=)DId2t%ELrUV>hO-YWMfpHiMuo>87t7Ah|*uPU!A-&cMM27q^g_khL0l3;nT zA{Yb)gH^$HU|(<;m;i4Dt0RVDsd__m0Fc1m1&iEl?|1PDwkERs9aOIq4H4WvC31G=PEB%UaRg_ zRaJ$l`l`mMrmAMBW~t_=9#_p*ZB^}2T~=LHT~{+xb5wIv^H4*od8_%Vg{WcFuxdxu z!qtds>1yR_-D-D~QUGB>iXnB721pa61=0%X zfOJ7lKt>?TkgJf#koP(YI!ZcPI(j+=Iz~EXIu<&XI@UT~I(VHJolKor zol+gPPL)orPQA{g&X&%fx_fnXb?tTCbfa`hy0N-s-FV$&x{10p-DF+1ZinuO?z-+Z z-9L3d>weY!t_RQ))7!3RspqJN&~wxC&_n8Z>tXbw^vHVgddKt<^|JIBdPREOdi{E5 z^e*dN(YvO1L+_Q|H@zSFK>cm{3i=xQP9cKr$c8T||TSM?w0Khl3< zU~k}RfHDX+h%iVtU>KY<7&5qG@X+9;!54#X20sjeh8V*L!&pPAVVU8C;gaDQ!wti8 zhUX108(uNIW_ZK!mJ!fM%gEKp+sNMtZ4_h_Vw7xDZq#EmVl-nkXEblLXtZRsVzg#- z-e}9{qS0le+eQzJ9vM9`dS>+A=!4OpP#|3D6|MB;Dks$%M&SlXE5)Onx`HY;x7)hRJP{dnOM}o|ybF6*Jv#y3=&Gsko_> zsf?+dsiG;!6l`i`8fcns$}yccePFiNOwY{CEYd9AEWwOsmTbl_D>7r5m77(X)tJ?p zHJCM-am;$n2F*sy_-3cgX3PX;3uZUWf#y=?a^{NW%H{{m)y*}{waqQe;pWcfzUD#Z zq2^d~ym_>FtU1N}n0cakv-yVk3-gZ_+bxtVz!sVo`WD6())uZ7!4?>c2n&h@)gsd( z*COA7X;ErXZc%AbZP94aV=-fK-Qt$T9gF)Gk1U>8Jhymd@dhRilY+^>w`_greU)% zfu)wEsinCk%+lJj#qy-3z;e-Y*>cVDjOC`~dCM)!OO{tGuUo#cd~f;D@{{Ek%kNe| zt8G?0tae-NwUV&XvvRW{Ta{alT3xpKYOP{zYaL{bwe%Yrn%lx{U2WZLJ#Bq${cO>; zLAFu0G}~I+2HPgv7TY%44qKjWkL^iYq3w$8y6qX;4cl|J=WVap-nPAG`_T4@?K9g? zwqI?3*a7Y2?G)`a?X>N5?DXs`?QHDq><-!a*oE00wF|c++6nD`wYy-qWp~Nm%HG93 z#6Haas6D|x(w<}=XCH5$U{AA8u`jh}+gI9G+t=DR*f-mA?c3}-?Roay_DlA65A8an zcgX8d(xLi8lVanNzZam;biaoKUzam(=!$7_x^9q&0laD43e)bTT11%3d25H9+vgX_W# z;83^;+#QaD`@m6fe>fT*1joZ;;AA)zo(QMIQ{ee?PclhbyKb<6lRHu5UX{YPXKxZ9iPv=k4yqbM!KujTK5Oat#hz-O! z#CgOG#BIb~#C^oaBioPcItTr5xZ4%CukHuk5$>_>#qK@s%kG=* z=iRs5FS_4!f8_qu{e}B$_jm3e-2Zg{?6J#3!egI@tcQ{Z*kiwknuoo|Q4g|5f(Okb z#Us-r+auQ_&!ftt)}zCt*Q4KK$Ya#ww8xBxz+=&4$>X`FnkU@T-80ZL#*^$x_dM=d z>)GJR^E~M};5qDh%5%bV%5%o^jOTUF??@nW8*(Rd4^kW{g_J?cAq|nnNHe4b(h_Nn zv_(22kw_n;9}n-oC znz)Be-`v;G4AMgL|0HUD4yH~i1}pZ9+eAQ@m9 z;2)3@&=Rl^a4X;kS{1F0)QGq(Z8Xups%BEq3@#a2TBFP1H%Jj15*M^0?PvH0y_i815XF81fB`p z3_KrrG4PMTtAW=8p9Q`Q{4?-#(5@hfpnXBIK}tc&L8?Iqf{cQW1yu&s1l0vK262M8 zLG3|ZK_`L)L5o4lL90RQL1%(Cf-VN#47w9^Kj=}=)1c=;pM$;y1A@hZLBZf)onZZ7 z!(eEzUGSk`$Kb=k-odC~|6p`*bTBPAB{(fOBlv#so8WiBAA&!H5JQfI6oeFoutLg1 zDnn{Q>O-1BT0+`FIzuKyrbA{!1R)C{OChTv>mg@CHbZ_5xe)R)R4UXgG$1rJlpDGj zdK&}4?8iVbdKg0t6k~;fW1KMvj5`L2@y7UK{4fESKnxK>!o*?XF-e$YOd2Kw(}0=A ztYJ1VzhZvFT*h3*T*utRyuiH1d=J|ZwmVEbOe#zv3>2mkb|CCvn0r`87$=MuHX61Z zwib3i>_*t@uyJqC#}ct*EE8LTEyE6CN3dhq zaqMaAG{+hVBcatW53}5xNW!{I9Z$m4uk{abZ~k&1Dp}g z7Iz5eh&zn)$Ki2ATqG_UN5d84N^xvl6|NT7fNREaaqYM+TsLk8C%`S>gt%qg8tx2k z19uL00k?&_hyGJC3d#y^r6HSI6t)jqoOTGrS$%1%CwZf%n4u;{EUe z_;7p_J_b+5C*W!L6nq+uZG_UzZL#6{3`)S*iP6*kRV7AWC(Hu4T1r|nczmi z6A}pwLMfq~P(i37)DY?j4Fn#cn{bjaKo}y768MC1f{?IAI78SZ{6@G)xJ^m2#yGi2#df)ghxa~L`9Gy;vy&!)QHlEzKC-XuOk&A?IMpxW=FO} zPDKhMS0dLV&qQuTUXQ#Lc{lPwuDkE5SOzli=A{WX{y66#F#xMeN(y53!$Ozr=y!?Bd+wyyAT0{NsY-Fmc$pqjB+Z8F9zs z3gU|5SaDTxwQ&t`&2cSpD{+64mB|`pW3m(3mF!K%kmJb-Ok{^&Clb?}al3$a*Q-GB1l${hgiULK6qD+BM^e6@t zBZ?yhN%5heDE<^YC5A$#P$`KNIwhNuOUb7cQi>@oN)4r-GC^6OY*H>!u28O1Zc*-1 zo>5*2gFn2)8n(^bK>*j3*(F8Iq|&slko%b!||i>g7}sAwfJA+ z&&K~2e=+`Y{MGpD@ekr(#($-5qwb*YqVAzeQ{|`%R1g(R)uI|vZKyCPR*wlQu)+-$7GJdkHsBpKDKe}Yl2L|fdsPz*95l& zR01}EkPx4ck&u~?mB2{gCiEq&C7emvOgNvgm2fHHO2YMoTM2g)9wagi5iL8iMojfiO@vTM2kerMC(NV#AAtBi7kmsi5C-}CGAPtpJb8b zorF)SPCA)1mNb{NkR(i6Nm@@jo3xp9HR)c`gQUkv&yrpweN6hC^o<6fZKLg=InvT- zg|uQCi&jpnq*c?}Xx+4vv;o>MZGtvMo2AXu7HN0s+vz%V6FQ7;O}C>TqKDEG=^6Aw zdNI9}&Zbw38V&=@03TllLWq zlGTzmlC_g{ll7Bbl2OS4$wA4X$=Kwh$>iktIcQ}?9Gr7ET>r>dr^rKYClrk1Bxr`Dx5 zrgBr;Q#(_6sr{*AsVk}HQeUQiNK;HROtVR|O|wfol;)A(-+g1 z)7R3^q;I63OTV4|EJH3sC&M`dn-P8f98$ zI%GO$`eyoP24)`1Ov^0HWM&p+mSlEi4rKn3c_;IJ=A+CfneVg2vJ|pFSt?lvvedJ* zvUIZavy8G#vYfLJS?*cLET1e?RzOxzR%ljO7A`9~D?TeBiobR0PntvqUBi}3ECm)p`kRO;IoKMfM$)C)>lK;Ix ztH7-wx}dP2v!K6Vs9>~!Uocy+Qm|fdw%}aBg@Ubu+XW8_9v3_-cwO+W;A6q3Le)Z> zLPVigp>LsoVPGM)5MM|vj4C7*78gzz-Ya}w_?aomlx8Y3Axs;lJ=2}(%|tN+m?6wC z=22!i^B6OYna<2)7BkD4mCPDuBa_2yWwtYinX}9b%-@-pnOB)Nn75htm=Bpxn9rH7 zigpz3F4|ipQ6yC)QzT!cSOh9kDcWD8R%Bm0`X zD9$e~E3PQ6F0LzXEN(9DDIO>uE*>kMES@f&E1oaDTLLJNERio!Dgl@5FVQN|DbX)6 zDlsncEjeD&SHdq@DA_8xRC252ISatr#*$_!us|#o){YnipmT4$YMZL-d@eq;U4y3D%5 zy2koc3M#cP#g!f}?I}H5`m}6snNFEWnR%IInRVIWGLJH^GT$=)vcR(7vdFU7GD_L8 zGJ08RSw>k_SzFm`*)L`1%eKlcm0c;jU3RbRVcCmhzM3 zv*q*U8|4?ue=omWe!cuw`Q7sSl9l@^RV&piwJLQg4J(Z+%_=P_gDPp2xs^qgtjhAr z%F2ey=1Oj5du3^@T~$+6U)5B_sp_j5 zteU7=s#>o)TXn8#tLjqKm8xr1Ppkf{maLYpmaA5*R<2g9R;$*i)~?pAHmHVIJ6F3_ zAE|b)MppY&qpJO@1FM6pL#tD&>#C=!uhjr*AT=H}F*QXsyqdw9ks5x@c#WWDt>#S4 zX3hDUt(uE9cWWNiJgs?A^S0(g&8M0#wV+zNTDMxSTHjj#+TdDDEv^<{ORdeU&8sb} zEv_xCt*))BZLHAJu{DH0w<2oa+#EK6PPr)VjnvMqPd#v#z9$T~}3CTUTFq zqHe5it?o?SX5IO^t-4EfSL&|U-Kx7=_n_`e-S>Jxy;%MB`d#&V>m}>=)yvk)*DKbW z*Zb8c*EiJ9)Zb~?*`VFv(h%Md+dyeJ){xkc(U9N3Y$$0cYp7_bYG`ffYUpk_*)Y^F z+Hk62qG7AyW8?P5J&h8L`x@mNl^Vf~s*MJX){TyhPK~aOZjC;TevRnH;KtC#yvDA^ zi;XuMpEdqy5^EA~0yP;lL7VKF;7!g=h$hb_?RSUkQs-?N5r)9cju4T1ltL0(Kla`MyUt4}~ z#kjk;d%2R_ecS_F11_BF%tdhBxk#=L*N=k6_ww1J%wXxf{ZS8G?ZKv8M+os#*+Lqha+Rn6X zw*A^J)~?x(Y)7{f+Uf17?YZsc?d|Pd?IZ2u?Wfyk+85fF+E?4x+b_4@Z~xr>tpm`p ztz&1$o(_qQeI2qL3LT&hqYje}vkr?6%MP0k`woW=c!zU`YsZm}h>pCD?vC}2=bdt$ zR-J*J^vghVq+s2dNDf0|@#yo4D zD=(Ob;gNV0-Z5ShFO`?U%jV_q*gOtzgvaMi@TPdPym_9Gx58WJo#mb5-QzvvJ?1^- zJ?FjRz2&{Wp>o3Z1nxx6iLMjBoOsbK*=^YE-tE_o?hft_?Iw1UyQ$rY z-SqC%?(}YEcWF1fyQ;gsyQ#aSyS00!`)2pE?$_P#x<7V*?f%gt*0a4wuIFHnPLF<% zQIAQFRgZ1Yp&odTQxC1Dwr8$qwP&m6Vb7DEx4nQ~xn9Ly&0gJJgI;K_d9P)!O|MmBSJ?j7wt)jQF9y7yx5 z`;*Ei?M@y&S#YxV^qKd;`keZX^m+7o_4)Oo z`-1yI`?C6)`nvlD`$qcseG`3ieG7d{eXD)zeQ)~Z`d$0I`!W6T{R#c){mlNR{+9le z{X_ku{iph;`e*y+`xpDq_uuHh+y9{dasP|{*ZuGMKMd>`kR8w&&>t`wFc~l(upF=% zupe+7a2jwO2pzx<932QBAPz(g#0y244)m8vHgSHnd}C_mJd}^pM<;!jRbzdWbL-Jrp}c z8A=?Y52X&J4;2rwh8l)ihdPFMLp?)7L!(2dh9-xmhMo;e4qFa84kL$;4ikpshEs=G z!{x)x!)?Qz!zYIOh6jg7hR22%htCb)8-6(aWcc~;tKql9ABH~-e;xiYA~vEl0v=Hv zIWTf?L~{f(qC28LVl-krVmjhILK&$X85_AY@@-Uo6h3-%G;_3Iv}lwyS~glY+B(`k z+BwP_?H=tN9Uq+@of};kT^U^;Jv+KN`g%-iOl3@COnXds%wWuH3^ryxW;b?dj5<~^ zc6w}a?A+L$vHN2$#=h{S_%i$hd`&)tug8b-P5BmlOTH`LjgRJs^09n8Kax-4$MGrr zOnxz+%Wvm*@w@pa`2+l6{uqCpf0{qTKhNLdU*uorU*TWp-{Rlp-{(K#KjA++wda)X zDdeg6Q&p!XPhC6pWgI+iH4Yzl9!HG3jibgx$Fbx1apHK?IBA?do<5#6o-4#YhqwxYGPyJ*NN*B zcP8#nJeqhu@oM7j#QVwZlQNTvlgg8-lj@UNlRA@nlh%{2lcAH?N&F;nGHNnrk~~SB zOq`@orcRbkR!mk+)=bt-HcoOTxsz>^os+!D?#ZReyQg=Z);sNWI_Y%%>G9LQpMG=t z%jxe^z^QFh5>pCOpedE915@f#no}lIuqo>)yD9jT^AuvrZ7Oc6XsULKGu1lPF~yte zpBkDPojNr&F?D%*@3i@}{j~dZ*!0n9(lmX#Xqq+MFx@iUHr+YhGu<~mI6XWqm|mPd zH@!7|Y5L0a&FMSS_op9Df0)@e1Da8pIWVI>qcx*5qd#LbV=`ktV>#nF<2~a$<2Ms9 z6EqV#gPl1#Lzsz}iJHlq>6lrWc{D3AYc?A=OP{To9hse)ot>SZU7S5LyES`h_K(?X zvo~gM%|4%fGy8t_&)IKtfVpjRJLYufT<84eLgvEej?NM0V&=$m)Vaht+Fb42>fEcj zPlBBSWr3h@0i~`zjt0@UTR)uUVdJ29yG5qzkgnB-hLi4&zNtY zU!H%uux|mn;I$CDkhGAzkhYMqkiSs2P_anp^jY*=s+$RJHwT0F~JE5DHMfv`weB5V+z6b=bTh10@C z;i~Xg;cvpCDo`(#@quORttbEqz_yu`IDHvwUD#eOYT+XIX#QaM@w`$g=w~ zZ8>*2f0?;lvRt;zUY=SOE}vaKw|s5+N0g zS1GHwXv$hz^m<+|hg zk&VEOkPX7dv5l0C>I@S(4Rd(|d{^4 zA&N!{q(my@L@wk;sVEKAKs8YqfgLh z$oDz=0$o8@(U<53x{2OM}MF{(M$9Sy#^sfg9u_k3=)uo0yLln10;hJ zT;PUONQ3&&6k0+nXbbJ22lRwq&>Q+dUl9{k_z}<0Q z?CXaI;UPF1=ioeCguQqyF2UpQcsvPD#?$d!ya+GDEAc8^idW+;cq`t9Kft^20eldD zh(E?B@Jaj$K84TW^Y}8pg0JEm_%{9y-^UN|5BN9yJN^UziC>aP5=De0nutg&i6bhK zOpL@t+$7aU(nt-`hP*}El6Is$=|DP?P9&XlCK;p`=|}pL@niydn@l8=h>uXhlgVTX znM$US>Es?QliesX{uB!|ffa*}*PJ|$<#MRJ9F zMedS&>+E}9c_CeF;Ia2C$W**H7r;GCR`b91R&8drm> z>F+LV!a+2(_!kK$$AFN^sfdPEUfny)(I#lx6gk$SdZ<2XfEuDks4;3n#Z*G2R7PWI z9F1R#Qc!c$0<}b~*i##3s-Tqe^j-EegS!38M4A4?7+asNs6TRSK;2LV>W+G#o~Re< zjryRzs2^2Q6;)FW)zSo-NRz0J>NlVPXdoJd2BS=rg@&MPQQOkc1Tp%Ua+jl8HBjX`5+GBr{YHLphF(0DWfjiV{lN^R`w_Wz_Aq`r(q zCRyjkwIr*b93&)kSS8UAcsLIgV;9SblYP1Gb&@@_u)}*yoqjhLK z+JH9F+O!_6PaCkgC}T^c+tJQoXgg?~0NO?CvQ!3Q)sg$qe&k>?bNg?^#t*Jrx9-G= z)$R|WBX10j(uUMh{o-SEB4ktDa0;CZ2J$I7jn1I6v@vZ$o6=@MP%og1m7q4KEvi7} zW#}5Z9(4Q_Z5cpc(^esnZZVKPdm_#v=dEVi~3a&r57X4V5+a8NCKlw8#rhR=JVf9KU~s)Z*W- zYa&g6B;*J{BJCRh9qq>eKBdxHs{=5C1v$#W1ZGH~{pkQYupF#l13Mi=2U8F0tyT9G z*MOQ(3yGmN)PcHC&p%DAPs^l;4x!nXS#twu2#wHsXwu#5De?C9dJ6Npk1O!dELu;3 zDwzt+pt(O$qb4mFy%IG_e}+aKBp$SeHvVNAy`T)>$lZe9WIi{E=5E}MRzaA^bYTnGb-Ct(l%$5w@fG;BoX)WWHm1+ z=+Ul2j<-c-k%vtOV#Lt{JtYO1ql(yK$na)*JvE!3$a*xaJZ(MmBaIFSS)bVGP~)m) zQv>m=ScXj({%s5gk*D9Eowu9%K_gIo!W4q(d#Fx7Qs^FD1*hYgifYY%3v8Rr&H;4_V%E@yRQ@irF2?|73HwHS9(VC!otjP zWl)Z0UJ8mFRKVI&`cA0Fde|`VjQ~}4EQj^MuF1_thXAOa{btyQ92;Q^Y=v#`0c?jI zuoHH{ZrB5R>3ei0okeHUIkfRyI*-n$3#gy|V1{6pTm{ln)-q+3&2&noVo`|q^){(&tNR`_RR5& zZRhpm6@?~q9oCk?*YFKpLCfen)xq9^yGULR-@>8f(L$H2T#OBs{_rirIa z4SYF+E2mg(^aP&&#pnex!Y{O(WneY6Fut~H)w-1@t9aNjPhs;yPiAtn{)a1lgo61K z)&}4ut#}g%MmQWfDllM-3Ffc>htaik9bHd1(2WUnQw5H|kvNK7qmhwrrd#MKcD>Dp zbNegI1vXR_8&+Tq(-Ex1Dy*hk={EX7Io2|8576xl%tfsGwJb|Z7GSG!qcZbyhIG%& zY8PB-m2qJs1OnJZchG59u?1VP4cn0zJFpYGup6gB9b5y~WKXqm9sk~xt(KGYW2Qbk z=_m9gJxWh}f$QP=xB)Y1h#TR?xCw5Go8jiTg@3MPgzx~}O+TVX=q|e7&spoWYaJY{ z4c$YhUB>NjduG)E4&Y9G+hu!3d2@#5cnW(|hDP_YxcB{411gD$yWp<=P1Ynq8Sch} zi#^qd^}P=LUB*3_)1J5&?hSSNW#eIi5d z`r`rqfK5pTGG_ssTyu$e7>qM7hZA&i-2sTl+_qL}^2o9z3)k z<6fJbTu&F)wHyz_!JlAGY3f&L-O-nnFR&89#_eb{A`b_pfJC( z>=1Yxss2+gLoO!ZxBUZLDl(CUFuvp=T*Q=q%2qm_!h)KLr}=XSXngcE{q}EJ zfM?+Ms#(DD{xQ8o&-^_D=HdBO3|L4n(z8|BzYrRCaWMT$=(&HUe|a$d^n57WJ^phJ zf1lP+0;}1-2ComYzXGqt>*!_r8U4H*Z@?SzCi(@vNpCUsXOB(u*B$HbYwjHct!9@H zXsxqzy!nNLLT%kM3x|2Up{7u%+k>I*pjYU$&+u+Ws35KO;JtVs-ruLllgo-dwgb^? z^hRdr$6^>aae-N0<=fL-;WLie4|nNAWTGHT{OVdxl2o85(ksME2JR z{yW}(ickB`m*~Ur8GM%I^L&ZUFCQmo0{AyRs^hqTFNW&05Fb9npZo1uDh_|a9JI}{ z`Tl+Veu=MDW$zpMfZnaj-u)0HH-nJeqWAupy*riJ`|j`8>i;Hrk1hBa+uiVw_zC_A zKcx@pBl-hSq8r$$ILW1326GVVu`h@;OpVDV+Gh}kN z45ct_T*S6JIqUv&-XtH1AriJ%5HWobAX57C|FBn(c(zv%IZ@DG=*$?k_JskH-F-2O9u#PA?Z$fFiEP^;Gm+Fk)CMg zzcy5d*PHYS(Q1$+F|DR9t#)l)TCLPnUH#Nl|J>1X9~nSKBFAPjkPIS&NhZl6Lr6C9 zkfCH48BTJ@2p&W{#PA^ILBfNS2N@5sJjC%3&x4!?1rJIdRGUdI$s?mkJ{%yUk&zS; zFDWMZWGqVILCu4P2L}&sx`>A~$~@NKp%xDU=lfc`c`XEC5WFdPWv#hv1*qb<-r*s$9Zs3%K%m@rDx{(=O5Gh$SEFDE7ggdCTDu4 zXQUVB=9ZDuRV67o$EJ;>6#p|nm&j)f|6p5ye9l8n>JDY{D%;j7dsf$abb<78R9%4}Dqm2M-NH(|Ar^uxYen6e}ao-yGG+FXXqN`(Jrz93a2*(B$9U zYeUBzR(+6HJ{Ehmjf7Jp`Fc*u$+%c9j*I8yoPtww zDjr(#(3*!fJiNt2TOQi+(4L15Jak--QaCL#a#}8l({Xyvz@(V1;ZDI7*@=gA9y;^T zg@>+eL0bCe6zynmA{N5AT9tBF9cX1 z6~qeS1qy*mpb;bpk_0Y6s-T9TmY|NHo}huCk)Vm7tH75nC=tvQtP*S&92OiAoDB0&kCOtJ}-Ph`10`g!&ij|!ppwGcZwb!Jvw?$^t|W=qPIljMAJnJMTlGBo_k{gm+lG~EIl1Gxqk|&aArHDLo^-BmGk*keOw6nXjX)t8Acbm@G#&QkEynmzBuI%ifkvl2O@Y z*;3hN*$LS#*`KkIvC*+HvC`Ps*!bAg*!rt@i*Fg+?GEym2 zij-odR2i#`S1OchWr9+tG$?&(%7MxP}w!^-~R3ja22S z3RHzEuj*aZeAOb=64f%*3e|emHr003PStMJhpI!WBdTMnk5!jdH&xG6FV$h{ShZTM zRVS)->J+tAZC5+hZgq2Ydv%7or@FVguX>o;s~)2+QIA)@t)AplQ}t~1T=jglU%gPh zSiMxeTwS5wufCxEM*Y1eN)xS7X>=Nc#;7rCoEo<#O;b}-Thm@MK$EX2(M-@x)c7=| znuD5~nx|Tc)~HR@rfa)syJ@>?dun@Y`)d1Z2WrP^-_tJDexN`OS2a4F$>!Z!&w6TVGs znAj?@Z{ncD;>1abGZJSe&Q83Mct7!Z;vY%jNvb46Qm3SDNfVRaOInb$GO0AFENOMp zOI?^QS|`=nbspVV9n~$?tAt9nl@rozZ=#d*IVO)JN-M^b);HAE%e=m3p;a ztFNuEtFNzbsBf%qs&B4uukWPqtnaEHs2{A)(r4?(=zaQG`Z@Y}`UUz``U?Fz{RaIe z{SN&u{T}^3{Q>>=29=?Op@Sja(8bWrFvO5&$Ty5O6d8&Q=L}a2cMJ~<4-G#Uo*JGT zem3}iHM~v^OV%Vilj|h+OdgOtG1;HIE_qk-?&Lkm`;w0)UrWA`{EIQtXfPU$W~0Su zGdheeV_jndVh zT5CFBI&L~;I&C^@I&Zpex^22^`p)#g^u+Yk^xX8b=~pwDqs$6(qFHA)n2lz;*=cs0 z)66x^jm>S$ZOuK*L(Rj@Bh91Cqs?CPSo3)EMDrZ;Jo5tcKg^5FOU%p6z7^(`=2G)H z^Q#nlO5c=eDZ5g>v&b!WOFc_R%OFdZWu#@S6I4YNjCjn)*a&FZwKT5DKqTkBdISQ}fLSzB7$Sle3LTRqmv z*16WL)-SC0t*>kvo7-n=V;gKMw9T+Bur0JLwk@?)*w))N*|yrY+jiO>+y1b<+uzUc+A7Ue`X=W{iOX<`&s*W`%U|8`#t-8`}g)|4&)Fx zA{;`8#1ZR|JCu$jhuP84(aDkJ$afStMmvfe)G@{3o9>w5nB|z`SmD^>*x}giIOI6t zIPLh%amDea<15E~$3w>tjwg<1ju(zsPH+;Zz$tU8oLXm+)8Mo^9Zt8ihO?HlhjX@b zxAU0ug!7d1jPtznqVu-%k@LCpr3<+tT@qKk%iuD(EH1mtwzv+sK5`v#9e15{opL>Qy>y4UBi(Yh)$MS*-8I~`-SylJ-A&xh-L2fc+g3?rirk_Xu~MJKsIp{kGfh-sC>y{=)sx{UTMAYEE^hW~Yuw9h*8ib!O_U$}<+i SICSUggzoGbUip+d=f40^N&_MQ diff --git a/WebAppUIKitBase.xcodeproj/xcuserdata/seankim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/WebAppUIKitBase.xcodeproj/xcuserdata/seankim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..f49fa77 --- /dev/null +++ b/WebAppUIKitBase.xcodeproj/xcuserdata/seankim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,6 @@ + + + diff --git a/WebAppUIKitBase/AppDelegate.swift b/WebAppUIKitBase/AppDelegate.swift deleted file mode 100644 index 2678098..0000000 --- a/WebAppUIKitBase/AppDelegate.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// AppDelegate.swift -// WebAppUIKitBase -// -// Created by Sean Kim on 10/21/24. -// - -import UIKit - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - - - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. - return true - } - - // MARK: UISceneSession Lifecycle - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - // Called when a new scene session is being created. - // Use this method to select a configuration to create the new scene with. - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { - // Called when the user discards a scene session. - // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. - // Use this method to release any resources that were specific to the discarded scenes, as they will not return. - } - - -} - diff --git a/WebAppUIKitBase/Common/AppDelegate.swift b/WebAppUIKitBase/Common/AppDelegate.swift index 4dd12c0..a110ff7 100644 --- a/WebAppUIKitBase/Common/AppDelegate.swift +++ b/WebAppUIKitBase/Common/AppDelegate.swift @@ -7,25 +7,43 @@ import UIKit +import AdSupport +import AppTrackingTransparency + @main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. + + + + + return true } - - // MARK: UISceneSession Lifecycle - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - // Called when a new scene session is being created. - // Use this method to select a configuration to create the new scene with. - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + + /// 앱이 Active 로 전환될때 호출 : back -> fore 시 호출 + func applicationDidBecomeActive(_ application: UIApplication) { + + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + ATTrackingManager.requestTrackingAuthorization(completionHandler: { status in + switch status { + case .notDetermined: + printLog(status) + case .restricted: + printLog(status) + case .denied: + printLog(status) + case .authorized: + printLog(status) + } + }) + } } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { - // Called when the user discards a scene session. - // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. - // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + + func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { + let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) } + let token = tokenParts.joined() + printLog("Device Tokens: \(token)") } diff --git a/WebAppUIKitBase/Common/CommonUtils.swift b/WebAppUIKitBase/Common/CommonUtils.swift index f62c8e7..931064e 100644 --- a/WebAppUIKitBase/Common/CommonUtils.swift +++ b/WebAppUIKitBase/Common/CommonUtils.swift @@ -5,4 +5,128 @@ // Created by Sean Kim on 10/21/24. // -import Foundation +import UIKit +import CoreLocation + +import Alamofire + +class CommonUtils: NSObject, CLLocationManagerDelegate { + static let shared: CommonUtils = CommonUtils() + + private override init() {} + + //MARK: - Location + weak var locationDelegate: LocationDelegate? + + let locationManager: CLLocationManager = { + let manager = CLLocationManager() + manager.desiredAccuracy = kCLLocationAccuracyBest + manager.distanceFilter = kCLDistanceFilterNone + return manager + }() + var lastLocation: CLLocation? + + + public func checkLocationPermission() { + printLog("[위치] Check Loc Permission") + locationManager.delegate = self + locationManager.requestWhenInUseAuthorization() + self.toggleUpdatingLocation(true) + } + + public func toggleUpdatingLocation(_ toggle: Bool) { + if toggle { + locationManager.startUpdatingLocation() + } else { + locationManager.stopUpdatingLocation() + } + } + + // 14이상인 경우만 산정해서 한거라서 14.0 미만을 원하면 다른 메서드를 만들어야 함 + func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { + printLog("[위치] locationManagerDidChangeAuthorization") // 처음 불러 올 떄 요거 불려짐 + switch manager.authorizationStatus { + case .authorizedAlways, .authorizedWhenInUse, .authorized: + printLog("[위치] 권한 허용") + self.locationDelegate?.checkPermission(true) + self.toggleUpdatingLocation(true) + default: + printLog("[위치] 권한 미허용 & 기타 오류") + self.locationDelegate?.checkPermission(false) + self.toggleUpdatingLocation(false) + + } + } + + // 14이상인 경우만 산정해서 한거라서 14.0 미만을 원하면 다른 메서드를 만들어야 함 + func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { + printLog("[위치] didUpdateLocations") // 요건 값을 가져올 때 불려짐 + switch manager.authorizationStatus { + case .authorizedAlways, .authorizedWhenInUse: + printLog("[위치] 권한 허용") + self.locationDelegate?.checkPermission(true) + if let location = locations.first{ + printLog("[위치] 정보 수신 성공") + self.locationDelegate?.getLocation(location) + } + default: + printLog("[위치] 권한 미허용 & 기타 오류") + self.locationDelegate?.checkPermission(false) + } + } + + func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { + printLog("[위치] didFailWithError") + self.locationDelegate?.checkPermission(false) + } + + +// MARK: - URL + func afGET(url: String, param: [String:String], headers: HTTPHeaders?) async throws -> Any { + return try await withCheckedThrowingContinuation { continuation in + AF.request(url, + method: .get, + parameters: param, + headers: headers) + .validate(statusCode: 200 ..< 300) + .responseString { response in + printLog("[LOG] response: \(response)") + switch response.result { + case .success(let value): + printLog("[LOG]") + continuation.resume(returning: value) + case .failure(let error): + printLog("[LOG]") + continuation.resume(throwing: error) + } + } + } + } + + public func jsonToDict(_ input: String) -> [String: Any] { + if let jsonData = input.data(using: .utf8){ + do { + if let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] { + return jsonObject + } + } catch let error { // 이 부분 + printLog("JSON ERROR: \(error))") + } + } + return [:] + } + + public func jsonToType(_ input: String, as type: T.Type) -> T? { + if let jsonData = input.data(using: .utf8) { + do { + let decodedObject = try JSONDecoder().decode(T.self, from: jsonData) + return decodedObject + } catch let error { + printLog("JSON 디코딩 오류: \(error)") + } + } + return nil + } + +} + diff --git a/WebAppUIKitBase/Common/Prefix.swift b/WebAppUIKitBase/Common/Prefix.swift index e9c4a3b..ff44f75 100644 --- a/WebAppUIKitBase/Common/Prefix.swift +++ b/WebAppUIKitBase/Common/Prefix.swift @@ -4,7 +4,7 @@ // // Created by Sean Kim on 2/20/24. // -import SwiftUI +import UIKit // MARK: - TYPEALIAS typealias VOID_TO_VOID = () -> () @@ -26,13 +26,6 @@ public func printLog(_ object: T, _ file: String = #file, _ function: String #if DEBUG let dateString = Date().convertString("yyyy/MM/dd HH:mm:ss:SSS") Swift.print( -// """ -// __________ __________ -// |* TIME = [\(dateString)] || FILE = [\(file.lastPathComponent)] -// | NAME = [\(function)] || LINE = [\(line)] -// |>>> PRINT = \(object) -//  ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄  ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ -// """ """ __________ __________ __________ __________ * LOCATION : [\(file.lastPathComponent) : \(line)] - \(function) @@ -149,9 +142,6 @@ func copyToClipboard(_ text: String){ -// MARK: - CUSTOM COMPONENTS - - // MARK: - EXTENSION extension String { /// 마지막 경로 구성 요소 @@ -379,34 +369,27 @@ extension Date { } } - -extension Font { - enum NPS_Font : String { - case regular - case bold +extension UIViewController { + public func makeUIAlert(title: String, message: String, okTitle: String, okAction:((UIAlertAction) -> Void)? = nil, completion: (() -> ())? = nil) { + let alertController = UIAlertController(title: "\(title)", message: "\(message)", preferredStyle: .alert) + let okAction = UIAlertAction(title: "\(okTitle)", style: .default, handler: okAction) + alertController.addAction(okAction) + self.present(alertController, animated: true, completion: completion) + } + + public func makeUITwoAlert(title: String, message: String, okTitle: String, okAction:((UIAlertAction) -> Void)? = nil, cancelTitle: String, cancelAction:((UIAlertAction) -> Void)? = nil, completion: (() -> ())? = nil) { + let alertController = UIAlertController(title: "\(title)", message: "\(message)", preferredStyle: .alert) + let okAction = UIAlertAction(title: "\(okTitle)", style: .default, handler: okAction) + alertController.addAction(okAction) - var value: String { - switch self { - case .regular: - return "NPS-font-Regular" - case .bold: - return "NPS-font-Bold" - } - } + let cancelAction = UIAlertAction(title: "\(cancelTitle)", style: .cancel, handler: cancelAction) + alertController.addAction(cancelAction) + + self.present(alertController, animated: true, completion: completion) } - - static func nps(font: NPS_Font = .regular, size: CGFloat = 12) -> Font { - return .custom(font.value, size: size) - } - - } -extension View { - func endTextEditing() { - UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) - } -} + // MARK: - ANNOTATION diff --git a/WebAppUIKitBase/Common/Protocol/LoactionProtocol.swift b/WebAppUIKitBase/Common/Protocol/LoactionProtocol.swift index a351262..034daa4 100644 --- a/WebAppUIKitBase/Common/Protocol/LoactionProtocol.swift +++ b/WebAppUIKitBase/Common/Protocol/LoactionProtocol.swift @@ -5,4 +5,15 @@ // Created by Sean Kim on 10/21/24. // -import Foundation +//import Foundation +import CoreLocation + +protocol LocationDelegate: NSObject { + func checkPermission(_ type: Bool) + func getLocation(_ location: CLLocation) +} + +extension LocationDelegate { + func checkPermission(_ type: Bool) {} + func getLocation(_ location: CLLocation) {} +} diff --git a/WebAppUIKitBase/Common/SceneDelegate.swift b/WebAppUIKitBase/Common/SceneDelegate.swift index 8838e81..980d035 100644 --- a/WebAppUIKitBase/Common/SceneDelegate.swift +++ b/WebAppUIKitBase/Common/SceneDelegate.swift @@ -22,34 +22,15 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { window?.makeKeyAndVisible() } - func sceneDidDisconnect(_ scene: UIScene) { - // Called as the scene is being released by the system. - // This occurs shortly after the scene enters the background, or when its session is discarded. - // Release any resources associated with this scene that can be re-created the next time the scene connects. - // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). + func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { + guard let url = URLContexts.first?.url else { + return + } } - - func sceneDidBecomeActive(_ scene: UIScene) { - // Called when the scene has moved from an inactive state to an active state. - // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. - } - - func sceneWillResignActive(_ scene: UIScene) { - // Called when the scene will move from an active state to an inactive state. - // This may occur due to temporary interruptions (ex. an incoming phone call). - } - - func sceneWillEnterForeground(_ scene: UIScene) { - // Called as the scene transitions from the background to the foreground. - // Use this method to undo the changes made on entering the background. - } - - func sceneDidEnterBackground(_ scene: UIScene) { - // Called as the scene transitions from the foreground to the background. - // Use this method to save data, release shared resources, and store enough scene-specific state information - // to restore the scene back to its current state. - } - + + + + } diff --git a/WebAppUIKitBase/Info.plist b/WebAppUIKitBase/Info.plist index dd3c9af..0eb786d 100644 --- a/WebAppUIKitBase/Info.plist +++ b/WebAppUIKitBase/Info.plist @@ -15,8 +15,6 @@ Default Configuration UISceneDelegateClassName $(PRODUCT_MODULE_NAME).SceneDelegate - UISceneStoryboardFile - Main diff --git a/WebAppUIKitBase/IntroVC.swift b/WebAppUIKitBase/IntroVC.swift deleted file mode 100644 index c03da97..0000000 --- a/WebAppUIKitBase/IntroVC.swift +++ /dev/null @@ -1,8 +0,0 @@ -// -// IntroVC.swift -// WebAppUIKitBase -// -// Created by Sean Kim on 10/21/24. -// - -import Foundation diff --git a/WebAppUIKitBase/Scene/AppDelegate.swift b/WebAppUIKitBase/Scene/AppDelegate.swift deleted file mode 100644 index 4dd12c0..0000000 --- a/WebAppUIKitBase/Scene/AppDelegate.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// AppDelegate.swift -// WebAppUIKitBase -// -// Created by Sean Kim on 10/21/24. -// - -import UIKit - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. - return true - } - - // MARK: UISceneSession Lifecycle - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - // Called when a new scene session is being created. - // Use this method to select a configuration to create the new scene with. - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { - // Called when the user discards a scene session. - // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. - // Use this method to release any resources that were specific to the discarded scenes, as they will not return. - } - - -} - diff --git a/WebAppUIKitBase/Scene/IntroVC.swift b/WebAppUIKitBase/Scene/IntroVC.swift index 1e67d9e..35836a3 100644 --- a/WebAppUIKitBase/Scene/IntroVC.swift +++ b/WebAppUIKitBase/Scene/IntroVC.swift @@ -6,12 +6,205 @@ // import UIKit +import Alamofire + +import SnapKit +import CoreLocation class IntroVC: UIViewController { override func viewDidLoad() { super.viewDidLoad() + CommonUtils.shared.locationDelegate = self + } + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + if isIllegalDevice() { + self.makeUIAlert(title: "안내", + message: "변경된 OS를 사용하는 기기는 서비스를 이용할 수 없습니다.", + okTitle: "확인") { _ in + exit(1) + } + } else { + if NetworkReachabilityManager.default?.isReachable == false { + self.makeUIAlert(title: "서비스 연결 문제 발생", + message: """ + 네트워크 문제로 서비스에 연결하지 못하였습니다. + 네트워크 상태를 확인후 다시 실행해주세요. + """, + okTitle: "확인") { _ in + exit(1) + } + } else { + self.checkAppVersion() + } + } + } + + + private func checkAppVersion() { + Task { + do { + let result = try await CommonUtils.shared.afGET(url:VER_URL, + param: VER_PARAM, + headers: VER_HEADERS) +// let result = """ +// {"status":{"code":"000","message":"성공"},"data":{"finalVer":"2.0.8","forceVer":"2.0.6","forceUpdtYn":"P","remark":"기능추가","checkVer":"9.9.9"}} +// """ + printLog("Success : \(result)") + let response = CommonUtils.shared.jsonToType("\(result)", as: VersionResponse.self) + + if let code = response?.status.code, code == "000" { + if let currentVer = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String, + let finalVer = response?.data.finalVer, let forceVer = response?.data.forceVer, + let checkVer = response?.data.checkVer, let forceUpdtYn = response?.data.forceUpdtYn + { + switch self.versionCompare(currentVer, finalVer) { + case .equal, .bigger: // 업데이트 처리 필요 없음 + CommonUtils.shared.checkLocationPermission() + case .smaller: + switch self.versionCompare(currentVer, forceVer) { + case .equal, .bigger: + if forceUpdtYn == "P" {// PASS라서 P 한건데 Y 해도 된다. + self.makeUITwoAlert(title: "업데이트 안내", + message: "최신 버전이 새로 나왔어요\n지금 업데이트하시겠어요?", + okTitle: "지금 업데이트", + okAction: { _ in + let appStoreURL = URL(string: "http://www.naver.com")! + UIApplication.shared.open(appStoreURL, options: [:], completionHandler: nil) + exit(1) + }, cancelTitle: "나중에") { _ in + CommonUtils.shared.checkLocationPermission() + } + } else { + CommonUtils.shared.checkLocationPermission() + } + case .smaller: + self.makeUIAlert(title: "업데이트 안내", + message: "앱을 사용하시려면\n최신버전으로 업데이트 해주세요", + okTitle: "지금 업데이트") { _ in + let appStoreURL = URL(string: "http://www.naver.com")! + UIApplication.shared.open(appStoreURL, options: [:], completionHandler: nil) + exit(1) + } + } + } + } + else { + throw NSError(domain: "com.version.API", + code: Int(response?.status.code ?? "") ?? -1, + userInfo: [NSLocalizedDescriptionKey: "Version is Wrong"]) + } + } else { + throw NSError(domain: "com.version.API", + code: Int(response?.status.code ?? "") ?? -1, + userInfo: [NSLocalizedDescriptionKey: "Version is Wrong"]) + } + } catch { + printLog("App Check ERROR: \(error)") + self.makeUIAlert(title: "서비스 연결 문제 발생", + message: """ + 일시적인 장애 또는 네트워크 문제로 + 서비스에 연결하지 못하였습니다. + 문제가 계속될 경우 고객센터로 문의해 주세요 + """, + okTitle: "확인") { _ in + exit(1) + } + } + } + } + /// compareVer에 비교를 할 문자열을 넣어주면 된다. + /// + /// [결과 해석: 현재 버전이 비교 버전보다 (RESULT) 하다.] + private func versionCompare(_ currentVer: String, _ compareVer: String) -> CompareVersion { + let currentArray = currentVer.components(separatedBy: ["."]).map {Int($0) ?? 0} + let compareArray = compareVer.components(separatedBy: ["."]).map {Int($0) ?? 0} + printLog("Ver current: \(currentArray)") + printLog("Ver force: \(compareArray)") + for i in 0 ..< currentArray.count { + if currentArray[i] > compareArray[i] { + // 현재 버전이 비교하려는 버전보다 큰 경우 == 그냥 일반 동작을 시키면 된다. + return .bigger + } else if currentArray[i] < compareArray[i] { + // 현재 버전이 비교하려는 버전보다 작은 경우 == 업데이트 조건 처리 + return .smaller + } + } + + // 현재 버전이 비교 버전과 동일 + return .equal + } + + private func moveToWeb() { + let VC = MainWebVC() + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, + let window = windowScene.windows.first { + window.rootViewController = VC + } } } + +extension IntroVC: LocationDelegate { + + func checkPermission(_ type: Bool) { + if type { +// CommonUtils.CommonUtils.shared.saveUdData("Y", forKey: "locationYn") + } else { +// CommonUtils.CommonUtils.shared.saveUdData("N", forKey: "locationYn") + self.moveToWeb() + } + } + + func getLocation(_ location: CLLocation) { + CommonUtils.shared.locationManager.stopUpdatingLocation() + let lat = location.coordinate.latitude + let lng = location.coordinate.longitude + CommonUtils.shared.lastLocation = location + printLog("Intro \(String(describing: CommonUtils.shared.lastLocation))") + printLog("Intro Delegate = lattitude : \(lat) longitude : \(lng)") + printLog("위치 권한 허용 > 웹뷰 start") + self.moveToWeb() + } +} + + + +enum CompareVersion: Int { + case equal = 0 + case bigger + case smaller +} + +class VersionResponse: Codable { + let status: Status + let data: VersionData +} +/// API 확인 변수 +/// +/// code: API 정상 확인 코드 (e.g. 000: 정상) +/// +/// message: 코드에 대한 설명 +class Status: Codable { + let code, message: String + +} + +/// API 데이터 변수 +/// +/// finaclVer: 현재 가장 최신 버전 +/// +/// forceVer: 이 버전보다 미만의 버전은 강제 업데이트 시행 +/// +/// checkVer: 개발용 및 업데이트 관련 버전 +/// +/// forceUpdYn: P(Y) 등의 값일 시 finalVer보다 미만의 경우 선택 업데이트 동작 시행 +/// +/// remark: 현재 버전 관련한 설명 +class VersionData: Codable { + let finalVer, forceVer, checkVer: String? + let forceUpdtYn: String? + let remark: String? +} diff --git a/WebAppUIKitBase/Scene/MainWebVC.swift b/WebAppUIKitBase/Scene/MainWebVC.swift index e9b227b..5e19d60 100644 --- a/WebAppUIKitBase/Scene/MainWebVC.swift +++ b/WebAppUIKitBase/Scene/MainWebVC.swift @@ -5,4 +5,15 @@ // Created by Sean Kim on 10/21/24. // -import Foundation +import UIKit +import WebKit + +import SnapKit + +class MainWebVC: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + self.view.backgroundColor = .white + } +} diff --git a/WebAppUIKitBase/Scene/SceneDelegate.swift b/WebAppUIKitBase/Scene/SceneDelegate.swift deleted file mode 100644 index 8838e81..0000000 --- a/WebAppUIKitBase/Scene/SceneDelegate.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// SceneDelegate.swift -// WebAppUIKitBase -// -// Created by Sean Kim on 10/21/24. -// - -import UIKit - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - - var window: UIWindow? - - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - guard let windowScene = (scene as? UIWindowScene) else { return } - window = UIWindow(frame: UIScreen.main.bounds) - window?.windowScene = windowScene - // 여기서 메인 화면 띄우는 걸 함 - window?.rootViewController = IntroVC() - - window?.makeKeyAndVisible() - } - - func sceneDidDisconnect(_ scene: UIScene) { - // Called as the scene is being released by the system. - // This occurs shortly after the scene enters the background, or when its session is discarded. - // Release any resources associated with this scene that can be re-created the next time the scene connects. - // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). - } - - func sceneDidBecomeActive(_ scene: UIScene) { - // Called when the scene has moved from an inactive state to an active state. - // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. - } - - func sceneWillResignActive(_ scene: UIScene) { - // Called when the scene will move from an active state to an inactive state. - // This may occur due to temporary interruptions (ex. an incoming phone call). - } - - func sceneWillEnterForeground(_ scene: UIScene) { - // Called as the scene transitions from the background to the foreground. - // Use this method to undo the changes made on entering the background. - } - - func sceneDidEnterBackground(_ scene: UIScene) { - // Called as the scene transitions from the foreground to the background. - // Use this method to save data, release shared resources, and store enough scene-specific state information - // to restore the scene back to its current state. - } - - -} - diff --git a/WebAppUIKitBase/SecretCode.swift b/WebAppUIKitBase/SecretCode.swift deleted file mode 100644 index 612a4ad..0000000 --- a/WebAppUIKitBase/SecretCode.swift +++ /dev/null @@ -1,8 +0,0 @@ -// -// SecretCode.swift -// WebAppUIKitBase -// -// Created by Sean Kim on 10/21/24. -// - -import Foundation