From 9639affd7be806908caf1255c739fbad8bd78405 Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 15:27:01 +0900 Subject: [PATCH 01/25] =?UTF-8?q?:sparkles:=20;:=20Error,=20DataMapping,?= =?UTF-8?q?=20Keychain=20=EB=AA=A8=EB=93=88=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dependency+Project.swift | 3 +++ .../Derived/InfoPlists/ErrorModule-Info.plist | 22 +++++++++++++++++++ .../InfoPlists/ErrorModuleTests-Info.plist | 22 +++++++++++++++++++ Projects/Modules/ErrorModule/Project.swift | 7 ++++++ .../Modules/ErrorModule/Sources/Feature.swift | 1 + Projects/Modules/ErrorModule/Tests/.gitkeep | 0 .../ErrorModule/Tests/TargetTest.swift | 17 ++++++++++++++ .../InfoPlists/KeychainModule-Info.plist | 22 +++++++++++++++++++ .../InfoPlists/KeychainModuleTests-Info.plist | 22 +++++++++++++++++++ Projects/Modules/KeychainModule/Project.swift | 7 ++++++ .../KeychainModule/Sources/Feature.swift | 1 + .../Modules/KeychainModule/Tests/.gitkeep | 0 .../KeychainModule/Tests/TargetTest.swift | 17 ++++++++++++++ Projects/Services/APIKit/Project.swift | 5 ++++- .../InfoPlists/DataMappingModule-Info.plist | 22 +++++++++++++++++++ .../DataMappingModuleTests-Info.plist | 22 +++++++++++++++++++ .../Services/DataMappingModule/Project.swift | 7 ++++++ .../DataMappingModule/Sources/Feature.swift | 1 + .../Services/DataMappingModule/Tests/.gitkeep | 0 .../DataMappingModule/Tests/TargetTest.swift | 17 ++++++++++++++ Projects/Services/DomainModule/Project.swift | 3 ++- 21 files changed, 216 insertions(+), 2 deletions(-) create mode 100644 Projects/Modules/ErrorModule/Derived/InfoPlists/ErrorModule-Info.plist create mode 100644 Projects/Modules/ErrorModule/Derived/InfoPlists/ErrorModuleTests-Info.plist create mode 100644 Projects/Modules/ErrorModule/Project.swift create mode 100644 Projects/Modules/ErrorModule/Sources/Feature.swift create mode 100644 Projects/Modules/ErrorModule/Tests/.gitkeep create mode 100644 Projects/Modules/ErrorModule/Tests/TargetTest.swift create mode 100644 Projects/Modules/KeychainModule/Derived/InfoPlists/KeychainModule-Info.plist create mode 100644 Projects/Modules/KeychainModule/Derived/InfoPlists/KeychainModuleTests-Info.plist create mode 100644 Projects/Modules/KeychainModule/Project.swift create mode 100644 Projects/Modules/KeychainModule/Sources/Feature.swift create mode 100644 Projects/Modules/KeychainModule/Tests/.gitkeep create mode 100644 Projects/Modules/KeychainModule/Tests/TargetTest.swift create mode 100644 Projects/Services/DataMappingModule/Derived/InfoPlists/DataMappingModule-Info.plist create mode 100644 Projects/Services/DataMappingModule/Derived/InfoPlists/DataMappingModuleTests-Info.plist create mode 100644 Projects/Services/DataMappingModule/Project.swift create mode 100644 Projects/Services/DataMappingModule/Sources/Feature.swift create mode 100644 Projects/Services/DataMappingModule/Tests/.gitkeep create mode 100644 Projects/Services/DataMappingModule/Tests/TargetTest.swift diff --git a/Plugin/UtilityPlugin/ProjectDescriptionHelpers/Dependency+Project.swift b/Plugin/UtilityPlugin/ProjectDescriptionHelpers/Dependency+Project.swift index 8dc18a8e..e3bac5be 100644 --- a/Plugin/UtilityPlugin/ProjectDescriptionHelpers/Dependency+Project.swift +++ b/Plugin/UtilityPlugin/ProjectDescriptionHelpers/Dependency+Project.swift @@ -15,12 +15,15 @@ public extension TargetDependency.Project.Features { } public extension TargetDependency.Project.Module { + static let KeychainModule = TargetDependency.module(name: "KeychainModule") + static let ErrorModule = TargetDependency.module(name: "ErrorModule") static let FeatureThirdPartyLib = TargetDependency.module(name: "FeatureThirdPartyLib") static let ThirdPartyLib = TargetDependency.module(name: "ThirdPartyLib") static let Utility = TargetDependency.module(name: "Utility") } public extension TargetDependency.Project.Service { + static let DataMappingModule = TargetDependency.service(name: "DataMappingModule") static let APIKit = TargetDependency.service(name: "APIKit") static let Data = TargetDependency.service(name: "DataModule") static let Domain = TargetDependency.service(name: "DomainModule") diff --git a/Projects/Modules/ErrorModule/Derived/InfoPlists/ErrorModule-Info.plist b/Projects/Modules/ErrorModule/Derived/InfoPlists/ErrorModule-Info.plist new file mode 100644 index 00000000..323e5ecf --- /dev/null +++ b/Projects/Modules/ErrorModule/Derived/InfoPlists/ErrorModule-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Projects/Modules/ErrorModule/Derived/InfoPlists/ErrorModuleTests-Info.plist b/Projects/Modules/ErrorModule/Derived/InfoPlists/ErrorModuleTests-Info.plist new file mode 100644 index 00000000..6c40a6cd --- /dev/null +++ b/Projects/Modules/ErrorModule/Derived/InfoPlists/ErrorModuleTests-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Projects/Modules/ErrorModule/Project.swift b/Projects/Modules/ErrorModule/Project.swift new file mode 100644 index 00000000..87345b95 --- /dev/null +++ b/Projects/Modules/ErrorModule/Project.swift @@ -0,0 +1,7 @@ +import ProjectDescription +import ProjectDescriptionHelpers + +let project = Project.makeModule( + name: "ErrorModule", + product: .staticFramework +) diff --git a/Projects/Modules/ErrorModule/Sources/Feature.swift b/Projects/Modules/ErrorModule/Sources/Feature.swift new file mode 100644 index 00000000..8d35d5c8 --- /dev/null +++ b/Projects/Modules/ErrorModule/Sources/Feature.swift @@ -0,0 +1 @@ +// This is for the feature diff --git a/Projects/Modules/ErrorModule/Tests/.gitkeep b/Projects/Modules/ErrorModule/Tests/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/Projects/Modules/ErrorModule/Tests/TargetTest.swift b/Projects/Modules/ErrorModule/Tests/TargetTest.swift new file mode 100644 index 00000000..b1cf7940 --- /dev/null +++ b/Projects/Modules/ErrorModule/Tests/TargetTest.swift @@ -0,0 +1,17 @@ +import XCTest + +class TargetTests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + XCTAssertEqual("A", "A") + } + +} diff --git a/Projects/Modules/KeychainModule/Derived/InfoPlists/KeychainModule-Info.plist b/Projects/Modules/KeychainModule/Derived/InfoPlists/KeychainModule-Info.plist new file mode 100644 index 00000000..323e5ecf --- /dev/null +++ b/Projects/Modules/KeychainModule/Derived/InfoPlists/KeychainModule-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Projects/Modules/KeychainModule/Derived/InfoPlists/KeychainModuleTests-Info.plist b/Projects/Modules/KeychainModule/Derived/InfoPlists/KeychainModuleTests-Info.plist new file mode 100644 index 00000000..6c40a6cd --- /dev/null +++ b/Projects/Modules/KeychainModule/Derived/InfoPlists/KeychainModuleTests-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Projects/Modules/KeychainModule/Project.swift b/Projects/Modules/KeychainModule/Project.swift new file mode 100644 index 00000000..58d5689d --- /dev/null +++ b/Projects/Modules/KeychainModule/Project.swift @@ -0,0 +1,7 @@ +import ProjectDescription +import ProjectDescriptionHelpers + +let project = Project.makeModule( + name: "KeychainModule", + product: .staticFramework +) diff --git a/Projects/Modules/KeychainModule/Sources/Feature.swift b/Projects/Modules/KeychainModule/Sources/Feature.swift new file mode 100644 index 00000000..8d35d5c8 --- /dev/null +++ b/Projects/Modules/KeychainModule/Sources/Feature.swift @@ -0,0 +1 @@ +// This is for the feature diff --git a/Projects/Modules/KeychainModule/Tests/.gitkeep b/Projects/Modules/KeychainModule/Tests/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/Projects/Modules/KeychainModule/Tests/TargetTest.swift b/Projects/Modules/KeychainModule/Tests/TargetTest.swift new file mode 100644 index 00000000..b1cf7940 --- /dev/null +++ b/Projects/Modules/KeychainModule/Tests/TargetTest.swift @@ -0,0 +1,17 @@ +import XCTest + +class TargetTests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + XCTAssertEqual("A", "A") + } + +} diff --git a/Projects/Services/APIKit/Project.swift b/Projects/Services/APIKit/Project.swift index 6043c319..6efd2679 100644 --- a/Projects/Services/APIKit/Project.swift +++ b/Projects/Services/APIKit/Project.swift @@ -5,6 +5,9 @@ let project = Project.makeModule( name: "APIKit", product: .staticFramework, dependencies: [ - .Project.Module.ThirdPartyLib + .Project.Module.ThirdPartyLib, + .Project.Module.KeychainModule, + .Project.Module.ErrorModule, + .Project.Service.DataMappingModule ] ) diff --git a/Projects/Services/DataMappingModule/Derived/InfoPlists/DataMappingModule-Info.plist b/Projects/Services/DataMappingModule/Derived/InfoPlists/DataMappingModule-Info.plist new file mode 100644 index 00000000..323e5ecf --- /dev/null +++ b/Projects/Services/DataMappingModule/Derived/InfoPlists/DataMappingModule-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Projects/Services/DataMappingModule/Derived/InfoPlists/DataMappingModuleTests-Info.plist b/Projects/Services/DataMappingModule/Derived/InfoPlists/DataMappingModuleTests-Info.plist new file mode 100644 index 00000000..6c40a6cd --- /dev/null +++ b/Projects/Services/DataMappingModule/Derived/InfoPlists/DataMappingModuleTests-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Projects/Services/DataMappingModule/Project.swift b/Projects/Services/DataMappingModule/Project.swift new file mode 100644 index 00000000..2b926c25 --- /dev/null +++ b/Projects/Services/DataMappingModule/Project.swift @@ -0,0 +1,7 @@ +import ProjectDescription +import ProjectDescriptionHelpers + +let project = Project.makeModule( + name: "DataMappingModule", + product: .staticFramework +) diff --git a/Projects/Services/DataMappingModule/Sources/Feature.swift b/Projects/Services/DataMappingModule/Sources/Feature.swift new file mode 100644 index 00000000..8d35d5c8 --- /dev/null +++ b/Projects/Services/DataMappingModule/Sources/Feature.swift @@ -0,0 +1 @@ +// This is for the feature diff --git a/Projects/Services/DataMappingModule/Tests/.gitkeep b/Projects/Services/DataMappingModule/Tests/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/Projects/Services/DataMappingModule/Tests/TargetTest.swift b/Projects/Services/DataMappingModule/Tests/TargetTest.swift new file mode 100644 index 00000000..b1cf7940 --- /dev/null +++ b/Projects/Services/DataMappingModule/Tests/TargetTest.swift @@ -0,0 +1,17 @@ +import XCTest + +class TargetTests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + XCTAssertEqual("A", "A") + } + +} diff --git a/Projects/Services/DomainModule/Project.swift b/Projects/Services/DomainModule/Project.swift index 22d768c9..5956fb29 100644 --- a/Projects/Services/DomainModule/Project.swift +++ b/Projects/Services/DomainModule/Project.swift @@ -5,6 +5,7 @@ let project = Project.makeModule( name: "DomainModule", product: .staticFramework, dependencies: [ - .Project.Module.ThirdPartyLib + .Project.Module.ThirdPartyLib, + .Project.Service.DataMappingModule ] ) From 864d5237470b0c5aa46426aac11e0d4f9df86569 Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 15:28:18 +0900 Subject: [PATCH 02/25] :sparkles: :: DMSError --- Projects/Modules/ErrorModule/Sources/DMSError.swift | 12 ++++++++++++ Projects/Modules/ErrorModule/Sources/Feature.swift | 1 - 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 Projects/Modules/ErrorModule/Sources/DMSError.swift delete mode 100644 Projects/Modules/ErrorModule/Sources/Feature.swift diff --git a/Projects/Modules/ErrorModule/Sources/DMSError.swift b/Projects/Modules/ErrorModule/Sources/DMSError.swift new file mode 100644 index 00000000..1b42c920 --- /dev/null +++ b/Projects/Modules/ErrorModule/Sources/DMSError.swift @@ -0,0 +1,12 @@ +import Foundation + +public enum DMSError: Error { + case unknown + case custom(message: String, code: Int) +} + +public extension Error { + var asDMSError: DMSError { + self as? DMSError ?? .unknown + } +} diff --git a/Projects/Modules/ErrorModule/Sources/Feature.swift b/Projects/Modules/ErrorModule/Sources/Feature.swift deleted file mode 100644 index 8d35d5c8..00000000 --- a/Projects/Modules/ErrorModule/Sources/Feature.swift +++ /dev/null @@ -1 +0,0 @@ -// This is for the feature From f2eaf02a8472ca097abb779445b2a1d9ecd254db Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 15:29:54 +0900 Subject: [PATCH 03/25] =?UTF-8?q?art=20::=20=EB=AA=A8=EB=93=88=ED=99=94=20?= =?UTF-8?q?=EA=B7=B8=EB=9E=98=ED=94=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- graph.png | Bin 0 -> 77495 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 graph.png diff --git a/graph.png b/graph.png new file mode 100644 index 0000000000000000000000000000000000000000..a9edf932b0f1e41de6c589ba3dbc81f42ca60358 GIT binary patch literal 77495 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
8^NpznG41Z18_rfYD=EhY!+0RE_DO(^mXH z!rCy+Ic3#~LXLBqQ`X|@vNG-cgC)YkkXZPofAiYhg5Wa<#*ZhB=Z@F2h(-j3rY^F! zzW#HTYk;Kz>9DQirIcs{Eohop?jh;iL4O+aVO(@ynHEVf{jvA1qcKVjL;!ItpA7dyC0iZdV1|BT zdHn)EhAZXz7OLn?`I&1yEFQaflK#W(iHVM64Q9BHH-vtsIFki34$SYS{C>Dgi}OBR zJ+F$(mIA4KY;Q$%ZAEn#wDHi>g)-O=XgHK{uw9n6lk1sAg;1oW+crG;n8-r~$t5`M zTiEfM>yXw#H*9rM=d6k1V39#+Cg)o1&dU}yTZ$*D11su^lNTt5-W8F$mmcJeHG0%x z@}zg(DB|$Fy8I)F1`m_J!!V+1oYAu}^C~F`USeR(#C5{zS>YA4of9oacSyAbv+ z?5q#UO;>(1SqguAC{gh)_$D>$pv8mM)U{tOk06~gHZ^4jfHQyrNjDVId**CC5*Tb8 z?Jt*Vp#bKGF}4FN3#U53h1c>ZhaFZMNeX0>`PlL&0#u(cAPv*jPtA444* z62;@K7es%_nN188AIi&-bRI2AfA2sg{d=ErcK;e}?5F4-H@d~!DL(yp4W3+ipf^|m zU?^y)?_jvY8;w!(k$RyEmrflEZL%qWS8p@+F?1Sduflclmz3FL^q?6EqqtmLtP>Uw zx<8vjsGK~l`Xp)~r1P(7?9f}C{8>l?kLO)^oop~^iQ|tNt#6L1Da!aYi{~oJzaM=g zm60{LIiDQZEXldLee+#iRqdPU1#&C_1D0Jd{r0-&?OC2Md*4L$>&>N-q21?x_z6+s?_lC1gf;I5MYhduYPf? z=_n&43@033ap_lu{Pn3j&F)gKaK^Bc+c|^U6LCAEsiPi9*=GrK*G+U~ukDjPCcjU& z5IMJiT;}7`xCSbDuHYl_L%T#K6O*zD9q;F3b~Dv`x?Gu4!iER8=e|`cqkqVKx0f&9 zT8Go@Np_(W`|1(I^2XzsifacuV-0hVB_`K93J_+qLQ%ANpj`e!@2XEha>*-mS z$dmtGSDq+DI&FE2|E#Vm=qA@jwDaxtJo7&w&b1QQ99~kwb^$=3-O`kEbaC2!9)s4n z3o=hd?bgTKNfV1x{Mz52wf{VNdGR3H+Y6<(x3`%fWU)BM@J&x;<)+zTZQh#so~!xZ zQPFC7zMO%dQyJnBv_B^Q2>4uuF@7BQo(68!y|U@#p4pY$NPBiM%TPu{kyExSmtdHeEm2E5f~_WoI`y?3=xN-T9vV0` ze9%%Yn>%~QF4QvbyKRZcu+4&Qh*Dryl8Ast_H+JhHTp5&+CUK&Cq8&}U-f06-K*~% zQ&{h2WwQkfQQBxy5`8GN%j+26<$5^jvOO`fX_l?ayL)u5rNxoTr6r1?u$2WZn-NiO(dSfXN)AO0)dHGWoj zRCThNcMLG~|0~dC{9l2tk<;VA3WTn6^7y@S*`S)2-uSUa2dVCz{|42^D@RC;kR$+V zg#GXS_mQZNAHRY8Cn7Y9x1j(9zyLBT2-=`Xcv23aVrc_FWTopuUE|+l#^5oCUhN}# zdH_QqmBg_BeZ$z^%0U0xzST(4ga0auf};Ob6!$FM>yv>x^P*-B%96{K|NCZchsEbY z=X=U;oAk<_-h*e=Bq6{r_#=l1vQR^V=qASffd9Uw@_#>I3h<7APx(cv3*X&{R8Wy$ zDi|f*3SU23WoP*RJ*ou@`WqWqV(4hU_^sPkcBwL=TSqN+4yL@VK@k@K>Y2k+g|x?4 zONLsBbt$kmuwb2HDIcjC`7ZBTSXdD9TTsh}glI>{b@|S_(qw7GeX=l49mU$%5+m0? zJQ>k2H}o(j9cNe@(YDD*ZEMR_%>&q?O<3L1>QG+w!I))-%m-78nkY0nwC9qtdY-va z*ORiIO)0l9L)zRBkBYSNpm0}_i`qb+W7L1x*qdit*FX2S5vWjrfouz>dPXSV`YNnZ zR~|GU^+rBEpf*?4j*R?i97hMOC(#lSf{nfwI;gKer?RN{OOSkU-iXQz1e#bi8^i#d zj2C6iI8dR5;OQO}ypStM+K$wjd@A@0ibPO! zh(PCqngLYm%Pz0mMGIV@a57_Z%5lTrA)06nk;NTP!sX(lv$0n;a8a7lyGcR!z(*>Q zmi_qcohmR71a24BR_XFr2a#Fcsr2qXID@j>Aj(H8t_XeB2;;$U^Iwtrtk5oH`({MZ zN@x)i_>1fG2Hf2Mtv~=4ow9Mw;!+ur-`i-U@5@QY*Cm?0QqXt#vwM?ebw82Y86Afv zr5A`~9jfXt{iHKjw|ORQxB;@nsN0YTpyk7()BR81zl$b&Z1Qq>*CcQ7yUbu-{}E8h z!qL>#$8+szKK^^^*n~=M!5j%ei%iNf{X>}{Iqn4v0(ie0`_9mozF)%2Gtt*lJce55 zEnKY;*A>f|01~LMxcFq=NBT6f@hu3+4m9(}0%m&?ESpkdXm}WLF`@T)MFA;A zE0>u1`OC-I@1krv+9bl}2V+ZihE7x^eTXJ(D8~|#7(gpc!koONwOiWxpYwDJkmL5ScC}Cs>$#Ztr z;C2{kM%m}s^j}H9_D+#W0|1u11O%YlUGNc5WZS<_qzO+P?dgYPS;^% zY8n|HC2OLF4+_2jnP3AnGoS?f83H}EvgDF}0+0gf*=OurOsjc&3q7vi!v^T|tnlSA zCg2beRteC%96$gOgZ%70l|P2EiW+|0m^?rqEw~~~xIXIlh35``H0p~;9WWTOl-#NRkdzbl5==63Kq(Ir(UBqQi($CtF0ST|El- zc8y~Zv_rR#_{n=mmiHyva^0_8StpzBSP~HOZ0h6l^iiY^DKcofLikP(YZNR=E9B81h9LGdNyj3Eq zrG0_CKtVxhS+laOrG>?p{DSo2hAaNf0Mk$HQ46cjK`ZPXo~hxa$1_QS(p8{%wn(M| zR`x*Z_1W^(KI`BE!omTphL1Ul6+*mv{T7t!ysEcv*p2m!Cn??2G&N0xKDX}D#sJbq zOnH9a$_8^r*IJ(9(+7V}chB&OiFwRFfC)RfR&{noTj=$!$BCW0SCyAgyug&)^fWPn ze}`F%5t{*5LNN`EerPZi9d8_PRY239a-(#?8s5mlX`xY5@SA?EaYKivS0oMY^rP8nLWBy$W1ppcn&^7XX3Enwrw$;x~ZBqY@pXto1Ua zTkTm=_xt>`dzI}2i|*)}ciqe5ufM~9-GZ*Z96%9N3>5vR#{XgA6jB4$Q_8zLuL8KN zjC8&9>&ZbSQSGq*@bp2N#YYM*moKFL@=79)q+GadxzoJZtFB&2yr9@8Bi~%~s-K)| zUD)q`^)oPs#ZOd3H1UR|r+``>o~06Y&dN0y9bow9n-6f}0Lu90M`KG%i}Ph@1t8#n zW7iJVXJps{K<>dK7XfP+;UF^NcM|2x-?Fnou2ehX?14boL9o%26Zdszew#{?+R4!2 zwT&I7Cy~vewbh4DSO{Cxw8mGxw8NLa{Z^1SRUOeLZMlp7XpJ9lmmfH=m>_MD)$3c3YHJxFvl2i1H2EZqE>s2!f>6DWnw=N(SNQ ze{kD4fV9dP;$-i-3Z#iO7Qn<1AAmaBR08!H5XkU006C`Y^c&CUUCJmfX0^XFbMOL3 zqY}99ql38By1KgZsmIhY!%NLJE{?=0%_}W)8v^=j0H#goPGZg;vS1+!2|vY`xo_dL z+~O;pPg9`k!TD?~Pp1%|&Zz?{EW{yZ<(kiFl;_nl`t`UH{=uB1f6T!$0}i;u==-4G z1}(nVR?|&S0B8fSoTg;*K-}la8_=oW`X%#t8w?2NUDG$X4605yYe5Cyv$9cFSs4dp z;%jR7fW$HH?J8_tItq&Y_l3O^;bsEH@hcwDao_xk_kgzUUCSs=Bcmvhy~;60dNjsM zw*>IF%8^aE%po%tqOrnd)1SEq`G#e%$`h)l~~%w;nHNgdqV)I%$vj&(2OaAbPt3&5iESBZTUSun9fk z`C%s=(Fj+|@;4)mT;dPlguE5K$3J%v^H{eBVXy;}^&5<}z}tAm2e7Sn2&vovY=^LK zx3{+uE;zI@ky!yHy$A2_iHfPOA1vUC1_(*#tL-AJP>{Hdh>PohpiraEl@&a4Qsavj zMj&BtPS(b8m@7e;NDA~NldV5ZUKV4uPbj_tJ?JOE)WrbWFE6-{%Wm3ZwA7PiHC_?I z|F@2PRq7n!bPIZL0i9&={BSxf=QG)#g4)elK=dy_=CTOUNT4$hX^Cb&LaW#}kaRJC$ADjt+vak(A6?WiNn)D`j_h&pihA|6bptRl@^Vk%I zdh}!5yY+A%W^@<;)5H^?Z?Uy3A3i^JUrzIP{o`}93V1)RK;}p%m5YJvR|5MO?$h0O zn5G ztAQA-Xi_Y2CUw2`Rcq%OJd`@~b^(}+kfh;rK&ajPG2~_#Tywksw{FBq5o~w_Fau)1 z2w}>}s+qro1Q63YfK|rhxbK2>i5+SOC>P)#ms*%f5njxVIG5Tkpn2X zZR0r?{!2p^7UKr(_i6crl-_1mRx|)r5{6^TU08 z&HQLQ1~nF#t5i@mdmH0E57x%Vnxy9`v@O*lNb0+M4S9Uzcei3waC|&TJ*Cp~nxRSL z9A;R^Oa^5950B>&3!HvqpwzPtbKJ+Rd8ai3x2WQ_(>#K4dX< z+@Lwyz(AcNOb6FCcnU&jZUZNo4&-p0CF>=!dT}TZpe+hj=TEr9!FORxot;#k6gD&@ z17Ii+n4fIGT!+$x2K+JzqP(1^j@chdov#4FeiVE<@R4A2SE2*0it&lS1A~}<46t@7 zyZQ#%+e@tl0Ad1)P=VTwz3=KvP!;$A4w#&X45xw5mMt!w(C#q&bAuOz*T}r6wl)cH zj3Gc^a+XwlFtCJnPwU^=B<$0%6XZ<|5~52asD&#>67FZb+kw2wfLpDy$6`noc)(A*b@3Z6@k-!y4jCAh!Tvoj-7V z+ZXJ``9BM#E$q30nhl#*GM1MwvKIFYVdtkG`0W~m!Kk*@AUuSf3qy}m)$$OYIwIBp zfd{Z$8O9zQ5K67~PJq<=F}%wNFdzUtSpQta{WfAq4Nnn63Qz=3aPs+;&N||3F$K0z zV1@!H@nPi+{RDz-^=8c)B6$N6Pw==$@VF_Mfp!G<`Uq%URZiFkJ969lgQ1H#{@Zg_ zxu7+1d2jCq+@7^&pzH_m{33lgnJ~@B4vHD+!)s75 z!}ACB3PI!14WRLa8@GQTYKAR*R&cKOve(Z~~$s9NDOx?tw?XX!I5Yg$nUBg~Wpz z`2X0qu8)9r25$PM2AD`A;($T=XA2rMcEDj5=TD5K1ncWB{bw595Y15uxf1zjR>*qCBFSkR_ke1HsN{g*6FKy(KdG9nA&7fy0=E zVo;hP3#~eY#o4t1-s8pDlJG8U?hf1n&){d%AU|91zn={|yN?b(`*gy_#VEH1lmd34 z_4NOr5`O1(jeHj%jGxmK$9!%$L}YD{X+<~5T;EJz98~sWWa}blgvSGMH7&ePg4Udb z;fWsKTeqO%sU@rG0#iF+LQk@7Qr$sJi%tX#zXA$xEb?JQ)&-%FA`b~i9)c9J;2~o0 z5OR1(sV06iLga-*JR8ctnVOnP!KV6Bt97fV4GsVu14BkyTAJ2xg1Zre&w3GYrFWP@ zKalVe(so$LlZVKe==o>FON4XkoX1izn}1#?m!&c z7d4J_!2O%NNCxWT%|GCHCmS}WD5Sjh1R+R1gT*xMPZtLb9Rx_Kg`DAye>>F!hwkq> z(&2#wLTbHMv5HU!^g%F%&sdOX4QRgz3IeWsmukYPQ9`&SfO|{RzA3FV?Se#65QauV z1!@NZPB1QSdBlb}5!UJKecIOjo!N|@pbL2G`qh4n%%?y`Mg`6;LP&*ZstZqDy9snxkncbi^ZdW^^B8sOericc1k8Q< z1bg#wXUG1J(TqUcYJnk`Iui0zf<{fIObnZ8&wYev29fM{r{S0W(wRZd0r}|ULie)= zq@eVN0#X$StqMxqz?c4%aVPweX+-cmw*{1FH|bjiOy8Cbsl=#2tv zFETd}bRU3w90(KKz(5%_%K{*ZY#3sFkL9JLaO;7=51=BEUFSRJwix_k=0En>dbH#r zk4aZ-YLnhAp`9O8B9-H$8z0@Zp}3t_k*VE~i=kXS3akKUvyFIO2a|bz75XTVBsl_=9F^=1nXKn=zbsh= zL03v7UybApk^wEj2JroQpvbWmA;XNu#l>}?DUf~&MB5v*&ttLfvl&Si0X2BX6_(@` z5G+M9m52nu(s8M9nZ9g3jQAfG05Z`Va63%?;T+b+88qV%dDnzhw-|5v7F3irdADn6 z4I&*|2}D~y!AVb7cm&wkjQ&?})g8z^S&DTiu9^aOqcw>Mty_~jUvhJ2VG!IpyJ4$` za#gJtIFm4eom(I%f@lgL5wpwYgk0s2nLAW2s4g+DUxiA_nfL2FV@Ezx$S60WT%qFA zD|E^TmI?tqGH?jRKC_`wQd05{tUP=*3)na;?w7ngB;kWy#>-Udum!m>Gk>~x2p}o( z5#Jd=2Z_tVT(_V>#tw}uqznKF4_TatH~8IbC-%)e*y^Ui9A*B*l0Hz3gJ|JES^xxV zD4lCbZ*4RqxFWfv&ILMNLq={ycaMt_H8J1a8d2;qhQaZ;y93F(q=WE|-*Y zRCZp2h*UkHq9Xvuk)#t60Yoba1qN^hbqOM2=>3^EkG=k9{B^VV=%^kKi(P6b5tXNK zvTIFxSdG)j^&?|qLIZIu#C<70fRY2zNE&z=kdP=JBS*b@1#-*dM-sGrR0B(a4bT7m z%wre?IlTEv1#WJnuVF8?Q~^6Bk%dtMpBoG;`EPQeA1sOEMidrvI=EgI7#Kt#OPeDcqZeb6BP|%}UC?k8^r1ueu zAs|x(VfoXrb_(})K;Uyz%3dEzxcwohVT+{M(8)5zLzOfrN(|8*%%hlFKro9f)u%M%%ut zZ-S_wJ9x%{x#ECiMC=i20umsWR4W(*?EBtobMe!6$+1GVF!T_qWc_N@b&P`mGa$Ci ztUrCgdmZvgup3G^ozjYdP~R%?I(0_$3lJ3^q}3DVy+;Mrhu^s@qe%1sE;EDBd^kx{ z;4$NbwOZjYY>Xi7#H0`?XHGj-{zYc&!BP~eTz~{c~IG?sHXONv&n;}`f}5y zk%aCGtwC>t*J%~JKe*|YS3F7-Sbv~0VN5NSr2Nhb~tjy=&m%HRJ^qZBtx9yGr>3tI_ZM1qd;URJ-^QOe~p z`N8I7FeorW4kMU9c68Z0<>ue6_%h@)X|zFeqo6FeV&N@QC*IuKV!AY!=V(`Mipo6l z!4<_0LOYgxgYw|Ix99QI>p0jft$H{tNqX^D#z#h~{?K&3thf1V?EU(Kb7quUt9Z2W z^r72LnCpDlnAs4&V8DK$-FZEiJ8ef?W382lk#nXS=%|b zNhdcR*DR+uw@o&18^xE0iBUdJ5vrH(B?)VHgSwSFV|Kq8OWgCX8l_qC3-|U&!OMek zW+MdyL*BSvVo-V!Xh=+fR@J*lNvV%n2+YvWM{CWLmMdKU)3N=&p36KWwAmuWvENaUd{xL?QENS;jp<=rQlD1_1`a$8QD3V*u zo}~-$X`ncy1VBq;yd7xI*U-$xn(wISbJ_(dSCwcS~uV`zJmE>Gr9Vw21C6 zA+IT<&dP3z0jaWlW^XMN9(ukcxo~3*9z0$R3q9wn`a7p&)3; zLYDnDit)nFC}{yQbvPl`3vlcdP>i93^zX+Wc{W_&pMIQ&cayt|3*qX3mwN&DK>8BK zZ1j^~zmygryHbKl+9}EEugsLRwDQhY)f<)ICV>1~`JEut+RmBc|4<+rQ3tDWyb$#m zgIMA@Q^6lBN{3lBpC=T{v~@ac<=)G zZ5+h1w1*n?I`Yu6rinz$=#SMLH!B@wE4aj87seFa`!^UADzXcRUM(n!~PZ_QUdx_M5pmt6E$_-=z`^`YBIN=v*N^eZX^Cyb9+RW;0=Lrc3V6JF5G$0v< zTuAuA4>Oga*ORa2(FcW2C`KTWa(cg+<{Qx@xps)mo8iX)l9QtkkN1QqDbab%{HAI{ z1NEpnO47-#n9ismHn{fC{6r_o^1R|;$>{0nLBt0tDlCR>c|-B6lP2oM=&09BN_qFk zp}>NaC{aK#a~^`eIj{%p^Zt9H9K;*Ac!IdMk;(?*=aJ$Y$kE9QkRdfrL@|~c8x7L% z!rp$8`oFg``U5(QR-KMRdw&@<#)?H7Lz`(#XtI@%=NDoLeJhTWCh`Fi8Q^vuVCwqL zZ17{U5_9isK2PXF<#tBztav#y;y17DJ9|LBGMcyhaQd(&J%hOd^TW7KSZQe~KT|l- zEy*Ct2&&uH-!?!RjdTc+c&@N8yP_f*`daY`33j|%ugc5*fS677M3n%Ur_VQ$7{$VY zaKloA%F&{6hoYrLy~ZC3(5P99O=*N-Wn^T6OlY%@AT0qf8bK`tDYL*KMO4(FfdZ{ip(G?( zN5(d`%x!;IW8x&f3&U=yT&CP;Vaoi-bmy35q8u%BMN@kHdzWCjX6>s%;m);ws?0iE z@;Z!grM}djJLh&gOc_tR*yxDp;d?#(5 zMNqF-S4&2Sg;L3%PuoEM5%M}npkPQb$O;v|V9a5}=(x1z8ox)voyHFk9f%#lzJ9U8 ztXFDm&`th~J~#iTWO%I=1g-&@sO<0(iXq~;O zX!JuXwQ_Qfgbz?G=D60C80FWbr{W|`i)lt8Ac+wV_*Li^7LQux_@KeC-zGf@etr^Y zc{b@m^VN_o?!e;DtRBd@!bsUQj<|lj4nk67W#An431MQ;oEn6+M;_SmCAkWaLD>(o z2!%(!oePxs!LxS!X#Q^jCUNFX9xjPn+5VIfzkOpR>CB%`GylC+Fi}R+n+~HEgAUQ` z0mI%7aZs=-U&wOovnbCJ>hK=5D2KXmU5A9cLRFSA)WYuT5~TP^pr7I|5nV*$Xhw~eAQGk) z{o}XO4_2m5qqQMx%z}}w#1+FnN$eTdw@)|(DP12WQxFE@1hn01$2m%8O%J@D{OXe) zV<^M@R-({9x5e%JsH(mz#%I_OzrANse`)NF>3*m%!BxP5NhWx#DSYl{#78xZB;GW4K&S ze49xFy@P9}&$5Hntb=vAgLPG_(J8i!*#3iiS%g@Hj=u<%;cs(ROHM+LmB%8#)#@$f zwH3E~GtP{M@HZ2=P@fEyI`b_AiUl&B(so0*xJAISJa!DS&~E`+VMN$0PTMi}seQEIwg7YwW*moZFnzntQHPT(v007@QD zq0a-2uN;vYIDPR6#O5|upR02M7x8Jknbl*Ok{D41@!us|)nnv|_{(OC(8|0hC*Ic? zw(OT)Jrr>6vEKyRPScyF!w;o4 z93m!4_xQ;K^bOidihbX5|Jr}9iEUby|6EBPMSJGfTEfKhF69t>TWSf$@H3{M^f&DH zMHB~1q}PPdZcON__6ihVPjkJh%MnV8-AWqt=dS<2Uap|TJF;hT7@-r|_uY*tBgpXQSV%9QPX^`Y^um zeZhX_!1a~KnOMf8X(-DoXY2E!#z2fVhcbmZ{v&&c+vceKpAMR8Zn^@FZaRXa6`NbCpOtP5+ z!yW?^;V6~D^>vRw_cgd@usUgZOnCbl5!?%Y$NlAE^DceMZ2tIF>9Oruw5`t-9b$9X zX#rv^SCdi1(r+g}Nz{8J@+jh1M>2iDyjY{OsGL}ftCloj(x=-*p2&nN;jVu(BJ_u7 z{Nv-p6zmlI!ObVTZ6vnqyX&XCONq@8J}dWzf}lUtePGap5r{Cur7|!$_}QCyEho?V zym2(j?wd-)x8(fh=*%VywZB&~bRN($gsNq%mWkXndFMO&97!R)oL znNhjbs(|2f?r17mBdw>1pBc9-c}R{i#mf}j8`>LtBMZt3xB)HS$dzur#}n=UJ=Z>1 zvaL25)?##~k0$@*I}S>iun#R(JHd~Mb|bAWT)ah?+%2!;eed{&AH?_y3JTvqVU$S7 zlLx#wg|Kkr(w)sW|3Z76fr*JOcq6y9Zf*n|LzY5bs?%=fpQJb{Au(1$Xk5wiJzCr@ zI#2{(c}!;4hbCH~@26LcDL-zoGQlmyxjRZLcT2h#3==v#xoiV=@G(OgP&7l{XV89F z+AHl@guu-B>}cDIrgtW&eQpLaUnA)4aSRQYI`op^itCFNBq=3moR5?e!50l$Wc68n z{x;!4HBB1GAWfU`S~myN*X)+>=p0%Rd`I4Zj34b2zwzDzeC`Np){3%E13i4fDQEMv z(5>Pv|4S7n@EwBk$xM-Hvf4>GS=nx#ZaGd4jv|X8dPJbO28NT=8{YJwXBa?LdCo^F zKB_UFaF+*N^S(P1MkJYk|HlLCfwiLL@)wS)wCy7Qr$^3HW z(Uc^vF2{TR`Q;-hGt>e8%?YC~gwY`BA5l5^5`xqIjH< zE;K6>G_7bcxeDL%eOs+)U#UXk5edQAy;WQHmkCV|2uG^UbMGypJ-SYHJ1wAwY2+m7 ztjaV0^-bJ~D@5{7+DH{TIjYmIi>^ecQw>Y&iwJ==pwkhF0F)TYS7~3regN3bd3^YJ zyYNL5;5}-FPhk*(rlw{<`<#*1^YyXncRyG84D#Q3(Y$-#bj-J7jqNsyw)6G2A20SX zSD}9|;bdEEXb%~@E$$0j(UM9Ui zDz$)Dv~H-hJ;K=FsOZ6c&XNxu%2{lndj*B9{*BZ|#3DrsAs9t^9RmCF)BT-n1f;56 z+pQQT81^hp`fJK_CkiH&wBLryyT5+1T+C0}UpKSct;dnmyLfv8otWcGV=D<3)WPkJ zGh<3T7o^+p=I#5pM3GOIj))|${2}`5e>J3urPDHALub5Yyq0)muyUEt-cfT`G zt)7DkEtZ8J+!cm#Kme>1Y)g2hLi-W!ET~g2MG-6&*X9zx$++*FHE+x=F#cSsB2Hgz z-@~lpIKVQpIq8LHS{u1h80|MQ+c(m-Zv>N3v;?oH4fETfzBS_{&XSGmvfZqT>}0O} z+G_;&;2r3!agf&?;`2MJVu#W8{lKO|C3-~iRUsmqnEHluoCrpsXTo#+P%*m#vFPm| zo~URi_^&0?vNY0~GW-5WD-3+?Tb5J!tMbJv;!$Drhz1T#vO=GkQ7Ey_cQ*pg ze{JyZM)~c$iVhW(_aCVP1LxXbwZCkf15)H_+5c^lMw!{Y7;SsBOOKyMHasU^KFNGd zy?f&*JvW>|_(jKIPf9B|6-XzqG(lTj<7CEzk>@pPI|2WRR^rnj3luWKd+}0hHa;0qNTquvsiuESLp?%Ih#NG!#aPKN;$M&C5F;vaMatY6QDnjpSZ1S z8@T&7EWNIp<0q)4P0&#kEYlzcDkXv5=yHtOVCn22KB^GP(DP7+wkDz~y{LM$IelZO zYrHI&PxlS*cQ5cQzbSw!WXN#u-OKa$YqX(yzZKsRCPhw88|*V^CFx8}=`=f#I4iAf zXSni_>`P?a1HT0bC}?)WqLFq zP%nz5_H63XP{Y85V8@q=mCT#7EkP!ui!j5u?Zw?^VSOxhl39{nzc9@rN)P#0u|1W^ zme!c;8m8`NG-dX5n6CP_Dr-_;?Zq3tsyYoz`L;{qvfcaFIW_8G8^6`_$3KnhnkCFb z{ggbonypP7uTi56Oet;16qKqDOT1Pd{+@e+Ul&g3XF?@R%>OB*`~MO4)=^bPZU3hV zf}~0}C?F_Z(j`bpi*z^A-Jvv6(j5ZQ-Hk|h=b^j1bN21?yz_f!&6+j;pbL-Z+-JwN zuYJYmOH%Oh;~m}hw_l(ZiNzmBEAf1~|we(FTxcGwcNv~R^R^7+#qAnQh- zh@vjXh?A?RO#a>W!@0kjLwBeQGE34M%T_<~H%xrn$GptA-OYmE#g5;_vSl5I$`R}m z{5NsqXDepl2v+bA-m_t%A45dJLs+PzM9A`MXrH&_H4bSS1wRz-*w~l#web*wIjphi zW0WRJ>b%6|+dWxyv9)AjqL9%YwHVi)QODm1I?&y<5F45w95YeWI6T>7_H{TrNZOrX zJKdWYhn3HOA7w7MJ`z@!n4u$89ein-6GGV&up4aE24s6Wd`I`ZJaS=yuFe{2wd|0 z+(X&Sp_KK9UM`M2+{nD%(gj(aild}$d1zJcEVp#dQ~D|Qp_au_vl8N&G0ADaXP(l1J(<&KF%+&hmjChyjmzxrG7CGn-P&)=__D|f z-pEw=9 zrTBKYcNK4WJdT;%U}*%^;4E-9=p}KeyAxLPcEvWp$Jb?&PcqQ|*&cO00A}~=c)tFZ z+j|1|LlIqbxg(*MNlVlr-x(|K$tpeAUg#C_3r8~uBx_0e|Bf^OJ26gOdn09~gE?cW zCCZEFlt5)X`<2jj-yQxK?%1dwj@8VN*VubUjvjDCfJcp<*Un$UU95k@o~k%eji49w zbF(CmK_Z)SFjJ(-l9XdGeKgB!YZ{fSps<;+(qzoFQRIzUwn&AHVOI&hUDvm{oDDIj zJ4wTHF~gH*9lAccNKcs9%9{8I$T4IV1KSQi>VmslLpXI&2>~rbZ9jJCVn|LioBwO! zxD4lUN0N#W6>!{a?$%BGLwOo3JM9 zzhvYO7h0$_vwR=T&U`A;>r={RtQjNs8b4|BbF+AzJLqlNih!G_mNsT?tcruppIXfQ{ii=Ff$3 z;=KKR(oKEkPe`wILw#v7>nor1F7ehqx38Ci%UhHnqWRiicZgfX0{}tO1GuW4Z zt>RHaNAuvAKQfae8yuT8=F9&JO1i(fI==887Wxe12{$%*@0tyhDdZPR=5GT+I%wZr z^4ta8@JCR)Bd(uVj&*^{YabUKLP+q(?5u_|Fpb2oBN8hUzSPl>MWg4Dr-(&4eQ3cB zjgZAsUkXSldq*H4Av8_`%F6zjX_vH1{+bq0k$zA0ygQo$)<<3M3)Z<{j1bH7eF4$p z@OWVQL`uD3SvfFpWv`!o%;wV2D^V#ko?j@q1@v@xLZwo~$l^nU;xBl`JVf6)0ruBC*YBP=x;>4axS{3FuGLlZ^?~4GI@j zdDF3K$TFoX?OYpNVnA&3nA#kH7!$4Pi%FFvwSX<-EEh_Fh`Nl3wv343g~*uL9@s8? zu_kUVGx!x-8H(Py<6aSBGFq`jteZ&rnn78K@1J!n`{?raZU=P) zRB6hyhKuc-MBKfs_$>v`mfqOxk7c&E#UZB4Qh}C^Wr*L!wEDAfGQ4ndnK5r3%lQrO z)f;m3NUkpCA;xVT;qbnI*WczDaXj>fICa8`$i3YoVt z6kjW{@1JKqG_zL>>T8ck7(E<8`e$J59l`;-5>yuv$q|++t+4q~HO!j(8T@iT_4na{p)Y@$MaFkCS zIQvbhqeK2=5$s+yvd*}+{@ED^d7M`v3dMS#1kvS@ZR%(-r6|T`kM<0^!L6o9Hp+@8 zC5CjCFz}^3M$HE~uJg&W@3K^I??xZ}Nu$N&3h^nlM;Njg%D*bLSMB4H;y!q+(c>*p zK*d)v)LmxsXhZqia6aVaL#hC+F9~DWv8JRP#jeglF1_O&v^8*a*T#6zizRRxhN{{e%zG;PGrU^bgrJv z1HEBW`QE6AyB8FQzs45+g<8&Z8IAS(xXew4Ml;6)exthzhW@q;u3X)Y z4vX*;zA;a$`;Pe6{DB5J+3+(r!OY%C<3-GyFq4Kegb>36`8zbapQAh&%>7gA`i^)} z2R|cuzQXs|B#H{#sJVs(&}NvlRWH1may?bWTm6Y&5oT=?$vGDZ$10r~G18wYH#=|a za1}LnlSq~J!g6kY-guvbEGiJ8`UB5=C4D05=P+w_ztzeu)0-Cm^P8&4rOYDL{_StV zHbd0CQ|q-u)&fQRFD;9nd|ynn_NSNM@0Um1V?C^e<2JDc2j&nB7bozP^a@Y zSh6MDyPHghnQ^g^5M2~K{OBo2LA(GpK>zvU#tXW3{hwdq{dv}^`M>_%>v8b^?+XHc zFuZt%&c$Fc(~qs^XDIn_reKd*&vQTafFTPG@xL+cjQO0=Z%o`Xg3hG&E8K(1gYj4s zD()V4a280u?b@mcgIDKtz{6NX{m8L2E>mlIjaNj>ek-7nm-gJ*)Rk@Cp*D?TaVlM1 zq&iC-rG2@fwva1&T{4D3n&xd97?CYyViIeN&gx`X=ywo{zEyRLUY%;dCiN}Pb_1Qk z1b55xU}_JE@uGgOp~0EG-l8T=>BjDNy+65@ML=nN)6EwPQBq3V(*PkE-1>~Vw=G6H zF4DUxiFDSda?FEGq)Q8=AE&R2cj-snIo*+|Zf80*VhL-``x-|(=g^SW!3)-8(sx~$ z5{uurO^p}LQz9YnVvzqByWP5rrgJcGPAXIgtT0zayFHBRd;5-iqC1NhDaDzguT09i z>59L%<;7K6nVnuzvVHPSXAEU{A{~>p&+J=;rTa2|mr26Ea!xwdKK9(ps19989D=Q< z%ydD`Ai)wLKAfDnT8iE#)1=?^*t|Q$C2}pr2uSWO>h0Zgey6u1?Re6s}QZ zefznh)fRW}WmeH|*m1K)Sq${tEIZXFjV)IRyUUoW#R8EOD6v_(^R38%w4an z&$OQ0-e0}I!Bm#i9uq33YJn^EaatQCiO@TE%DXnrCrb;%+Nkn`pH?OATvM7-CEnO> zhL5}PfR_>YRYlnnlq!6=H%kUH#c-=+k~YwL@^Q=Mr%?W5e}xWRV4BTE&AkRE+jC4l zpKbXZsS+tx&U@ZT{+x+{?|t81d-&YLPjhW4W4x3kbc*}Dswq46E1n|tQDi5a`d#cJ zMHY3A@*USkz2w~jiNmElJgNPC#2|!sonfOtEhB5zhaWY&y%YOrpCl`+(_h8m=|LB~ zf=DuO)0j#ZjaalWMcTN76f2|CGuTi-8)mx~?-EKkdf4ask`}l2%FcWcPS3TqrS9Sa z_n(jB-9w{xK7{e(aJ9}H-!t}`ttgh>_zv*ZYu#1xJ>xi2ianeNaFSze?@ykZ5^6jO z?(R2?n)8CcHQtqFjksRqa2DfJ;i40weG}SUogJ#N@%*TzNOk_fl) z!6>!kH?iT${?#@&##{p}()DvNbBGxdkD$A5rh|EMo8gf4e1Pr%iDuiBx~Yk4r^DXV zeQTi#Fd)j=D@eR@;or*DjM7p1MfSNpo=k?24jhCM_9o({{He!H?MgtPiqyIez^?4S zqqF!?G*irdN)Rt0;jhh-Q_dgeR{p!U4BX3c4vG*LPk;G>yu)5>Lv{?7)nBqs&Arj+ zeUeZyj3kF(oJhgHF_hLvM_lxLnw`(3M~?C(P~Glxe7nAvGCi)@Sa^kjxb*(Q7i+#| zvhQvZ@2cI`rHDttT~P{;{-j*RWxuBHkNpQyajkd1luo32Oz2hAZ z26e%zi1b`HXpe!@!#fC@KWih^ME&(>aNbbYCEkxE+t}GTG(I)ObCDMgeWJ0s`QO<< z^kuzhVW3;+_{vTOE>Vp~BWBc8Kht4w1sK?A14`;Y`D*8xRfKE=tYtp5zxf-aRM9#d zivINfdKTMM9^9Pz-nZNj;4~)=5@v7p?#|~m;?lIND$oa%&or8+w%KfYsJ-W_^A)$} zP+P+bs9dDhCj&6+dOp$I7itDU~V*Ui+^g#e88a$;^ZN_yK&)HZfP2%Y+6A z|HFJqB)wcwlwL%K|woqC}Sga zEHDGv9=&4&Fm=9^g_=kxwBrz)`c#ePEhAx##qHr2$uJ5>615J|`kl+2Z8{#?j*5x} zf+spqcxt8Zh^LYML_kJn68(h~1r*jYB}js&oXh1q9gETkNv1pPB-vY)O2ev4?SO{ za4-|*;dnL^jXK(CTys9Gt?IsG|Kb^Cak=^2ZO5GT#DVOf{lpjhKmp6{FH{j@hSVN4 z?>ZvR0NiZE>gpmi_-tlFYSQLfpDwi^u=Fs9S}D0m(^2MPK#5S-t>m4EcvCQKi_}K$ zolO=O!ZROi&0CI7-V!>yvhkx-`Jllzv+AIVK!IVud7|q)0Uo6(;InpY&3@neWD@Q# ztS1|G+ya-p=k-uuhw~c;*C$DL9k@Jh%fbVAs&S=#F*poL4G(OSZZ%$&XnBdv z>3_t9jvtq7*?(ne^7<~3<F3DP5xkJyijV-A)wC;8Uyi`kFnLsj=R zs=k}klQ!R;suewK5;oo)b+UJ&U8I<6JnZYCi1M>rQWV`?{2s&aWH~p0_+@WT@ZLsX-)& zE!|ut5BA_ZTFG-I9k)YjNodTc(-7mYg<{*gFlK(j7izU!?0&ly&B)-6u{7`eYTt#v zja_Ypx2K%Jt>#@%suoIlx%5(J*i&b_U+*439A1fsXfdG~{xkjYT=)7pP121kf8qs2 z%?dNzSrL5L1Jx`I{(AMmSSp_iOs~;_vbBfqNcv3Uy>P4L214!e;Nz?i3&J5huu5$o zLWY(Vy88DUt)p_KBdC#QPuv1-G?9;%spJg#bBd<3H z)gU&)t_ntTa{hUU#<+E)+R|p~H6y5yi`XisXhh8dYl|ly4ptv+8@Z# z^N*xj#NPd!8w|zwWye@)@2{_$?Ia8=%WLxe%_gOOG(TBjZf8ArxunkSAzVC=EArxpyqXYP|T7iTzqKd>(PgyXUz3X|e zpUp~J__ytK{)40yr>)tQ%dKH@=Zy3pb19Eb22)!kHb^>?^g5642UK~&-?!S$XK5tO zZKGMQmwf2pDxjUoLfGyb^MDp;<%&PtcJHmHA@Lw^%-V7(pEf9J#vdi@^Hc>}@w6;V ze95eOs%s5m!>!SJehwFKP}1w1HKMw7jrA-t+iTe0aG3<5X}Z z^?|obW?;g4;tO45=*Zz_hzMlwZ$mP}@z-|0ZuiZ_%U1-`g{xFZju&E58RPQ`yVvp` zDAO59jYpVA#PKk@cQkM)eM;Ez<+Jupi z!o%qY{dktf_>uQXD{CD#@K%%EAJ#saT+zsk9E%IL^IA46Hl}^rF ztE4o)yUP(|PUVYeA0}rtEBs`&&+7qQFMe#lzuOF%Z(G*T63TLI&gQyWddp>DcBVXJ zsxzN#s97hWar4kILS0XYwZ2ejk;nr3b3>!&^aRoH@xKfs$P{eZ!>*jz z@l{ssRCW`H>w@eryFFbJTf@&vrPTK3!IXK^4C>CDjjRmOvbnXDG2c`cT(XGESa#0h>ws%)QX5_2U0+Wf4%Wy1wr~ph z8-vP}g9Zos8_Z*~FU~B3>FV$6e3n3Oyk<4sn)PWh8h5S9ZV9~}`sw-%;S-&dI}6cl z!M2Q(QAA4a4otaf10M4qs-6Mu^*btxqiu6qg&X_D6DRYb1X%g@{P`U-VDlfmL31{uSlnzVNMq{>7K#c>T@1pd|OQP&se?`)e22<9T(Q zwdEE2T_Nfp^yHNr(-fiR$#ZO*GqXLEh<@oKIbgod^YC3#^2r3qnpM6S%GuP>~8P_Y$qcA%c5N^-wu!D12eukExT5;H1 z9oJPV=5{C*EM9#%GLuKuxV1&VHIjJWHo}!M%vZ9OIpMn5c4U4r5{Geiu$={`Hx
    shChM;`EPwm8#0%y9}{(rCsRzT@pT?Lyy`=yOGf3VZ(HlrRoU?N z8zk-L`rD9J*r0?qp+rU!uR`bHhpTT5W=33UmaEfRWA?}9$3`P3l17@<oFyW_9L+GAf2gzbQumFL&4^Ez4OO z@$nwrTH)4y2ioZAC#8pb6ig+4jKzk98z?P!Qk~dsNtc)#DwCA92F^sqm`?C(Ar54= zeq>yt$@8RvDF#AH-J^kvOhq6rRj?tNy>;2o@@n0kNatMWu|t1vM-1iJC(F8eztGbx z=?Hh38&T;j?Bwp!bz{Gs8Qg!ttxenY*n_2P(J=ktk5q@(1uOEY>lR?1$cwcC%N5FG!06t#4+@KtRdrq0*Io zGcI`iXPZv6(-JzSQc_;)n!IvdsnmMPsi9@jl5CUbb5AtvXYhBx{dBY%9Tv5p;j1O{ z$8Sf+G0&GSWRgm!M!t!}X;`^;lp*aUry}lG%#M}E@#sjQpEYB7N&2i?B1{$pWRB2j z@^_NI(ogPP>C3=%;;cE$c%;E9SB}8H!Lp-|2F?jAZp_fwtJOe?@NhHF280@C-y5*5 z5GlUFUDY1yqTSP;eP4CGmNGWb@1dovaj-h9uy%VJC-*g%KKgD;td2|~du^jLIDH0p zH5Tlws<#>SbPI{5q>-ji7rjAH_1uyae<5%3WvC49TY^PaT_jAR%+>d6TTT1A*?{8ro^3%hDR#*(qi z+e*5+*h(sAE{(*9`?**O4R8L-ta2h^1xdNO*sqq`l{8!vzco>+9|Q)uwM1+8w#eAE zemV~Um^}t^?i5_(?}6M!w0B=E#{Fr)2b34SX)%w*!(;!lFQ;_(%6?14qN?qoe!6SJ zvvLvTZQnz~4p$5X$Ua8maR!oW2 z?X+vmBUp3R@Lidw|2OGkY@`H}37fjp7#TvftGDDpjVtU-tFiXn8l7eXm0@{~n2o2| z8aM6S7eqX%a~?m_L-GYTFi=Acj&nI#`9-??uN}mJ%jlw@qA`1?k7>Ksc|@$K$b5bE zY3fl=3@`M*`CT4Ni>PEESt|`<_zF-pP68Kw9jEvj(o#x0{2H zi#R^|*V-pvq#MZTT3!#N<8G2L;cQ714C7 zzlP;0iK{l4Txn;TH!J5$Q^DAN{bBP&THIljxIfO83nlrb(=l~=zWvG4rOq$3&Uoa) z?coh6?$-;ookl#f?A~tE{WtJqn!liq@5@d&TWS!gt0}i$5rG=+?>TJUihKAgEeM;h z-004}zd(8l3J5a`tu;Q6cggQm$#0>Rpev+Z_+5WGR4M1TLSc& zoijdBW)xg{pX+z@gc@a&H|SMycwegz57`r)E8U(GCh#^?IJ3(X&H1%vZVVqteHyI~ z-BV36SZ%>h9GT$Pfn(w z=nr-%MnF4tZ|U*yzRSI(`O^U_kkSUt3Txks*-OE_*~L@MGwS!~=M|LW{I?k(GzqT0 z56aES57jO-ATSM^;}g)8w0QrfFssuPk;7K`6^)77B`g6Me7jboXtXIb7l)d=%M2!P zzA!dUwZLGePGS{EJo3Nxs>yUW0ffWMxv}N6&;xjE@i7PrAa-w4+E2O_f^y%B1KzB zKU32Tmt4Z|WSTHrwiE)|zO=3$J@}|pvPoyC>8z5W?KreuEwH!Z8*tnH0J3Duw|j-p zPWY7!%GJOl=WZM#EPjt|HJge2gDGol^%g7jO8)Kt)B>z_C2u!oyNnxee)f|*OBODU zHa@3LvZ;uP-wUn=Z`J2a-y)c#q-w3D z7NwCL{V}q$TbkaL+k?cHs&0pWm#N=)x9PFt4}W##&uFlA^qOoA9*H%a`0I<((o7kx z)JWAd`(h>3NXTq985BJ#SI~BND&=2oZ+POgnEiCRR>TA`*6id_`RY1?z?M|az{Awy zv6jT=O6?^HAipvrCT06tkJ$Ce;c2}N8u15#K@~Wdp`e8A6*wV5sB7-W#Gv0Y+Oz{PIM4NL3%^>NAbNFZRa4 z^~-zrI(0^}3zw9>p-EYY%+SSE5`aS)SS6R=gHkPwz#M=`@rC%q?@n9@DU{1KiYOM* zW_l4fnm$7+mN1+5lCw%!`lG(g$fjb6k$AHO4}+WsSYu*5gA;? zKONUQhz(}4H`e+U*_Af$Yi*f1c6c}~-b8_F4MEcMNCP|F;gN3wRK3BDQ+NwOfk$w2 zMHGkYklPE#D4#UrwU;%IwT0((`i{+Uk^2{ts{^9ag2(kb_b`qr?@VCtC* z^zv+%y&sZiXeDOyNfBxQUt#lfjq4vr6EW4nB}%USrd! zqJ1sjUh#WZFgtRio#K768il%d&{DJsPGws(jjiQh4iCuxsWtI}>jLoC>tTT zCm-YX#QWLv`^!Iup`0V9B9IRY3SEe_0mc}ljbxIT@zt_cE1_Rb(Ez&_cZwl1Yt|NH zZ%n85;xrUwT(1s;)RxDK1-YsN33&-=Kho>|USNwR%m+kg{IB{Nj-1oq za-I~gQ9*X_|CHGvF#c=o`@dhO{fPYE3pU9?C!s}keRKQ&RO}F~|EE6ZIv|=x=`-N) z`QmDJNia0}bgpdu8?k@y>i_EB`!&7>L3^93 zNaO(b{;wX$>dy;5P#Urs1K!%^q@NvvAOhw?{5_75z^~D*8bD@&V3|3^#YRA->d`D9 z%KYsD{fPe=XvTlT!vz?fP>VX~d|9tq3DpC9GN@UX=WI;=j&9~#yG3<&@NHdP9V>Zr zNr^1p)qlUTm;1j7d-P5CbqlDr?*l-XR?xFlyAsMB2PESGv&#@PJkA2L(3Dx#Ji zXmCE^0KkQ7wYJBBUL*N7dm*>i*Vo{o8ta=FkDt0rG2$FpzJ&MZK$H+wZD`!#f9fR^ zZ8+F6ykvEnmLy{JY*-^v;zxSGygV7l-)FubAnAC}S05|Gcjc3w{u+X@Skx>b0Ko6~ zng`S-X7}|iRV>!wC{k;!)v7is0TbU;O0+#4>fAdpLD42-l!!NUE!Nhqwl7W)bFYtrJ zwZ7$jc%ZUpa%dxk~>8e=0ZpxX5(wiEvJR11Qq2|?q4L?4(8e%+gC;+$NInWMzEP|ys!ql=CydICx(kv1VsGVOb-IR z*Q*JpMSxLE`oJG$_#^!gw4@)8oD3edhEbmOR9I`KB-@^_aB}lU-s9txozB?#PiLJY zw%*DDs`@)bt-bse{&DF~JL;$$zZo1C*h5_RYqJ%4M#J4M<{Sa}6)-}ZbOCsvhDUSk z9rhItCU2og9ihElHQuHL)5xd^#bgeZS}{2+jdBJ4!9tpKxaNa7S=+sKz}YvK*sk@wGgY1f$cdxas;w7~ge3p&EO+ zdG8w!+P9QMflstqdhNPLe(HJis0H7mc2(wg4Mug9OX#aom}PYYk+H`1X0xhp^B_lu zwtZd+mf!mJE;fMxcNa$5z9z+*YGQzPC%x7Gr$q=zK0I6L3^M|xV{?~2zqUu6fM~JI zujSU!alrmEu&pG4^|U8;E1EFdk?*u8ax*&nH9vW2>gp7Qq)Vxm9abg1FG1{wLhgZm z6W@_MCmT6ARkZs2zdq#F%)2-Pyp9~?q8eT1)pH`6n)9!UDKT6HIa)Z0(0>F4K{gB` z5Cfh#1j7Wq%%E@IwXaxBMWq|?IaI1GhMsw8&eCF{%PQl(am$m9*{< z{b`uev}3x(no&{i3K8nmP*?HK?4)9fiww!95$N93I%9v?>j&9G{uhSDlQO>y| zn&(fOu+-#zGH#;%FBs7}<;-rE&PlHG&cXOBe!!F!_sgI^&!R>KmTR^Cph*ujxd#3& z2tFS9e7-v;q_B4{0yF*cu1pf4EZC*&Otq}Sr0i6+Ko!kU#ao3&Z?s3*zWb&OAxN>K zC=zsL8!Nms7`C2aN*RvEWEK82k0b;1B{7@vl=EKW# z|JS?Esd}_48NSiHFgr~s6A=>BB;j>APcuqwvfG&m0dSYmYD=vFuAKrQRo@vkRsw^` zA`P>Jreq*30KpIdoMNE~IgjQ7P*c>z;i$lW@N%oOm57^OXQw|PfHenYJSWY1M@kCndwfoT}_G>097wiu&L6u0uV_&P& zuAL{Zp2lkV_7?x$%9mN!0I!_j_bL|%7=;xuWen{o0WTX^1m06N^+i>GfaxEqlb=-I~U z167rh2t?zIcLm-RMYEl5Y6=w3yKj!)U;(o9$5cLd2)zo2h|aTJ`%P^3=@L9vSSJ9~ zp#gfUHt0(1D(eF+cmPOYQf|6_=fMvhUH}9PVc&LVYa=!I@5R=dkk1tqmh9M@MAY-; z^w>8`cPgjsRhcUY3J9m-jIUO@S6{VI`7dImeXtx&81%WuC?~DW5&$Os#H?I&HLmPI9kn3=U8jTpFw z6~@Q?DdNu7-U$_x3o%6g8rN3LXY3`=uk_K#{zxZ2Wyh=sJ?-1QNm@|K`YNht>MWzyj~IAlZ8)xH;tqef6Y!4*)XeKcd`3% z!Q&1O$bsKop9uj%9bmj4Lli==bL!_Xuh)?gyvN4IWYyFpfHnpIZ$rcoz!}eunc05F zLk~z1fX(I)TWMK4!wBn4bTbEVhEEYCJN9B2`kR$v-!$?CpH4+Aguzdp*=#$Xb)r5B z`SdrP_b^U@CWEiXDBekW)F}U~Gb95^SPwpO!C767fH(Wz2|lw2Rp5)W7#@UPVo1WLXnnCZrO8tW<2|lUVXpXBlk$nbU`MO3QL_@cyuy0yS#o5`(GYTQBlIa_$H)B@_EL^84?4Z)Yh|q$f8{7k2V$Mz zJQ+o(XHSnZQYgfyK*yjeok+&xp!Q(J{8q!kKgO(jAXu;ayVbUCkW*ti^MSFx>23*sAFaUEm2zqKdB~xz32U zAc{+&mkO@v1Vz(@U$nMjhOm3Kbor9NQ$hEqs`3PU7bOpR@K1ha^;)(bZ=<~PiCklR zq4?~L%-uGP_oLfa*uQdoU<@yVsCsNz5lB4KX|KISNgRb^*p%r+%oJ$=y)S>3&yDlpk^e*uKRxbv7eR{dW5Gu?Uh8N^e-rt# zkXEl!73e$Y>l^%1%rBi`0i>|0JqN%I1jM-zi;ea5&$6-*`V|nn0p#H19A=q)SI(0Z z`Kp^gNsQtHKp?oD?*h?<|7uih*=1R{HflClu!oD`86|rgvwFey-e94xTp$uOrtsrY zU|Fb_W{jFJZJ&iq;D;c9Ndu&z5Rs0Q`0uo)OlpO3{f5lU%%3IPoxx^K2XH{p{`#ud zpWi#MU6%*2m>|MiFbQu00Ec+r-ri2!4UMbAqv-XqAb~4?GJ&NESjwutmj0k<@MpE zjio=pjE8=WvOSCtWC$)$9~Ck*qp3u6cDryTKh6M~Gp9vcAeE=Xkm3TdQ8VmSZ7SHb z|4=(XTm*p6f`fy{nqHmzPC#-Z^>exH8z;ZdkpPQ|m7smi=Jz>T^MVXD)~Dz>C!Ww= z=d>sDa*m4*t;c(3R{<0>oIuntWa;QSF<9YuM2SiwA3qB|nsH^|@mvYd*GewQZd-0J zo4S>7h&@^Dx`G+QKY`#9*ZWESW*z(r)xzBNpVw%{{I5%KeWdr55&xQ6Lc|pyX#ik; zW#Du|hhaEVB)&J-1%PV+t^lasz&{UxG!+yscX^dY6LriwwDE&%ix z48Rg+lUf@f8ZO}|*0~FWAy%JzUc#lipW{OaSb%cV;@GPg9U-2O8-FfIDIEzf_`+u( z?c|~!!zXeK(8lB5n-k2{*{@_JT0B_4c;sm<`KrcT?OQS>K07yUKmuzpHDYE&X zNoASU(uaSk5CCdq(rtU@us<8WUlN)JJQeQ!8gJ-63K%&MR0GJoaR5-lC~*RKX0oIb zVO@r2#DEBBbhbSXxKhKFrb;AEi;tzb_gEDRRokn~VR3x!F8+HsBIQl*(CusF zzt4O4?|HvCJ9C1II|Wb}F#zfb5WW|@9+IE{VN$R6gmX=mZ7bFmwQD#{*V{CF_m_It z7YC{PKUG7f%^)P@B7orPfd2?U-?VeDDwTmV8vov0^<8%=n<)Uk0_;0I+@>zb7ByKSSUpFyS@P zv9S<{T~=MaFILMVu-|Z{ho(5Qq~s@v8L_e@6#V2%bvs4^xEtX2fgm_1U?GlT_%9r6 zKu-YZMmggq&;$a4XbjjS<(S|Z!17EEGzNPZJ&gs;XOakFc0->C#3`uEK0goq>JBMj z0Dv9@nC}LN$`Rrb>m2}5&7*8CC@7GVXxc1VU{bdm{%AH^6Fw@<9RlW?#dM-TL|(VD zQjFp+wBX-nC;iO`6HYhGw97ONN0~IV?tR$M|EH-}7 z6s3XTuwLm1KjpgI6g9()j#Idu9E zoNUdJ-mVEflq9s0_NYn10O^tdhgSIy;1K>ahzDFf*)LzlmWtyoL)jPHBEcGrr%G}1 z0(eNqxuuGFKy{6Uf*MCFozQ35acR^EnPApC9;}1Rq`%lPcL1PET8&DvL!d}ak1GR! zsP9np3MJb?Kf-98u%hwKLQK+*+oCX0k}J0>DWx|Ux$lP%>7Ei zlIA`8(sX}qYSDP6Xi>NI=Esj8hgWWe$1_0P1{){<8G^MBSp7!;D-EH*Qx3%&A!}gw z9vYjOu0Ylo^TP#N%_-nY3+aP^(Xsk#FJzeuiO2xKU}R)u08Mw!ZmLM91joJ;2w=$5 zT>%dS0@0;YHWN33)qZ;%+YEr){($>y3y54KqdU+xg}~ZiWe2<@cUlgl!sE2jrxAsf z2I9E>+c2E9AT0k2Ey);eiMSuoertgaQ_Z3miqqZMq|7x?EUFll)&tl?AdCVOMx=qx z8yI|CAju$Exq1L(V!*N?siNcuJ_Gj{<^&K|Y_DGMkN|)VfV$rRBT7LM#(r~UU|=w7 z-ASC}alHlUBY^<`Dh@M|^trhI4jPe)DU=U19CC<%xf39R1k5Q={(#gd0Kat$Jy$5V zpgYF&XSz@K{`!;ZrDo znYf0brvg_I7Lze*3i0LgK|XR87M8hJ_F|gFv5>M2;AWoy_D$+3UFz#@ODzDjX9J{0 zKnH} zf06(UXOwJ@1CZMW%WZ+cXR`C3q`&pxhj=p3!Uy80X+ZG^8X6Se58x0v0*v@la3TTN zd>vS(uOI~`1i6fWiwW=^ zf>5Rv6+x)3b&nC+tzd<|fm{(oj(7wx48ZXGhdsj!5Vf4(f-LDMmi&PhX9ZBCb?$Gk z01nO{@E5bVGtoa%T$x*f$R-ro2C`9r2?!{N5VIDdL3cvuZv(pMf4;xb>wzfvUr0dU z2OK3&0o46j_GtI!aE3GBT0+9LGCjgVa#$W``C6rr_6NY@hmTc%Q!O+E5%$yV@gPX& z033KgcP4tjgew?WQ5JBd0dw2|=t05&tPe?09e6%)Pft%nLSO(j6$lyp%%=St<+ne8 zoGgfx`-9VZ%!Cc7c&!2~skEapfTD_EJwjm@JO9zQQmK5&z`+WKqyd14K=nuRm{eL|gjyl(SwJ@e z(q8Le#HB;}=7EhE>$*v&taOHa2A~gT3n^_tY**kA0NCZ=uTp^Yy}K zg`#d5<%up?!@3jTh{uB$0A27Upb8`7$dNn`uGYOkpRDcjXa!;s0U$0|v`%VOW)Kht z+JYd&0?zslkVg;#+D(9aCJ>Qn=Rfre0-{3rXg1RcD}drY8IzY`OPKWNPhbNp4P1g$ zYOI#T`Ab$>gq7U>8IhNC=YPcu8yb=zjV^$wW_H+BuCkcx0ehtv%!W#d_II)ENPr8+ zHXKOm25AQJh-*cNGyD(d556u)5r)F{q#ebG=X0}Ddcb)&1z3pC=z!~#5g^f~Qv${A zD)SZa-Ha{|mjEa79w?iX0w%wRIPV{THJ_@nCWrhQNNf#q5`bBjl0$*!(256~g;pak z;g%}Nqj z**}j&Y}Xev;s3)a_yMZ+e;hPFqyTZiZ{Vme1@ezf7|w)1^YZ^?d$}6DBX2>t(F)9A zGNU-iEJ4WMWw2^lxROHwG&vQL0Nk{z)AQ&Dmv6Azoq@XsAtJ$-MmH?4#m?C0`Cs-$ zngcB26{XLg{{okG5G1u!z{;?uME-E%+^7j9iYAJ+2Ep4hAh4KzJQKeMqHj}xiX z+`7aFNbX!<+qNBC{8O_5uryj6iTuV+XtIG4k2DC^fNjCKdVL%D9R%~Bn~gBV`Cp_A zuwcPac>+-KkXVa~QF1$w4v6QlUKWQf+tC6dF9-1Sx`A^IR{nCisnIXl0N_MJY8(Iu z-UZfC?EX(_4)8e3?LpK37hP{1)nym-dz&aqD2OyD-AJdPAYIZSAxL+3sFa{|Nq2X* zNJ~j~NjFG0yz}#ZPdtB|wJ_E~@Z#EgPkd+gd_YwLuc!<5k&v$=sC}Uh;wqR&9-os# zvt56z32+^00F1=eX@MXBxKLV%<>p`+b-)==D)tioUn?Xnh2k|@1G9*MGw>Wz;&PKw z|1PWnvZr6IATWF3apj8eCGe<&gagRArDUfNp)7*~GJpdDQ^~zWh@8AWfBwwwp(P~i z2y;XcaWpQQ@e{XlUxZ1V|I&~ZV3Ef@$N!Cl_rzO zmrZ>zfS9_BC@&&PbATl&0w6Ms!yh&8C?^xk?o9$O4!{){Zn|ghWPu1?AH~SPr2Wh} zOHM}^OUwy*7#E~ZsxW#H!JUHP(U1cA1G9yx=8_3UTu)hd(VI?``2kt2uhgK|))&TN zWy-8TNp}%JT7=~yCklcz2~*82w83UY8u5^j!Ttkwaaof=ykR~{<^f3sV&ptLCq}(y zFPyw);KZzr7HZYjT{pU4?I-RdA~!e|R`5)Sj0py7tLZ$3r@b@x7Mex-lKnpYok&Qb zLX5iBfr>7|M?5AKPU9h)dxof0!hmp0M41ML2d^HU+4|bbW$zR;fXfE@+Uj&I2hbGA zA$Ey_(eL?ZnqUMBV3iSAB%9w{zKC!b5`fBe7lJ}?F94_#hXhI$Mp0+R+p8hMVR!_v zb$!uap1LFp(l9b2Vy`sFwha^b#Q;Jcvvc@fHF4*XjYU1`Tq4 z$invEu<2Az;m{%i zP~r9kwZrm!t1?w7carmL0Xsn038q&&!msZyv~K}onGzAMX_w>m|DSkfz#PhcbYQ%p z?hD0u1hf$W%v{ecd^*})nG6sFIT$*PpyVOYCAPk#tb;IQz6y91AhID=7MvUeIboW- zL@N-lrGY~QY=tb)-oSQIL)jAi6u)Wc4nT9jfjU9l4SCM&<+g)lEPKAZrv5Hq8<>p- z$bcdNHEdmg0YE4R{bBz*O-l3re_Cm8(|h0)o`Yv%L+tb7b|MJ}PJxGtN=nRtucV=+ zMI1jMgh)Av3dqTeU7>PJ{X}GnK#XjIoaHmvY6v-&!S*!4@MNBYg?U?UL=S-@yu;J! z9rt!fDPi9I8rnwH|Mfs+_=pueYbL(>iJ1QgX;8o6B|JkboU?8)h3)X|N3@sMo~pHN z99s9VjTX6II?s4qy8*b!X>1F&Ri+FcPp*%cJH%t>M_Yoq!x)f^1N0u@8KkTHyYD`H z`gcR?I_9~cPm$y9y!2pdT1v`i+JdUjqGX|JE4z+kl@`Phhg+0wA(S3K=T7jvLD&n! zP#j(vLmTiQN6KKwA*^jJ(rzBBFnecwi9i)WQh=>t`xvUQIk4fGO2@k)v;0XOrQQTS zM76?n{P`q8xCPiyTmU{t#&ZEc@mPV~w1JZz8XNmnJUzvrHvy8jV%s%2;UJ2I~ z)ih%v4u&AST|-QmW)BCtEs#(Ga9#-aj(|KON;I>s`>3!dTTR(BdAc!2fc^9~cX()I z1gemhh$+yZ$ACFmK>#tpnqe$p$K3!(526VKU_ywt6GXt8-Ofvdjz}61AS!SXG9SVz zBVRr1+cawc8aZNUJp!GDh;)EC3X>-9!OAS`_wuj6kDw1@XklI`72Dnws26=c{gpwl zJ&|@HBw~Ur8HPW`PUPeT61(H}|f z=dVI$FN;Vp$Z2UMKvM67y^{wW3JQL2NY>D{(&moO5&VQ350XGp5h@&|g$A5XSnKR6 z^#WU8sSs1|+j+rtCZ3qEv zxJ3mKcyWpQ6BFNJxyJ}k1X-kgP4g4PvNmJ* z)mu)%Xv=V5iBQ8iRJ@@F1@cZ9@)-ejS6g3uxfl+MgcP}Ky!hZ81sb7rIcgv(nbtI8 zPV_+-mImj2M{kdY5TQkz6Fds7R>ukS!vN>(t{|VGfgZEfv120 z^mM;L38~;r_iM@VMx)CzWpi=|Fx86`p|53ql@yf}Mt;ZFp{kegmu+JusHO z;j$6p>7YOJOl#9H)*r~NyYM;6W-Ew;&QK%xzn0-r%pA6}IH-vch#jCh34ePR{nDjk zAXl03?pw&w=nxoHcrc>{QSapwfEfmj1(eP0U0=;!OE_c+;GZBAtd@cnSYeG?dqqeT zYnnH0LF@Y@9HB=OA-*=88zrZznhkND22eu8K?RF|RWI+*6EO=}jEab$h9A*rNi=91 zs9Oq>6ocBd#KXpRVNvvDz5pn1rZ_S#R|EGYsrCUAv3D}Qv|N!@fH>BwQ;a~9z{KIR z$CVH7-0Fl^69GxT3eZUa`uLUE?aWpWD$ZLt`F#YSoW9jnHD}H)l)2D!ob$Hzr7cT= z#~>^hfTV!-KVQ71fPgj<7ay{-u*d`5NfyzxW}o}Q==&m+u-L`--dRf~u$e@LMnt3| zh!tiyW-w6|2Ba7dJr0t^3lN4_C~^Mye3Cw+xq2~F0!?gt*tmQT6pnN@hJRMrUvyJO z&f{`J3yM{PtBXqjKQt=~z`0*&gRp)&*cUz>qKFkp&n@b+LiB=(TyAe**G@Aay*151 z5Jx+R9+YrX8@8n5^!yF-xJXqMTLm~z^!8gUA)~m(mBmF?@jZBkcHv3$ ziL$le2My3}CYha^Yf^dwl6NktX03abc-YaVnB|Mg$$ZFtglG3b4~wX9gr&Wc%ta<7 z`@}0u;04Yi#MpX}{UeSr5eHtte?$_*od3#cdwd8?Bm~n0B<|k22^yGH?R3CMR|!<( z=79WxsNt#5MY0M}mH9$i1)Bm9S|Et6&;e)2>io+didO(ffvi5#hl=M1B=9dlJcOEu z$hjYDY!9HoL!zU{rTYmrK(pb$K1Bz@212p`H4F@)B&Y!3&_F%K=Y=M~HzXlLHoB@A z5Sf9LlnBvK{qTnvrVmJrb$@RGlPh0If|G!6zQVXX20A%FrSO?Hw>VUZNd>7Gq05Pq zeI^rof{kqh;%f%^(|?-;Eo2Nhty`1rkn#Tpe~2I7%|<4Mfe@V$40Yku;&{?0f$cCE z8IfMdW3fZs5K$`%Kqx3vQ&YA+lxd9<-Y-_s2Lf{!DayQfN|-7o;Gi| zJW>iGfBLl;1arQVKerKx8HjbispSjHh6~cf>ZvY+8vX}Vd!s|n7zE*H30l-%%Rc!g zOj=%E4%CdY77`GS?)N;0t@sl}C`8nlouB_w2V{SxP=pEz!gS>aTLBYJX!u0XR^bIg z?hkdkZUj*$i0CDhUV`<(mLa+&p(24B)PDOFFOf*PTruQMAme{uzRwc~qW23BO6xRt zw8NamLLtC}t>HXn%5DSiW*<^^+X4xxhY78MW&CSD{T&7*+zr96=`W+ z;3k3*YYPtOn+lx|T~~nGeiWT*6W~3^^qC06sGg7j-=lD}3v523*}b+M;mq&T_ZwlH zgXiF;1{A=FE8nyJL)J(4Z}@Hhf@YY>gJkVbQC-QngR{;nmy!+K-h;m(wmCkEwTS{=h)i*)VKu zR@T$l{$Hh;=$l07;mokfZQ9TPb%9I+p}}P_%&zf3P!~2xL&`22PS5 z#n*?_4N)EK5Z4qfn?c88{epPOn)S}*PU^rsf!5&+j7va7Jll0MpROtI=n}?Dz+~lB zHdJB9LR90~ahn@g?jr;o1hfbaeVkPrZuX%Fj}n-IaZ@C`sD95b7myReb`i@VAW^2O zv$N|6qp$&m1N0e&sN8<7%t62Q1>nCx3~I%-ejn-9oeOv9l!gL%(CAm_GZ<Jki=_xJMdqcogP z@7#!qe-F_MNF%M_+otA^O&-o!;smvOb}cn6?Ecw5h3W?Y%!kZ?rc^`xz#Gcw5I_9a z^^iC!!5LlUEAaet@}p0$Qq)glv+i^EkL5olBZFoSnuu`mkKIpcOO)CSnNuZ{)YlH3 z>7G9P$9570VkP_~tix;Ev<)=m?RRuftv*k9oxLHo%d@GLix4!gjD;2g&=MnL0IJGK z0NDt8j>6t~o!95r^TnJD1|+J59)W=UsMdJ)gbZgruD$!{JzMPC+@W73NH)xK95^T! zDr&+2I?_e7ClndzLbr)VjV)k3KU7Z2i^W69K68*faHGSmO}{ifa04cidp7o^_KPC{59nl~ATCnL5&<>e_$er-gg$j_v zb*>yG!Wj;Q=3dRuUHSOkJwCpLpJ9RYsfqiNkx2Te5fhHBN;d_RZlU4>(Gr~!K9VPL z{d3tFKv^l}ve~&q8&47R4%mD-Yad`^_yngkSd(6Q)3fmz07?)P%=~k5(()Mv_}>JoJmEXifLPm<_tra+QRYa*K@g4*vD5 zAtTpnBE6y)Qz`eGED>*ttIL{)AM-JbO>%gI6de#*C$x zDDUoWb@OALj-UbDZ%IjyfR!V>P}TI9q?mKtlB}5FX)~7pqd;266f52koZoNn7`*VJ z#UXM0emuHSwy3W+n4a{I%jtA+d8t2L0vj}1h`6w!1f34b#_FLnI5vRbqC?mFZ47#) z!_gP)D>40W%y!|}JQo{~tu&*CP7TPEpjM&>`4yyj^2*9lYDe&AWkX~Q_dPpl${D2m z)q5;!WjK1cU!~hJ!kCPPR)=Z2jj`ZI1XP_wByqi3fMyt#mRiJvu)Nnw65p5JbS31; zX^#*YF0pjrm7%KDupHd08KX$>ShQ9uyt<6(f*;DFZF}`Tp`p>fPpYe&W@}afm*05^ zRfsP6zs*NXL)NJ`e>x|;qpW5Ba*nFM>NDe0N&;m|5oq~ja)oKs?{O@sBp2^50so2F zjGdWf6N)Gy(ed#r%q;QL*tB)5s*`!0`u!W;p=?kDYP2ru#8XqPUVJ|cqt`mi zeq^17^_FyjJ4p-aEKf4#G#7(f?z2%cas2o;%~yE=VXq2u^fdP4-1Qul)lu0kn)ll9mGSj)@61#CyrfNvm)sE-z)06L? zc>2k~?QKRU9y|$N>}OAJSMpm;0+&Vz<2V)CWFv+u8eiOLdN7mZ|Nf14*FEXP&t3TK zTVFB!h-$8XmH2E*LY*plaoO%UV*@QztQHp+`(X1sLu3iz^ICuEy%IX&y?=!l8)N3; z!mO-6P-j8ZXicxSdBnxtbuIK1b8^)ZTHh3Oyu$X3siC`hP7!oocJ4JFHNsL%y4aAfV|n6bx(=y472=~hk#aTNoR z6H)C2Q3cU{;67FnFr8kTHKr`4;mNS&tSVRlo!^=w8PXK;xfBwG%_r52z1Zgs=)B1ELXnuY~z%Yg*7w z3U#>r+>c!pO|Lx0H0)-s^j9g$4`IV&dTjRbaWsV$NR{+zsFAvRCWA)(xtL-#ij=A5 zo)1`)-G(X83oN~0(^C?VL&J8Eu$4E7--6R6M&KVbAxoi@DiWrt5S+mGI3mxynrEvp zer1h@CB{l(OO1jGrDk~y_5t)__O%tTS(pA-mzy@)5 z$8@adQ(=QrG?pya%VaOeOgkT#p7` zMX2Scyn9Vle}16-H`~Ax)F_17B+a!H&U&qk5Cn=jO?9q8CEXjs^w3|CsqM>Bj2kA8 zWnrN|D38Vb+Ve)M7B_6FT5U>N;fH8AMrIU76yxsb+R`L9I{wixMnLP@Y$f_2aZDrJ zCm6~2mj&`3M>Q0gUpfoSy>M1-4xW-kn*4T9gag-)SM{0trghSusoo@u<0aYUJa>H! z_brZ`Z*Lyn8Qa<|oy7lBdr9P;W0OqvK-HdSp|I++ufgv$tp<0qr$N0dAD}v1CtnvH zFzX@nY%_cRzst+4IbCeKbQ|GpRg|>TL0Sw2NBH*$UaSr zx`w#yuXJ81uSOK6I9!HOYWMm1=L8mvq!;DV{4VHhkyFE6IcH|WxA(g5y|B2fYq?J! z<^;vtclD!R5CXnEn%Jf?bb&!Rt+VCR%kS34jK8-+$uUl(JF)%thJRdMm`PAeRO~D# zUSCiG?cFTw_zdcuJwk95;&r9EKhp7^yeSkUeKmZ$n@_zms+u4F$h9i5x1itWh{9k| zrJgL!?3vkFjufm4*xbYT?)sSzGQ0P_$3k(m|wkHdcXF&-u0bg zI}l`lLAo|Wu`^ySLByW#IjfPWz4!?Avc~@=m&_ZOPvBti4SiI|an}=PblQ>@gjVC4 zW`y`3vljfVzM|r(kSxrb_||(o^djdS+KNNZvOzWOL2+yc24y|r#MOJwejTl?Kl}CN zu0Jw;rW0E1)*+KJJNg0Y4e3*87IGlJ&d$;ntq5ST*+S{*cyAdQVXl8$qX)@~%O`mL zzR&mu>f80BUAKU*0c_IjBb-!LXTgdX&oeWnW*c&H9^g7Qq6x4FSR5Rh0~J6vC%W^m>QDK z)&XaWTK!Vx^yCGl=yF@=vU8|!F-0%v?aryKoKHKJTB8Y6dQyfhHD9wgaMz=!)~;Az z#hS>?n!U@~nW^5d*maea?P@cooK@mcITLiEq4)?^|CUV(kGpc|C*IV+yhTTpXlJuM zJQu=fr2MQm>$-5R&+*kic>IYux6F~)C6f90z~ZBI5I>tG?kmPzzvOCrbE2^@78{nV zhu+b9yQ5}!7QiKsI_g}JSwWqfG`=^vK4n_CU!;P)XO z0?V&2onF@GHo#UMOZ6x{&gLmJ8Mns%yINw}y`c&Kd z&79IWFJ-TWZ2>{pXJ~yTK(IP0%*gl-7XgQWasxX z3KldKm4wn6L*BC!WUDA;hf>xvA1(fo^Q|=-r4(-B=v;3`qqF;K_&Z*fwcro3h+OI# zkDxZZuACgrF3|@RDbt+krybMU&<`I0HbD2D3xN-w8;!T09OoFToV{Qo3OY75! zdUQ84KdVR1D&LGwH>HbXxmwMaM;h;qZ0+A2-#ChsL}0wruV(N$i>{c`|iu>ZsD4D-+ak_ zN;s5hN%SL5Aq&3N2LkygIdY?%_p*=f$zvHE=4ayP#%Es+VsXEq6&9qSmPKL-_4FMf z9xbC$)S(Do6g_^bDou2~IFxk=K|+AIK(10cgKvqEoG=d zKCvl9+?6nkR0S?9V+||3p|x9nvTH2#7`Pp;_w$6QxgPMTNco-PF1K*2hT*JfQc?=% za;%Y;#k80h;(hz%ue456`&F zR8#b-=7#Lxidvj06W;{YAmXOd^54;WNU8Uv|DsWbY?8Te!nGut5F<_@&G|HjkR*14 zGiJXxq0z}T}S^gW`2FL?uJE5 zN^`s0HF=r}Wdg(J)W;)Xq0GTX+9Ydtk;7^_Zm=x;qrAfqX?W@4D5bQdLn(4(>U>C+K=&Ncc%DlBi58*rY_wx zal3tZxwDUBC)B%T^Fa?|P%sV)*;LXVV-8v9hR@X8{bHnuZqzXQk8fE=vNA;_hLpP@ zi554^Rg#uUHCE%`A(S<{#f7BF z!ndkXqO2zBRypy0x+wE^yI#`xQG?Iqub4NV zC#Obv2{M(r)}6jK+q{36DU>6F_OX%#}yC$Ofp+&|)t~xm(WM^ZTq%8n)5=@zI z4t3SMBv=bxh5Ar#(K=q@jrE}%-6mU88~((s?h>TZyky^2NA(Yo6MJ8Y^!~2S>JOKdkHXJ>UE>4 z{g5g_GGk_vC_BrMpEOK+6P?evPeUDYAr|VTp)TVtx!z@=T$-$?Rq0N{c0;6ugz`}U zhU9OpEz!uqv#lpT$CK2F)o!2@ib4^qTq z4ByCM&!B9)2(R=;-suvxrZ`@{cVSCfO4(?tQJjIfLDbT7AJ6WTd2oD;Jfz^Nx;u$4 zS*8wm5&_M^geELnF6naH?=W~(>aEra=6%ZL&-dhPnmE!&(jNs7I>q{6-4_|4)r!aw zEyY2TTrprLb0&F}vX^vaXPVK%&OX>NDELof2XM!{RIXC8qDiahkU(yTVvd3n#=^_{ z@$t{cfzeCC$}ngx#j4W6YFrp^}Y;&W~98{hgO=;Vu_9 zaM+9s)_lwpZ99;w zk7s@~;@@zP+?iI*n|>#eJvnMP{fCa0zpLlZIUeQgXpP(k`TO~#ge_)4a}lnT(Mr-C}yv%PE3yS zw~Q52&KSlEqjG3Eo>U*AT}f7K2eMc=ePOI@Q@Q?J{Zim5yj$+?3+BcAl>hFvn`>1k zobz3>vqhDvjy%g%KnO85haCBjO}?Uly-~{784%g1I`U*x)lwZ@JUYI1Ar0eGYp>gp zz!_#+sgic}uy#6Cc0zUG{iM%t5Hu>|&GD16HW#ml(Jh6$!GwL9UYNqIEKn=|%;)(y zyL)8p&7W&r_UuYL(HFa;7pn)%KOCa$V>h!}mh{Yo=;7Ww{r9HxM|ctbbe`;N{Ps3q zm?w+lm4l@~W9Wwmap>_FU;F#$Tia>HM91dgWJk9$+TJXu~=(~b{9eomV?@sX{`*_6?QVtdS83XE8v0afY1 z*5b{FJ(91Su;__5ZiSFqJ60;LHWd=KQTMkCaSsD^fT7bt!crpB3GT> z3sNF2SFW{f*Y3;0w{w^!MzPttr?of#J<&?6_oA$2NI})y1P;6F1gWbu_TjIE!l;Y5 z_pEK@#IEC;N+(j~44PLz(uA1OO5<$FbUfA^rMI$|FP=+zw1wVr&`c0LS+f5ngnk@h zvh;@FkeMEXL;YDQ)!*d?wXrGpU`X;HuXB~`9qvqe*+w!!l$ieP;`(Ttr!H_^`sC#J zXl96997dO=o_Tq3@al$b`j7>e#A=iv$4-;G397I^FGfZl z%ka@Dy4{9@VqVo*k!P%WDPB|mJ3jhy;i*_fXN1{!qzzwhs>r}pG?&fFmHzf=Pn?bL zBd`6@s?mcPkn?Q{It|Aba9Dzl}(gi67gBpQknWh&1_v+K*8+s)_Pl zZ-~h{7XJu%In7s)pw7H1&^9r#K$YYFI=3f)?eA2-5}8nA%Ba7;>%LIWeTN!x>jbx`WQ2F z-ni3}! zNX;D*VqA%y)lZj|UEAOq<3}oPoNT5tkyu3-%!a&J9q4doO>j%Ryj(U3?AWxBj4Ic$ zs`>irhtCAuQ>DQEV6iD)tmok`RBD@7W4uXE2=2$r&p_Qmib7ZK?f$P!G&Y;oiOSQ) zBSBub6P)Y1d>;$*>0afT8J5L^_;|M#d1j6ue;IyMwRlS8$bJ%%u~_u38F@U)Rn)Ll zE-#^~Ft05o#S$NKl4N$VG{gO)?k@>z^T9l9tBtgASF!I!T2x1Dxur&fmoyBn!=cn_S19` zzQBKFmi&2_tJ9p&#b|;vgXTWc?$Dp*C<|7Hy&aywz9(P)R&zM~UHv^VW#ZA`gnn#3 z)dAt9m6Oop%DO5x>3~t<9~Y+eOQ7S(JIt*@H~^yG^7BT{r44UHke0 zA8WsRiH;tBz$er#t=`o&C{@Nmyn`ehh^6RFOPL96Bj0?~OZP$|aaV2Ub<>#Lt1A<{ z8)kobZ1Xk|2bKMGu-ID8tPQg6#ph8uT)*ekYs1|xAVb$kE>rI(RJic2D`$LsSfsH~ zQ)eWs&}Mj|vUkk=5p21+01b@mAMCH?Gdow@2^RVfk#7VND4z_Wr%qia_N!x_W?scD z`rm81_!ESj;7;4Y&yTedE7Laaq(JdVwt6j*guqsloW#|qz`Af$S4{y^wql$2*zMzV29VBxjQH<@df zaPrb~M#JvtoP`dKumf*}2Lz{-hk{#Sbc)^{>VzvUGVQ0A?=T#AL$^y2myXm=ejDoS zNQmY+AKq4~Kf9UediwH##~}t=edE-ILvQ}#%-777tLxQ*4X(ZFSjUT+RzYbkP1%-u zdMALuA9a>bITRwTMt!!*d~})%Y@CGplgwNUjj)ha=dfMYtp`)6qoeRA zPHhi|v}Xqmmu|bR)Zga(=6t1h%KM;Ocst=8R~Bw{bC!XupG%)}7dRwZ;`*TFsF|6b z6~=_${ziIqRQCI;iVqF{`oi9wkd2C`8c5Y|5PBodRM^KhUq`wXw0`Rz|JjMavzJwh zk$E|HFffi8zxyGbG-bqhQ``Q%Ug>>b(%f`A>URe9Bd{qeNhMDd^?CxjRBRTQ&0|#? z3(;AZHC@)(r_2~9y7$VwR@5ijz26~HB5Vzq={asr(!YNbxQS#!Y|3&7C zq}~Q$BIk$m*943!_k_IJ(A8A-le{M*@lOtYY~_#Esnv+iOPu=Z9JCA;XYkM4HBVQW zctjFxi(CT(cPyJvhbkh5~^2<_6}NznVzk7qdcI3-4@q?*lkR> zDh?agBhxi;QT$GKHI8T7LgjjsoZz|^_GTt?Pg*W78f&v;kY0>sf{OOpJbCGtbX|Al zLDqThdum)R4 zBO`%(LNky3O4n4dCnsD^j$F=9;g?f>aXfkY-D-*z>{~(Ozucm_)4=D%9LBD3&IP_x z;yXv|>u&4G)Bb`h@!hY7W>b777~BCq;OeB>YpUFq)222myQwnwuVnT{ODRxkc9w7U zgc{UrIexfwaML{Bpgo=c9R2DnBq--W@lA(|EkWDRGQEiiH1(ZUAqF);!C9%tOgv0N za%;UgV>-8lgCdf@=|#)?g}HVX;T~`XIB$2`Qc_h$pUy=@-B?6Q=`u)=fBAI%;(1xj z)$&Fd;ZyzUt-8?>o3U_j!zT%)&xu~;UzB73;pTBmvlNBNR>893gLGxxy zm>+<3;ML-TjVYIoq>l#v`A4iAZTz3az$U z3|LmHEv~v>5BlV;ps=~Ub3qSHN#akw-W5u)oo!G3(f4J8Ks2-eZ+UC!>3NTfqmIXI zh@5)D?%|DFx3e`fgvp$q*SV7kC3mx*te-~XkYqFLUlFOPNy$=(RlU93*Xj|1ua?;% z{u5&tJ6^Yr*C{iWdAf-nFWk%#rL^xYRXf%{-d<92D}lGKB?dq0<{IC=rFDs{4x!UE zUfIO!psX_$p~s9PmAe8Ov|zDh*Gl@IZhIUk{)ljmeJx`A{S!HO4$1Q9_UWFUGCo{- zB_HNUJ!x|3J$gYK0Rl#P2?r}KzGpXy%@7MxkVUmz-iBsxdsJLk7wnbSM-*ta@y-AF zY!Ig=1Hqd6-evI%g*ue->tnV~QEIAvL*aPrpT+~|Ryzx@@24_p)p_YmSaz&g6{Lb_ zz8z?DJK1@spSJVso4v0wmG!bJ)8xdx+2jtTk0nwn`-i7rGv(j2@0A7x?rnxVEr?a} zALP79wQ)W`^`aigq{tS7a5e%ju({MSOcJ97kke%&tCi2r%V zF9(mQmzAMn_7B0`zR73wn$-QJ*jajevEE6b)a892;b}kb!8V_}OOc=mh_#@6(&q{)@qYPwYx78NSHvW9gAjH1_Z_;5Q65?pzU9N9g1 zT$s`8YlHYJZFd9cU8?I+zIfDM%xgzMOs7@xmhRHY{vbX&^Dpl~EN6ooOGjaY@lt^a z>UWe(2dI8f~}@f8wHOZ&J8 zmioM$i^21IZFN&A80Zx7k;gJwwtARFw3Jw=RIoZ!&A%K1`X4QUFu+rb0JPVGl=n!hsM#OeC-%c+K>hT&gRw4AX`$4_ zJNz5az_!=vi=pMl+lDat>gH8jathWT&=+$DGco+L)!96B`1BA;)~{JyiOt){e!m{M z-NI5_;@Kg5Uqd@x#xxmM&B1rlWt6o>u7s(jYWrB~lc>3u(Z{IuNfj{c#J#*2W>t2= z@_S-Z5)CD*B;BC-^klscoeqsnsK*bh=LxeowRspnrJ~xF8?cpEV1zW_uyy2onUxls zn(-vUNSYQ|ReP|QL17?BWMX7S;u-a0QPE#H;+!_V6eQ^$E)Z#Gy$D0+aXvk%>ABby zeVA(!Q@wwPZnJk$NI?wIAgy(_kJ9e@TPYRU zuFpagorba_*sSc)Z_Kxf~fE=%PQ@qcZ0_Xs>^e z-R<&{#n$mO;t{(%(9*re2gLI9Dda)w^ek0XW-oG&ktAFco2`Awg~*Y zr>VYb3!Srnn{QLX%(B05seSkFo|9Aldl3U-{t3mdck~)$y55y)HIDV!o^~QZ`;##g zL{~{Zs8aE~PR(*NrrV1v#KZmgG63C^Te5m<%(CyQu@O9YvmjPYTt$3$`WSrxUuN%M z?gJ|l39sD(Gm6?)QJ1;V;a-0J`S|d#h%%Y9-*7is?cLbdGA^8L{Oa7X7`eEril;l5 zs28@!vd#-)K#zPSX!q&%S4|G%(;K5Qw0bTg#0_Ke?JOc{W3F}hl^voVo(a4WFV1Rd zF4+^f8tVHUZ_#Y(>KOWMvkhS_4qY`t@V>$HWQDlK8b+c6v_p`yuj@_UXlBl7Je z_I&FZdjj`RH|QDs_0G@3HlJ!5nXW+mzUoKrCrX{ei^fj4F<)G7cY=W-CZsK-hf5fO z14qaS-1tNPX$5S~Q+Yui;rPfUEN|YD%SW{}u8tp&^=r0<4v(?Wzwj~CiT>1LG>AuBQ|2lzZq7ykYlf@Wri1rP~xR_rUR#Z4S{hhvquSX^$ zhiH7IXIUE5ilt~$dX+}grAnLNRWY~_Xw>ekSi0KwYBc?q)9o}tZ`a)3T z@Cl*E*{de#mmXx=WPifN##<{ipDl&)m2sdrFUO++_Ylw7lSWx9#o#pVO4sH5akRxt zTm$9!Zz)ad0T{hMNOxm7LNE4~$YxJ9;*QZfcz4mC-g+D%a>ePG*qtL9)sU*RyuwJa z_OLld3gc;*5Am!)TN3fRu zO9}d?>joa&jh6pIFl2k+O4HCtEUcu+u*YeL_J*nq=icFt!Y9v{H(?LKdV@u#;GwH_ zpCw)MBR51Ag0Jc}xxzGZFA0R3+a<=sC$0qsJm!1j#2^|(WLngq1UaoP2X4*b%&2^> z_WrGY*PX7e_>Otl^U6HN1cHh@8*P&I&6?Eq>V;wSwsaT45f~u#e%3dy*6y?_B7{vX zPt;#PT=w2pX6a)s(g>@aw)ndKDY3!&O3N(9FI_@*C^B~ z7u+y6BTuJM=g&YNLSEpyBtV) zFQrU0H@L9k`684Go8q$7OqbXZBgdagBa%N(;(Ml&P1oSlo{e>35%VKtsj$pCTvg8 z#tN#v86YZ7C@v{!*|pY=R-N&9CB?{dsOdYdf2ev&v4HeaaE5%=UQ}Pa*nTS1S(G0u zsoUnr;v=HCwKC!*ws}{Zm52NMWP-;fT6q!Sx|A&%_S7vxpGm67iV+PlUMZ|_VYLg& z)}$iym1^^7slQ-}dNX<^aIyS~G)TAY1qf^JMe@5x6TUE6!~_b`KPbG~SbNDNfT*26eZEfT2U8~X;N4B`? zQGD`FYU+Ary8CJx$=u0`)`Hz(kAIXA*LFqy5yj^kcJDSc@5E_~Ha+}?TExt>CM^c5 zcFn5ybhNZd8&@(38$FM_kb9Db_Z%MT@4~P65#CIb)-q<0TyGD!jSA6_Nh);Z*xKgX zA^s^mCWGaCAfn=DsfqdD1f%;+zy3#o5c7W&2(@qhj{>3Odl)7I-{rp#FJ#Go17P5} z5Fal-!F9v`|5NY}C|>+G6XCzlHr@FjRmtx^eWW(Yg}7oTpMOg&JynJ1OqEum%2Fu3 z6jP)zjqJBwlh+8oOhSZp=zuDBl+$}JbdbqeAX zS|Y;yqqj@qbIqPezm|X2G{VmKZqj+IZ=T%WXQIX#W*xVu*Zugx#}LgCl{DL{80N2{ zvZ$+F>?=fWu3xof*p{v^C-6w7gJ2W2D08xR#+<*_#dFhe-@4a;ui0WW54X}<8OEH{ zAG;GpjdzzYqYszlWQa3vx%D4b}1d^?MIS8JLUe)S8!U?C5ew=8C?soO{n#DQizYk48u9GUZCr zws4Ds16K@Y&Zgc7-k?B&wD{)DiHQls3@FEy{K~Ov7wp|P7?rKvl0lx)Xb)M`mGo;i zB^}18N~5WZW2h^>|870HZiU>zR%F5U%{=Qp64pCStanIQeK1&0JWo=sx+zE{uo>rK zHVPKtY8rl}xK?EE$^u;1ox6l-lRMkfLnEW4v=8(>6U3x>u-IAT%_wM0^(lDrBrD!g zl}AH^CpBv9JeKM>XbnAR!#rpUE%W|>_z=-4^U^764=wXavGpc_g2S}2 zUL*OwYLz20%x7TXn6kXh9dE8)S)88k9i{2)2je#^PyXCA4kBtLM!ET(eU-ZS9d)HD z71IVa6F%ZE6){xhG4R7#Mx#_o2~SbnW(d0(FWgcXoTwsB5gdGpAzWkh9U(G4@#OLh%m(CZPQ3Ng^PGN5wz&+Wv0C0B6%OapfE zH=lQgbi^`)_cDXw`Uuo_nutUDHtgu?bcwq7kF2)q_N8HLVTn!s8mwXy4odVG`jen` z#IzBZyU5DQ+V@sVrnz4YFDAyXMW^}{g`1Gvo;IDGMeivox&CdU(#Mq@U%Cu`nz5&O z7|{G2?<^83Y|bN|?L0rFNeJ~z*S$bS_8<{^_I$2a;oxGod*=;?7O$9tdJ0Qq8Vg1{ zejrK5rBuY05-m%nGV?;pcy}BdV&s=KOf@Kl+whVZHV%#CcmdXbe%^$8!bWCh>Gk#T z3-s-VCS20*T=3&(62c;_Vx*p^^g#Uc1n2Nc%mE0jycDELoO# zq|(wbm`*l0Fd(3;j16Nc9qTn~xF^<3E!rms1syDiJ0D4%Y*COhlp;rsf9c9<*Xvtg zHnfUH8AEaYrbcfb_86XUI;q{bPkR8BP0Dvt_tk9`RA)&N9&Q7HjwjSY&!5vqJIXlB z{-q?tp!PPTadRbG>Sk4a9>b+?-QgnM7$r$8_{lN!6|c1Q7jp^yu#nIul1|!AY6kk$ zw6bs*0|p~OsOahSV1hYVEA7h3-o}L0(fHIXk;Dv_zaRWe-{wvw3mqc2%^ zQfaQf#GLcs$RfXajw2>>jKu2bsaAJ$bu;X~$i2j`68l@%CStS~ zxkTjqa<$%m9)!vxJ(}frDGF0tH8eD;J1ra>IN(*<+S&C_kNXuCMtz)>d4|(Md>jhqR~>I;3EDm2gM4i2Mw%t<{{)Dp@*zJ(}hD}-lk zLf${`6Lu*mTttuR36Xzav!$YbFeix-7LG*{ebty8E+8k1ESjy3K`coYqU-(2^u$e@ zE!L_wt}0G?iU{3Y<|etG9t;AOQ&JL!(TIA{*AfyE?fFiZjuI4Mu-*W&u;#C?udkkk z-wqCsFdiWNJwE;Nrs)j~fS!Bt$L{wJx~Pmrsx-Oe$^ zN<{wt94ApQZg(DT6Dw411t5P z;K%W~i7ktwMsL6H=c_gt#w{G~eqBbnMcUc#z5ZQmHinTo84Dgs5IS=GsSB1<5a_u2 zARwpE6#apODm_>+c=2k1B0N}>`aviiru5>h!?bz14l9mjZQOTB3blFCz130t5erYzSl%)#QJHW_#>2yl-Y@OX=0Mn56Gc18|XrX@iy zxf~8WcMrUDf12HV`G7!?sSXAfIX^Wc)kHdbcJ%t~=AB#iLySdlIdBsubH;~?I}90H ztzu^G|60Y&H=Ubd_g&y_+9PkvzK4I4;R9|u)|<`^JXrZ=j$FvY;@x+F`;Q-Xi39Jt zehfTOnW>Qhcw`mu3~Cc8;1Ni|-A6rCgn*mPC!JK8=+Oc^c|t?PX<91quS_N#)j6i4kEe9Sez36IIVd|qRk3TX1cRB+1$^ti}0*@uh+b#{I(EkS$ z48rYC)O}AszZZBMONdtM{rB#ZmN>3wWcgFOa|RzPGceB9SXQrLa9M09bn@ZmqR45S zZHtuiR{JeK`cmSjF>sOX&d;09rX9`j**<6Ut(+M?FT0D=Hj8$f?w$9h@(%D|?MFJ% z_Q2h_z}ShgJp?>^yTl5z3H0-#sgpsC={k$m$m{4h(x>gXq77~ogPX<#+SFAEe|O&F gfVHYYMf2JJOm?~dp8DjP3NrwKr>mdKI;Vst0PjL?0RR91 literal 0 HcmV?d00001 From 295581f233de4ac4ca0b77a86dc9458f49d97e16 Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 15:52:17 +0900 Subject: [PATCH 04/25] feat :: BaseViewModel --- .../BaseFeature/Sources/BaseViewModel.swift | 33 +++++++++++++++++++ .../BaseFeature/Sources/Feature.swift | 1 - .../ErrorModule/Sources/DMSError.swift | 12 +++++++ Projects/Modules/Utility/Project.swift | 3 +- 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 Projects/Features/BaseFeature/Sources/BaseViewModel.swift delete mode 100644 Projects/Features/BaseFeature/Sources/Feature.swift diff --git a/Projects/Features/BaseFeature/Sources/BaseViewModel.swift b/Projects/Features/BaseFeature/Sources/BaseViewModel.swift new file mode 100644 index 00000000..e534509a --- /dev/null +++ b/Projects/Features/BaseFeature/Sources/BaseViewModel.swift @@ -0,0 +1,33 @@ +import Combine +import ErrorModule + +open class BaseViewModel: ObservableObject { + @Published public var isErrorOcuured = false + @Published public var isLoading = false + @Published public var errorMessage = "" + + public var bag = Set() + + public init() {} + + public func addCancellable( + _ publisher: AnyPublisher, + onReceiveValue: @escaping (T) -> Void, + onReceiveError: ((DMSError) -> Void)? = nil + ) { + isLoading = true + publisher + .sink(receiveCompletion: { [weak self] completion in + if case let .failure(error) = completion { + if let onReceiveError { + onReceiveError(error.asDMSError) + } + + self?.errorMessage = error.localizedDescription + self?.isErrorOcuured = true + } + self?.isLoading = false + }, receiveValue: onReceiveValue) + .store(in: &bag) + } +} diff --git a/Projects/Features/BaseFeature/Sources/Feature.swift b/Projects/Features/BaseFeature/Sources/Feature.swift deleted file mode 100644 index 7d846fc7..00000000 --- a/Projects/Features/BaseFeature/Sources/Feature.swift +++ /dev/null @@ -1 +0,0 @@ -// this is for tuist diff --git a/Projects/Modules/ErrorModule/Sources/DMSError.swift b/Projects/Modules/ErrorModule/Sources/DMSError.swift index 1b42c920..6fef0d8a 100644 --- a/Projects/Modules/ErrorModule/Sources/DMSError.swift +++ b/Projects/Modules/ErrorModule/Sources/DMSError.swift @@ -5,6 +5,18 @@ public enum DMSError: Error { case custom(message: String, code: Int) } +extension DMSError: LocalizedError { + public var errorDescription: String? { + switch self { + case .unknown: + return "알 수 없는 오류가 발생하였습니다" + + case let .custom(message, _): + return message + } + } +} + public extension Error { var asDMSError: DMSError { self as? DMSError ?? .unknown diff --git a/Projects/Modules/Utility/Project.swift b/Projects/Modules/Utility/Project.swift index 78482080..ed4ea86d 100644 --- a/Projects/Modules/Utility/Project.swift +++ b/Projects/Modules/Utility/Project.swift @@ -5,6 +5,7 @@ let project = Project.makeModule( name: "Utility", product: .staticFramework, dependencies: [ - .Project.Module.ThirdPartyLib + .Project.Module.ThirdPartyLib, + .Project.Module.ErrorModule ] ) From 62f9c35889140f030d5cc14f0f7326a71e395f69 Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 15:57:11 +0900 Subject: [PATCH 05/25] feat :: Keycahin --- .../KeychainModule/Sources/Feature.swift | 1 - .../KeychainModule/Sources/Keychain.swift | 11 +++++ .../KeychainModule/Sources/KeychainImpl.swift | 44 +++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) delete mode 100644 Projects/Modules/KeychainModule/Sources/Feature.swift create mode 100644 Projects/Modules/KeychainModule/Sources/Keychain.swift create mode 100644 Projects/Modules/KeychainModule/Sources/KeychainImpl.swift diff --git a/Projects/Modules/KeychainModule/Sources/Feature.swift b/Projects/Modules/KeychainModule/Sources/Feature.swift deleted file mode 100644 index 8d35d5c8..00000000 --- a/Projects/Modules/KeychainModule/Sources/Feature.swift +++ /dev/null @@ -1 +0,0 @@ -// This is for the feature diff --git a/Projects/Modules/KeychainModule/Sources/Keychain.swift b/Projects/Modules/KeychainModule/Sources/Keychain.swift new file mode 100644 index 00000000..5b6589af --- /dev/null +++ b/Projects/Modules/KeychainModule/Sources/Keychain.swift @@ -0,0 +1,11 @@ +public enum KeychainType: String { + case accessToken = "ACCESS-TOKEN" + case refreshToken = "REFRESH-TOKEN" + case expiredAt = "EXPIRED-AT" +} + +public protocol Keychain { + func save(type: KeychainType, value: String) + func load(type: KeychainType) -> String + func delete(type: KeychainType) +} diff --git a/Projects/Modules/KeychainModule/Sources/KeychainImpl.swift b/Projects/Modules/KeychainModule/Sources/KeychainImpl.swift new file mode 100644 index 00000000..ea2bf918 --- /dev/null +++ b/Projects/Modules/KeychainModule/Sources/KeychainImpl.swift @@ -0,0 +1,44 @@ +import Foundation + +public struct KeychainImpl: Keychain { + public init() {} + + private let service: String = Bundle.main.bundleIdentifier ?? "" + + public func save(type: KeychainType, value: String) { + let query: NSDictionary = [ + kSecClass: kSecClassGenericPassword, + kSecAttrService: service, + kSecAttrAccount: type.rawValue, + kSecValueData: value.data(using: .utf8, allowLossyConversion: false) ?? .init() + ] + SecItemDelete(query) + SecItemAdd(query, nil) + } + + public func load(type: KeychainType) -> String { + let query: NSDictionary = [ + kSecClass: kSecClassGenericPassword, + kSecAttrService: service, + kSecAttrAccount: type.rawValue, + kSecReturnData: kCFBooleanTrue!, + kSecMatchLimit: kSecMatchLimitOne + ] + var dataTypeRef: AnyObject? + let status = withUnsafeMutablePointer(to: &dataTypeRef) { SecItemCopyMatching(query, UnsafeMutablePointer($0)) } + if status == errSecSuccess { + guard let data = dataTypeRef as? Data else { return "" } + return String(data: data, encoding: .utf8) ?? "" + } + return "" + } + + public func delete(type: KeychainType) { + let query: NSDictionary = [ + kSecClass: kSecClassGenericPassword, + kSecAttrService: service, + kSecAttrAccount: type.rawValue + ] + SecItemDelete(query) + } +} From c0fea0103752c9cb5d5c832ea8f33f8f7af1f273 Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 15:59:58 +0900 Subject: [PATCH 06/25] feat :: Keychain Fake double --- .../KeychainModule/Sources/KeychainFake.swift | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Projects/Modules/KeychainModule/Sources/KeychainFake.swift diff --git a/Projects/Modules/KeychainModule/Sources/KeychainFake.swift b/Projects/Modules/KeychainModule/Sources/KeychainFake.swift new file mode 100644 index 00000000..cda52e1f --- /dev/null +++ b/Projects/Modules/KeychainModule/Sources/KeychainFake.swift @@ -0,0 +1,17 @@ +import Foundation + +final class KeychainFake: Keychain { + var store: [String: String] = [:] + + func save(type: KeychainType, value: String) { + store[type.rawValue] = value + } + + func load(type: KeychainType) -> String { + store[type.rawValue] ?? "" + } + + func delete(type: KeychainType) { + store[type.rawValue] = nil + } +} From 4ccc9266619d0aa843adfc5f54c385146a679357 Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 16:09:13 +0900 Subject: [PATCH 07/25] feat :: JwtPlugin --- .../Dependency+SPM.swift | 2 + Projects/Services/APIKit/Project.swift | 5 +- Projects/Services/APIKit/Sources/API.swift | 1 - Projects/Services/APIKit/Sources/DmsAPI.swift | 6 ++ .../Sources/Plugins/Jwt/JwtAuthorizable.swift | 11 ++++ .../Sources/Plugins/Jwt/JwtPlugin.swift | 60 +++++++++++++++++++ .../APIKit/Sources/Plugins/Jwt/TokenDTO.swift | 13 ++++ Tuist/Dependencies.swift | 3 +- 8 files changed, 98 insertions(+), 3 deletions(-) delete mode 100644 Projects/Services/APIKit/Sources/API.swift create mode 100644 Projects/Services/APIKit/Sources/DmsAPI.swift create mode 100644 Projects/Services/APIKit/Sources/Plugins/Jwt/JwtAuthorizable.swift create mode 100644 Projects/Services/APIKit/Sources/Plugins/Jwt/JwtPlugin.swift create mode 100644 Projects/Services/APIKit/Sources/Plugins/Jwt/TokenDTO.swift diff --git a/Plugin/UtilityPlugin/ProjectDescriptionHelpers/Dependency+SPM.swift b/Plugin/UtilityPlugin/ProjectDescriptionHelpers/Dependency+SPM.swift index 36f555f9..3c2711d8 100644 --- a/Plugin/UtilityPlugin/ProjectDescriptionHelpers/Dependency+SPM.swift +++ b/Plugin/UtilityPlugin/ProjectDescriptionHelpers/Dependency+SPM.swift @@ -9,6 +9,8 @@ public extension TargetDependency.SPM { static let Quick = TargetDependency.external(name: "Quick") static let Nimble = TargetDependency.external(name: "Nimble") static let Needle = TargetDependency.external(name: "NeedleFoundation") + static let Moya = TargetDependency.external(name: "Moya") + static let CombineMoya = TargetDependency.external(name: "CombineMoya") } public extension Package { diff --git a/Projects/Services/APIKit/Project.swift b/Projects/Services/APIKit/Project.swift index 6efd2679..ab4ef12f 100644 --- a/Projects/Services/APIKit/Project.swift +++ b/Projects/Services/APIKit/Project.swift @@ -8,6 +8,9 @@ let project = Project.makeModule( .Project.Module.ThirdPartyLib, .Project.Module.KeychainModule, .Project.Module.ErrorModule, - .Project.Service.DataMappingModule + .Project.Service.DataMappingModule, + + .SPM.Moya, + .SPM.CombineMoya ] ) diff --git a/Projects/Services/APIKit/Sources/API.swift b/Projects/Services/APIKit/Sources/API.swift deleted file mode 100644 index 7d846fc7..00000000 --- a/Projects/Services/APIKit/Sources/API.swift +++ /dev/null @@ -1 +0,0 @@ -// this is for tuist diff --git a/Projects/Services/APIKit/Sources/DmsAPI.swift b/Projects/Services/APIKit/Sources/DmsAPI.swift new file mode 100644 index 00000000..4ce7f777 --- /dev/null +++ b/Projects/Services/APIKit/Sources/DmsAPI.swift @@ -0,0 +1,6 @@ +import Foundation +import Moya + +public protocol DmsAPI: TargetType { + +} diff --git a/Projects/Services/APIKit/Sources/Plugins/Jwt/JwtAuthorizable.swift b/Projects/Services/APIKit/Sources/Plugins/Jwt/JwtAuthorizable.swift new file mode 100644 index 00000000..fcdb412a --- /dev/null +++ b/Projects/Services/APIKit/Sources/Plugins/Jwt/JwtAuthorizable.swift @@ -0,0 +1,11 @@ +import Moya + +public enum JwtTokenType: String { + case accessToken = "Authorization" + case refreshToken = "refresh-token" + case none +} + +public protocol JwtAuthorizable { + var jwtTokenType: JwtTokenType { get } +} diff --git a/Projects/Services/APIKit/Sources/Plugins/Jwt/JwtPlugin.swift b/Projects/Services/APIKit/Sources/Plugins/Jwt/JwtPlugin.swift new file mode 100644 index 00000000..0af2a5a1 --- /dev/null +++ b/Projects/Services/APIKit/Sources/Plugins/Jwt/JwtPlugin.swift @@ -0,0 +1,60 @@ +import Moya +import KeychainModule +import Foundation + +public struct JwtPlugin: PluginType { + private let keychain: any Keychain + + public init(keychain: any Keychain) { + self.keychain = keychain + } + + public func prepare( + _ request: URLRequest, + target: TargetType + ) -> URLRequest { + guard let jwtTokenType = (target as? JwtAuthorizable)?.jwtTokenType, + jwtTokenType != .none + else { return request } + var req = request + let token = "Bearer \(getToken(type: jwtTokenType == .accessToken ? .accessToken : .refreshToken))" + + req.addValue(token, forHTTPHeaderField: jwtTokenType.rawValue) + return req + } + + public func didReceive( + _ result: Result, + target: TargetType + ) { + switch result { + case let .success(res): + if let new = try? res.map(TokenDTO.self) { + saveToken(token: new) + } + default: + break + } + } +} + +private extension JwtPlugin { + func getToken(type: KeychainType) -> String { + switch type { + case .accessToken: + return keychain.load(type: .accessToken) + + case .refreshToken: + return keychain.load(type: .refreshToken) + + case .expiredAt: + return keychain.load(type: .expiredAt) + } + } + + func saveToken(token: TokenDTO) { + keychain.save(type: .accessToken, value: token.accessToken) + keychain.save(type: .refreshToken, value: token.refreshToken) + keychain.save(type: .expiredAt, value: token.expiredAt) + } +} diff --git a/Projects/Services/APIKit/Sources/Plugins/Jwt/TokenDTO.swift b/Projects/Services/APIKit/Sources/Plugins/Jwt/TokenDTO.swift new file mode 100644 index 00000000..043e13d1 --- /dev/null +++ b/Projects/Services/APIKit/Sources/Plugins/Jwt/TokenDTO.swift @@ -0,0 +1,13 @@ +import Foundation + +struct TokenDTO: Equatable, Decodable { + let accessToken: String + let refreshToken: String + let expiredAt: String + + enum CodingKeys: String, CodingKey { + case accessToken = "access_token" + case refreshToken = "refresh_token" + case expiredAt = "expired_at" + } +} diff --git a/Tuist/Dependencies.swift b/Tuist/Dependencies.swift index 357e937a..0aeb3c4f 100644 --- a/Tuist/Dependencies.swift +++ b/Tuist/Dependencies.swift @@ -5,7 +5,8 @@ let dependencies = Dependencies( swiftPackageManager: [ .remote(url: "https://github.com/Quick/Quick.git", requirement: .upToNextMajor(from: "5.0.1")), .remote(url: "https://github.com/Quick/Nimble.git", requirement: .upToNextMajor(from: "10.0.0")), - .remote(url: "https://github.com/uber/needle.git", requirement: .upToNextMajor(from: "0.19.0")) + .remote(url: "https://github.com/uber/needle.git", requirement: .upToNextMajor(from: "0.19.0")), + .remote(url: "https://github.com/Moya/Moya.git", requirement: .upToNextMajor(from: "15.0.3")) ], platforms: [.iOS] ) From 28e96f22e705e1963d56f8a54e6cf1713968c97f Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 16:13:10 +0900 Subject: [PATCH 08/25] feat :: DmsAPI --- .../BaseFeature/Sources/BaseViewModel.swift | 2 +- .../{DMSError.swift => DmsError.swift} | 8 ++--- Projects/Services/APIKit/Sources/DmsAPI.swift | 36 +++++++++++++++++-- 3 files changed, 39 insertions(+), 7 deletions(-) rename Projects/Modules/ErrorModule/Sources/{DMSError.swift => DmsError.swift} (72%) diff --git a/Projects/Features/BaseFeature/Sources/BaseViewModel.swift b/Projects/Features/BaseFeature/Sources/BaseViewModel.swift index e534509a..6ec871ff 100644 --- a/Projects/Features/BaseFeature/Sources/BaseViewModel.swift +++ b/Projects/Features/BaseFeature/Sources/BaseViewModel.swift @@ -13,7 +13,7 @@ open class BaseViewModel: ObservableObject { public func addCancellable( _ publisher: AnyPublisher, onReceiveValue: @escaping (T) -> Void, - onReceiveError: ((DMSError) -> Void)? = nil + onReceiveError: ((DmsError) -> Void)? = nil ) { isLoading = true publisher diff --git a/Projects/Modules/ErrorModule/Sources/DMSError.swift b/Projects/Modules/ErrorModule/Sources/DmsError.swift similarity index 72% rename from Projects/Modules/ErrorModule/Sources/DMSError.swift rename to Projects/Modules/ErrorModule/Sources/DmsError.swift index 6fef0d8a..8c59d31b 100644 --- a/Projects/Modules/ErrorModule/Sources/DMSError.swift +++ b/Projects/Modules/ErrorModule/Sources/DmsError.swift @@ -1,11 +1,11 @@ import Foundation -public enum DMSError: Error { +public enum DmsError: Error { case unknown case custom(message: String, code: Int) } -extension DMSError: LocalizedError { +extension DmsError: LocalizedError { public var errorDescription: String? { switch self { case .unknown: @@ -18,7 +18,7 @@ extension DMSError: LocalizedError { } public extension Error { - var asDMSError: DMSError { - self as? DMSError ?? .unknown + var asDMSError: DmsError { + self as? DmsError ?? .unknown } } diff --git a/Projects/Services/APIKit/Sources/DmsAPI.swift b/Projects/Services/APIKit/Sources/DmsAPI.swift index 4ce7f777..b9d535ba 100644 --- a/Projects/Services/APIKit/Sources/DmsAPI.swift +++ b/Projects/Services/APIKit/Sources/DmsAPI.swift @@ -1,6 +1,38 @@ import Foundation import Moya +import ErrorModule -public protocol DmsAPI: TargetType { - +public protocol DmsAPI: TargetType, JwtAuthorizable { + var domain: DmsDomain { get } + var urlPath: String { get } + var errorMap: [Int: DmsError] { get } +} + +public extension DmsAPI { + var baseURL: URL { + URL(string: "https://google.com")! + } + + var path: String { + domain.asURLString + urlPath + } + + var headers: [String: String]? { + ["Content-Type": "application/json"] + } +} + +public enum DmsDomain: String { + case auth + case users + case losts + case notices + case meal + case images +} + +extension DmsDomain { + var asURLString: String { + "/\(self.rawValue)" + } } From 16bcdbceecb4a2ae56eb3ae6ee6d79b123e9326c Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 16:31:12 +0900 Subject: [PATCH 09/25] test :: JwtPluginSpec --- .../Services/APIKit/Tests/JwtPluginSpec.swift | 94 +++++++++++++++++++ .../Services/APIKit/Tests/TargetTest.swift | 17 ---- Projects/Services/APIKit/Tests/TestAPI.swift | 57 +++++++++++ 3 files changed, 151 insertions(+), 17 deletions(-) create mode 100644 Projects/Services/APIKit/Tests/JwtPluginSpec.swift delete mode 100644 Projects/Services/APIKit/Tests/TargetTest.swift create mode 100644 Projects/Services/APIKit/Tests/TestAPI.swift diff --git a/Projects/Services/APIKit/Tests/JwtPluginSpec.swift b/Projects/Services/APIKit/Tests/JwtPluginSpec.swift new file mode 100644 index 00000000..e1796f8f --- /dev/null +++ b/Projects/Services/APIKit/Tests/JwtPluginSpec.swift @@ -0,0 +1,94 @@ +import Quick +import Nimble +import Moya +import Foundation +@testable import APIKit +@testable import KeychainModule + +// swiftlint: disable function_body_length +final class JwtPluginSpec: QuickSpec { + override func spec() { + var keychain: Keychain! + var plugin: JwtPlugin! + var api: MoyaProvider! + + beforeEach { + keychain = KeychainFake() + plugin = JwtPlugin(keychain: keychain) + let customEnpointClosure = { (target: TestAPI) -> Endpoint in + Endpoint( + url: URL(target: target).absoluteString, + sampleResponseClosure: { .networkResponse(200, target.sampleData) }, + method: target.method, + task: target.task, + httpHeaderFields: target.headers + ) + } + api = MoyaProvider( + endpointClosure: customEnpointClosure, + stubClosure: MoyaProvider.immediatelyStub, + plugins: [plugin] + ) + } + + describe("JwtPlugin을 사용하는 API는") { + afterEach { + keychain.delete(type: .accessToken) + keychain.delete(type: .refreshToken) + keychain.delete(type: .expiredAt) + } + context("Response가 TokenDTO의 데이터 타입으로 온다면") { + it("Keychain에 Token을 저장한다") { + api.request(.success) { _ in } + expect(keychain.load(type: .accessToken)).to(equal("access")) + expect(keychain.load(type: .refreshToken)).to(equal("refresh")) + expect(keychain.load(type: .expiredAt)).to(equal("expired")) + } + } + context("Response가 TokenDTO의 데이터 타입으로 오지 않는다면") { + it("Keychain에 아무 데이터도 저장하지 않는다") { + api.request(.failure) { _ in } + expect(keychain.load(type: .accessToken)).to(beEmpty()) + expect(keychain.load(type: .refreshToken)).to(beEmpty()) + expect(keychain.load(type: .expiredAt)).to(beEmpty()) + } + } + context("Enpoint의 JwtAuthorizable인 .accessToken인 API요청을 한다면") { + beforeEach { + keychain.save(type: .accessToken, value: "Access") + } + it("HTTPHeader의 Authorization에, 앞에 Bearer와 함께 AccessToken키체인에 저장된 값이 자동으로 담긴다") { + api.request(.withAccess) { result in + switch result { + case .failure: + fail("요청이 실패함") + + case let .success(res): + expect(res.request?.allHTTPHeaderFields?["Authorization"]).toNot(beNil()) + expect(res.request?.allHTTPHeaderFields?["Authorization"]).to(equal("Bearer Access")) + expect(res.statusCode).to(equal(200)) + } + } + } + } + context("Enpoint의 JwtAuthorizable인 .refreshToken인 API요청을 한다면") { + beforeEach { + keychain.save(type: .refreshToken, value: "Refresh") + } + it("HTTPHeader의 refresh-token에, 앞에 Bearer와 함께 RefreshToken키체인에 저장된 값이 자동으로 담긴다") { + api.request(.withRefresh) { result in + switch result { + case .failure: + fail("요청이 실패함") + + case let .success(res): + expect(res.request?.allHTTPHeaderFields?["refresh-token"]).toNot(beNil()) + expect(res.request?.allHTTPHeaderFields?["refresh-token"]).to(equal("Bearer Refresh")) + expect(res.statusCode).to(equal(200)) + } + } + } + } + } + } +} diff --git a/Projects/Services/APIKit/Tests/TargetTest.swift b/Projects/Services/APIKit/Tests/TargetTest.swift deleted file mode 100644 index b1cf7940..00000000 --- a/Projects/Services/APIKit/Tests/TargetTest.swift +++ /dev/null @@ -1,17 +0,0 @@ -import XCTest - -class TargetTests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() throws { - XCTAssertEqual("A", "A") - } - -} diff --git a/Projects/Services/APIKit/Tests/TestAPI.swift b/Projects/Services/APIKit/Tests/TestAPI.swift new file mode 100644 index 00000000..9f5518ba --- /dev/null +++ b/Projects/Services/APIKit/Tests/TestAPI.swift @@ -0,0 +1,57 @@ +import Moya +import Foundation +import APIKit + +public enum TestAPI: TargetType, JwtAuthorizable { + case success + case failure + case withAccess + case withRefresh + + public var baseURL: URL { URL(string: "localhost")! } + + public var path: String { "/" } + + public var method: Moya.Method { .get } + + public var sampleData: Data { + switch self { + case .success: + return """ +{ + "access_token": "access", + "refresh_token": "refresh", + "expired_at": "expired" +} +""".data(using: .utf8)! + + case .failure: + return """ +{ + "test": "how", + "access_token": "access" +} +""".data(using: .utf8)! + + default: + return .init() + } + } + + public var task: Moya.Task { .requestPlain } + + public var headers: [String: String]? { nil } + + public var jwtTokenType: JwtTokenType { + switch self { + case .withAccess: + return .accessToken + + case .withRefresh: + return .refreshToken + + default: + return .none + } + } +} From 566015c7701b0651334f5b0a0985e20e143210dc Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 16:44:08 +0900 Subject: [PATCH 10/25] feat :: NoResponse --- .../Services/DataMappingModule/Sources/Base/NoResponse.swift | 3 +++ Projects/Services/DataMappingModule/Sources/Feature.swift | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Projects/Services/DataMappingModule/Sources/Base/NoResponse.swift delete mode 100644 Projects/Services/DataMappingModule/Sources/Feature.swift diff --git a/Projects/Services/DataMappingModule/Sources/Base/NoResponse.swift b/Projects/Services/DataMappingModule/Sources/Base/NoResponse.swift new file mode 100644 index 00000000..c9f10c41 --- /dev/null +++ b/Projects/Services/DataMappingModule/Sources/Base/NoResponse.swift @@ -0,0 +1,3 @@ +import Foundation + +public struct NoResponse: Codable {} diff --git a/Projects/Services/DataMappingModule/Sources/Feature.swift b/Projects/Services/DataMappingModule/Sources/Feature.swift deleted file mode 100644 index 8d35d5c8..00000000 --- a/Projects/Services/DataMappingModule/Sources/Feature.swift +++ /dev/null @@ -1 +0,0 @@ -// This is for the feature From 367559be926c66ed6ca26fec3fa576900e57b52a Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 17:02:21 +0900 Subject: [PATCH 11/25] feat :: BaseRemoteDataSource --- .../ErrorModule/Sources/DmsError.swift | 2 +- .../Modules/Utility/Sources/DateUtil.swift | 19 +++++ .../Modules/Utility/Sources/Utility.swift | 1 - .../Sources/Base/BaseRemoteDataSource.swift | 80 +++++++++++++++++++ .../NetworkModule/Sources/Feature.swift | 1 - 5 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 Projects/Modules/Utility/Sources/DateUtil.swift delete mode 100644 Projects/Modules/Utility/Sources/Utility.swift create mode 100644 Projects/Services/NetworkModule/Sources/Base/BaseRemoteDataSource.swift delete mode 100644 Projects/Services/NetworkModule/Sources/Feature.swift diff --git a/Projects/Modules/ErrorModule/Sources/DmsError.swift b/Projects/Modules/ErrorModule/Sources/DmsError.swift index 8c59d31b..bb6af472 100644 --- a/Projects/Modules/ErrorModule/Sources/DmsError.swift +++ b/Projects/Modules/ErrorModule/Sources/DmsError.swift @@ -2,7 +2,7 @@ import Foundation public enum DmsError: Error { case unknown - case custom(message: String, code: Int) + case custom(message: String = "알 수 없는 오류가 발생하였습니다", code: Int = 500) } extension DmsError: LocalizedError { diff --git a/Projects/Modules/Utility/Sources/DateUtil.swift b/Projects/Modules/Utility/Sources/DateUtil.swift new file mode 100644 index 00000000..feba72dc --- /dev/null +++ b/Projects/Modules/Utility/Sources/DateUtil.swift @@ -0,0 +1,19 @@ +import Foundation + +public extension String { + func toDMSDate() -> Date { + let formatter = DateFormatter() + formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss" + formatter.timeZone = TimeZone(identifier: "UTC") + return formatter.date(from: self) ?? .init() + } +} + +public extension Date { + func toDMSDateString() -> String { + let formatter = DateFormatter() + formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss" + formatter.timeZone = .init(identifier: "UTC") + return formatter.string(from: self) + } +} diff --git a/Projects/Modules/Utility/Sources/Utility.swift b/Projects/Modules/Utility/Sources/Utility.swift deleted file mode 100644 index 8b137891..00000000 --- a/Projects/Modules/Utility/Sources/Utility.swift +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Projects/Services/NetworkModule/Sources/Base/BaseRemoteDataSource.swift b/Projects/Services/NetworkModule/Sources/Base/BaseRemoteDataSource.swift new file mode 100644 index 00000000..a7e19880 --- /dev/null +++ b/Projects/Services/NetworkModule/Sources/Base/BaseRemoteDataSource.swift @@ -0,0 +1,80 @@ +import APIKit +import Foundation +import KeychainModule +import Moya +import Utility + +public class BaseRemoteDataSource { + private let keychain: any Keychain + private let provider: MoyaProvider + private let decoder = JSONDecoder() + private let maxRetryCount = 2 + + public init( + keychain: any Keychain, + provider: MoyaProvider? = nil + ) { + self.keychain = keychain + + #if DEBUG + self.provider = provider ?? MoyaProvider(plugins: [JwtPlugin(keychain: keychain), NetworkLoggerPlugin()]) + #else + self.provider = provider ?? MoyaProvider(plugins: [JwtPlugin(keychain: keychain)]) + #endif + } +} + +private extension BaseRemoteDataSource { + func defaultRequest(_ api: API) async throws -> Response { + for _ in 0.. Response { + for _ in 0.. Response { + try await withCheckedThrowingContinuation { config in + provider.request(api) { result in + switch result { + case let .success(res): + config.resume(returning: res) + + case let .failure(err): + let code = err.response?.statusCode ?? 500 + config.resume( + throwing: api.errorMap[code] ?? .custom() + ) + } + } + } + } + + func checkIsApiNeedsAuth(_ api: API) -> Bool { + api.jwtTokenType == .accessToken + } + + func checkTokenIsExpired() -> Bool { + let expired = keychain.load(type: .expiredAt).toDMSDate() + return Date() > expired + } + + func tokenReissue() async throws { + // TODO: Token Refresh + } +} diff --git a/Projects/Services/NetworkModule/Sources/Feature.swift b/Projects/Services/NetworkModule/Sources/Feature.swift deleted file mode 100644 index 8d35d5c8..00000000 --- a/Projects/Services/NetworkModule/Sources/Feature.swift +++ /dev/null @@ -1 +0,0 @@ -// This is for the feature From 9dd77214efc7dc141f7084296fee53fb07c23dd8 Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 19:04:46 +0900 Subject: [PATCH 12/25] delete :: DI Layer --- .../Application/DI/AppComponent+LocalDataSource.swift | 5 ----- .../Application/DI/AppComponent+RemoteDataSource.swift | 5 ----- .../App/Sources/Application/DI/AppComponent+Repository.swift | 5 ----- .../App/Sources/Application/DI/AppComponent+UseCase.swift | 5 ----- 4 files changed, 20 deletions(-) delete mode 100644 Projects/App/Sources/Application/DI/AppComponent+LocalDataSource.swift delete mode 100644 Projects/App/Sources/Application/DI/AppComponent+RemoteDataSource.swift delete mode 100644 Projects/App/Sources/Application/DI/AppComponent+Repository.swift delete mode 100644 Projects/App/Sources/Application/DI/AppComponent+UseCase.swift diff --git a/Projects/App/Sources/Application/DI/AppComponent+LocalDataSource.swift b/Projects/App/Sources/Application/DI/AppComponent+LocalDataSource.swift deleted file mode 100644 index d33c37bd..00000000 --- a/Projects/App/Sources/Application/DI/AppComponent+LocalDataSource.swift +++ /dev/null @@ -1,5 +0,0 @@ -import NeedleFoundation - -public extension AppComponent { - -} diff --git a/Projects/App/Sources/Application/DI/AppComponent+RemoteDataSource.swift b/Projects/App/Sources/Application/DI/AppComponent+RemoteDataSource.swift deleted file mode 100644 index d33c37bd..00000000 --- a/Projects/App/Sources/Application/DI/AppComponent+RemoteDataSource.swift +++ /dev/null @@ -1,5 +0,0 @@ -import NeedleFoundation - -public extension AppComponent { - -} diff --git a/Projects/App/Sources/Application/DI/AppComponent+Repository.swift b/Projects/App/Sources/Application/DI/AppComponent+Repository.swift deleted file mode 100644 index d33c37bd..00000000 --- a/Projects/App/Sources/Application/DI/AppComponent+Repository.swift +++ /dev/null @@ -1,5 +0,0 @@ -import NeedleFoundation - -public extension AppComponent { - -} diff --git a/Projects/App/Sources/Application/DI/AppComponent+UseCase.swift b/Projects/App/Sources/Application/DI/AppComponent+UseCase.swift deleted file mode 100644 index d33c37bd..00000000 --- a/Projects/App/Sources/Application/DI/AppComponent+UseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import NeedleFoundation - -public extension AppComponent { - -} From 5d11999626880e27a30268fc3769d2fdbd1bb13c Mon Sep 17 00:00:00 2001 From: baegteun <74440939+baekteun@users.noreply.github.com> Date: Fri, 14 Oct 2022 10:33:48 +0900 Subject: [PATCH 13/25] Update Projects/Services/APIKit/Sources/DmsAPI.swift --- Projects/Services/APIKit/Sources/DmsAPI.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Projects/Services/APIKit/Sources/DmsAPI.swift b/Projects/Services/APIKit/Sources/DmsAPI.swift index b9d535ba..8ddb22c6 100644 --- a/Projects/Services/APIKit/Sources/DmsAPI.swift +++ b/Projects/Services/APIKit/Sources/DmsAPI.swift @@ -10,7 +10,7 @@ public protocol DmsAPI: TargetType, JwtAuthorizable { public extension DmsAPI { var baseURL: URL { - URL(string: "https://google.com")! + URL(string: "https://google.com")! // TODO: 서버의 배포가 완료되기 전에는 구글에게 몰래 요청을 날립니다 } var path: String { From 1f52d07e5c16c5c1b7aa9d8341a856497550d865 Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 15:27:01 +0900 Subject: [PATCH 14/25] =?UTF-8?q?feat=20::=20Error,=20DataMapping,=20Keych?= =?UTF-8?q?ain=20=EB=AA=A8=EB=93=88=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dependency+Project.swift | 3 +++ .../Derived/InfoPlists/ErrorModule-Info.plist | 22 +++++++++++++++++++ .../InfoPlists/ErrorModuleTests-Info.plist | 22 +++++++++++++++++++ Projects/Modules/ErrorModule/Project.swift | 7 ++++++ .../Modules/ErrorModule/Sources/Feature.swift | 1 + Projects/Modules/ErrorModule/Tests/.gitkeep | 0 .../ErrorModule/Tests/TargetTest.swift | 17 ++++++++++++++ .../InfoPlists/KeychainModule-Info.plist | 22 +++++++++++++++++++ .../InfoPlists/KeychainModuleTests-Info.plist | 22 +++++++++++++++++++ Projects/Modules/KeychainModule/Project.swift | 7 ++++++ .../KeychainModule/Sources/Feature.swift | 1 + .../Modules/KeychainModule/Tests/.gitkeep | 0 .../KeychainModule/Tests/TargetTest.swift | 17 ++++++++++++++ Projects/Services/APIKit/Project.swift | 5 ++++- .../InfoPlists/DataMappingModule-Info.plist | 22 +++++++++++++++++++ .../DataMappingModuleTests-Info.plist | 22 +++++++++++++++++++ .../Services/DataMappingModule/Project.swift | 7 ++++++ .../DataMappingModule/Sources/Feature.swift | 1 + .../Services/DataMappingModule/Tests/.gitkeep | 0 .../DataMappingModule/Tests/TargetTest.swift | 17 ++++++++++++++ Projects/Services/DomainModule/Project.swift | 3 ++- 21 files changed, 216 insertions(+), 2 deletions(-) create mode 100644 Projects/Modules/ErrorModule/Derived/InfoPlists/ErrorModule-Info.plist create mode 100644 Projects/Modules/ErrorModule/Derived/InfoPlists/ErrorModuleTests-Info.plist create mode 100644 Projects/Modules/ErrorModule/Project.swift create mode 100644 Projects/Modules/ErrorModule/Sources/Feature.swift create mode 100644 Projects/Modules/ErrorModule/Tests/.gitkeep create mode 100644 Projects/Modules/ErrorModule/Tests/TargetTest.swift create mode 100644 Projects/Modules/KeychainModule/Derived/InfoPlists/KeychainModule-Info.plist create mode 100644 Projects/Modules/KeychainModule/Derived/InfoPlists/KeychainModuleTests-Info.plist create mode 100644 Projects/Modules/KeychainModule/Project.swift create mode 100644 Projects/Modules/KeychainModule/Sources/Feature.swift create mode 100644 Projects/Modules/KeychainModule/Tests/.gitkeep create mode 100644 Projects/Modules/KeychainModule/Tests/TargetTest.swift create mode 100644 Projects/Services/DataMappingModule/Derived/InfoPlists/DataMappingModule-Info.plist create mode 100644 Projects/Services/DataMappingModule/Derived/InfoPlists/DataMappingModuleTests-Info.plist create mode 100644 Projects/Services/DataMappingModule/Project.swift create mode 100644 Projects/Services/DataMappingModule/Sources/Feature.swift create mode 100644 Projects/Services/DataMappingModule/Tests/.gitkeep create mode 100644 Projects/Services/DataMappingModule/Tests/TargetTest.swift diff --git a/Plugin/UtilityPlugin/ProjectDescriptionHelpers/Dependency+Project.swift b/Plugin/UtilityPlugin/ProjectDescriptionHelpers/Dependency+Project.swift index 8dc18a8e..e3bac5be 100644 --- a/Plugin/UtilityPlugin/ProjectDescriptionHelpers/Dependency+Project.swift +++ b/Plugin/UtilityPlugin/ProjectDescriptionHelpers/Dependency+Project.swift @@ -15,12 +15,15 @@ public extension TargetDependency.Project.Features { } public extension TargetDependency.Project.Module { + static let KeychainModule = TargetDependency.module(name: "KeychainModule") + static let ErrorModule = TargetDependency.module(name: "ErrorModule") static let FeatureThirdPartyLib = TargetDependency.module(name: "FeatureThirdPartyLib") static let ThirdPartyLib = TargetDependency.module(name: "ThirdPartyLib") static let Utility = TargetDependency.module(name: "Utility") } public extension TargetDependency.Project.Service { + static let DataMappingModule = TargetDependency.service(name: "DataMappingModule") static let APIKit = TargetDependency.service(name: "APIKit") static let Data = TargetDependency.service(name: "DataModule") static let Domain = TargetDependency.service(name: "DomainModule") diff --git a/Projects/Modules/ErrorModule/Derived/InfoPlists/ErrorModule-Info.plist b/Projects/Modules/ErrorModule/Derived/InfoPlists/ErrorModule-Info.plist new file mode 100644 index 00000000..323e5ecf --- /dev/null +++ b/Projects/Modules/ErrorModule/Derived/InfoPlists/ErrorModule-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Projects/Modules/ErrorModule/Derived/InfoPlists/ErrorModuleTests-Info.plist b/Projects/Modules/ErrorModule/Derived/InfoPlists/ErrorModuleTests-Info.plist new file mode 100644 index 00000000..6c40a6cd --- /dev/null +++ b/Projects/Modules/ErrorModule/Derived/InfoPlists/ErrorModuleTests-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Projects/Modules/ErrorModule/Project.swift b/Projects/Modules/ErrorModule/Project.swift new file mode 100644 index 00000000..87345b95 --- /dev/null +++ b/Projects/Modules/ErrorModule/Project.swift @@ -0,0 +1,7 @@ +import ProjectDescription +import ProjectDescriptionHelpers + +let project = Project.makeModule( + name: "ErrorModule", + product: .staticFramework +) diff --git a/Projects/Modules/ErrorModule/Sources/Feature.swift b/Projects/Modules/ErrorModule/Sources/Feature.swift new file mode 100644 index 00000000..8d35d5c8 --- /dev/null +++ b/Projects/Modules/ErrorModule/Sources/Feature.swift @@ -0,0 +1 @@ +// This is for the feature diff --git a/Projects/Modules/ErrorModule/Tests/.gitkeep b/Projects/Modules/ErrorModule/Tests/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/Projects/Modules/ErrorModule/Tests/TargetTest.swift b/Projects/Modules/ErrorModule/Tests/TargetTest.swift new file mode 100644 index 00000000..b1cf7940 --- /dev/null +++ b/Projects/Modules/ErrorModule/Tests/TargetTest.swift @@ -0,0 +1,17 @@ +import XCTest + +class TargetTests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + XCTAssertEqual("A", "A") + } + +} diff --git a/Projects/Modules/KeychainModule/Derived/InfoPlists/KeychainModule-Info.plist b/Projects/Modules/KeychainModule/Derived/InfoPlists/KeychainModule-Info.plist new file mode 100644 index 00000000..323e5ecf --- /dev/null +++ b/Projects/Modules/KeychainModule/Derived/InfoPlists/KeychainModule-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Projects/Modules/KeychainModule/Derived/InfoPlists/KeychainModuleTests-Info.plist b/Projects/Modules/KeychainModule/Derived/InfoPlists/KeychainModuleTests-Info.plist new file mode 100644 index 00000000..6c40a6cd --- /dev/null +++ b/Projects/Modules/KeychainModule/Derived/InfoPlists/KeychainModuleTests-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Projects/Modules/KeychainModule/Project.swift b/Projects/Modules/KeychainModule/Project.swift new file mode 100644 index 00000000..58d5689d --- /dev/null +++ b/Projects/Modules/KeychainModule/Project.swift @@ -0,0 +1,7 @@ +import ProjectDescription +import ProjectDescriptionHelpers + +let project = Project.makeModule( + name: "KeychainModule", + product: .staticFramework +) diff --git a/Projects/Modules/KeychainModule/Sources/Feature.swift b/Projects/Modules/KeychainModule/Sources/Feature.swift new file mode 100644 index 00000000..8d35d5c8 --- /dev/null +++ b/Projects/Modules/KeychainModule/Sources/Feature.swift @@ -0,0 +1 @@ +// This is for the feature diff --git a/Projects/Modules/KeychainModule/Tests/.gitkeep b/Projects/Modules/KeychainModule/Tests/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/Projects/Modules/KeychainModule/Tests/TargetTest.swift b/Projects/Modules/KeychainModule/Tests/TargetTest.swift new file mode 100644 index 00000000..b1cf7940 --- /dev/null +++ b/Projects/Modules/KeychainModule/Tests/TargetTest.swift @@ -0,0 +1,17 @@ +import XCTest + +class TargetTests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + XCTAssertEqual("A", "A") + } + +} diff --git a/Projects/Services/APIKit/Project.swift b/Projects/Services/APIKit/Project.swift index 6043c319..6efd2679 100644 --- a/Projects/Services/APIKit/Project.swift +++ b/Projects/Services/APIKit/Project.swift @@ -5,6 +5,9 @@ let project = Project.makeModule( name: "APIKit", product: .staticFramework, dependencies: [ - .Project.Module.ThirdPartyLib + .Project.Module.ThirdPartyLib, + .Project.Module.KeychainModule, + .Project.Module.ErrorModule, + .Project.Service.DataMappingModule ] ) diff --git a/Projects/Services/DataMappingModule/Derived/InfoPlists/DataMappingModule-Info.plist b/Projects/Services/DataMappingModule/Derived/InfoPlists/DataMappingModule-Info.plist new file mode 100644 index 00000000..323e5ecf --- /dev/null +++ b/Projects/Services/DataMappingModule/Derived/InfoPlists/DataMappingModule-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Projects/Services/DataMappingModule/Derived/InfoPlists/DataMappingModuleTests-Info.plist b/Projects/Services/DataMappingModule/Derived/InfoPlists/DataMappingModuleTests-Info.plist new file mode 100644 index 00000000..6c40a6cd --- /dev/null +++ b/Projects/Services/DataMappingModule/Derived/InfoPlists/DataMappingModuleTests-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Projects/Services/DataMappingModule/Project.swift b/Projects/Services/DataMappingModule/Project.swift new file mode 100644 index 00000000..2b926c25 --- /dev/null +++ b/Projects/Services/DataMappingModule/Project.swift @@ -0,0 +1,7 @@ +import ProjectDescription +import ProjectDescriptionHelpers + +let project = Project.makeModule( + name: "DataMappingModule", + product: .staticFramework +) diff --git a/Projects/Services/DataMappingModule/Sources/Feature.swift b/Projects/Services/DataMappingModule/Sources/Feature.swift new file mode 100644 index 00000000..8d35d5c8 --- /dev/null +++ b/Projects/Services/DataMappingModule/Sources/Feature.swift @@ -0,0 +1 @@ +// This is for the feature diff --git a/Projects/Services/DataMappingModule/Tests/.gitkeep b/Projects/Services/DataMappingModule/Tests/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/Projects/Services/DataMappingModule/Tests/TargetTest.swift b/Projects/Services/DataMappingModule/Tests/TargetTest.swift new file mode 100644 index 00000000..b1cf7940 --- /dev/null +++ b/Projects/Services/DataMappingModule/Tests/TargetTest.swift @@ -0,0 +1,17 @@ +import XCTest + +class TargetTests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + XCTAssertEqual("A", "A") + } + +} diff --git a/Projects/Services/DomainModule/Project.swift b/Projects/Services/DomainModule/Project.swift index 22d768c9..5956fb29 100644 --- a/Projects/Services/DomainModule/Project.swift +++ b/Projects/Services/DomainModule/Project.swift @@ -5,6 +5,7 @@ let project = Project.makeModule( name: "DomainModule", product: .staticFramework, dependencies: [ - .Project.Module.ThirdPartyLib + .Project.Module.ThirdPartyLib, + .Project.Service.DataMappingModule ] ) From 206c44b86258f9f14c728d921505ce42e7434c39 Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 15:28:18 +0900 Subject: [PATCH 15/25] feat :: DMSError --- Projects/Modules/ErrorModule/Sources/DMSError.swift | 12 ++++++++++++ Projects/Modules/ErrorModule/Sources/Feature.swift | 1 - 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 Projects/Modules/ErrorModule/Sources/DMSError.swift delete mode 100644 Projects/Modules/ErrorModule/Sources/Feature.swift diff --git a/Projects/Modules/ErrorModule/Sources/DMSError.swift b/Projects/Modules/ErrorModule/Sources/DMSError.swift new file mode 100644 index 00000000..1b42c920 --- /dev/null +++ b/Projects/Modules/ErrorModule/Sources/DMSError.swift @@ -0,0 +1,12 @@ +import Foundation + +public enum DMSError: Error { + case unknown + case custom(message: String, code: Int) +} + +public extension Error { + var asDMSError: DMSError { + self as? DMSError ?? .unknown + } +} diff --git a/Projects/Modules/ErrorModule/Sources/Feature.swift b/Projects/Modules/ErrorModule/Sources/Feature.swift deleted file mode 100644 index 8d35d5c8..00000000 --- a/Projects/Modules/ErrorModule/Sources/Feature.swift +++ /dev/null @@ -1 +0,0 @@ -// This is for the feature From af49fd19d5f67c1a53e8c8cce245664ea5fd9043 Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 15:29:54 +0900 Subject: [PATCH 16/25] =?UTF-8?q?art=20::=20=EB=AA=A8=EB=93=88=ED=99=94=20?= =?UTF-8?q?=EA=B7=B8=EB=9E=98=ED=94=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- graph.png | Bin 0 -> 77495 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 graph.png diff --git a/graph.png b/graph.png new file mode 100644 index 0000000000000000000000000000000000000000..a9edf932b0f1e41de6c589ba3dbc81f42ca60358 GIT binary patch literal 77495 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
    8^NpznG41Z18_rfYD=EhY!+0RE_DO(^mXH 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 literal 0 HcmV?d00001 From 30dc531c98d313401e11d0a344297bb9df580766 Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 15:52:17 +0900 Subject: [PATCH 17/25] feat :: BaseViewModel --- .../BaseFeature/Sources/BaseViewModel.swift | 33 +++++++++++++++++++ .../BaseFeature/Sources/Feature.swift | 1 - .../ErrorModule/Sources/DMSError.swift | 12 +++++++ Projects/Modules/Utility/Project.swift | 3 +- 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 Projects/Features/BaseFeature/Sources/BaseViewModel.swift delete mode 100644 Projects/Features/BaseFeature/Sources/Feature.swift diff --git a/Projects/Features/BaseFeature/Sources/BaseViewModel.swift b/Projects/Features/BaseFeature/Sources/BaseViewModel.swift new file mode 100644 index 00000000..e534509a --- /dev/null +++ b/Projects/Features/BaseFeature/Sources/BaseViewModel.swift @@ -0,0 +1,33 @@ +import Combine +import ErrorModule + +open class BaseViewModel: ObservableObject { + @Published public var isErrorOcuured = false + @Published public var isLoading = false + @Published public var errorMessage = "" + + public var bag = Set() + + public init() {} + + public func addCancellable( + _ publisher: AnyPublisher, + onReceiveValue: @escaping (T) -> Void, + onReceiveError: ((DMSError) -> Void)? = nil + ) { + isLoading = true + publisher + .sink(receiveCompletion: { [weak self] completion in + if case let .failure(error) = completion { + if let onReceiveError { + onReceiveError(error.asDMSError) + } + + self?.errorMessage = error.localizedDescription + self?.isErrorOcuured = true + } + self?.isLoading = false + }, receiveValue: onReceiveValue) + .store(in: &bag) + } +} diff --git a/Projects/Features/BaseFeature/Sources/Feature.swift b/Projects/Features/BaseFeature/Sources/Feature.swift deleted file mode 100644 index 7d846fc7..00000000 --- a/Projects/Features/BaseFeature/Sources/Feature.swift +++ /dev/null @@ -1 +0,0 @@ -// this is for tuist diff --git a/Projects/Modules/ErrorModule/Sources/DMSError.swift b/Projects/Modules/ErrorModule/Sources/DMSError.swift index 1b42c920..6fef0d8a 100644 --- a/Projects/Modules/ErrorModule/Sources/DMSError.swift +++ b/Projects/Modules/ErrorModule/Sources/DMSError.swift @@ -5,6 +5,18 @@ public enum DMSError: Error { case custom(message: String, code: Int) } +extension DMSError: LocalizedError { + public var errorDescription: String? { + switch self { + case .unknown: + return "알 수 없는 오류가 발생하였습니다" + + case let .custom(message, _): + return message + } + } +} + public extension Error { var asDMSError: DMSError { self as? DMSError ?? .unknown diff --git a/Projects/Modules/Utility/Project.swift b/Projects/Modules/Utility/Project.swift index 78482080..ed4ea86d 100644 --- a/Projects/Modules/Utility/Project.swift +++ b/Projects/Modules/Utility/Project.swift @@ -5,6 +5,7 @@ let project = Project.makeModule( name: "Utility", product: .staticFramework, dependencies: [ - .Project.Module.ThirdPartyLib + .Project.Module.ThirdPartyLib, + .Project.Module.ErrorModule ] ) From 439afef7c37dd35c24a13edee87482e69a64a1ca Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 15:57:11 +0900 Subject: [PATCH 18/25] feat :: Keycahin --- .../KeychainModule/Sources/Feature.swift | 1 - .../KeychainModule/Sources/Keychain.swift | 11 +++++ .../KeychainModule/Sources/KeychainImpl.swift | 44 +++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) delete mode 100644 Projects/Modules/KeychainModule/Sources/Feature.swift create mode 100644 Projects/Modules/KeychainModule/Sources/Keychain.swift create mode 100644 Projects/Modules/KeychainModule/Sources/KeychainImpl.swift diff --git a/Projects/Modules/KeychainModule/Sources/Feature.swift b/Projects/Modules/KeychainModule/Sources/Feature.swift deleted file mode 100644 index 8d35d5c8..00000000 --- a/Projects/Modules/KeychainModule/Sources/Feature.swift +++ /dev/null @@ -1 +0,0 @@ -// This is for the feature diff --git a/Projects/Modules/KeychainModule/Sources/Keychain.swift b/Projects/Modules/KeychainModule/Sources/Keychain.swift new file mode 100644 index 00000000..5b6589af --- /dev/null +++ b/Projects/Modules/KeychainModule/Sources/Keychain.swift @@ -0,0 +1,11 @@ +public enum KeychainType: String { + case accessToken = "ACCESS-TOKEN" + case refreshToken = "REFRESH-TOKEN" + case expiredAt = "EXPIRED-AT" +} + +public protocol Keychain { + func save(type: KeychainType, value: String) + func load(type: KeychainType) -> String + func delete(type: KeychainType) +} diff --git a/Projects/Modules/KeychainModule/Sources/KeychainImpl.swift b/Projects/Modules/KeychainModule/Sources/KeychainImpl.swift new file mode 100644 index 00000000..ea2bf918 --- /dev/null +++ b/Projects/Modules/KeychainModule/Sources/KeychainImpl.swift @@ -0,0 +1,44 @@ +import Foundation + +public struct KeychainImpl: Keychain { + public init() {} + + private let service: String = Bundle.main.bundleIdentifier ?? "" + + public func save(type: KeychainType, value: String) { + let query: NSDictionary = [ + kSecClass: kSecClassGenericPassword, + kSecAttrService: service, + kSecAttrAccount: type.rawValue, + kSecValueData: value.data(using: .utf8, allowLossyConversion: false) ?? .init() + ] + SecItemDelete(query) + SecItemAdd(query, nil) + } + + public func load(type: KeychainType) -> String { + let query: NSDictionary = [ + kSecClass: kSecClassGenericPassword, + kSecAttrService: service, + kSecAttrAccount: type.rawValue, + kSecReturnData: kCFBooleanTrue!, + kSecMatchLimit: kSecMatchLimitOne + ] + var dataTypeRef: AnyObject? + let status = withUnsafeMutablePointer(to: &dataTypeRef) { SecItemCopyMatching(query, UnsafeMutablePointer($0)) } + if status == errSecSuccess { + guard let data = dataTypeRef as? Data else { return "" } + return String(data: data, encoding: .utf8) ?? "" + } + return "" + } + + public func delete(type: KeychainType) { + let query: NSDictionary = [ + kSecClass: kSecClassGenericPassword, + kSecAttrService: service, + kSecAttrAccount: type.rawValue + ] + SecItemDelete(query) + } +} From 39eb108a45e2dfbfa488ee761235b9ca1d3093ee Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 15:59:58 +0900 Subject: [PATCH 19/25] feat :: Keychain Fake double --- .../KeychainModule/Sources/KeychainFake.swift | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Projects/Modules/KeychainModule/Sources/KeychainFake.swift diff --git a/Projects/Modules/KeychainModule/Sources/KeychainFake.swift b/Projects/Modules/KeychainModule/Sources/KeychainFake.swift new file mode 100644 index 00000000..cda52e1f --- /dev/null +++ b/Projects/Modules/KeychainModule/Sources/KeychainFake.swift @@ -0,0 +1,17 @@ +import Foundation + +final class KeychainFake: Keychain { + var store: [String: String] = [:] + + func save(type: KeychainType, value: String) { + store[type.rawValue] = value + } + + func load(type: KeychainType) -> String { + store[type.rawValue] ?? "" + } + + func delete(type: KeychainType) { + store[type.rawValue] = nil + } +} From e9380194ac111b737f8528679deaf03c4de2545b Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 16:09:13 +0900 Subject: [PATCH 20/25] feat :: JwtPlugin --- .../Dependency+SPM.swift | 2 + Projects/Services/APIKit/Project.swift | 5 +- Projects/Services/APIKit/Sources/API.swift | 1 - Projects/Services/APIKit/Sources/DmsAPI.swift | 6 ++ .../Sources/Plugins/Jwt/JwtAuthorizable.swift | 11 ++++ .../Sources/Plugins/Jwt/JwtPlugin.swift | 60 +++++++++++++++++++ .../APIKit/Sources/Plugins/Jwt/TokenDTO.swift | 13 ++++ Tuist/Dependencies.swift | 3 +- 8 files changed, 98 insertions(+), 3 deletions(-) delete mode 100644 Projects/Services/APIKit/Sources/API.swift create mode 100644 Projects/Services/APIKit/Sources/DmsAPI.swift create mode 100644 Projects/Services/APIKit/Sources/Plugins/Jwt/JwtAuthorizable.swift create mode 100644 Projects/Services/APIKit/Sources/Plugins/Jwt/JwtPlugin.swift create mode 100644 Projects/Services/APIKit/Sources/Plugins/Jwt/TokenDTO.swift diff --git a/Plugin/UtilityPlugin/ProjectDescriptionHelpers/Dependency+SPM.swift b/Plugin/UtilityPlugin/ProjectDescriptionHelpers/Dependency+SPM.swift index 36f555f9..3c2711d8 100644 --- a/Plugin/UtilityPlugin/ProjectDescriptionHelpers/Dependency+SPM.swift +++ b/Plugin/UtilityPlugin/ProjectDescriptionHelpers/Dependency+SPM.swift @@ -9,6 +9,8 @@ public extension TargetDependency.SPM { static let Quick = TargetDependency.external(name: "Quick") static let Nimble = TargetDependency.external(name: "Nimble") static let Needle = TargetDependency.external(name: "NeedleFoundation") + static let Moya = TargetDependency.external(name: "Moya") + static let CombineMoya = TargetDependency.external(name: "CombineMoya") } public extension Package { diff --git a/Projects/Services/APIKit/Project.swift b/Projects/Services/APIKit/Project.swift index 6efd2679..ab4ef12f 100644 --- a/Projects/Services/APIKit/Project.swift +++ b/Projects/Services/APIKit/Project.swift @@ -8,6 +8,9 @@ let project = Project.makeModule( .Project.Module.ThirdPartyLib, .Project.Module.KeychainModule, .Project.Module.ErrorModule, - .Project.Service.DataMappingModule + .Project.Service.DataMappingModule, + + .SPM.Moya, + .SPM.CombineMoya ] ) diff --git a/Projects/Services/APIKit/Sources/API.swift b/Projects/Services/APIKit/Sources/API.swift deleted file mode 100644 index 7d846fc7..00000000 --- a/Projects/Services/APIKit/Sources/API.swift +++ /dev/null @@ -1 +0,0 @@ -// this is for tuist diff --git a/Projects/Services/APIKit/Sources/DmsAPI.swift b/Projects/Services/APIKit/Sources/DmsAPI.swift new file mode 100644 index 00000000..4ce7f777 --- /dev/null +++ b/Projects/Services/APIKit/Sources/DmsAPI.swift @@ -0,0 +1,6 @@ +import Foundation +import Moya + +public protocol DmsAPI: TargetType { + +} diff --git a/Projects/Services/APIKit/Sources/Plugins/Jwt/JwtAuthorizable.swift b/Projects/Services/APIKit/Sources/Plugins/Jwt/JwtAuthorizable.swift new file mode 100644 index 00000000..fcdb412a --- /dev/null +++ b/Projects/Services/APIKit/Sources/Plugins/Jwt/JwtAuthorizable.swift @@ -0,0 +1,11 @@ +import Moya + +public enum JwtTokenType: String { + case accessToken = "Authorization" + case refreshToken = "refresh-token" + case none +} + +public protocol JwtAuthorizable { + var jwtTokenType: JwtTokenType { get } +} diff --git a/Projects/Services/APIKit/Sources/Plugins/Jwt/JwtPlugin.swift b/Projects/Services/APIKit/Sources/Plugins/Jwt/JwtPlugin.swift new file mode 100644 index 00000000..0af2a5a1 --- /dev/null +++ b/Projects/Services/APIKit/Sources/Plugins/Jwt/JwtPlugin.swift @@ -0,0 +1,60 @@ +import Moya +import KeychainModule +import Foundation + +public struct JwtPlugin: PluginType { + private let keychain: any Keychain + + public init(keychain: any Keychain) { + self.keychain = keychain + } + + public func prepare( + _ request: URLRequest, + target: TargetType + ) -> URLRequest { + guard let jwtTokenType = (target as? JwtAuthorizable)?.jwtTokenType, + jwtTokenType != .none + else { return request } + var req = request + let token = "Bearer \(getToken(type: jwtTokenType == .accessToken ? .accessToken : .refreshToken))" + + req.addValue(token, forHTTPHeaderField: jwtTokenType.rawValue) + return req + } + + public func didReceive( + _ result: Result, + target: TargetType + ) { + switch result { + case let .success(res): + if let new = try? res.map(TokenDTO.self) { + saveToken(token: new) + } + default: + break + } + } +} + +private extension JwtPlugin { + func getToken(type: KeychainType) -> String { + switch type { + case .accessToken: + return keychain.load(type: .accessToken) + + case .refreshToken: + return keychain.load(type: .refreshToken) + + case .expiredAt: + return keychain.load(type: .expiredAt) + } + } + + func saveToken(token: TokenDTO) { + keychain.save(type: .accessToken, value: token.accessToken) + keychain.save(type: .refreshToken, value: token.refreshToken) + keychain.save(type: .expiredAt, value: token.expiredAt) + } +} diff --git a/Projects/Services/APIKit/Sources/Plugins/Jwt/TokenDTO.swift b/Projects/Services/APIKit/Sources/Plugins/Jwt/TokenDTO.swift new file mode 100644 index 00000000..043e13d1 --- /dev/null +++ b/Projects/Services/APIKit/Sources/Plugins/Jwt/TokenDTO.swift @@ -0,0 +1,13 @@ +import Foundation + +struct TokenDTO: Equatable, Decodable { + let accessToken: String + let refreshToken: String + let expiredAt: String + + enum CodingKeys: String, CodingKey { + case accessToken = "access_token" + case refreshToken = "refresh_token" + case expiredAt = "expired_at" + } +} diff --git a/Tuist/Dependencies.swift b/Tuist/Dependencies.swift index 357e937a..0aeb3c4f 100644 --- a/Tuist/Dependencies.swift +++ b/Tuist/Dependencies.swift @@ -5,7 +5,8 @@ let dependencies = Dependencies( swiftPackageManager: [ .remote(url: "https://github.com/Quick/Quick.git", requirement: .upToNextMajor(from: "5.0.1")), .remote(url: "https://github.com/Quick/Nimble.git", requirement: .upToNextMajor(from: "10.0.0")), - .remote(url: "https://github.com/uber/needle.git", requirement: .upToNextMajor(from: "0.19.0")) + .remote(url: "https://github.com/uber/needle.git", requirement: .upToNextMajor(from: "0.19.0")), + .remote(url: "https://github.com/Moya/Moya.git", requirement: .upToNextMajor(from: "15.0.3")) ], platforms: [.iOS] ) From 88e3159b7d81a4f96fcba58a5d5f507c9752e4ec Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 16:13:10 +0900 Subject: [PATCH 21/25] feat :: DmsAPI --- .../BaseFeature/Sources/BaseViewModel.swift | 2 +- .../{DMSError.swift => DmsError.swift} | 8 ++--- Projects/Services/APIKit/Sources/DmsAPI.swift | 36 +++++++++++++++++-- 3 files changed, 39 insertions(+), 7 deletions(-) rename Projects/Modules/ErrorModule/Sources/{DMSError.swift => DmsError.swift} (72%) diff --git a/Projects/Features/BaseFeature/Sources/BaseViewModel.swift b/Projects/Features/BaseFeature/Sources/BaseViewModel.swift index e534509a..6ec871ff 100644 --- a/Projects/Features/BaseFeature/Sources/BaseViewModel.swift +++ b/Projects/Features/BaseFeature/Sources/BaseViewModel.swift @@ -13,7 +13,7 @@ open class BaseViewModel: ObservableObject { public func addCancellable( _ publisher: AnyPublisher, onReceiveValue: @escaping (T) -> Void, - onReceiveError: ((DMSError) -> Void)? = nil + onReceiveError: ((DmsError) -> Void)? = nil ) { isLoading = true publisher diff --git a/Projects/Modules/ErrorModule/Sources/DMSError.swift b/Projects/Modules/ErrorModule/Sources/DmsError.swift similarity index 72% rename from Projects/Modules/ErrorModule/Sources/DMSError.swift rename to Projects/Modules/ErrorModule/Sources/DmsError.swift index 6fef0d8a..8c59d31b 100644 --- a/Projects/Modules/ErrorModule/Sources/DMSError.swift +++ b/Projects/Modules/ErrorModule/Sources/DmsError.swift @@ -1,11 +1,11 @@ import Foundation -public enum DMSError: Error { +public enum DmsError: Error { case unknown case custom(message: String, code: Int) } -extension DMSError: LocalizedError { +extension DmsError: LocalizedError { public var errorDescription: String? { switch self { case .unknown: @@ -18,7 +18,7 @@ extension DMSError: LocalizedError { } public extension Error { - var asDMSError: DMSError { - self as? DMSError ?? .unknown + var asDMSError: DmsError { + self as? DmsError ?? .unknown } } diff --git a/Projects/Services/APIKit/Sources/DmsAPI.swift b/Projects/Services/APIKit/Sources/DmsAPI.swift index 4ce7f777..b9d535ba 100644 --- a/Projects/Services/APIKit/Sources/DmsAPI.swift +++ b/Projects/Services/APIKit/Sources/DmsAPI.swift @@ -1,6 +1,38 @@ import Foundation import Moya +import ErrorModule -public protocol DmsAPI: TargetType { - +public protocol DmsAPI: TargetType, JwtAuthorizable { + var domain: DmsDomain { get } + var urlPath: String { get } + var errorMap: [Int: DmsError] { get } +} + +public extension DmsAPI { + var baseURL: URL { + URL(string: "https://google.com")! + } + + var path: String { + domain.asURLString + urlPath + } + + var headers: [String: String]? { + ["Content-Type": "application/json"] + } +} + +public enum DmsDomain: String { + case auth + case users + case losts + case notices + case meal + case images +} + +extension DmsDomain { + var asURLString: String { + "/\(self.rawValue)" + } } From 13920ef9576ad801ada0685c81250bc04a98ba19 Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 16:31:12 +0900 Subject: [PATCH 22/25] test :: JwtPluginSpec --- .../Services/APIKit/Tests/JwtPluginSpec.swift | 94 +++++++++++++++++++ .../Services/APIKit/Tests/TargetTest.swift | 17 ---- Projects/Services/APIKit/Tests/TestAPI.swift | 57 +++++++++++ 3 files changed, 151 insertions(+), 17 deletions(-) create mode 100644 Projects/Services/APIKit/Tests/JwtPluginSpec.swift delete mode 100644 Projects/Services/APIKit/Tests/TargetTest.swift create mode 100644 Projects/Services/APIKit/Tests/TestAPI.swift diff --git a/Projects/Services/APIKit/Tests/JwtPluginSpec.swift b/Projects/Services/APIKit/Tests/JwtPluginSpec.swift new file mode 100644 index 00000000..e1796f8f --- /dev/null +++ b/Projects/Services/APIKit/Tests/JwtPluginSpec.swift @@ -0,0 +1,94 @@ +import Quick +import Nimble +import Moya +import Foundation +@testable import APIKit +@testable import KeychainModule + +// swiftlint: disable function_body_length +final class JwtPluginSpec: QuickSpec { + override func spec() { + var keychain: Keychain! + var plugin: JwtPlugin! + var api: MoyaProvider! + + beforeEach { + keychain = KeychainFake() + plugin = JwtPlugin(keychain: keychain) + let customEnpointClosure = { (target: TestAPI) -> Endpoint in + Endpoint( + url: URL(target: target).absoluteString, + sampleResponseClosure: { .networkResponse(200, target.sampleData) }, + method: target.method, + task: target.task, + httpHeaderFields: target.headers + ) + } + api = MoyaProvider( + endpointClosure: customEnpointClosure, + stubClosure: MoyaProvider.immediatelyStub, + plugins: [plugin] + ) + } + + describe("JwtPlugin을 사용하는 API는") { + afterEach { + keychain.delete(type: .accessToken) + keychain.delete(type: .refreshToken) + keychain.delete(type: .expiredAt) + } + context("Response가 TokenDTO의 데이터 타입으로 온다면") { + it("Keychain에 Token을 저장한다") { + api.request(.success) { _ in } + expect(keychain.load(type: .accessToken)).to(equal("access")) + expect(keychain.load(type: .refreshToken)).to(equal("refresh")) + expect(keychain.load(type: .expiredAt)).to(equal("expired")) + } + } + context("Response가 TokenDTO의 데이터 타입으로 오지 않는다면") { + it("Keychain에 아무 데이터도 저장하지 않는다") { + api.request(.failure) { _ in } + expect(keychain.load(type: .accessToken)).to(beEmpty()) + expect(keychain.load(type: .refreshToken)).to(beEmpty()) + expect(keychain.load(type: .expiredAt)).to(beEmpty()) + } + } + context("Enpoint의 JwtAuthorizable인 .accessToken인 API요청을 한다면") { + beforeEach { + keychain.save(type: .accessToken, value: "Access") + } + it("HTTPHeader의 Authorization에, 앞에 Bearer와 함께 AccessToken키체인에 저장된 값이 자동으로 담긴다") { + api.request(.withAccess) { result in + switch result { + case .failure: + fail("요청이 실패함") + + case let .success(res): + expect(res.request?.allHTTPHeaderFields?["Authorization"]).toNot(beNil()) + expect(res.request?.allHTTPHeaderFields?["Authorization"]).to(equal("Bearer Access")) + expect(res.statusCode).to(equal(200)) + } + } + } + } + context("Enpoint의 JwtAuthorizable인 .refreshToken인 API요청을 한다면") { + beforeEach { + keychain.save(type: .refreshToken, value: "Refresh") + } + it("HTTPHeader의 refresh-token에, 앞에 Bearer와 함께 RefreshToken키체인에 저장된 값이 자동으로 담긴다") { + api.request(.withRefresh) { result in + switch result { + case .failure: + fail("요청이 실패함") + + case let .success(res): + expect(res.request?.allHTTPHeaderFields?["refresh-token"]).toNot(beNil()) + expect(res.request?.allHTTPHeaderFields?["refresh-token"]).to(equal("Bearer Refresh")) + expect(res.statusCode).to(equal(200)) + } + } + } + } + } + } +} diff --git a/Projects/Services/APIKit/Tests/TargetTest.swift b/Projects/Services/APIKit/Tests/TargetTest.swift deleted file mode 100644 index b1cf7940..00000000 --- a/Projects/Services/APIKit/Tests/TargetTest.swift +++ /dev/null @@ -1,17 +0,0 @@ -import XCTest - -class TargetTests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() throws { - XCTAssertEqual("A", "A") - } - -} diff --git a/Projects/Services/APIKit/Tests/TestAPI.swift b/Projects/Services/APIKit/Tests/TestAPI.swift new file mode 100644 index 00000000..9f5518ba --- /dev/null +++ b/Projects/Services/APIKit/Tests/TestAPI.swift @@ -0,0 +1,57 @@ +import Moya +import Foundation +import APIKit + +public enum TestAPI: TargetType, JwtAuthorizable { + case success + case failure + case withAccess + case withRefresh + + public var baseURL: URL { URL(string: "localhost")! } + + public var path: String { "/" } + + public var method: Moya.Method { .get } + + public var sampleData: Data { + switch self { + case .success: + return """ +{ + "access_token": "access", + "refresh_token": "refresh", + "expired_at": "expired" +} +""".data(using: .utf8)! + + case .failure: + return """ +{ + "test": "how", + "access_token": "access" +} +""".data(using: .utf8)! + + default: + return .init() + } + } + + public var task: Moya.Task { .requestPlain } + + public var headers: [String: String]? { nil } + + public var jwtTokenType: JwtTokenType { + switch self { + case .withAccess: + return .accessToken + + case .withRefresh: + return .refreshToken + + default: + return .none + } + } +} From cfff4b796f052c0fc756b2000fa8e7f77e39b591 Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 16:44:08 +0900 Subject: [PATCH 23/25] feat :: NoResponse --- .../Services/DataMappingModule/Sources/Base/NoResponse.swift | 3 +++ Projects/Services/DataMappingModule/Sources/Feature.swift | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Projects/Services/DataMappingModule/Sources/Base/NoResponse.swift delete mode 100644 Projects/Services/DataMappingModule/Sources/Feature.swift diff --git a/Projects/Services/DataMappingModule/Sources/Base/NoResponse.swift b/Projects/Services/DataMappingModule/Sources/Base/NoResponse.swift new file mode 100644 index 00000000..c9f10c41 --- /dev/null +++ b/Projects/Services/DataMappingModule/Sources/Base/NoResponse.swift @@ -0,0 +1,3 @@ +import Foundation + +public struct NoResponse: Codable {} diff --git a/Projects/Services/DataMappingModule/Sources/Feature.swift b/Projects/Services/DataMappingModule/Sources/Feature.swift deleted file mode 100644 index 8d35d5c8..00000000 --- a/Projects/Services/DataMappingModule/Sources/Feature.swift +++ /dev/null @@ -1 +0,0 @@ -// This is for the feature From e15bdecc6b5ac468c8881db6c9f0d1b9b63c37d0 Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 17:02:21 +0900 Subject: [PATCH 24/25] feat :: BaseRemoteDataSource --- .../ErrorModule/Sources/DmsError.swift | 2 +- .../Modules/Utility/Sources/DateUtil.swift | 19 +++++ .../Modules/Utility/Sources/Utility.swift | 1 - .../Sources/Base/BaseRemoteDataSource.swift | 80 +++++++++++++++++++ .../NetworkModule/Sources/Feature.swift | 1 - 5 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 Projects/Modules/Utility/Sources/DateUtil.swift delete mode 100644 Projects/Modules/Utility/Sources/Utility.swift create mode 100644 Projects/Services/NetworkModule/Sources/Base/BaseRemoteDataSource.swift delete mode 100644 Projects/Services/NetworkModule/Sources/Feature.swift diff --git a/Projects/Modules/ErrorModule/Sources/DmsError.swift b/Projects/Modules/ErrorModule/Sources/DmsError.swift index 8c59d31b..bb6af472 100644 --- a/Projects/Modules/ErrorModule/Sources/DmsError.swift +++ b/Projects/Modules/ErrorModule/Sources/DmsError.swift @@ -2,7 +2,7 @@ import Foundation public enum DmsError: Error { case unknown - case custom(message: String, code: Int) + case custom(message: String = "알 수 없는 오류가 발생하였습니다", code: Int = 500) } extension DmsError: LocalizedError { diff --git a/Projects/Modules/Utility/Sources/DateUtil.swift b/Projects/Modules/Utility/Sources/DateUtil.swift new file mode 100644 index 00000000..feba72dc --- /dev/null +++ b/Projects/Modules/Utility/Sources/DateUtil.swift @@ -0,0 +1,19 @@ +import Foundation + +public extension String { + func toDMSDate() -> Date { + let formatter = DateFormatter() + formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss" + formatter.timeZone = TimeZone(identifier: "UTC") + return formatter.date(from: self) ?? .init() + } +} + +public extension Date { + func toDMSDateString() -> String { + let formatter = DateFormatter() + formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss" + formatter.timeZone = .init(identifier: "UTC") + return formatter.string(from: self) + } +} diff --git a/Projects/Modules/Utility/Sources/Utility.swift b/Projects/Modules/Utility/Sources/Utility.swift deleted file mode 100644 index 8b137891..00000000 --- a/Projects/Modules/Utility/Sources/Utility.swift +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Projects/Services/NetworkModule/Sources/Base/BaseRemoteDataSource.swift b/Projects/Services/NetworkModule/Sources/Base/BaseRemoteDataSource.swift new file mode 100644 index 00000000..a7e19880 --- /dev/null +++ b/Projects/Services/NetworkModule/Sources/Base/BaseRemoteDataSource.swift @@ -0,0 +1,80 @@ +import APIKit +import Foundation +import KeychainModule +import Moya +import Utility + +public class BaseRemoteDataSource { + private let keychain: any Keychain + private let provider: MoyaProvider + private let decoder = JSONDecoder() + private let maxRetryCount = 2 + + public init( + keychain: any Keychain, + provider: MoyaProvider? = nil + ) { + self.keychain = keychain + + #if DEBUG + self.provider = provider ?? MoyaProvider(plugins: [JwtPlugin(keychain: keychain), NetworkLoggerPlugin()]) + #else + self.provider = provider ?? MoyaProvider(plugins: [JwtPlugin(keychain: keychain)]) + #endif + } +} + +private extension BaseRemoteDataSource { + func defaultRequest(_ api: API) async throws -> Response { + for _ in 0.. Response { + for _ in 0.. Response { + try await withCheckedThrowingContinuation { config in + provider.request(api) { result in + switch result { + case let .success(res): + config.resume(returning: res) + + case let .failure(err): + let code = err.response?.statusCode ?? 500 + config.resume( + throwing: api.errorMap[code] ?? .custom() + ) + } + } + } + } + + func checkIsApiNeedsAuth(_ api: API) -> Bool { + api.jwtTokenType == .accessToken + } + + func checkTokenIsExpired() -> Bool { + let expired = keychain.load(type: .expiredAt).toDMSDate() + return Date() > expired + } + + func tokenReissue() async throws { + // TODO: Token Refresh + } +} diff --git a/Projects/Services/NetworkModule/Sources/Feature.swift b/Projects/Services/NetworkModule/Sources/Feature.swift deleted file mode 100644 index 8d35d5c8..00000000 --- a/Projects/Services/NetworkModule/Sources/Feature.swift +++ /dev/null @@ -1 +0,0 @@ -// This is for the feature From 05e3ca5c4efae77e293d22584cdf53136c01baea Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 13 Oct 2022 19:04:46 +0900 Subject: [PATCH 25/25] delete :: DI Layer --- .../Application/DI/AppComponent+LocalDataSource.swift | 5 ----- .../Application/DI/AppComponent+RemoteDataSource.swift | 5 ----- .../App/Sources/Application/DI/AppComponent+Repository.swift | 5 ----- .../App/Sources/Application/DI/AppComponent+UseCase.swift | 5 ----- 4 files changed, 20 deletions(-) delete mode 100644 Projects/App/Sources/Application/DI/AppComponent+LocalDataSource.swift delete mode 100644 Projects/App/Sources/Application/DI/AppComponent+RemoteDataSource.swift delete mode 100644 Projects/App/Sources/Application/DI/AppComponent+Repository.swift delete mode 100644 Projects/App/Sources/Application/DI/AppComponent+UseCase.swift diff --git a/Projects/App/Sources/Application/DI/AppComponent+LocalDataSource.swift b/Projects/App/Sources/Application/DI/AppComponent+LocalDataSource.swift deleted file mode 100644 index d33c37bd..00000000 --- a/Projects/App/Sources/Application/DI/AppComponent+LocalDataSource.swift +++ /dev/null @@ -1,5 +0,0 @@ -import NeedleFoundation - -public extension AppComponent { - -} diff --git a/Projects/App/Sources/Application/DI/AppComponent+RemoteDataSource.swift b/Projects/App/Sources/Application/DI/AppComponent+RemoteDataSource.swift deleted file mode 100644 index d33c37bd..00000000 --- a/Projects/App/Sources/Application/DI/AppComponent+RemoteDataSource.swift +++ /dev/null @@ -1,5 +0,0 @@ -import NeedleFoundation - -public extension AppComponent { - -} diff --git a/Projects/App/Sources/Application/DI/AppComponent+Repository.swift b/Projects/App/Sources/Application/DI/AppComponent+Repository.swift deleted file mode 100644 index d33c37bd..00000000 --- a/Projects/App/Sources/Application/DI/AppComponent+Repository.swift +++ /dev/null @@ -1,5 +0,0 @@ -import NeedleFoundation - -public extension AppComponent { - -} diff --git a/Projects/App/Sources/Application/DI/AppComponent+UseCase.swift b/Projects/App/Sources/Application/DI/AppComponent+UseCase.swift deleted file mode 100644 index d33c37bd..00000000 --- a/Projects/App/Sources/Application/DI/AppComponent+UseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import NeedleFoundation - -public extension AppComponent { - -}