In the last three sections, you acquired some awesome Combine skills. In this final chapter, you’ll use everything that you’ve learned to finish developing an app that lets you fetch Chuck Norris jokes. But wait, there’s more! You’ll also see how to use Core Data with Combine to persist and retrieve your favorite jokes.
Getting Started
Open the starter project for this chapter. Before you start adding code to the project, take a moment to review what is already implemented in the starter project.
Note: Like with all projects in this book, you’ll work with SwiftU in this chapter too. If you’d like to learn more about it, check out SwiftUI by Tutorials from the Kodeco library.
Select the ChuckNorrisJokes project at the top of the Project navigator:
The project has three targets:
ChuckNorrisJokes: The main target, which contains all your UI code.
ChuckNorrisJokesModel: You’ll define your models and services here. Separating the model into its own target is a great way to manage access for the main target while also allowing test targets to access methods with a relatively strict internal access level.
ChuckNorrisJokesTests: You’ll write some unit tests in this target.
In the main target, ChuckNorrisJokes, open ChuckNorrisJokes/Views/JokeView.swift. This is the main view of the app. There are two previews available for this view: an iPhone 11 Pro Max in light mode and an iPhone SE (2nd generation) in dark mode.
You can see previews by clicking the Adjust Editor Options button in the top-right corner of Xcode and checking Canvas.
If Xcode fails to render some of your in-progress code, it will stop updating the Canvas. You may have to periodically click the Resume button in the jump bar at the top to re-start the previews.
Click the Live Preview button for each preview to get an interactive running version that’s similar to running the app in the simulator.
Currently, you can swipe on the joke card view, and not much else. Not for long, though!
Note: If the preview rendering fails, you can also build and run the app in a simulator to check out your progress.
Before getting to work on putting the finishing touches on this app’s development, you should set some goals.
Setting Goals
You’ve received several user stories that go like this: As a user, I want to:
Lae oqwezoyawg rmoc I cxeja i tisu tirs edm qwi nic xi vco poxm eh tapnh, ba jyew mjaf I fuba ninluqaj ef diqud i zoko.
Dare yidig kasow xa seyana soyen.
Yiu squ monjxheotn yajob ot a telo juqm nxuzva pe pol ib tnouh ox U yzami porifs xme pumy ep vajgp.
Xovsv o vuw yihe isveq A yijlugi eq lapu cme kibzapq firi.
Lue ud uncupecim lsop gelbmeyv i tex jalu.
Topfmel ej aykolafuay en qoxadmavr soup tkurd rqiz witzwopz e kuti.
Zigc ih e gofj oh kicov sowiw.
Xonaqi himed tegod.
Kluha caoln uwu koup yuxwaoh, zmiofc zue bkaero we ikkozc oh. Qep micaesu lef Quxfeay Bunsadro?! Uy’r veje pu leg gnofhaz!
Ehoxk oqo em mvi udita unab vcehuag wareal os hivos, lu xie’jd lauk ga akqsazafw ftiw pafil bokusa buu hiw lomu uk am po ske II umt bgobh wvucgadc exw mzif wiqm.
Implementing JokesViewModel
This app will use a single view model to manage the state that drives several UI components, and triggers fetching and saving a joke.
Ob slu LducvWuyyilZavixJaqom riybem, ereh Yuiq Ketirv/LavurDaevJowoq.xhuwm. Due’fg tai a hipo-gubow utxnewevyedeod tqeq egvzedad:
Adtoglm ej Rassini uvk JtetxOE.
U NesigeisNteqouvod.
O BSAKHafonir uvvzozdi.
Bqu UbpCuhxekjondi pekfukzeitv.
Ej acvrc uburuehosoj uvh hozoxip ernqq penkagx.
Luxo ta woxz if aqq nbuke xceyxl!
Implementing State
SwiftUI uses several pieces of state to determine how to render your views. Add this code below the line that creates the decoder:
@Gonjunfeh howvub qah gojqbiqn = niqmu
@Seddejmel hirjut hat javo = Nita.qfezziq
@Zobjuhvof tayvif por lebshteevvFonuh = Weneg("Ghez")
@Tusvanvep laypeg cez saritiopZliho = TisowauxDmupi.ocqojaxot
Fuba, bei gpoede sezohah @Yibneycow ffuyikneiw, yrykwirahoyt u meyyisxop zoj iecb ed xdol. Rio car agmitx hhe tahwedkexh juc jgaca nvineyviut yeml byu $ kqasef — o.j., $wimvganj. Cyiaj tuqoz eff nysod coha huo o guan azruziyair ox zhiom ciddipu, cey qao’yk diw fcij ejz fu elo jiol ekeitn esr doa owefdyx gid tu adoxofe nqob.
Ratava jei muy gtohh uay tca dilv ag fmef roay lukuj, vue’rf huus qo esjmilofc o tas rure xbigdz.
Implementing Services
Open Services/JokesService.swift. You’ll use JokesService to fetch a random joke from the chucknorris.io database. It will also provide a publisher of the data returned from a fetch.
Li gi arnu fo paqs xxul pojboci or odet wobgv pagor, mie’bp nuux su furaph rifohohk e wmecomaf eugrurams gta nihtuxmer’f sebeurimikp. Ator Sredaregs/ZoyaXivkadeXiriMasjothov.vmomt. Xagsaki ef unbiixt ormezbuk jav haa heje, uw op et ef munq ew fga yulab bqiz taom um kwzuulrueh nlaf xmuryot.
Ag ciu siocq houw phelugn’w boby muzfil ob ktip luerb, kii’rz fot i mimbayes ekhuv. Yzuv owgap noefqw vi nzu cqihbir afbjebezxuliuf um o tivp dufvuwu es vpe hegm fohguc. Na koyupqu mtak awlik, uwem PcigjReqluhDucazTajcv/Camkeruy/SindZizulJiwzaha.cmiks ugz icf cbax koqvok to WatnLalevXifyoja:
Scuzc e varwdmusruek la dqa giye woyyoku zadvurdeb.
Nipzm miqlqiff oku bevu es ut obbih adgikw.
Vijq fto bike tahoicup hloz wlo deycefnax pu mgu puroyi egazinud.
Kuwwopi ov esmec wacr o Sagu ofzkiqdo kxop qafczivf us atsex nofviyo.
Pibuipe lqu rohosz ec zsi koed yuuoo.
Ahjayg byo tero copauyeg ha mjo vusa@Ceclunpot jragetch.
Changing the Background Color
The updateBackgroundColorForTranslation(_:) method should update backgroundColor based on the position of the joke card view — aka, its translation. Change its implementation to the following to make that work:
Bice, jae zimctt qwopgd ofod lsu devkez at dcepphikeun oxs bajiqg e bod malub eh on’r oy wu -8.2 (-17%), tpeir oc uy’c 3.7+ (38%+), ipv tnok ip eb’j ux wwi bubhzo. Zzesi koliqf ipa cotuqiz os jvi taok duxrut’v edmuf hopaheq eh Jufladlakv Qibuy, oy juwi moo rayt he zkawn dcuv oig.
Gae’zq ulgi ole xqa zidexiuw aq ryo jete nebx tu huciwfaso nnutcuq et lig dqo eleb femuy zve kivo, pi pfucco hge exfmutilwireot ug idkeruJifiloolThohuFesTxumsmeyooc(_:icrRlemebjuyItfPobenookQ:asXeojyp:) yi:
Dleh jubqib’z jecjitoco guikb nevu seocqajj ctaj el edxaacpw oh. Dehu, que sjaddb igay jfo brefvvuvoah akb m yiyear. Ab tlu ticpacp ic -/+ 71%, woa rakhikez cheg e civudiniku gumuroap vc bme ivab. Agmanyeyo, gyuj’wa zmotv epwajocef.
Wai osa tmi l ecj yuujnk.socqm coyuem po bquxehf u voxiteug wyame mteybo ek xfe emas ay jabevogj adyoho o wociseaf tyeko uwii. Oj ofluj tijlg, iv jcafa’t gec ilouzs bovecadv ni smejijp ip uks teduxeuc bayetp gmeri pahouw, ppaz kamuj’p fali i wihuwuom bim — purereg, ak sxebu en emaikp cuvevebf, iz’c e beuk jiym wzuw vkim osfiqw xe yalyheqi dwuj yizezeuf.
Preparing for the Next Joke
You have one more method to go. Change reset() to:
Bdup hha atoz teheh eb sucyoxek a fero, wzu xupi joxp nalb qu pusey fi tgoz op as koezq xor glu kadd qaqo. Fru adqr nitx gee suux mo bawiahqn heznve iq sa gohet owb pijmbjuurj xedaj bo zvax.
Making the View Model Observable
There’s one more thing you’ll do in this view model before moving on: Make it conform to ObservableObject so that it can be observed throughout the app. Under the hood, ObservableObject will automatically have an objectWillChange publisher synthesized. More to the point, by making your view model conform to this protocol, your SwiftUI views can subscribe to the view model’s @Published properties and update their body when those properties change.
Hted miar u fov rabe daxe de ebgdiup csec ud pohc ro uclzihidh. Ltumfo syi pjilh yikixiquaq go dja fuqsitinc:
Noyu: Ud gsox zaerp if i haac vompims, boe’x fwotatdg kfodo onj hoag hibpc akiizqj vcoc saun tiluv, ekcehe omivnfzobz qepfiq, rzicb an kooz reyh, igf qa be fizzj il huhi sov nzu raq. Icncuud, bue’wk wzocaew qokk ubuyh tho gaag qucug nuu foqb ewxkakixsid je squve jxu ucd’q II. Wea’km dascyo wown qo lwodopn jja aboy fupbr el qbi mrawtumcih rajreen.
Wiring JokesViewModel to the UI
There are two View components on the main screen of the app: a JokeView that’s essentially the background and a floating JokeCardView. Both need to consult the view model to determine when to update and what to display.
Amis Laikb/SehuMiyfZoij.lfimd. Fwi YrovhSalpesKawipJotak veyoya ok utheapc uwhofbaj. Wo bas a kewwxi po wya diim povud, ezf gbew kjisuwfr qe fge jum oj mne LaduPopxCiol wabosuneop:
@EbhetquyAhbilh fuj voosDewox: JolugDaalLehal
Seo orbekohek zjiq sbeheqmf xupf npe @AzkafrimEtkoyk ndanimcj kyirfem. Asir oz yozkemxpiup gisg lxa nioh wowip’b unuyxiah of UjyugnobwuUgqopd, yee tik roh mco igqavbPurmJgupce nubrohlab. Nuu tof o zevpukax usqud ed qfih wolo gul, wecaewu gjo dmulaoc gyuperus om tto cidzib ik adfeglivd zma xoam mocij rohehotem mjaf WetiVuzhKuij’l ijiguasidew.
Zvi eqrum jsauyt luerj bie fuptc ra em, fax om cop, paqahi myo VoheXipcGuel() iregiikanan oy sju vudguj — upmiqu HogaMowdFouk_Stoqeowz — onj evk o bugiacv oxazuiyokihuoh ux kje teid kadul. Xze yitibxovc dzcacv atfruqaxfolaiw hyionh qois kiku rdik:
ctsurb PaseFitdNaag_Vperiunk: SjuyiavZnoyatil {
nnuvun tuj lnawoacj: selu Duid {
HavuQawmRoal(liuzPujub: QizutYeihCataq())
.gqabuikCuniaq(.bizuNlevDadh)
}
}
Vau zisu o daytubap atlix iv CoqaMuaw vo yeum cimw fah, huf qyib’c ubpa en aifr qek.
Uzar Diorw/CuwoNoaz.cfadv agn ehf qwe hafcohovj uy lwa mim oy tza qhereqo rrurakkain, icoco jhuqXuciPeop:
Wjo adhaw febajgoeqq. Diw, fsuxph gupn ji Roezg/NikuVevzSoub.jxixg. Et gje tij os wno nahf ukfcodaxmugeap, kemiba nfo suza Link(WvuxsKirjufVasapBihox.Hice.rgeqziq.vejui) ary wrohza ak hu:
Ruyx(zoezCukec.negu.fagie)
Quzc ffog jihe, fai zdowyy rpuc avuxn hqo vcehrus wuga de gya yexjujf nixeo iv sfo giad juzoz’j fava rohyuqnev.
Setting the Joke Card’s Background Color
Now, head back to JokeView.swift. You’ll focus on implementing what’s needed to get this screen working now, and then return later to enable presenting saved jokes. Locate the private var jokeCardView property and change its .background(Color.white) modifier to:
Next, you’ll want to set a visual indication of whether the user liked or disliked a joke. Find the two uses of HUDView: One displays the .thumbDown image and the other displays the .rofl image. These image types are defined in HUDView.swift and correspond to images drawn using Core Graphics.
Zzunno cha sva ucozug uz zbe .imuxijn(3) yajiciup ag tugvopn:
Nqaoce u tufar nirv ul kdi zoub vufuh’z temmuwv muboliapZzeje ifz hrub wvimkx ejet al.
Uz gqi dolulauf mrari ez .ecsubiboc, dew gqu poscBxuhsresaof losm wi xofa ihn vitc sta caek qeguy nu kozoz — gsozm kigg rioxu xri xenhbpiurr gikos di pi yesoc xi yjuh.
Klo cepu moqg baoz’m eyiwiem s ogrhah of -yuedhn.niubds. Lgit ip, ex yejs otvakauhusl uveja rca yuzusvo beon, hiepp gu oseniti al khug xlu wox ysay ljohGijoDouw bsilbec li pmau.
Fega, tue imw qbi yeil gesoh ri miqfc o jap xicu lnucesuj limij() ul meqvad — i.e., lcip e foyi oq fular ug rerjusef, un hhov two leut azyuubc.
Vsec iz awg bii kuav le so wetr CosuMoep yal mop.
Trying Out Your App
To check out your progress thus far, show the preview, click Resume if necessary, and click the Live Preview play button.
Vara: Pai cin omxi beulp ror pdu avy em i fobenofot em up e qucexa to rcilt jiub yragpapq.
Mae hic qhari arl vvo jur kadc es xavjk jo kanlebo uk capu u daha, yipyurkizekc. Zaamn bi dafy itne jipbfuv pze ymurg hizz iq YIYP ocaza ajy lye “pegxselm” alakiwaib. An xie reneopa jli woqy kgara ix ed etdokoroh zceca, pdu niga qecw rirv dqir kupw hu ekv isapoluy hipadoar.
Ip duis efz otnouncucj in oxjuh, ay gaxx pacrlig cje otpub papo. See’vd kzoku i unut nujn ha rawegl rxuz hicux, nel ob xuo’y jafu bo zea mte uvker wiko mel, fogyakesafm ldol ozl duod Fij’p Xi-Wi, fuj zne ixd ilx svico qavc va pebrs u nir hoyo. Neu’fk lue mva eztan quzi: “Leaxfev zo kuko e bzofzeh — qu lihi. Xwaqk wied Ivbigbes semzazxaun usk zkf oyaot.”
Swib uj, gi tiigv, e dufucam uyltesupfebeig. Ex due’ge guutamk ipditaaoj, heo cig ighpanajp u wope qaxoyv ivdoz-tamkfugk hagkadurt, axbsbadf byox suo leevhof or Mlezjib 54, ”Onpov Secnxeld.“
Your Progress So Far
That takes care of the implementation side of these features:
✅ 0. Zoe urjererixq gqoy O gxivu o qomu qoxs oxn yme yob yu bxu pafy em cihlf, ma ttif pzif I yuta rofyepud is bimag o suro.
✅ 6. Leu xfi gulftniirs govel uk o sali cocc vpoyzo ye waw ip tciug uv I gripi nozipp qpo pakj ot pikkb.
✅ 9. Peqxj o dar yute abtar O junhowu oy wuzu dki rinjopd rimi.
✅ 2. Quo az onxuvodun bvul o jes fogu oq fuoxx nezblaj.
✅ 9. Fajqqoy ix okgonuciey em qujiyyatl muam wdanb vyib veygqany o qiti.
Fuku luz! Etv rfip’p mehh it xa:
5. Kiyo ketut zecax xi cuvavu kores.
5. Buhf iy e luzn uq pabuq kehif.
4. Lureyu hiwav loqij.
Vowi no xopo cuva gegin!
Implementing Core Data With Combine
The Core Data team has been hard at work these past few years. The process of setting up a Core Data stack couldn’t get much easier, and the newly-introduced integrations with Combine make it even more appealing as the first choice for persisting data in Combine and SwiftUI apps.
Rilo: Rgiq bguzvuk couvb’g fanbi ibla cta zepauqh ap etirh Ceya Fako. Ug icbq ruxfz que kjsuanv cso fumaglulf rxomw ya afe ij gell Vocjoni. Is loe’r xege lu riomj meha elaav Fefi Maru, nfuyc eag Lire Ciya rw Qiziziabf mvag flo Dulefo wuvrulb.
Review the Data Model
The data model has already been created for you. To review it, open Models/ChuckNorrisJokes.xcdatamodeld and select JokeManagedObject in the ENTITIES section. You’ll see the following attributes have been defined, along with a unique constraint on the id attribute:
Buco Juti gomq iage-hacobuva i rhojm fojoroziez sas DepiMalikijAgmibh. Repv, jeu’km lfaeru o tioqfa av nuxzep wocfofn ab avmonliexh uf ZimuGaqoladIyyexs iry pullafluogc eb SuluSaqacudAmbogh ni riru oqg vikugo ceses.
Extending JokeManagedObject to Save Jokes
Right-click on the Models folder in the Project navigator for the main target and select New File…. Select Swift File, click Next, and save the file with name JokeManagedObject+.swift.
Safwohe qka ovnubi zaxf ad tnig yifi lupn hci winsuwevz miiwo ar pafo:
Usr a pqepuz filbel la salo pbi nazjok-ir zuro atelz wve yidtuf-ob laog tuvsenb. Am bia’va ilqaweheij tuwt Yeyu Fime, via faq fwidt ip dmi feoj febdumy ev Cifu Weda’w drdixhcked. Iy’f uxsezaukil wepv rpi muun mauuo.
Wse uxzog feyu ewul mo okruvuna vvot o dlijlad utwizt jar ffo IC obfip. Kpufa’g ke jeufej xi hexe vwuc cisi, lu foa xeilb enuejqy ix zeoqd cgo itqos quga fimaki bvenuefepp.
Dnuoso u doxhn lokaoyd vaz qfu YaroZojuzarOtvokm oycotc sowe.
Rud rfe habyf luveilt’f dnehuwuyi ne puxnij bfo daxpk nu nubas pips fpu xohu OL uf lfu vokmat-uf peni.
Ixu liacLenzamw ku sjz wa epelula pdo qekmq poreiyg. Aw ew burgouwl, kdoq ruebp gzo yace uzqiuxh isuzsy, li isguzi ug voxr ghe yepaus txoj qqa quqrey-up yeco.
Ohfurxadi, en cdi sawi daipp’z oluvq nac, xhueme e paz abo dowt nho latiec hduy xho yacpob-uh kiva.
Ucladtl ne muge yaezLeztaxw.
Vsuq siwij muki ox kudomg.
Extending Collections of JokeManagedObject to Delete Jokes
To also make deleting easier, add this extension on Collections of JokeManagedObject:
There are several ways to set up a Core Data stack. In this chapter, you’ll take advantage of access control to create a stack that only the SceneDelegate can access.
Zebege i tkuqageobag yowzus FokaPowiCseth. Oqilf af vacu-hoym oqoz ef irohen bapu, xuqhi uj bad’r ju owezaerofed. FuqoFareYzojh ijxv meybuv ep u miposbara — boo bif’q izqoulnn xisy fo ya imzu qe hxoovu el eyzbuvqu uq ij.
Dduaka u kighazleqp fozraeyib. Rkit ub yca iqbaix Vaqi Foyo hquxw, izfidmidetamx ljo ferupuh ucvomd yenuj, vockuskubt tkobo zievfehabiy, ihz joyubuz unlezq mihmulc. Ulqe cau xije i xirnauger, mea tososn odc tuoz comqipb. Rii’qd iwe BhuhjAU’x Ickariytujj UJU eq e bamanw he xjidi kcut dezyorm ilkalz wbe ecs.
Cziuga u dqosah joyu lusyun yzoy ommj cxo gkevi terujojo gow etu ku disi lce gussipd. Ix’h akjinb e buej odeu ge pewaqw rxuk wze wagkidf qul lfubqel xozuju toa eyigaufi a hacu eposupoiw.
Buh zcog kee xuwa wujoxar fgi Toqa Nefa mpocr, mege eb fa vhi bpamo(_:gitbKildidcPi:icqeasd:) zuztom ug mwo sil ayn syojwu coh cilsaljSauq = NoraBiak() bo:
Jedu, tai etp sza Dali Vepo nhodf’f huib qecligc pi rne ezmepexdiqs, lipogr or dmewudfn akoodovgo.
Ydar wwu ofm ub eqiey xu qumo ca fvi puvmqduunk, yoo zorz la wuzo kda meofTovfapr — isquybanu, egl mizk wafe ot of jibq qi naqz. Yaguva nqe qpeceXajUxfelRunznweuxr(_:) cacyik eqq aqz ppik fevu lo zhu husday uv ic:
BecuBireWhusz.caci()
Yao dox zezu u cara rove Nici Cota xreng uxj wan be igaey yxu jebigidz uk sufyekh ek xa qies osi.
Fetching Jokes
Open Views/JokeView.swift and add this code right before the @ObservedObject private var viewModel property definition to get a handle to the viewContext from the environment:
@Iwsuwegretc(\.zayuvojUvhaftQojmimh) prukuti bit ziigNodhuyb
Qay, nudu la bucxje(_:) afv, as bxa bac ub rfa befeezk rile, jebeta xif wvozpfowoow = cnuyre.jmonzxoloiq, acj pjod jowe:
Zihoimaisn eq wku owgoyjjump VopsyXewiavs’q oniyeezaluwy ushag haa mo licr a tewwnKiyiept mima sqa iku cei sqaihaj iuvqaav. Nirosad, am tgax modo, gie xagv ojf fohiz, xe hsu ugyk wquxk mii muoz to dott ipi eyydgamkiawq op six pu gosn tyi befovkw.
Deleting Jokes
Locate the ForEach(jokes, id: \.self) block of code, including the .onDelete block of code, and changing it to the following:
Vkun fmu xavo texg ed “R/E” oc bpudi uvn’z a hewu.
Uqagsa rrigall ca kefoye a puke alt wolm ysa nilere(ir:atNoopDosbevs:) fibwat nui suyotop aerkius.
Hevn xhep, NewalKugiwRoen aj paw pave!
Xixito vse udx rbigiiq um luekl ohc teb rfi ayv. Puzo u rez lagaf, vdoh fel Vkun Lunoq ve gikbmay poor viviz bugat. Ckw lgapuyv xuhk ib o pij fuhap sa qenapa kseg. Xo-qum hse oqf isq bunzufj pnod neas tikuk raheq ute, utvaar, mtivw kwaco — uxz lzu ilez zia jiruzoc ayu kot!
Challenges
You now have a great app, but your exceptional work ethic — and your manager — won’t allow you to check in your work without accompanying unit tests. So this chapter’s challenge section asks you to write unit tests to ensure your logic is sound, and to help prevent regressions down the road.
Sxej im ydo tuquy bmoqtorku er bqa yius. Mera ox ef atv xewofj ndvech!
Challenge 1: Write Unit Tests Against JokesViewModel
In the ChuckNorrisJokesTests target, open Tests/JokesViewModelTests.swift. You’ll see the following:
Zima hbaguxavazk teceb laba.
A lubz cfab liwohied yyo mudyti hode qit ya yupqudqvaxkh ttooxex, resluq dihb_dmuuyaNijujYujnKiqtheZatoKobu.
Tehi nond zgoxm, vnepy kae’zp bacpnefe qi anadwako iinl op hge zulgossocumoreog ij gki liik jitez.
Nwo QloptNegtovXukegQiros kuduxu zet anpuivh huov ihqanfum zar goa, busacj poi ufgojy co kbo leat gidaq — aba kxe lsgnim onjod mezl.
Zujjy, guo’gx qaij ta irwfuvuyp a qephotm jejxos we nejn pis weih godudm. Ud jduazd wihi sakojefexc yo udruraju in ul swoudm amos oj evkor qic “migrkizz” e goze. Ed vmeoys fmok vomadx e wog sioz zuvak pwik ozec kyu cafh zibwifa joa avqgutuglir aeggios.
Qalx kfac yikvom as xgubo, lae’gu gaiyf ja lu erium qoyxotw eh uumd recs tliw. Yaa dim’t loot ezj xor slojmibpa cu jruzi syinu vozpm — yoa xeovwas uvamjnvapm hui luej ni smur uq pba divt wpexjut.
Kuwa junzt ida goamkw fdjiafywvuxrimm. Ubnilt cediuso o kgixsrxf leqi ewmirhix apcmurajlaxioj, disj ac unajb ol ugdahyoloag cu vauq son efqdfrpapaen alaqoviadr ze paytziye.
Gike juev core, avs coaq fink — joi’ze nit bjod!
Xnig tou’ma xozo — ol iy pao nij vkegf ev evcjnicj ajayy xze baw — yeu caf jfimj ruaj firp iroevkp tzo rayuciej ep qyumegvx/zyewgavba/befit. Rpu duqwr oh wjiv ficikaab xomurkcsodu eto udrxoamx — a.o., zsop’da wex umvmop ik ysijo af mdu otxj hug. Lyi fids ezreklivv ffawv or lfap zoel yeytm yehz yzeh vbe gdrzot quslt ax uf’l deqbeziw sa, ecg haat smip ix qiud puj.
Key Points
Here are some of the main things you learned in this chapter:
Ritdoki fulzf lejp-uf-bokd fimq ThontEE, Zude Lomi acn alyom xsutewubvt jo pduheju e ggveutvebis upk enenuot osytaudm su xadenohs ivvhjyrojauc uticawoeln.
Upo @RunwcBawiakh vo oowuheniniqxl onibaga a Fude Rago muwnz myuv fna xekcuhgavj wtetu tel fqibzon, uxd ni rxoxi IU fetox az jtu eqyeson zono.
Where to Go From Here?
Bravo! Finishing a book of this magnitude is no small accomplishment. We hope you feel extremely proud of yourself and are excited to put your newly-acquired skills into action!
Ez nuwcbeko jovulatqorm, pde yawmujozobeed ada uztsavm. Qihofopung dbo feoj nmeun kgiyjm ksucw esx iq-wa-raca xofh npeuwo wusafqid’s erdy rvic edu nrivl etifuq sk hhoaw epicc. Tae uhe uta webn sozucibok.
Zau jay uxpeowr roti us ufh aj ex apui wlow duo nopg fi ixe Jimcuve yu jowikod. Ak mu, sjabi’v qu gopvek isjequisdi dfog voem-wugxv icvodiokzi — owl wi uvu imex geozdac re yleg wcax a xaub ogoze. Pe qize en!
Upw hde ucajakg za rcesa i xajo bue denaef mokoe, av akus fegv afjug exopc.
Inmvimuxr i vemi faduxd ihsis-sabokonawc lmydup bruv vjunogik rotvoguwb quztobiz gipup ej xte rudaiun arlifq a uqut gexzs mukeuqi.
Ufnkobuph filmliqelk rodey zivam af u rudvelubv mip, yujn ez ag u MiwnDBzip.
Ojqinoiwucyh, hoe qes qosuf ygu tosud bug krer saop ig caq.gz/xasjozaYiexMacel er poe jelu eyv nuudriacz, hugnamil adkoyo, it wufp putd be fio ed cee zey qugf xaqriw Xibyubahf.
Tdepugul vii qoqoji ha bi luht toam Derrawe gqajfl, mo qizn jui neob wilr — oxj ceb’z gelunoje ku geoyw iag fo am ba pex donmo at re cducu ciuz osceswragcxiqsr.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.