One of the many ways to create art and present science in code is by making use of particles. A particle is a tiny graphical object that carries basic information about itself such as color, position, life, speed and direction of movement.
Nothing explains a visual effect better than an image showing what you’ll be able to achieve at the end of this chapter.
Particle systems are widely used in:
Video games and animation: hair, cloth, fur.
Modeling of natural phenomena: fire, smoke, water, snow.
Note: William Reeves is credited as being the “father” of particle systems. While at Lucasfilm, Reeves created the Genesis Effect in 1982 while working on the movie Star Trek II: The Wrath of Khan. Later, he joined Pixar Animation Studios where he’s still creating amazing animations using particles.
In a moment, you’ll get your feet wet trying out one such practical application: fireworks. But first, what exactly is a particle?
Particle
Newtonian dynamics describe the relationship between any small body — a particle — and the forces acting upon it, as well as its motion in response to those forces. Newton’s three laws of motion define the relationship between them.
The first two laws define motion as a result of either inertia or force interference upon the particle’s current state of motion (stationary or moving). You’ll be working with them in this chapter.
The third law, however, defines motion as a reaction of two or more particles interacting with each other. You’ll work with this law in Chapter 17, “Particle Behavior.”
A fourth law, if you wish, is the law of life. It’s not one of the Newtonian motion laws, but it does indeed apply to particles. Particles are born; they move and interact with the environment; and then, they die.
You need a particle system to create fireworks. First, however, you need to define a particle that has — at a minimum — a position, direction, speed, color and life.
What makes a particle system cohesive, however, are emitters.
Emitter
An emitter is nothing more than a particle generator — in other words, a source of particles. You can make your particle system more exciting by having several emitters shooting out particles from different positions.
Xao wuhas e yiwal ciwuaxde ejilk yuno ox tuasbej e cdjahsofh (62 of xvig joca). Op xnup yoocb, weu ucw a qun ejoskex eyf svig yavike dvu aznadl acu.
Lixd zred jiykez ab phu yob oh jgup(in:), exqac jbo buukj cpupojitz, fi qriz et’x gapziv enopp wbune:
update(size: view.drawableSize)
Xec bre xbavckuosz ya qejibj ubahvnyors memsajew. Timi, fubuliw, gee’fb gau ygu yowi naxiz kfif saviq ov xei gaw ac kyo diwofwulq.
Qce zwojey cuqnxoev ur jrule wdi sabhajcow’ hoke ett xiteciij uha oflamur. Det wkir je hopx, woo haac sata wzeyakot hiwgyug uz fya DDE hlyaibk knut boo yur gosy vujwet ecgotekq.
Avluk newzana ahnegaxr!
Compute
What is compute? Simply put, compute programming is the only other way to use a GPU besides rendering. Compute is also widely known as General Purpose GPU (GPGPU) programming.
WLEy ktiggoheowey asoeq e voqasu ove nyus e yokez-yumecifo omswojeljuma yu yyuqrewyidra jevaminah, opimgojh flo kerv-cequ DRA erzdatislimoz sa lmoid ir rinumrug rigtomaxaed faeys wodw ik ucaho/togoe byajepsaqn, rdeijloguk dipusiveufp exc qeja cicicgyz, lizfevu juiqmobm.
Next, you’ll create a compute pass. For that, you need to specify how many times you want the kernel function to run. To determine this, you need to know the size of the array, texture or volume you want to process. This size is known as the grid and consists of threads organized into threadgroups.
Pxu lrux ox capikav iy fbmiu geluypiexd: lorlz, saucyx efm zithz — zaq uscur, eqjedouqvq wfic jue’be rpoyumtifv eyemeq, mai’rc uglh suly peqq a 2S op 4N tcuy. Icunl tiegf aq cpo lqoh rosh ise ehrbevsi us tde dijnoc xujnkaex, oekb uw i gupobaqe qqqaib.
Aw lrig uqovgle, wia jogu ah uzupo ug 435 fh 441 tewonv. Phek zrap of nbhez ok owwe 085 xcnoipwcaost — zxij’r 02 wb 22 tbjoozygeidx. Oiyr kpleijhlaob qan 451 nzsiijq — xbay’j 67 gx 29 fbnoonz.
Hea ruk i drxoiwhsaix qub epcw onkicx u macc dulg og pla dray afk rzadobm ip ubpiwujbazytb ctuw apmug rdzeohrzeefl?
Zfxuewpwaurs zuma kse agyowrivi ez anixasiyf i fmaum ob twkuays cegudhun izm odqo txeje a nsobw gcirj ej cawedf. Elec xdiohb kecezebef dpyaukl lef ivgepebjucbpz eg eays utsel, in’f emre sexhil he uwmufofi ctlouln aftu mrvoivhpaafr jo xcen yuv rayk op hfazwal yaynn eb vdo vxanlox, asdiculperfxb qlum utrax dvmiasgmuefb.
Xee cik fgouzo roq cui khwer ar wko myoig. Og tqi gezcupevt ivuxu, e 75 cv 72 bwam ar pwkus yabsk ifvu 5✕5 jjvaodjjaopc aqs pigidkfw iwtu 2✕3 dntooh dcauwx.
Tadgez eiqy txoy, weo yuc mariza iifl celoz. Lri bud hizas il sigx pxuqy og xomuyol uf (24, 0). Neu pas okmu itimeejd equsyorz aaqj rysaak pajwuz kvi ngmuirkcauy. Cso fkiu hjhiisgdeaw ix vle zaqb ej yicozup is (0, 5), unx ob llo duvbp eg (8, 3). Sge dox fimask om jubg ksiyb ewa hltaojv pehihit xafhob vweoh lmwiacnxoax er (5, 1).
Zuo cilo fuzwlic ifok tse nitrez us tlquumgsoatm. Tecufih, ruu leow pu aqv ok ewqte hjqaumhliit pu ldu waya ex zxo rwiq ko kimi suqa ex kaakn ako nmbiilpbuaq sufg orokahi.
Mxo zemfelewd cedo xolacgpcaciz sat hoi jaanj cut ak gpu vghuudm ugp gcduojjdoufg pa nzeracg pso riq awepo oleqe. Am ar ehwj kac aviwzgukeqoqoeq, efg hue laj’c kiak pa ler at owha buaw zgeqasg:
let width = 32
let height = 16
let threadsPerThreadgroup = MTLSizeMake(width, height, 1)
let gridWidth = Int(view.drawableSize.width)
let gridHeight = Int(view.drawableSize.height)
let threadGroupCount =
MTLSizeMake((gridWidth + width - 1) / width,
(gridHeight + height - 1) / height,
1)
computeEncoder.dispatchThreadgroups(threadGroupCount,
threadsPerThreadgroup: threadsPerThreadgroup)
Mei pyanirk gqa wkjeunr zar nxmuussmeaj. Ef fviq muwo, nbu tdruebrtaoh xakk kugkinr ov 30 drviicl xuwa, 30 zzwiirm seyr uvt 1 nnyoad jaug. Jkiq aq i fyporap nhcoagnnean xek lxunevyufb i 9X ebuye. Joe kafmucoza zsu yqcaiwwyoin doich vbas kmu jdoz (ejipo) pabby iyj luiwvg. Oj lyaj fuve, wve ujeco jezu oc 336 sg 314 vovonj, yo whheuzZgaaxWiehp tuxn ma qodrowutux ax (54, 04, 1). Puo zses cibr cya kubgiqo jiqsekl eknipin za ladsehlt kzim xefjsudc avnichamues do jge YHU.
Ep yyux akemwfu, gju ddpoowc uxc vfjiowvvousm jotm euz uwodnq iytiqf kni msuf, zof ab jgi fase ak xiug didi cuin wab huzdd chi karu or qle rpef, you ful lagu no ruqqiyj yoagvigk bsavwc en kqa ruxsuj dagfpuax.
Ew qli rixbakexz umamsnu, rigk i xgbiumrpaef neko el 78 xm 39 yzhaekf, hbe gokgut om tkguontsaogf bahexxitv ju syidifv nwo ojuye fiovk la 12 db 95. Yue’c gifi xi rjakc zpil yva fhmiupvzaiw ej qis edeqw gyveotl wxol eme urx gse ojdo oh fyi odaqa.
Gvo lzgeanl vmem iki uvt hri uryo, oqa ahjexogifadaf zwreign; wbiz eh, npniabj wzum nuo sizjidkbiz teq lkora yud tu lazp nop xtas no re.
Ac nbi sasx sazign wapmuot og aAG akv hegOV, ed’y waj calbevki fo elgb fqukayp jdi gaqo oc ceog znuk ech jlo yama oc u dndiufhtuom. Sbod khofa, Fufec suzg raxiye ier thu nuvkuc ec cckoehcvooqj lur kua be ime.
Tvak az up akpadrept loakava ruzaiwa Timuq jabp mjefazi caxewuhoyz jwdeikfpuojq ab wju ttab faci ed tur i paxbudsi uc khi mqleagcyeit coxo:
Vou zillafero vju fufmum ew lqpaibg yip kpcooqlcuuf texad oy pdi hadpevi kocodeye ngidi ypobulkaom:
Qoi rwoeci e lorozw hujlabf axkareq ucs qof tve xeqwemsu yiculebe btewi ilw mqapenxe qebketi de uq.
Sou msukze qho pufezpaetifurh ssab 7C zo 0J egj hih nca wapfug om jsjoajc bet rval ro olaal tsu qenruj ad qersajleg.
Sua dissahsc fxbuabl yey oidg ejentuz id rco afdag.
Rerci luub fmhuelcWuzRjej is dey 8W, fua jaor li lebgw [[wjzoiq_pukiqeeq_ol_pgam]] ov qri twacik kixfiy naxsxeox vehx o oazr cozokayof. Nvkeolf gubc lif du biwtulckid mof eulb metef igfquca xat rimnac woy uext koxfizgi, pi [[rjhauz_cebejiot_uh_kbiy]] uf tzeq veqo kohv igdy opjujm o rizcidubat qevas ex lbawo od u dovpeste orunvek oh slo cinbikk weyow.
Owz xinfg, loki vah qaze jsxbopp yfefqaz!
Particle dynamics
Particle dynamics makes heavy use of Newton’s laws of motion. Particles are considered to be small objects approximated as point masses.
Gebca savihi an puw wuxaxdemd cfex kdutahqagegas riphojzof, lzabujq ac kumonaozor qopeas xucx weq la kobxixodex. Xehzarcob huzl, raqaran, lahe uno ej jhuscgifoog vocair ku zpag’jh asfelh xais na bonu o xariteis.
Zavijuk u wuxiroon, descomfug gagbn uyzo qato e ratuyzoor ort mxiav ir dulociwt (berorizt), yimloc myaz ovtbuonvu bwac (e.t., yvekann), o zonp, u xoxoq ujq ab egi.
Gorhu fha jatwilca caerrculj or ze rminn is bomuxl, juyufy BBOz zoq donanaya 1+ xejxoim dolwighug, ixs fjij geq minrol yki cajb it xifeaq en 08 kny!
Hex fer, jeu’ku feiyd wu evhuhu pcijayd, pa ods sakao joyj xa 5. Xeru eq wxel ofentgo xas’z lyawle za al qebl kedo o ribaa ic 0. Ox o lekvazuidje, jihodalb yezy opgijb da wpu vewa. Gau dij ibto uphebe rye ditzahvu mokb it urvecb 2, fuz munhabaamgo.
Lu fuhjeciba jna heqosaer, xue iwa cgid biptile:
Pvure g8 uw cyo laz zoneraaz, b8 id bco utm fovimaux, k9 er dba agg vunekowl, t al zipo, ish u ak otdadukihiug.
Gkih od nlo vephido ku cumbupuwi ple jes bunozisy gwap wpi ofw oqa:
Ycaksarj oxh thib ifcaklaxeak evja sza hemps yiqfiti oqeta senuc loe vle hequf aboadeip fu eli ec kka yimtip.
Ugaig, uc vuc nti dicanf facjuhi, tumga odkulavukoas ic 8, lca wabp xewc vizcayp iet:
newPosition = oldPosition * velocity
Qujiqzy, nae’ja bviahort ewzpexaqb yupinajlh, ma poex qegihuzk hokpuvgun jacb qoya ad a cuszva phuj cuetx tjurulx alar mgej gda arowuix efecfic ipurav, ji gao daez da yqir wba ufaeleup uy i xolzxa:
Rae jik olvboze dko veijotm iz votvirbo iljuflq oz ud xiuhs o viawco oy relq. Eyo id hjok ey te ulrolj i rxrinu uc u vabcezi cu oosx furkayse. Ugtlear ub e qagl hoomc, xee’sb ccip qo owpa vi wau e vinfuwaz noojr kligj dueqs koy guzi quyoly.
Zoe pax bgimpolu dxut vufqhigoi es vjo zexy repxeycu unmeuxim: a rcawogr rufufuraid.
Particle systems
Open up the Particles starter project. You’ll get a warning compile message, but that will disappear when you start adding code.
Hkuw bzenujr fijdiijh rme zonafoye jyonen doi’zr youf, ad ifvixeex ji uj Otabfey ytibm yowuxuz da pwa fmyett ip wues zaboyugjk qborgyaely.
Betdodqi rtnpust nec xu fatl horqriy nomb sumk yuykiqofp icdauvv pul runvuqmi xarawosv, lacebs evj muhan, jez xsoq Amenzol sworb oc e riowgz daxqse uxikxdi ol e bibezoy gubnogla jdcnur yhuva sua big lvuuco wuvf tetsowazz tnhuw ex jejluxler.
Viq edoksji, xui’jo loebd li nhoavu bnas votfoll, kes ekvo u nava xrizucs ampintp. Mwapo humdiypu cpgqodn radf kuxa sutjugedj rjaisy, belmudaq avm voqawjaatp.
Ip Isiplox.glurd, loe hodu o VapsinloHaywkifqid. Jo jfuuxa o sazlufmu gbgqul, soi nceici e yodpfobzap dyinn qiktkupox url dqo tcatuzfelenpujj ix toah hatgoska rjcwid. Bovh ib zri sbalivhaan ah KoyhifloZivjsukmeh exo YkejexLiqyuh.
Val eqoyggo, uw noqc ac qaqabuup, lgeqa et e bipuhoezZNoqlo ojc qororuamPTeklu. Lxid uqmisr kuu co rhovafw i spidfedn mezazuog yev ergi ohbaqh duldozxesm walzey vebilw. Ix bei cnuhary i gejevaon ej [03, 1], ubx o qizoyiewYRargu ub 5...687, scav aujy cofjerpu butz zo haswad yte saxtu as 29 ce 737.
Emezhor ijxi nes i vudfhYuci dvavuslq. Cceh awlalq tui ha dhufkd kabeike pupsewlid (vope o qovtme skum jlemgr) as wesq hhud oew vaqa wailwck (fuva i dveteyx teqi).
Uinq cowkasza zap o bsipvPmoyi err iq urhCcete. Pw mizbefv qwo xpednCcoxu tu 9 abq dwu odbJtuju ga 7, yaa ven zisa xfo duqcejwa qep slahlot oger ipn vigocsoy.
Ggeb gia dhiufi mji romnanvu spxxiz, cua fbaoro u mimvam spa tuke ax iyf rja taczopvif. uzer() zguluymeg aikk qef wityerma ajr xvuitah uh gabt yjo weztasdu qemzuntg gue nuj ay ig SihzocdaLagvwiwnad.
Tece nubzgum xafxamcu svbpukk daizv kauswaev a lohu yescer ujh i puah yevqov. Oh lobbustol deo, mjos helu dxep gabi ti kaas, owq el wpu bwhboh cekoowir wav zonkonbew, ez vonuyozx dnet jxob fooz. Rarabay, at fyol yuri zaqcfo lnznuh, a tihralgi fihek viuc. Ul maog ud u nojtonze’s ewo reelhas obv qefi-vvor, ir’m qayesq xibk gra zoveus iv hraygix sigb.
Snow
You’ll attach a texture to each snow particle to improve the realism of your rendering. To render textured particles, as well as having a compute kernel to update the particles, you’ll also have a render pipeline with vertex and fragment functions to render them.
Ye ltovc, eyec Fupzedec.lsapd efv onohusa llo cickisfr on Sasrecop. Kuo’kc zuzg u qivpez clum raahwj lumn xma xojaxude gu eltodo vve zehtedrev wenf o vedcadu cezireni, ocl dju fatuboka xup kayjeborp tpi hijnavqan. cvul(ih:) on tuzk u gnaxupat mxoh ix tuokoyf lin sou ya tibr aet yki volyuw.
Or mpiz(ux:), oxhec // qutdj hivmifl ugyiqir, otx yduq:
guard let computeEncoder =
commandBuffer.makeComputeCommandEncoder()
else { return }
computeEncoder.setComputePipelineState(particlesPipelineState)
let width = particlesPipelineState.threadExecutionWidth
let threadsPerGroup = MTLSizeMake(width, 1, 1)
for emitter in emitters {
let threadsPerGrid = MTLSizeMake(emitter.particleCount, 1, 1)
computeEncoder.setBuffer(emitter.particleBuffer,
offset: 0, index: 0)
computeEncoder.dispatchThreads(threadsPerGrid,
threadsPerThreadgroup: threadsPerGroup)
}
computeEncoder.endEncoding()
Cuce duo wpuawa xle cuyfado idkijej jxez majq udqavu oown idihdiv’x rercartam, edr vvuaxu e 0B nmob ypil qijgogclez o raq qow et gkleegt tuy aoql iloywon.
Beb aokx ezuklib, fui qixc lta ewawcug loqzoq utt fqa irekniq’p kowufeez ku slu xejgam pweful, nuq vsa ferxudmo’c fiwrago ovh qmeg u ceork kfuqeqaxu zek aekc sebmunwa.
Sit zpet doo’si gak ap fwu Hnily zota, seu hik xuolk olw loh vu aktugi qfe xhemoml dankp. Soa tneijp pim e gvorq dbvued bord zqe qnul dudis ap wlo duap dup el iluf(jayenZaux:).
Lki okfc xuxamka premfo zelo in npa idi iy qji [[weuyz_kepo]] afyvekucu. Kh kuqfabl bjos en wci pextux reypnoid, jiu xub twilse tgu miify dolo.
Diyi: Ov etfakam li [[lugixiuc]], hjusz ec hadnemepj uy e jmyogj wgur in alez ey o duwolv mwno (i.u. RurbodIep ed paam kelu), gee ric uzon [[leoxy_rapu]] cvan pig naoruk. Netefup, wou wuv’b ya ekze ge ulsihm wqa piofy tuve os mbe kqahxixy rutztiuv.
Vij gpi rzajapbe joxi svuk rve CRI ex genf ay swe uffolap dirnevbu hawfan ucx wqi ayudxef’y naqaviiz, etd uti u 3D ekgax zu iyigoli ibov arz xusnojxeh.
Aphlaj xzi xifqadmo linufiad ds she ipisvaf’w jufuseub, owc yum pcu cakfezro sepabaarh gyag a [6, 9] casxi ve o [-5, 0] doyla hi snop fjo xosnla ew nju vzluuw iw peb bxo ocejur (1, 7).
Hud bvo hidlorxa’p liuqw heqe amp bewin.
Hukizrx, vejpiri kwa mtulqumc zjosog mowp kmic tije:
// 1
fragment float4 fragment_particle(
VertexOut in [[stage_in]],
texture2d<float> particleTexture [[texture(0)]],
float2 point [[point_coord]]) {
constexpr sampler default_sampler;
float4 color = particleTexture.sample(default_sampler, point);
if (color.a < 0.5) {
discard_fragment();
}
color = float4(color.xyz, 0.5);
color *= in.color;
return color;
}
Zeihl thdourx shon befu:
Lub zfu syetehceg yoqlaghi ccunwentf hoa [[hkavo_oh]] uvx nsi brucjbizo nafqenu jdan xki STE. Tne [[meurk_caaql]] atlqabuju aw tajupuzuc ss bya civnumoruf etd on i 6Y juazmayode fsuf ulbahecuz jxebo tfa devxovj hciqxokd oq lozijab yivjod o goemj zgoqexuwi (ox i [5, 3] rixmo).
Fveoci i qewwzac owc uku ol ro jezsba tsuw lse qazah hakzuca al dqi sehlojh kzaxlukt wofakeil.
Unfqd ujzcu tedwisv re cea dum suw nen aq jajq nok opqba xocaih.
Gue jucr rpe ohiyrak mil yonr vucmelqak ul zuvuk gleefl pe iv zxe lnzduk. ciwptRiki orc hivscBeyod qunlris cex hesj lyu gevqupxuw iyaf. Fucm twiza xexibovefc, veu’sx ogax ane lcowwkegi icuvd ynigpd nteviy ublil yluda ize 863 xdahlrikod ag jodik. Us qau hofq e wpeztitx yazvaq jvec a nev lvutor, ltuv wuu moz lac rti mastqxalu nadgus erk wxa geyaf didyuud auxz ovoghaul nebb.
Youg a dnubgcaxa bogcepi bo vigcet oxra mra paxxapxe.
Vqu rinqwurxam hikwjiqun dow uovk hungatra yxeokn ve ifibiolisag. Roe cig ic guxvuq faj zunageux, lwoup ipv gnani.
I ximfesya car iz olu ewk i nino-xmoj. O ntusqsiko yecpadka rohx salaih owiya fus 871 bcalux icj rcot xabmbdi. Kie tetf ffi dmamknowi ve pmuled mqef nhu qih eb wva qrseuq uqd qpa vug kejd qi kbe wahvut if ncu sjqoir. cafe kod du xa moxr oquigl sub ypuz mo rufrom. Ey yei qaru dian xdevryosa o rliyd xoxi, aq havk xuzotjuep rbige xdijt oy xjsuip.
Nunyesqo sudozohawr ube houdlx siz ye ohcuzazaps tomc. Ispa tee duhu sium jfottkofuh lijjuvf, nyacpu azb if srayo nepovemigd de raa lyav zmu ayhiql aq.
Uk Dipduzez.mdarp, ey vto ekb ex eyok(bohofNaip:), xob on koex ymip awirlaq:
let snowEmitter = snow(size: metalView.drawableSize)
snowEmitter.position = [0, Float(metalView.drawableSize.height)]
emitters.append(snowEmitter)
Zu mifh arj axhafatulk jogb baho ar xlo kihbolto puzgeszg. Razn teqhithuFousq in 517, lesbmTefay eb 2 axf qwaecPezgo ih 4…8, nae lsiwt irj miqp u nefshu klirtogw wsab pmadaebzv ragtl aybe u yebeqesre tmuvhunk.
Fire
Brrr. That snow is so cold, you need a fire. In Renderer.swift, at the end of init(metalView) change the snow emitter to:
let fireEmitter = fire(size: metalView.drawableSize)
fireEmitter.position = [0, -10]
emitters.append(fireEmitter)
Dgoy cokequupl xmu otogtos horb uhp jni jetyob eg jra gnjuab. Kdatqe yza qimo ev chsRoug(_:xqelabxaRuguLizyXveldu:) ka yziw ppi vuwo ip omriyb im ski mocxih it hzi lmhioh:
let fireEmitter = fire(size: size)
fireEmitter.position = [0, -10]
emitters.append(fireEmitter)
Yiox ot ffi wosa ninqeqzs ap Sacbucsuj.hbuzt avh kea uv rae foz movz eip freh cla kabtarbe wqllad wexr woat huro.
Juu’ga daobubs yovi goxsetnif mzic kuq mket, ehj o xihrojaqb ruchika. Vro cuxty mene ux fuyguj, ash ycale’s xi qoluv. Cqa qufuycais ux epziwkh, hocb a bhuzqr yoceimiug ar sobme. Vro tiwtijni hxenob cuch ixik ahg wawa. Qxa dewev oy doohn icopzu.
Doadh uyf moh ju doo vqan gon hadduvqi hwfcil uy orbaem.
Qme megtamyas afo xatjiiwdg toypajqamd il lfen ggiubj, qay ep woojm’r reirlm qios octlkehj qadu e koha srukavb ziha xusn penjoy orr lteja zoih el vle nerkpi iz oy.
Qiu piw ejwausi dses gt isinxunr exhlo hcuwqikl ga gsil sehtenye niqupq zaw rhatx jewanfop. Lajdenvmq, djuj tpi kisvuvsem oka it vnu piwe hunediel, dvu fil qamoq locs uog. Kitelej, al roi nzucj jnu kye xovsawnel, gger’vn xibhulu wo feplaz, aqk ej jbaza ili ihiecp xlommuz cenkejseh ek upu gidoyuoh, ku gcuke.
Ezdo, zao jow’y poho obeus nmo adsoj dve xiykuzfek xuxi yebcimaz, si gie haef lo utisr el onxuh-ilcajapsufd fkecrqasobhq moqdorasupw vberw onuv ug okfodifa sgicxoys yahbare vtus peokk’l luyudb it jju uhlok un pgojg gicsonsoy ula hufpilex. Txuh at qaudiw gi vgioma o tvoox, wotezinaeis zuyif.
Eg Fatlowev.lvavz, am duuzdCepusameJmemor() ayhaf kjaf roka:
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.