From b3e4eb06a89b83add32255b8e87b9a5ddfa5da29 Mon Sep 17 00:00:00 2001 From: tobias <thinkdifferent055@gmail.com> Date: Mon, 19 Jun 2017 19:21:51 +0200 Subject: [PATCH] Add basic player movement --- Pacman3D-iOS.xcodeproj/project.pbxproj | 12 ++++ Pacman3D-iOS/GameViewController.swift | 73 +++++++++++++------------ Pacman3D-iOS/Player.swift | 18 ++++++ Pacman3D-iOS/run.png | Bin 0 -> 6682 bytes 4 files changed, 68 insertions(+), 35 deletions(-) create mode 100644 Pacman3D-iOS/Player.swift create mode 100644 Pacman3D-iOS/run.png diff --git a/Pacman3D-iOS.xcodeproj/project.pbxproj b/Pacman3D-iOS.xcodeproj/project.pbxproj index d723f1c..b873d1d 100644 --- a/Pacman3D-iOS.xcodeproj/project.pbxproj +++ b/Pacman3D-iOS.xcodeproj/project.pbxproj @@ -18,6 +18,9 @@ F6FEE7161EF80AD500C1DE35 /* Level.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6FEE7151EF80AD500C1DE35 /* Level.swift */; }; F6FEE7181EF80C1500C1DE35 /* StreamReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6FEE7171EF80C1500C1DE35 /* StreamReader.swift */; }; F6FEE71B1EF8135200C1DE35 /* level.plv in Resources */ = {isa = PBXBuildFile; fileRef = F6FEE71A1EF8135200C1DE35 /* level.plv */; }; + F6FEE71F1EF8379600C1DE35 /* run.png in Resources */ = {isa = PBXBuildFile; fileRef = F6FEE71E1EF8379600C1DE35 /* run.png */; }; + F6FEE7211EF83C1300C1DE35 /* Opterators.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6FEE7201EF83C1300C1DE35 /* Opterators.swift */; }; + F6FEE7231EF83DAF00C1DE35 /* Player.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6FEE7221EF83DAF00C1DE35 /* Player.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -55,6 +58,9 @@ F6FEE7151EF80AD500C1DE35 /* Level.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Level.swift; sourceTree = "<group>"; }; F6FEE7171EF80C1500C1DE35 /* StreamReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StreamReader.swift; sourceTree = "<group>"; }; F6FEE71A1EF8135200C1DE35 /* level.plv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = level.plv; sourceTree = "<group>"; }; + F6FEE71E1EF8379600C1DE35 /* run.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = run.png; sourceTree = "<group>"; }; + F6FEE7201EF83C1300C1DE35 /* Opterators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Opterators.swift; sourceTree = "<group>"; }; + F6FEE7221EF83DAF00C1DE35 /* Player.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Player.swift; sourceTree = "<group>"; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -115,6 +121,7 @@ F6BEB8111EF7F99B00EDAA66 /* LaunchScreen.storyboard */, F6BEB8141EF7F99B00EDAA66 /* Info.plist */, F6FEE71A1EF8135200C1DE35 /* level.plv */, + F6FEE71E1EF8379600C1DE35 /* run.png */, ); path = "Pacman3D-iOS"; sourceTree = "<group>"; @@ -141,6 +148,7 @@ isa = PBXGroup; children = ( F6FEE7151EF80AD500C1DE35 /* Level.swift */, + F6FEE7221EF83DAF00C1DE35 /* Player.swift */, ); name = Level; sourceTree = "<group>"; @@ -149,6 +157,7 @@ isa = PBXGroup; children = ( F6FEE7171EF80C1500C1DE35 /* StreamReader.swift */, + F6FEE7201EF83C1300C1DE35 /* Opterators.swift */, ); name = Uilts; sourceTree = "<group>"; @@ -264,6 +273,7 @@ buildActionMask = 2147483647; files = ( F6BEB8091EF7F99B00EDAA66 /* art.scnassets in Resources */, + F6FEE71F1EF8379600C1DE35 /* run.png in Resources */, F6BEB8131EF7F99B00EDAA66 /* LaunchScreen.storyboard in Resources */, F6BEB8101EF7F99B00EDAA66 /* Assets.xcassets in Resources */, F6BEB80E1EF7F99B00EDAA66 /* Main.storyboard in Resources */, @@ -296,6 +306,8 @@ F6FEE7161EF80AD500C1DE35 /* Level.swift in Sources */, F6BEB80B1EF7F99B00EDAA66 /* GameViewController.swift in Sources */, F6BEB8071EF7F99B00EDAA66 /* AppDelegate.swift in Sources */, + F6FEE7231EF83DAF00C1DE35 /* Player.swift in Sources */, + F6FEE7211EF83C1300C1DE35 /* Opterators.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Pacman3D-iOS/GameViewController.swift b/Pacman3D-iOS/GameViewController.swift index 0268b79..6b8c8c5 100644 --- a/Pacman3D-iOS/GameViewController.swift +++ b/Pacman3D-iOS/GameViewController.swift @@ -9,21 +9,25 @@ import UIKit import QuartzCore import SceneKit +import SpriteKit import CoreMotion -class GameViewController: UIViewController { +class GameViewController: UIViewController, SKSceneDelegate { var motionManager: CMMotionManager? + var scene: SCNScene! var isRotating: Bool = false + var direction: Player.Direction = .north + override func viewDidLoad() { super.viewDidLoad() let level = Level(named: "level") // create a new scene - let scene = SCNScene(named: "art.scnassets/ship.scn")! + scene = SCNScene(named: "art.scnassets/ship.scn")! // create and add a camera to the scene let cameraNode = SCNNode() @@ -65,7 +69,7 @@ class GameViewController: UIViewController { scnView.scene = scene // allows the user to manipulate the camera - scnView.allowsCameraControl = true + scnView.allowsCameraControl = false // show statistics such as fps and timing information scnView.showsStatistics = true @@ -83,53 +87,52 @@ class GameViewController: UIViewController { motionManager?.startAccelerometerUpdates(to: OperationQueue.main, withHandler: { (data, error) in let rotate = data!.acceleration.y //print(rotate) - let pacman = scene.rootNode.childNode(withName: "Pacman", recursively: true)! + let pacman = self.scene.rootNode.childNode(withName: "Pacman", recursively: true)! let direction: Float = rotate < 0 ? 1.0 : -1.0 if abs(rotate) > 0.3 { if !self.isRotating { let action = SCNAction.rotateBy(x: 0, y: CGFloat(direction * Float.pi * 0.5), z: 0, duration: 0.25) pacman.runAction(action) self.isRotating = true + + var directionVal = self.direction.rawValue + Int(direction) + if directionVal == 5 { + directionVal = 1 + } + if directionVal == 0 { + directionVal = 4 + } + self.direction = Player.Direction(rawValue: directionVal)! } } else { self.isRotating = false } }) } + if let view = self.view as? SCNView { + view.overlaySKScene = createOverlay() + } + } + + func createOverlay() -> SKScene { + let scene = SKScene(size: self.view.frame.size) + let node = SKSpriteNode(imageNamed: "run.png") + node.position = CGPoint(x: 100, y: 100) + node.size = CGSize(width: 50, height: 100) + scene.addChild(node) + return scene } func handleTap(_ gestureRecognize: UIGestureRecognizer) { - // retrieve the SCNView - let scnView = self.view as! SCNView - - // check what nodes are tapped - let p = gestureRecognize.location(in: scnView) - let hitResults = scnView.hitTest(p, options: [:]) - // check that we clicked on at least one object - if hitResults.count > 0 { - // retrieved the first clicked object - let result: AnyObject = hitResults[0] - - // get its material - let material = result.node!.geometry!.firstMaterial! - - // highlight it - SCNTransaction.begin() - SCNTransaction.animationDuration = 0.5 - - // on completion - unhighlight - SCNTransaction.completionBlock = { - SCNTransaction.begin() - SCNTransaction.animationDuration = 0.5 - - material.emission.contents = UIColor.black - - SCNTransaction.commit() - } - - material.emission.contents = UIColor.red - - SCNTransaction.commit() + let pacman = scene.rootNode.childNode(withName: "Pacman", recursively: true)! + if direction == .north { + pacman.position.x += 5 + } else if direction == .east { + pacman.position.z -= 5 + } else if direction == .south { + pacman.position.x -= 5 + } else if direction == .west { + pacman.position.z += 5 } } diff --git a/Pacman3D-iOS/Player.swift b/Pacman3D-iOS/Player.swift new file mode 100644 index 0000000..24a897e --- /dev/null +++ b/Pacman3D-iOS/Player.swift @@ -0,0 +1,18 @@ +// +// Player.swift +// Pacman3D-iOS +// +// Created by Tobias on 19.06.17. +// Copyright © 2017 Tobias. All rights reserved. +// + +import Foundation + +class Player { + enum Direction: Int { + case north = 1 + case east + case south + case west + } +} diff --git a/Pacman3D-iOS/run.png b/Pacman3D-iOS/run.png new file mode 100644 index 0000000000000000000000000000000000000000..f09b7ec7f076aff1f5d19bd7620dab2af8867aff GIT binary patch literal 6682 zcmeAS@N?(olHy`uVBq!ia0y~yU}OMc4mJh`hM1xiX$%YuoCO|{#SDz<?jX#_!gth; zfq~0E)7d#7AS1sdzc?emK*7`5S)rgPKP@vSm4Tt+*4*Iqkl>eMw%_l4aq{kHnBtuu zB+8)><ka0DGEq%SkyF5{Lvi6v(ZGX(uC6T7Cl+)t_w_aOhz9ELbaCBaf1<dkuX%At z*QwtRs~2Zq+w=X|*?(KF+dW_NdG6-(><2h_rg<0#nl|vPbdnQ%(0u&Jv4>Ce92&V) z3K#@9Hm4{S|5avW_)%wLqpfs+eIEm3#bs^|h6BE{4;aX_|L1?@G&6>=p@s24$wUip zjs_71hpIlOWeg5(j16;Vs0A}DU|~o&ot*TTAwZWQLB0OjWrl{iKW0`lGDJ^N6lGj6 zkwHN?wZnxW!<u2u`LHfmh6n=&ku>ikmJBy^84Ntb(>xe9Y-c!dPJnw80|yU-L10I# zCId?~L&6DV<qC$DnG7OspTccEYOfP`uEoGmF>{m6P8Cbn#%K=RLiX@*JvohYp5odf zW{FIRvmEpeRnC+&YBb@0@c9e_!-9#Tf)AQM|E)O3x9;3Iv%YP7@w%_}v;9{}N_zb7 z>G{<K4h#$rOX@EE)6w57)nLumko#|u>N}Q<IPL|d-@DT`@jGl~Sn%>z_~!yp*tjm7 zu=D24r%#^T@H*lYop>s|_Fwv;_ygg8bAHy@{Q3U%!M;Z-jYhGJ?kqnZ96IyGXQ|Bj zNt`W7cb@gT|Jly{|Bvitr6Zn6J0rA29tR2)_PNaJ`E0aQsncna=26v4|5F~_*ZIwC zci)s@LzW$5^+eqjvB}KeywwFFN)9~w&cN_#cmBaE8XU|G8O;yRm;Zln|JQwiDnmn> z=cGaghBy}$y^vFz?T>RXFt{ve)Y{-E{pFy9&H*-=gRFNBa{oy%YjILJa>z-*i7TZ+ zrYJ#kO_P&G+u04WS_%4B9Ar%n1ZK2NF5uHU6uN`Ywt)XvBFDUg8haW!SsYJr2q!Au z>R?Rjics$35TDulL-C*oi%_?U!pRPiKqc>qrXGetT_Fmg9<rZoi<m6iW88L4v_8RL z)byuqkGtWN#!Z2?S9rEM?_6On)#A2@`$9^I;jDhK1+y;{ZIQC=F<bcj!s-nETm5#< z#|;j=kYG1Hl4GEE?6A{D3mwkM$)`6et>IaHOlm{e8s^=dUz5*oEN2mFbUnan#!~L2 zkSOQq5#bZzcf(_af{coZ;4MybPUe=tL+VPCS9otx+a>t(h(wZ+VS9v!j`B63eqnuq z>JH~4<|;y+&PM7xCop+#ToQ6g=#tx|yddS5IxA<Jct|NvK6xu8dlS3m6deWa6Rl6? zJ~{lv_=)rr#ZS>(bCVnjm;4BRq!Dx~%S-a9z*Cc_Y^gJh977k+3c9;uVThn<f0WbO zh1-JG2ez*eHYuHDdA3>1(|hUKMN=<JWr$~d&s_haWS8LGsd9ePFN9w@{nGu#^cT!u z%6WL(M4OLyq-#jdmSC4imn@f9Kf`C4<mGP3;~@s-hOcKlpUFQnKQuyXn^ukJ#8X^T zy{4*7mDbV^S-EQ2s(Y)rLqCU}4(VSR7hJo}Ez~&p@k-7s(^iMBnj7#sSUNa;rS*#T zRp~48L+qE-MgHw%i#+Ue*xz|c;DU|ukM|r?;7*p@T%n_w&AYm-w9)j4+QzdtYs$2C z&-g35yW4iv%7vEB#$LwZn}a@2Nwa5vJfrZ(oDx6I=NikWf3EAgC-PqNk*4%A6Q7-i zsWI8BrcIv~vD#yG;A;2Rd(GCpT|Rf&Uf11`zZ>}+k9(=dsJo~4pJSc-Joskt-Q`@% z#e8k8zOK_-mAzDY;cl1m{dvpZ&6u|@u3?@}{_=a3d!PT3sn!1*@;CR_@~`eZ5p0`z zRM>9woRhFQYFe0YBddS>_Qycy*uxIaOB1IiPJh@kapy&w#aG>W-S~SlkHtJzd7OJJ z_t;`JHZ?^xZ{JtG?`8%0?p&t1%-YA==lIz(XBVBlHq&&rt>JZ}=d+*BzCQc@_JpX4 zD4lI9w(Usu-1H=BS>(HId-7VNEF+gjghs_~c3V4lt?ISiYj-afT)xw9vft`?*U}Gf z__*!lww2o@H$1(;c6;5n+-<dq=}F@0+mEh0{BH8z$+f#`d;i+9^S0mQTP+(UTUWfL zNW?14>fWq#bKcq49{n=yrG9$Ed4cmcj2~|kKCO8qb8hhL%kJso={t*?KX-I@dN-Zc zn{KB!Tl(1D6MLU{m3%FXeOPtr>)hF!XCHdI;`aJ?X74iJwcnY4#$>+cyh!8X3x`iQ zKL~t!(Vlz$RD<mMYwG-+{TtJ_K3CRH)}I)@_WFkHOUqY%Pkb+K_sy<o{$snxHs<$? z?nTC*F+Z^V#P-wvhx6yfx88TISN@;!zv}-*hUE>ajOomsjgF1cOuv6r)hO=ov$wjP z`fbzAw~jpvb~=hW_BX9<dU|lJV#bL#6V@tze?H^f#B-T^tpRl}u3cbHe3saKxQ<7? zwY@dG&AzXoBSPw;;dImTi+7xh@4NhRndWkDcDkXz<$7H&Q!TqydRaEN%y*gWvOlJm z7J24s#M}ta9B&y*J*{<Sc{%&;|9Shl{n6Y<+>fipXXu}ZEvQ_0?$DRk<zg%KgmkQ? zIrwz=SxouhD4?}MtVi{eaJgz9SLGquL+MKT7tJnq+;EQ3lJooIq2*gO>CMDFrj;s3 zjhE^?-PxkPa>5=TUZ1<Ot>%f%DpSZcvbEZ4*gR?CghHoPioTP#rN2slmR5FpO=|0= ze@FAWx9iJIWj~p{dBPgjNL{XNPRm||L}^^tV&9aW8lJZQZ09M<X{+aHpM85~^Qqet z%;&tH|NpJfA)$wpwk>V*4%d~9c(!*<mgOd!!phrRk40Iv+rrq^*zD-qrj>iufA!n& z>FetDs#W=BH^v=2)pT$xWA<zAP_Cz~wXg47e;ex`p&xmFYvQlAxzcu`on7lhZi`PB zt-qmhr{bw}d;Y2YGw)2<vU2s2ohj$jE~UMEc29R+G~cvU)1OV}%j3OyYYXrFuq|)D zesjI8KmDx6?cL4WoOdqXZ?j`h>hhE4&RW}tED8A%@+-vb-KD!*6R-csyZBDJde1kL zH&<^*@A>}M?&QAPp^TxvSJSSh{`UO6`MdqP&Q&jeO#7W1yVfta@a=KtOU!@SmHD<^ z-+AS#>?PZfp#E#xuig2M%kTR)_kFo8uNiM>@0??glnY!cpS=9edH=f{uhp%xp6WFZ z*)PkN$)?NdXF1LKG|O#v@T}j_NzuFf&)8kO_Uc~MANSkx{BulfA}hT<hn&p3^|I;m z<n&MHd*)7^TU)31^G?F;Mcb;MC!f2Y#h?Fvmq5wGORoRBpIh&-J{R+8N6Dv6x1S1! z?+Bl@-YP!#Rmm%xf0Hl!AKyJ^_pEh0W3qR?tJ=G@I_>*Q>3Qbo?ta-@`BCiuwX5?i zZSU^=T$TU*==ZPp#qQP>ssBB9diTw8^>=Ic`0t7T;_%k-rt{tQtM<|V?%a5Pr#|aI z`GU_E@3?<wYi&ONZ{pW}erMMHnf<5Rc-vmjv#_(Yd}Lqr_vN4E&gWCktIZStx9H#L zb>d?Bbw94YzJBiFjEf7Wf0{mde{RjvzpoCwmRx`P*r8)``%YFE8^(PJ`~CJ{`JHmv z_lxiI`#-5ssMq+P@pI$X;0w!tPnMiK`9BNujL(0PjdgD`Ffb@2dj$D1FjT2BFf=qX zF#P<_z|ioLfuYoZf#FpG1B2BJ1_tr`N%2SB7#R3nJzX3_DsH`*TYVuew6uNx9S^35 zN)sj}33PNE6FAV*dPAy5G4RmRJ1qr*FF2Chxw@o`6`0wUDRhWQbGgnkdAh1mA%N>r zh=~_-go=pQ6sdJyO%5HN1`owPf9?NVXPTsU|LNWI^~L8tpZSwEgVXqa^|h$|U+2}{ ztNq3#m?<93Jh|a><IDq035FX)A~^T(*f85L-C>I1nZvW^@`cWj$-2>M`$QvHOTIYd zGw?H|GgnIlP5i;buE!YnYT--sWu*sV66Pq1b-LRpSZ!E#_SpRidF*bIMH3}_Sn9%> zKHjf$FX&q+e)9B8Rq6k4cd@?6mvTAvyz9)f_g4-dc(=@Xi3}Ulf4L)n=0>r-$<K1R z^!abXv-ekKAK<vGJgKjqBkP~vUm=N{St_c`QQ7A{9xyy`@W4EW`?KP|OCCIXf93xT zE=%X8-RGUb6yvaQ^V{hMZt;rT3qEkY@uF$Z;T>Hw_6JXo-Zkmco7tCLO}o71yJ~;S zie8TJjyh%V``DKN-*;?!D;E5;)-Y4=ys$s@Te9%1+F<=Hb7CIe*vtGQ)>Ybpy<pMP z^*2u&{a#k$>-xCTv-RwKMw^wYCe<Q;w<LKtH6F;<zQ<tI;Jnpq?-{$fkFH)gk+%Nu zqz6BwX6$F);ru(~{+sim7v6-%3*8Bw9I>9YEld0CyGaXP=XhGa|2BQ8@Rlf^&F^mo zY!1)$G+3EdxG(DWRR8z~4cC}=`EA~RHDPmjre{Ii*+;trtf!rh6p2nYEjOLca{Zdl zHtj~oTSm6O8TzxHozmwNyJE0y@z(UHV_Uf*l*8*iKcw&`TLpG6ORhLOPs+T~a|7$u znxE;#Rz9<rJ+9-Oo#R;$baJQ6r6}X;y3>NUWJ>W}Td_4th-aC^_0a7Sa!W%m7i?$K z&Gp<6&iV6=v*GIXc^`l82+Os<&9K@u{p~cC{woG$^Q7i9{54G#tJN-y%U_%L_>SZ5 zZSxnKB<oIRnSNC#Y##T74rS@IU02uMeq3rAFI2NBt#bD2(8~tfj-|yj+wh%XSr)iQ z;c}()Pr(OYrSv(=)<x>sFAu%EA=g)qX&vLg=ecS33yrVu)BljvJDr6)`wGLo^`Vyw z(~q9D+sK`EUt%|NclIysgO;X-|COUmblF1>y!n5HZF7E)tcKc^Yj4AwV)y)=zHXC3 z$4z<foNv8`4Hd%0w>PTn*!<{O{o1WQQ;)oH+NsZ+d*Y2?-SfQ@EB4oaPxIW6e^mOw z(x}Zg$0j~IGXLw@f2t20lJZ~85WK*#H&Uo({i0{}ck};$`st8;_U`QaH?RLs>(Bev zTUh7d{H4S*;A%SK{EK}*f7r~n7s@d``qDA<XWDzcdf^Kqwy{D!t7rVIU&Z?Q^7N#` zXMP?KJ+MEZXV$DJ=gs*&nvT4m)?RBq{qDovt{MN$5BS~kUu4i2v762MYw<2~o6Y)1 zkHj8t>i+WJ<_T{{-p>jK%et={@>G~^`02m(ii(zU$JXqE+P$nY7mvQa(Ldw4eOyMT zXNl4~shIfr?;n-EVYLx_Q9M5_(=$|p;SBd3mSg1~t+p|~JNYLve#wn`r69{Zo?8rJ z<)5we&VR9d&wMXc(sSxe!7ZF6-&todNAnAx{*iOK(O6e@CAVNX@3#`^x0*|=-5;2X zRR3;|Gzv0TdMCAKpZN99oC$nyZ~p(laCE~>SzY0k#)9R%eJ`Jy@@C%^J+t7)*JRe& z^&elay!Lsbe!w{ymWc)~w@r6!ID6fkMZ)#tuWyNKmzAp=z0mhpqfYH@wxq}8&TZKr zQi7F&^mYqAp0bp$%W+||Pp8LD7ptPb?|s`nDt%a|3B7K7Q0>$05v3MzuWi=5tbH#9 zJrDPZ6mu=wpIyIVrBJ56I-`C-@8z;-Otn5UJ>E+?zuC@YzU<{Pza`JVFzc;a@X>l} zAKRPb@=Q5vwbswoWOH`gnQJQ&5t8`1{8isB^M<7dv_d0G^OnbYetebjj%|Z=fj4i@ z{(WlKb~2W%IQ6>j!C}U%mz$5+d2C+(YrB<sL#Wh>O;JoT@(bGd82)WOR#-PvYX6R8 z<`v7*Ce=SUQFb7dxAQxD4ue*c+#-u<TIRtG@unK@(r++?yqmw|9B+VrHFLSS!9VjG z3?X`VeS3tH_g#7*W0TDsV7YDaJb?vnYQa9{c~y4bwlJ>PWTJh*dEdhW<!6rme;xde zIUw~+b^nHsPfEHTuRMEFzE5hs?B>SVjrpr{e(@cBx3ie(%HjFU_LtsBUr}<&Iu#~z zJTdc&Z}yI*N~Mo89%P=qt16qm(<8RRzF_&XchmM|-t>_DVYDI4xjg!R>PwHQGhIG< zH>bUuc~9y8`OQjq(<BP!vgLL2ZJx8lYmV1Puhq|T`}H<0S;F;(|IX^f+w0_`qJ(BP z9!Qlkof#JVX0`z5alr%nCYeRP8?LAby=Tn3JY(t07;nEt22=0P=UZc=5h8V{?uhJ$ z$Z}nFwuq)l-Iq-h%iiWodfnt%WHH~5`Pp@G9e2&iwGGEj<0Q^*R9ULS$9(TX$wRiy z9V*Xx&WeRqN6woxX?^yl3%|0xLxKvYvT?7!8LGcY@yNVt`M|?oCr)2C36Cy&?d$o+ zTr7MqqmJscJHJ=F%D6ji`4gM7w_gWW+wF?8nXdY;dUyCv#t4JE*Uxc&F6{c4`&;gB zWas~9o}qaRer&Ji?VDmC?yT82$LQSM>$W1z-sVT19I5~9CGBARg>8fHp_ntq$L?M` zy>|C9-;4SmjUMdJWjK4`E9d8eJs;n0%X@Q-`R0_<4W$SC%o=`Wdo7ara?tqqF6%|v zMdrzKsw4}x@GkgQRlZ0@COc>M8t=w`wjG7`52m)ve{Ce~u=i`pA(=Z_HRh}38I!9e zpV#~S_$hXS;nmvTLPzVlAE-XweUjPYd`|G1U_ItI_HCu|4z*tk7X9cq*(QB8H#e^A ztN$LJAKhAJ4L1**T{5#eUi>asjb7j%{wpu)m!vl?7CLJE)ab#qYtQZU7W=XEF&<;y zt?<w?<naH-e-pP<>+<CV=-g+LTVSy>V?$W?$qL{72mk(F>9LomqbB?-=UcIUTj{(% zrBmvU{d>c9{I`>?c=x^opLunURX1FeOsexZJo}wVu6Xxt>97X<jX(eXUOAodwDdie zV_CZ`=G<9uXm?`~U&u|F%~JOm#Ikl<@G!-#t~_Y#_x=0(<xdLa_Y^f;>pm=Ms<*{k z<J%+mN3s>)4o$tK$5+qvXI&brnf;Hb&y8*74eeWEbzT**{K(f#lXO}Bl6}3^4V4F* z8&=KdE|4}@r1UZGS8>DCC_Op$&@D6ODc=3}Hzeo&hvy9bncHXF3EAkht1BtaN%W^@ zv-AP}Em1yfO#9b4Fs{wMyD?<udXpWDb5>t{^l4$2$i;`E{hxPB-(hge*nHzpE^F6| zmr_T5{$iW;Kk98LuiQEZL)oB@68ZdVGA8_-zI|P!)`5bA+z(Ar0nHZuxdF^SjB`VE zR~hIRyq{%L{<E~V_rJ|P)`-YwZ2If+udAH14&1Xb!u<33MK|*Px$`{yUi?1v{gg=u zkK9w;(I>I~=eF*N2THn}z2{}yDz7-j@muu3<OAOu^tZ1|U97YALaXcb>q6pBcRaXn zB!2zNyVdna_i1cjWRbbbyFwwg`s>6aM=LTPWXC%izHrfMncR5GeqB|-qdB%xKYrP- zU7Ew-dwtFk%iC+WKI^M^yZ=Iv8AGT~rsv7b#`S-bZ=GVhP_mbg$9K+d>!!HhHMyzG z0UsV8*?GHb$MNX?OHpPFp=VOPPqr+${`Rz*8N<~}CyrSD+1+q`kJydC>Z9(>(>~iI zJU>zyBl2OF{)M=YGkNd$Y@8mw^di59y-0F@18;)l$7hTkSEgNNHf!8(q^tC_Fnj~s z2jgI+Ai3KD?@MO)&k~#X=|{x|HiPq1I;MDUNnBh#OK4(IrBVR%j7%$+Q&0CcN*$Pe zplq4Tk{CPb6`U5GZYs>5n@k$S8|{`kFNxX49LIZ!#m_`m>1naY1hx+|RtlUveARK* zfp*_k54m|f7Z~0d@hVkHh(6IfaPf-L%pXY&Yz0#@1x_C4KUwc_>e@0#75>}ItBuVY zGnYB4$h)WHF?jnldc>ur<uM(f!8Ebv3*)@AHyGs1Sd}VontzTxP`AuMML#_~hhe*P z-NZk4rf=ljbNWN~lT?ilQOnp0c0Lq8dERiQ)B&l44It*$nX?W=w#BK~|80D3Y|`+Y zXRim3-Hexd4+@<1g_=JbnKaCoD4S?uGhrcTkKr4o!XNi1Ngp`d7PHFDK0&2Gpunbp zsUU{egmH)F;n)KO-d?K?>^s2oKr-p<qt(0iWoLSp>{}Q(Ictron&3^T9~;?x*SYJO zcAoe<YqQDRl%1X`de^5c&9dC5tl(I&zU_-FW2Rns_A#BPoR^+?MSB$%bM<a#QB_}T zk{IT@l|@yZJ^Rp_S&5upetlP4B1@Z9H7sW?;N1Lb^|S>~Qg*1FS#??0@#I-$DZ|<K z(tmp9Ez3Hhv+Me$$s9aPVOb|GnV!5fSwm)}qW4wPX>(j2JM~6($!)o!qIKCMBj_w6 zTU46R%+3QfXK#hsvew+XG)c>l^GDk2X<x$+XkAU+d!g%gsYv_EZ(HXqImNTU!pNu8 z_ujMa4h&E-Rq()ajcs@2rUzbbIJwMuiH#fM>5h+w&PU07Q4Cu3Gn~cnztV%b%UqUJ zKHES2QG}_W=E*;S=M46oEa@=0{HO1$Q09uC=Z$5R&YJAMT;n2@^>49nyT|7<`=un( ztz2fM|5H7Xaar+_&1Ze4GDBIVryIisKI<>Aco^;?mG<wpPpgOV+4m3pCbrG`uN16! z$>;O@R4tcTng9G}aZP+S^S|$d<Yi7vDxcL$N+fH6Ogk!)&e`R0@>%@Un}7Hjt!IE$ z$t~EwQXq5Q&-KQ<N@q>}oBK3-{OsXN__x`&*~9p3{j5xZ%w<3SUoz=1IsZqyVdFAK zkcoU1^D{x3<eC3n0n2=D)b(xl_<Y9xxJbtn<NvEA&(<&11nFEpn`xp=&zYQm#y*W6 za@*LarJDQ~309cY|Jzuyp4Z^shwdkjTYR3?Gu}A<q5H|xn>^3{TW(kl>b<oa&G_$_ z5bdl#Y5r$#v;X^<YI$~h@T}9k_{W%cyN6Dm&dER1C9)<~!~{0|+@CSSHK`~q>GS-g z4%bJUvXvgMXH}DqoA{$<|Ji5ttUnecimqg<-hT0qKe#WMRahu}X1{<$mWJ!9lXv1~ z)XQyXRTNoiwz(?dUu2u_61zEEIxm|(PT%q`UT~%4ZKnB|y4>>?RBZb1^?LvFZU4@S fS1mF5m(TEcmyfIJRe{G03=9mOu6{1-oD!M<t=X+F literal 0 HcmV?d00001 -- GitLab