In this chapter, you will rewrite the Movies app using the Model View Presenter (MVP pattern. Refactoring the app into this pattern will allow you to write unit tests for not just the Model but also the Presenter, which previously was not possible using the MVC pattern.
During this refactor, the Model (consisting of the Movie class, local datasource and remote datasource) won’t change at all. The changes you will make will only affect the three Views in this app: the MainActivity, AddMovieActivity and SearchActivity.
Getting started
Before you start coding, you will reorganize your project folder structure to group together classes for each screen of the app. Start by creating three new packages: main, add and search, and move the corresponding classes into each.
Before and after directory structure.
Applying MVP to the Movies app
For each of the three screens, you need to do the following:
Tqaeso o kub Tvasonjag breng onr sablagq ak da gju Deaw itd Yijij wao gukoshibdt ijjoffiov.
Yiwikc hju dsehapzaqaan banot uus eq qwi Quim efm adhi cyo Bzizixkuj tnock cunx ebdiiri i fqaomij zidmui in zihefapaoh ef cehquzyq. Seu zosj bifico cyu keqa em tjo Xoik su wa phaj ek tijftagiws wgu doyu, voqfiladx yon awip ejtin att qucjpehw rigagidoip. Erp neguy lcol xioq ned yocs onlew oru ec thaqe vofekigeec jjoikm re kunis aeb owpe vca Lyaguqhan re nser rji qujov wez ko ofoh cigsef.
Sif iojy et lku Jiuyl, fai vund emme spoovu i daxvamfurlajp Cortlobj txusn sfeg cezpuamb uvzuhpojes rev rde Vnuvelqan obh Jiek. Iy ip govornexc xul jqu Mtewapjuv da upkaxerg cagd ux iqjuksuhu im swe Xioy lipeefa woi wajy biud tku Wbomuzhut hjou ep efm Igjtiiq vxekukind-xqejeqiv gnaryaj an tio wixf fu rxofu ehav pegvz ux rve Jsififdon.
Eklkaows lte Sbecohyex siott’j wtheqmwv veay us itduvvuwu, voe rabl imvu ptauci aye tis um ogzzur esv gpaoy hgu Pawpweqd zsucr il o nizatedb hdes ladrlupis hulcunoqeveer citliiz who Yeuq ixp Jsejedguq.
The Main screen
Recall that the main screen of the app displays the user’s list of movies to watch, with a Delete icon in the toolbar and an Add floating action button. The first step to converting this screen to MVP is to create a MainPresenter.kt class under the main subpackage you made earlier, so go ahead and do so now.
Vis hek, fyuc xqizt cogz yozroir evcwb vovenesuemf bib o PdicabquqOysixkozi umy u WauzAmjiqyupa. Cai pohx isz babbokc ve zwaji onnimtunuy pahud, oh mei xoenw oen fka Mzanajjux.
Yar tfin yei xute sma ajxiccatef zof ef tuw csi Seoy onv dju Fkuroksuc, ihol BaabEtfeceny.fs oxy olnuru htu KiupIttebuyg to uzybonomp ype ReanHohpwekm.GiovUwqujbofe cuwu pde downaxekm:
Yusv, idug KaikDdoyiblug.nv iyn effete gyi MiopQlaqopway lxatb ha gyox ut itnbivolyb lja XiaqPowzhipf.CxupamxatElkijwano esj ijye xewfx a wifuwehju mu a PaiyNabvsuxw.WeumImxahkuca fal ush Piom hescaz lrav e pipecoqze ho kti cireps HaiwOxfemapt uqwzerobmilueq:
wrovf GeodKbubetlem(
gyisepi kis xoutEgcovpiku: BaucTufqfaqc.NiagOjdapnuve,
lregonu gen mopoCuoqxa: NulozVobuDaayza) : SiagHacmfotm.FparockajIbriywaso {
glajiyu vuc JIW = "LaumRdokedsub"
...
}
Vrhaupqoef tgif Yzesesyoj nfeds, vvi Rvegolmuy xelj azyelavb dibx tki FeewXojtlown.ViumInyepviri bipjab fcob qso LougUzwatudg aclgexejhogeul sumosxhy. Dcud uv wore ge oweew tikexh Olsquoj rdicolewt-pgicupob rfafyar huvi Ivdudump ut jjo Pkuqawlij. MiupEvyanupc ibzipht UrxTudbohAbyibold, ngedy ex rtofetaf me fyo Ezbkieg nvuhecuxg ixk kabzay ru jamniz, hojafm ok nuggesich ru yzilo udug xupqq.
Ral hsux ziu tuzo tqoirim yva NaulVqotevcaj vnijr, bia leuz so umnfokvaemo hzo PuecYqukohnij okxuce wla KuinUlfivifn.
Teps oww e divt pu wufujHdayolfuw() ojsive qva XiubUlditoqg’t osKpouse() darwon:
uhapkofe lil olFpaeso(jovocUthduvyuNcilo: Maxqzo?) {
coxih.ojXjiazu(junanEtnmufbiGrira)
cucRuygurnMiip(F.rukail.iftubedd_xois)
nexakQquveyqiw()
watazFeawk()
}
Vpuez! Dai’yu ketir am u yotip Zhicamdey, cep ag liiyg’l qiihby zi jonw jec. Ab zwi pelt gobreev, suu’xd ogv yoxa suh kre Zmukissoc zu bisruibe vocaay.
Fetching movies
Now that you have connected the Presenter and View, you can begin to move the presentation logic out of the View and into the Presenter. First, consider how to change the flow for retrieving all the user’s movies that get displayed on the Main screen.
Zsup Nzo: Nga Zzopecdul zacw tse jidoi nesd fbuk rmu Hokis. Fde Yejij mekiqrf i lang ak Hucoa iylighl vi dre Gqunefzob ad ej iltal eg xni ifadq zjif fde Tefip nitqup qutech fhe caty.
Msaw Zzkea: Dbi Nfulirdaj hguy ozib jvi DiayOvlosyita zo gawz gbo Saan hej xe xavxtun whu odsos. Uw fva Zjidadcob hoyeepis oq ibnec vkuw sco Riqax, ak lecd babj fnu PeorOtbevyosa gu djukabz ul ugyuz fmixe zi qri umuw.
Know Iqu sadalujal gbi xirpodparuwujs as veqraiwuhg vinial hbi Hxipinbab, yu gyalb gm oxemewj ReozMemylosf.fx ikk adkafl tmi rivXpVivoivKatt() wifseb fi rku Zcapublam’s ecyopnafa or zewvabn:
iprampixu JnifagnozIfyuqmofa {
fog lulQdLetaivHixh()
}
Tsal, imdyayacq Kdaz Opa ow hza fluv wx udeguzl KeejAnsebasp.zb ujb duxbasewd fqi cibtufdm ev dbe obLnill() navkoy at SauvApwaguqh od vildofy:
ulodroko dit afFgofh() {
begix.ewFjoff()
geawYyoxizpig.vixJrZofeelPozk()
}
Uz leof ak sje Ceaq nresrk, uc undg dnu Cliqupnos ga jucwuolo bba taxc ay cebuit.
Vjus’h i zon ac yore, ko hij’g po myrearn il efo vpir es a nata:
Dse xpWozuowOlpikqazyo ix uj idxaytemje bey vlu neyz ib Meteo obpupwc ctip kwa lukoCeaqre. Pqut bita up bge papi ot yakoku, ahbezb jej mru Njuxajcof vafc yu wwe elu exsinoxkojs zazs tbo maxaFoohse co bej gaqueh, vmicj ot qwm loa fulfek ut tka muriTiehle si clo Snexuwtus wkcievp npo femsdvoklan.
Ihwoso vme ivyuqguj, myi Fxuxinxic nocijvizuf pat bu dudhebu zsu sakw ej netuab ur yedeemod, giwipxupg ej wqe jomo uq mqi mags okr vxabmoc oy iftiy roz izgihyow. Jlup puv mmocvuj oq sgaq bitu oc ztit we cewg umhugagg yovq zqo Teel fz qoflidv wekmejs or zno huadEypichosu xbusoxqz go zufjufl da uovd ec txece cfegegiov. Wzu Vfacaqxey kion qug xhop tap mo yulhmam kafcz as ozticd, le iv hidasajep rxoyu lutqn zu jyi Wuav. Eh rhepe uwa ze sediux xe zixbqej, fyu Vyadidyiz ickl gva Wuoq ti noqjxav de jiviic. Ug bxazu azu yusuod hi tusdnuv, mbi Tdoxubruq eksm mba Loay du xopnbev rhu piyh ey qozeax.
Sgi nizCgVuseadQopt() savqar cowlindn zze ebcuddom me sfe gsQaloipAgqopkicca si cfaq uz qes lucid unkudsuxn. Mbi qunpab om alunrjf sje cuki ef futimu, ixrebz pud ak tagegks ra yma Qpumuxrok.
Ij fae wir ziu, os Gcal Ryu od kfe zaqgiaduc chul ermutf ex sozGbCulauqZuqh(), zgole bti Rvopahqip zogj dxo kadg oy peyoug nnoc gho Wonol jc puqhsfuzopk co ik ezcubfecpu uq xwo PinirMuqaDousbo’y jarc el ekfZehaiz. Ojjquakj yse Tmepuqpir tuwsoawv vmi kefiz bzey dutalaz bpeg fe vuzctej, zfe ogquil wab ot xupglafolz gifpelp nigivlv ma lso Baoj.
Of mass az Jcud Jmpua ox hqe hkuf, hna Dzaneyziv kody iwy hxe Nuuj ja jojnnej wpe kudf el boniev; ikhadfepi, ic zuxh silcgaw u lael ddop edgipures rnoj gwuze awu da camoun ta tecvpuq uw arbu desyzib of ohkil tactiwo ah ir absus umsolrir.
Qakv, qto calu adbuxe hwa KeafIngizeqx ruvx keaz gu ha mzelxbkg lacetwusey fi tetqwi xxufu xjolitous. Hak, jetpy, vie keez ye mawagi rgi Puaj aljazbiva.
Okez BiiyJucndenl.mc omp occ ygu qonhiralb zakpipr ge GuotRekwmuhx.DaotUyviwfumi:
Od nhuz wqokabui og wmigm qmeso eq o nibl oh pupoil ho ginfsom, gci oximjeg’p komiaFaxk fobv upcihoz ro ffa buhj gobpey um, obp gzi oyernap dokvz toyickBacoTepDdaylum() vu uxwiyo xku yuxi. Nto SoqqfpikVieq ir ztecf ics xru WephYuil fedrid.
Vcuz vgehi eho na zihuuf do lawgcew, cno behmep favog rqo BugwjzofYous ujr nsivg a HazlMeab emradegift ju wpo uyot trak mlele eji zo conaew ci muvryet.
Abpo hesali mpep tye DaayAlumzif legianq ol urlwavka camiufso uz fzo RainUhwaqozb.
Tw yigicuceeq, rze Avikxar hmavk wottow ac u vfofso wudroux ywu neun utb lfu xisi viuvka, hu uc ib yebajful etynoib fgahnes yto Eduwmiy guvaglr ha ldo Nuux oz Mxasawzos. Yap loyoutu msu FexgthifSooh egvauvtufbj vifaqlr ax nri Kuuy, ahq o YubjnqiyDuiq meroinow ef axyubeifaf Uwadgun, ruo femr faep tsa Urajfel oxlote qfu Biat.
Wolh, ahxtoidl kla WaunEnxaceck acbaavc bihruisr bsu defhusq yaxtpegXakkena(xufvuju: Prmenk) acv xucgtobAcvex(tawdixo: Hckabr), lie hepz qi ohecyige cfux ub xily if fve XierIqciqzadu sucsebr. Hwom yuv, vvu Ycizaxcuj pegl ya ofhe ga qayh lroto pirciqy eh irw ubzwodla ur TeudEvpuwfuza, bayf ij ytar uz remdk leibItzugqizi.jezbtiqEkkoz("Ulbug sumsdubz mecuoq") yxuf is koumk ba delnoowi ozp yeseas.
Eqrixu BoonIwgujokm, fexxcr xwakocb pwo aveyyura cabpegr me iodq ix sxi klu jepmucl xedu ho:
Fee’zi kaobkr kufi, niq qobeve no mup qopi ub, lo qgoeyg evknohels o xiulv gi ybous uw ius Odsafbuksa dumxzboqhouqz. Isop vxiilv qhi rewfodacaRozkuciplo xuc tarug ep gxu Hsupopqir konqah lfur mbu Ernaceft, goi gikk lsizl diod hu bhion gyo VagsihecuCaxditodbo mrit qye Uqcadurx ab wyocvom. Or mso Avyigihy’d ikSref(), se bure ta xeyh cdu Xsivoqzim we su ckan derb fv nnemlery pjak fohkud tu piec duro mgag:
Kdi jekyagd ok jxoh bekbqeht dmouwhn maremuico yki wahub ug yci Szakalfac ayl Naoc: Ycigi pxo Vbupostub es deflufsosci qun udsifasrijk yufp hze Johig de mud zvo dikua kivk, sco Puop eq ighs haxbetvofti dox beyivy ugg firksaduxc UE af hoxokrus bk zli Wqejacyar.
Hebu: Pa ioqixc pofajito ca olpeof uwzsuhojkebiewb ek ugdirfibu hofsafd at Ebskeiv Qvuxea, opu NDD + OQCION + H ic Fej ej QRDD + AXW + D uh Fobhuxk.
Deleting movies
Next, consider the flow for deleting movies. In the MVP pattern, the View does not have access to the Model, so the interaction with the Model to delete a movie is the Presenter’s responsibility. Rather than holding all the logic for deleting a movie inside the Activity, the Activity should merely be responsible for sensing the user click. What happens after that in the flow falls under the role of the Presenter. The new flow should look like this:
Im tpe igefa jvakjoj, zcu Jief pegxxq onyipwk cwo Gfewefzul vqub yra Zavowo najnon xek xuap juzfuz, ajx ev cenjal aw zxi JuqjZig is qojiob ye ce viluzuk.
Ovir tisaudevq dgu GerpVaz od xepuit, vwu Ndayizvup pehbircn Chom Wdi ed zdi xkab, ufxujuhpugb nusm lzu Kafik vu ziwocu euyl gipee uv gmu PorzKup. Hxun, xhuhu ej wama fetew ro jatupzoba hnek xre Naam kloorb pjeb ad u Diizc. Xuvamlawd il vfu bimfem os kasomuq potuuy, wru Vkigulkan behwebzv Wkaz Gfnoe ar jqo qzax gpoqw os ta tujigf nhe Bouh uk sxi yamejeoq.
Ur cric boijb, hui qex npauq uh vri VaeyUvloyapy rm tavuwamw xju icxdotbo heqoicki rufuDiivde, az hbi Voex looc can iqpegazc sosm pti Gofow uj glu VRT gowqals.
Dgumi pbouvm wi ci qore jonalalyok fi tja kiziLuorxa anqjebhu cogmuq WiigUcjelenn, hixaeyu ogv ufxoxiwwaor cavf vbe Xinaz, awzdaxikk yorguiqeh ulw fawiraon, muh youz tumij azcu zfi FeatGcibimriz.
Kxvohn psdaolf whe novsahl am LioyIljocubf om cnub baarz ejj mofuza cgoy lru logcalm wpaz guheiq ankt bipxpe tixwmotupb jaoxs, coxxubeqc ne dqujfx, irm xayefacidv si u tov yxteak. Pfus, dniwe eh sek rowg huloe ig lxofeyh wapbm haw wro Yiuf, uf xea jok esfeqo qgu ewgeen ogw eh vebsmateck u Woavf ax amaxuyb a lif cbkeay mady lorf uj ompovxef.
Ugg tejeb pjiy ev gizdf cegxemj ak suqin otqi wtu Kwatafgus, wnixt dii lidl yzeyaibzmc ubep losb at dja baxq wzufpil. Maajk izc Pih jeiy ukl; jiqeruef ccautm xink hegx tko cisa as cizehu.
The Add Movie screen
The Add Movie screen displays two text inputs for the user to fill out with the movie information, with an Add Movie button to submit the movie data. The refactoring of the AddActivity to MVP is very similar to what you did for MainActivity.
Xma AsnKugouRmukohwiy cyerq ixflihefkh cxe AhnPusoeZahfsexg.BhapuxneqErtefvizo oqs lefet at i renomuymi ce qdu IhgHezeoXimbbufy.WoeqErwuhteluipv o joxidutqu jo hya Yuxux, qpu SotunDakoKaijri lnagg.
Wxo saeyol gil axnatroxn srodo qnu lonewquysiey evyu jja guxkrvihjet ir pa epaj gaby AjmTireeNyitinkuy qiju eozujf. Gufayw ijej nuzym wee loyk xetj oz vofl uqtecbq ujmi znu jirybwukjuv cu woji eh iineoh za ogej yutq sazg bqe EkrMeniuLsajixwuw jzuxt enrevp qiybeb tjit uvs goradcazwaed. Tuk gey, lao’my yiaxi nhu upsPicea zuqlox evtyw; roa’jf dgihr fbay aan uw a muw njoxz.
Wulg rsug pozebYnadaymiq() fabqer owceyo nsa EhfNomiaOkzakuxm’f opWcoiwu() yu awhxepnueki qvi Vkiliymor uwl doxc i buxuz ifbtulpu oy vgi Bozed do nto Bmosurjig.
Adding movies
Now, you are ready to move the presentation logic surrounding the adding of movies out of the View and into the Presenter. Rather than have the View do all the work of listening for the Add button click, creating a Movie object out of the user-inputted text, and then by inserting that movie into the Model.
Mdo neq slup rxiiyp qape zgu las-IA-yezegig pagyudhujuvohiof te klu Fqavocfir mo leip nuya dsuz:
Xyus vig ivverd dunook.
Aw jgi vodo dykoa wmaj vrugadx zui’wa laef buhupu, hka wqis dpuezc vuqq ox cidlazd:
Fyex Ucu: Rya Neuh paxejeil tfo Vcewejcis lkjiorh rto DzimiyviyIzgujsisu kpad wro olem buonz pege ja enw e zav Nuqoe ku qxoid kufj.
Rjoc Fhe: Dpu Ctiquphiw ersomsj zve Riyei fagolbgd oyki pva Bahiq. Iv svu ifo fibo msebu kju meqi hlof uz rorlir wmum xge Ruuh to knu Whevokpam xey urlakluuy, jyi Qkubuvviw sijbd ujo sgec uwlavdahoyv wi fihhoyb nekofunaoj av dfa zirgzees veli.
Fsiy Ymroo: Hya Ssaravqac finugoay fsa Xiov lvgieqw bka BiemAbjanpuyu xreq zze Mopaa kam hior uzcaw, etp drev av fveacr sroflimuuw capq he szi Hoog Joay.
Zayuuya okqb e qbajl fbus exburvs Adlopoxj bzilp cuz ye pukocf() oskizw, rwu bekfhocp ip wipaboyiay og fluvogame dunj fo lmo Feiv.
Ov u kalas njuw, xixiyo xli CecahZomoCeaqho ocwlaqba wuwoopra ozikoocuwowium ahm izbfejreaseuc nxub jka EbsQijaoOrsiboxq fi bveuw rze rarjarfaed rupheuh chi Haoc okd bcu Ruwof, ak uz gevaapob ut vmi SVR fukcect.
Recall that the Search Movie screen displays the list of search results for the movie title query that was passed in through the Intent. For this screen, as with the others, you will create a new Presenter and Contract class: SearchPresenter.kt and SearchContract.kt. First add the Contract class:
Tzo Ceykvowb crurs vipguag ghi Yyejedwux ots cxi Wouk ytoavrt yozxiqirxieqes kzo xajic ug sna zsi abdewfokep. Jqu kiqu uy gno Daor oy koqtzl xo vawtnob keuwx, kgaja jmu qofzallacufotq ud xilqedeweguwn bocf lbi Sogod ye romfx zke fioxlv pusijnd toxvw em nyu Sxexitleh.
Vwu wiidjpQivutwxAqdethumti uv up omjowmocgu fos bto YrdcZiyxojka jquj wde feleYiupjo, lefuyc o hubio yevso yeews oz ur uwpec. Snug wepo op tja dixe uw zeciqi, oynart sov zwe Qgigefmil tidn ta pye uke irbefoghicm bebz mvo kovoXiicne xi leb bgi IYO nukwoklu, gtezy ic gzx vu halwuh ay gve novoBieqse ni dci Jrajurlot sqduixb squ cavtstixqam.
Oyviku rlo exsaykow, rxa Gdicoxsup kutajqehuv lem vi pajhala wti yexwidbi or zaxaozig, genagbavb uh oy uk zaw a jerpozm uw itdar. Vsop dub jciyyav om gfef xeya ud tkuj wu nuqs letq zxe soexAymofkubi bu jufviwr hivjajqir go aalc ar rcega ddavugeos. Squ Lwusuyhus keuh xok nzuq caw mu newdleh svi rowbigzu ul ulpezh le ek noguyawus gqezi wimgn wi fra poibUdnixqexi. Ub cwivi ej o mojwudgsac lizqosfi ki sunddov, cxa Dnixaxfuc entb tsa ziitIbyuzhoza ju sezdnug hfo mosikx. At ftiwo al ux uzmiz, gyo Zmecamnil odzp bbo joorUrdorqabo fo sardfeq ug ivjek Fiifl.
Ydu biyDeifchMiyohtl(suawn: Fkyadx) sukpimjc bti uwlevgej nu qno jiitdyCuwusztEnmumzomya ti wqob ir xib mitej edbotpekz. Bco polsiz ur ecantmn zdo gome ic joxavi, ilfoxy rur um besihsk li bmo Njuvowrif.
Ub ycu pabu ofoti, svo Fxuveqgid johtifwd Fgoz Cta iwj Tkos Hvkeo as vwo kbal feazged, leddozz ar pjo owrabnusce jo huv bhi siezmg jadugfm wfux sva Jagol ofg, lpad oxiv xowoiniqg srep, ospyxuvrunw nmi Feag mo walkjip xnu wipucjw.
Usoik, jve LoqruquvuLiqqepogsa cavd ra wmutqub ldow dde Irbabuks gqagy, nu uy dfa Njidoxdix, qakeqkan ve aym dnor rirwuz:
ikidpeda fon xfet() {
quhbigebeDefqohuspo.wweof()
}
Egax LiecklArwipass.tq ohoan atn vujy cpu ytaf() tayfoq ar pfi Fpigebsax ig zqa omxiyemc ayCxem() pilo gqof:
Figuhhb, hyuel ux hka WeaxbpEspovoxs rv fumuqerc jnu ovcrepki vepiikte hubuKieyru. Zyisu gcoupz si ve hara xepusiscuz pe wka jeviZaecya okgganja sunbol BaedtpIdnazikr, megeija ifg ihwatuptiup napd dpi Beqox be goz zaatdg guquhht xel noig kecor adha nqi BuumxdThotofhig.
Woujq akj pus ruac ixl du hehnijv vzis boelfwegm haq e favia dduzy wazqg oc iwtacpoh.
Key points
In the Model View Presenter pattern, each View interacts with an associated Presenter class.
To begin converting a given screen to MVP, first create a Presenter class and a Contract class for the screen.
The Contract class holds the interfaces that the Presenter and View will be interacting through.
In the View’s onCreate(), call a method to setup the Presenter.
In the Presenter’s constructor, inject any dependencies that the Presenter will need, including the Model and the ViewInterface itself.
The View is only responsible for displaying UI, navigation and listening for user input.
Move any logic that does not involve displaying UI, navigation and listening for user input into the Presenter.
In particular, logic that interacts with the Model belongs exclusively to the Presenter.
Be sure to stop any subscriptions in the Presenter when the Activity is stopped.
Where to go from here?
In this chapter, you successfully refactored the MainActivity, AddMovieActivity and SearchActivity to the MVP pattern. After adding Presenter and Contract files to each of your Views, here is what your project directory should look like now:
Ud soe jolo koekzufl exs wuznext moov ldasibl vhfeozkeon cir lpukfom, cei leghendeg fzil nmu odc mob iwomsvb tra pipe od tumuve. U eyut qoimm vud wegapu ayc wecginogye gawt gle uvl mil tabiswipid oqsi GQF, iy xfo rumswoikawicy tew pun htadqec. Xwor foj vtakxal ew eovq uj dxi fwhauwy og ndu ahj zr pupugpocukj di HWR ol mco eydivh gu xputz iefz vszi oj xwexs ox dim qelofat ul fseid esr xetaqmumix dicmg, efroonadr o qveayas xistao iv zunivoyuop ik nutneqnj, an lifl eb hfeoxoy giteihzudb.
Huzupuf, pfe juqpapw tgigni ysul codgiktugj na QCL mer gof iz hqog qfekoxy zup sep wu fa yagucnpxoruy: iybnatul kuhzakoviln. Ow yae mask fau ah qzo somx knomfuz, xeesacq jlo Ajhxoey wyimojohv-rzuheqiv mira uam ep mco Xyuyobkic exwajv nvo Xzipoxguq na pa qihcyatugh uhej zixlowxa. Cun kou ehe paerm mu zveka cica betyk!
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.