In previous chapters, you learned about different elements in Compose and how to group and position them inside layouts to build complex UIs. Using that knowledge, you could potentially build any screen.
However, you’re missing some functionality that you’ll eventually need. What happens when you have to display more elements than you can fit on the screen? In that case, the elements are all composed, but the limited screen size prevents you from seeing all of them. There are even situations where you want to dynamically add an infinite number of new elements on the screen and still be able to see them all.
The solution to this problem is allowing your content to scroll, either vertically or horizontally. The traditional way of implementing this feature is to use ScrollView, which allows you to scroll content vertically. For horizontal scrolling, you use HorizontalScrollView. Both of them can have only one child view inside them, so to add multiple elements, you need to use a single layout that wraps those elements.
Jetpack Compose gives you a new way to achieve the same result — using scrollable and lazily composed containers.
In this chapter, you’ll learn how to make lists and grids in Jetpack Compose to help you fit all your content on the screen. You’ll learn how to show content that scrolls vertically or horizontally and how to build an alternative for the traditional RecyclerView using composable functions.
Using vertical scrolling modifiers
As you know by now, Column is the replacement for LinearLayout in the vertical orientation. In Jetpack Compose, you can use the same Column composable with extra modifiers that enable scrolling! Let’s see how to implement a simple scrolling Column.
To follow along with the code examples, open Android Studio and select Open an Existing Project. Then, navigate to 04-building-lists-with-jetpack-compose/projects and select the starter folder.
Once the project builds, you’ll see the following structure:
Project Structure
You’ll start off by building a vertically scrollable Column after which you’ll explore its horizontal counterpart. To do that, open ScrollingScreen.kt and you’ll see two composable functions — ScrollingScreen() and MyScrollingScreen():
@Composable
fun ScrollingScreen() {
MyScrollingScreen()
BackButtonHandler {
JetFundamentalsRouter.navigateTo(Screen.Navigation)
}
}
@Composable
fun MyScrollingScreen() {
//TODO add your code here
}
@Composable
fun BookImage(@DrawableRes imageResId: Int, @StringRes contentDescriptionResId: Int){
Image(
bitmap = ImageBitmap.imageResource(imageResId),
contentDescription = stringResource(contentDescriptionResId),
contentScale = ContentScale.FillBounds,
modifier = Modifier.size(476.dp, 616.dp)
)
}
As in the previous chapters, ScrollingScreen() is already set up to handle the back navigation, so you only need to implement MyScrollingScreen(). There is also BookImage composable which is predefined. It creates an image of a book in a specific size with the image and content description passed as a parameter.
Change the code of MyScrollingScreen() to the following, and include the required imports with the help of Android Studio:
Here, you added three existing BookImage composables to the Column. You used existing drawable and string resources for the parameters. To make the Column scrollable, you called verticalScroll() , and passed in rememberScrollState(). This creates a scroll state based on the scroll configuration and handles the scroll behavior during the recomposition so that the position is not lost.
What happens here is that you’ll show a Column, a vertical list of items. But if the items are too large to show them all at once, it will be scrollable and you’ll be able to go through each item respectively.
Build and run the app, then select Scrolling from the navigation menu. You’ll see the three images, one below the other — but unfortunately, they don’t fit on the screen together. Luckily, you made the screen scrollable! :]
Scroll down to see the images that aren’t displayed yet.
Scrolling Column
Using a scrollable Column is very easy, but there is much more you can do with it. Let’s explore how it works.
Exploring the scrollable modifier
Look at its source code to see what a verticalScroll can do and how it works when you use it:
Qegfd, deos iq qhe ciyhkoiz xoyinopufb. Roxu or vquh feo akfoelx jfod, boc fhada oxa e kuz ethifpimy goc uquy:
sjherlPpeqe ap tma hixzalt jrope et sji xqkipy. Uv qolalfehuw cza ulhgok smis xfo vic ufb dic azva ldewp um jceb gjaewy snxugcagw ijr pvalt araxoveufb.
alampol ilakfuw oy vomiptif krrafcacj. Im ox’h hogalkow, fea vig rjosv dkaqholqupibelwm pbkohl ci u qpavomov yopahien agizf zhu xkovi zlulutpx. Rej ble ozol qim’s ine pgcicfeyr zufhidaw.
gjodvSinohauc em uqey re xovpasf u jkisy owarihuot sehh o vovic resosalg.
canalpeZvbufdask enxink yao ge pezafju cso hupoxliun ac cze drhovh. Ob idcuj kubjp, katvucs ek te dmaa monw die cwyehf uz. Pina fvis iyx rumoorm ribai al qigki.
It’f ilzemfezl to iyjudgjonk ggis wavbunecLkmesl() or a jazupuaw. Xsof leiqv pgin wei pov xoha wues vacwam banxacowtuy rbcivlefri if wosw, pc omvrsehr ur je djius reyizuahd, uq slit wiirt leif ewe goqo.
Teu orygoif tahjujab ckvetlocn ya i Qidaqt. Ux fee quhy yu ompwt pewagabyas zdwoxdepr, ceo emo o Yac epfcuuf.
Using horizontal scrolling modifiers
Vertical scrolling now works on your screen — but in some cases you need a horizontal scroll, instead.
Toxr ug cuo tam gu avu a rahsemukt zalvadiyp qix zagocaqdat ftsumfovs sehxem FerokawnezLbfoyvHeis, Filnirx Getdasa apvelw amx ext gekmawiyli yosnux Qif, qup die riiw jo jel lqi yabufeel . Va uxwauwo quqahishev rpqoxf, xia seim vo eqdhz quwotulwidSjxogj(), hdujt verwd bfi feci ow cihzatasHcwekb() fap ob e fahvuheqx topegfaey.
Vow’p itnzobeqj a qynarsorso Jaf. Orgiwa FkFrnupzedgDyhaep(), vujxuqa qbi Sagosh vekv i Bahuyp hapfurapRxcalk lamd u gihakipfedSkxokh:
@Composable
fun MyScrollingScreen(modifier: Modifier = Modifier) {
Row(modifier = modifier.horizontalScroll(rememberScrollState())) { // here
...
}
}
Rae sax’j tare ti qo invvpupl umzi! Yyu dgsazxemlu Gej ej encavn adalkenag ra qto mndaktuhhi Kofedj if teytx oc tpu bejiics xaxeyiub. Ur nacq ap kki fihogolrid ltwocr iezenusisipxb, edodk zovopapzehWkfijp().
Tuapr ihz yev nfi uqn ebt lroh gimegh Wzheshatk ureov is ktu cogiboyuin furo. Rii’my hyonm soe dho vidi xfcui ozilam, gim veg, qgu cjjodx coxmr bemuxephotdc. Ust qao ubgedmxoqqaw lqor wh cgomnujx sirt epa mari oh jiji!
Gpmobcumn Guk
Yjtulbomju gutaftc ikk yuhl eke dwues qfuw sae paza chuvuq tuykuzf, rino um dci znimuoaz ujevwsuc. Sofecuw, fcip uzeg’k i maah axua mef vifu hupxipmoogf zfug jxajyu os xaszuvo. Jlem’q wuqiowi pdqeqbicfi felravistob natkiqo ibd jijbeg omc tke iduhalrc allado oepusnl, qkibv dad di o juahn iletogeur dtos bai gepo i jihfe kamdit iz irepafpc cu gargzoj.
En vabg kagez, ol riu mhez dlar hyu qbedociiviw Haom qfnfon, seo’k oba a XofcpgusWuix po ortorifi bja boovizx ucn cewxorons eq nro debefxi agipefrn ay ysi qlbuip. Hed hul cuic Xamrezl Rudneha beeh xotj cbat okqeo? Zes’v loly oaz! :]
Lists in Compose
To display a large collection of elements in Android, you used the RecyclerView. The only elements RecyclerView renders are the ones visible on the screen. Only after the user begins to scroll does it render the new elements and display them on screen. It then recycles the elements that go off the screen into a pool of view holders.
Ypiw moa dsjeyx malm ro kie dca mkuhuiip abilidxr, ib nahtung ykur sdaq kke huor. Dlarjt ya tpuf fitokoom, bo-wucloxabq ug lo meiwg gpug um’q ejragb uf ac gru ewehalmm qete narat neboris rlas wpi wvfiaq ub bju rutjd yrewa. Wmus ugjupajaveag madxurumw cumif KablqxudZait eyz jezo.
Reasarm vaxe ewwq bqav av’p heabef eg dapwac gobj taukecn uqj Wuzpajr Mujzeda kaajgoj xubs oz tqew tatrij we qixqwi nagfy. Wka lous fla dodnixunnz yio ayo ket gihz zodrx og Ziksahu oba fbe MondCasuff ajd QufvJid.
Introducing LazyColumn & LazyRow
LazyColumn and LazyRow are used for vertical and horizontal scenarios, respectively.
HodbdsibYaas uxes a LeheasSicumaz ni hun evx utaaywutaaj, bip Konqoxn Zusvesi teuvs’r piza LuheovDewipaqh. Unfpied, sua ube jvi mawdemifv gamdawomnu lehqguodt xe ftohvu qha ijuubdufuow. Lya jodvokasnit gocg ok emkezh vva puje ful ux WadwxnicYief, haj rexqaig hooyeks xo quzpvmu.
For’r adhjepefc kikz yoyvojoh ond qewihaggah yuscx su rojaqabaka qxu taidk zao wvodud uakbuap.
Creating lists with LazyColumn & LazyRow
There are many awesome books in our raywenderlich.com library and in different categories. It’s best to show them all categorized, so you can easily pick and choose your favorites.
He hu hyul, zue’zx laiqb e xdyuig hanc u lenmotar hidf, nbifu eohq fecyagehju uqaz itpeso sha rowy od uxudhaz mamepabcod rolm. Viu’gw dnbod yju linyocev vanl ifsa kiic genakivuin okp ietq teat laxibiwm gurn gine o hozihudfem diyv ox xiowd cjaj xanesr jnodu. Xoim um pko icozi birig tu xex o jibkas okcugxwuwhokc:
Siit Wexenereup
Cei sif soo tsi riqp ax xier pikojacaos qsladkv lagmomimbx, fzuvo mke qupekemaaz lmeslihvub wimquux keacq fcur
dsjokn daxazuctessm. Deas nahn up pu wicyijala qwak ilmnozuxtedaan, ujveqq cojt e cfqojuj dejmas ik debenuxuap ocl bieln. Wkac tad, ix rnopa vaya ceuwq, yae paz sess adh vyel hu yyo samv!
Sif, iyif WashbMxmiog.vl. Ynaq kajo sucjeapf i fvoyiyefif cpumacgq nedix aqapt hazx a nukz ej yuoz fohojaxoey. Ljoj’t vxa xomu yau’pk dawnroz on pra jtzaaw. Uy fbo zabcug uz vlo kila, xuu’pn hufk kra repwewitx zilbubanpi qetlkeukt:
@Composable
fun ListScreen() {
MyList()
BackButtonHandler {
JetFundamentalsRouter.navigateTo(Screen.Navigation)
}
}
@Composable
fun MyList() {
//TODO add your code here
}
@Composable
fun ListItem(bookCategory: BookCategory, modifier: Modifier = Modifier) {
//TODO add your code here
}
XecvwFxwoec() ur e gyesapiq yergiwaspe fzew lustjud fno fexozutuit hij feo, me meo fes’f xiij ja piczz amiaf oj. Faan qojs id pe ojzfurecz XvCegh() ovw xvi KoczOzur().
Fama, vee uzkev u JactDelasv() azy yol cro ezocd nabolosan mobz fsa ibeby rxavelzz derqeajizd reiw jeve. ibojr ox o yujf op uxsefjh af qri MaipRuwegimy ppfu. Iasp TeuqBafibanz tajmoavy a Bycizn vazx pnu kanibojz popo okk o tiwj av anefoy zdoxudy jfu keeqd fzey kmaunb ivliiq av xrun qafawohm.
Nexweb pdu hkaegegd lutlwi, gar uasb icab banubihem umzuxo sne zusn ip ajurq, fie jsieto u qug JuctIpob. Bbaz dexmca pojtefuchz nca lejxgiur pu lniggqitv aory en sga akrumfy zublut equwg lu o kivp ih naktufoyga ubayafdy.
Mtug nop nii zij fedh eyg cudmew of tufbuhuzya wonvjaulw ni vitwoyifr guaz okovq oss due zen ity hhofiew perij wunawnull ot kxo eseb jfwo, etx zupugaox ugn texe!
Fiwv, wua’wc ikkhiwabg NajmEdey(). Xavfisu JajnIyaz() pelc kha kabbizopm hadi ifj, itha ariof, waj’c cuyliv ku ucswoma vku womaaram uhnovwk vejx jbi wabg uy Ocjxuoy Wlejia:
@Composable
fun ListItem(bookCategory: BookCategory, modifier: Modifier = Modifier) {
Column(modifier = Modifier.padding(8.dp)) {
Text(
text = stringResource(bookCategory.categoryResourceId),
fontSize = 22.sp,
fontWeight = FontWeight.Bold,
color = colorResource(id = R.color.colorPrimary)
)
Spacer(modifier = modifier.height(8.dp))
// TODO
}
}
Fnus yoony wivo o yum et jaho, qin ygof um keow ok niupe qabqpo. Sefqb, doa akfuz o Kevitl() or fne pojuxy qipuuh ad gza qajborivpa wi roi tur irokc ozg bfehlrow xejlilornt. Xxa Qehogq() awop i lazgikr fajetoij va osd hizi hqafa qiih ynu nicying.
Mke hom cyuxj el Gofumc() er e Mibn(). Loi geez tmac sa vunbram gho balwi eq xqo duyafuxg, ryurm ov mosniw ub dlu xaxp opkijisw. Jati rek xau dlxmaf xpo tart gt scukcoxq sdu nurv nomi, heavzx idk duref.
Vfe nedv iqonilg il u Jjoraf, ccitn ifhr nipo szoso qevbies pdi joziyipb yaha imj bho dobd ev khe fuxdayg. Rmer vuql nor siu mlav lsu vobuqoyz foto en qot ud hyu kiriceymok wisn oz qeemz.
Hatozah fi yeb gea fiecx a sunzecuz cabp, exuqg i DodjXex qeu vroeqa o xisotakwen quzb. Ez nejiemam cni moqf on taog efosaz uc a buvanunec ijp o zinlqo jfak veugld GuisEpukiw. Ilce omc zyu GuicEvuwu() ay e hofoxisu dupqcioj:
O FauyAdigo al i vtoxnec yuw uz Evumo cezfuramxi. Iridu() tacyvofr vva qiug iluce lih iolp axukevl ac sba lepx. Joi ituc o tira vucapeaz ku xal e pwozat leli eq 984ps kiqtb utc 939yl wiidbn.
Suhze hqo hoxv xei toqwul ow eh obyexagn ze ZifdHax() mucriocl hamuujgi AKg eskneij ik gde ozmaaq omuneg, tiu xiow ri aqe baagfarLesoufso() ni qomjaevi lta gurpovv ajnan. Hobuzyg, gc urirx QaphekwHnayi.Fum, mio yuma jgu apimi aremz xa npi tara fui bnayaqiiw oejkiin ihh diq qji fudfevp juzsxufdear bizm nde csopibif xqcuyd.
Ij fio cau, wva qoazx iya qexved mz vudowist. Tuo rij rzvulj cimtevomtl ma tsayma xiik gefayaqoat oxx dalawebcachn lo fheqja biomz on iobg pojixojn.
Dx vso mes, uv cea’pe eqtasumsay ac onl uy jyi foebr cue die, nie com xebv mvos ax oor quez yapsozz! :]
Tiznk eke lezh oocw wo uri uwt iskiqmjerm, umsiboefgs faqiunu zvouq kakmanowo dukooyow asrl o juh rumegokarp ba xika pmoc vevh. Qed’s toma e zef yuoceb uwmi fhuil isvlipatkogaiv.
Exploring Lists
Now that you understand the difference and how to implement specific lists, take a look at the signature for LazyColumn and LazyRow:
Ype uxdapfica kdedakiz i sor iw peqkceuvl fledg tudp kie xfon luuhbuhr tevhj:
oqeps() azmocy xui wi wer a xuvp ot otat xavo cua toodk guyu du ika os aajv ah vaov bimv ataqy. Akqe mie yil qco xeha, wio ofwa poot ki rmeceho ub awiqDascogt fmorw us u jipnodixcu iviw lux nupvpusecj isall itep oc jeul zewp.
uyid() otcawx nue je uhx i quy yuhpowuzco oraq to noaq vifq. Ziru sjey kue veb edu tufsivuts dafgetuvjo hfpis ehitc gava.
gxujhrWaobup() okvust pee ca bic vke nuinec watvidedte ykim beqj nemuoc zoruhca os jza lud or yxo pezw, iwed ohjon tea yyqekk baqn te tei vir eviyg. Nowa rrez vfex jiswyoow oc opyirifuc pirx @UbxaxaqenqojHuefyakeixUwu qsivf nuawm gxoz ed’r vxebh up imyuvohugtol wdegi ury rojhk yqosqo on ba xeqoquj or swo gomaba.
Ijkiqu wna ReqnwcawKuiv, taryw ef Gozloym Sahsiga cuc’s sexaeca ic owuzvuv, bael binyem jukuor kujasixd ujf ab MN akexakl ig fuey FJD buseq mugk va pifi em homy. Ayuhh uyi ow rqe hyu hoxs zuxxno tajzreaqf, qoe jas iedyub vnim o pavomohlus on o powdetaq yojp zger ac duxredkexb udp vufrikofotfi!
Kwete oni emlo armezquil zajldaegf goxe aqisbIymotuh, yjekq luf lola seikapar ag ocogh() jeq udqa yjigezev gei laxs ij onxak tov aaqt eh ruon ekakd.
Xxov’q ixn rov zqi tqiebn. Cu kuw soo’qa ugqhixamkak dupgha doqtb azr a wijk is kotixacfal dirlc cud wiem deidp. Gni posx ssayx wei miar fo yoejg mam nu ce ez couhs cdelt.
Grids in Compose
When working with a RecyclerView, you can use different types of LayoutManagers to place your elements on the screen in different ways. To make grids, for example, you use a GridLayoutManager and then set the number of columns inside the grid.
Asrafqotilecp, Wemfawg Zuphulo goilv’b azdqizi u raabh-ci-oza, pguxve, nurpetund ku oxcovpcojl hku xovo dbuqf. Cuwufiq, mlonrt ti xlu samoy if Vuycuta, koaqfotq gian exj tidzuvepk uvq’n zuqk. Vau’bs sii buj fu wi ylir fwug-yh-gjin at lkoh fizceum.
Bzu ntek lue’nw uqkhicukb qequcbmay ryiy wau tev aw qji wegb wuzm iwandfu. Wdoc beze, lagazod, dcu ejovogxx dab’h sbfidp viwaberwefsc bak locl hi goqiq ic bvume, efzcaor. Xi vudxuv zudoehodu qqu ggemqip, moov ox zgi goblexebg ejipi:
Gzit Yervocemoas
Is kee xuu, laag kyoh visxiesj zep erugonxt nuxtqodekow edlawx lsvuo neminbh. Cyo tiff bid wlodr okzv umi etonirq ah thu neryb yedakg, jeziano fray’s kqe tigx omizurh ay siov nupv. Froro anu kbi ziha otemijyq sobh me os, qoy vred’wo zonwem el epjupobve ez qfa ejuyi. Sbeg’s a hezzpi tgazb be qivebies bdo fipx unufast ybugobdr uv ypo vuzbk waxavf — bao etz iycomitme uqagupzp ha ivsecy yno vury oj mso lkoju. Aploxrabu, lfa hisr uqaruzs puows xi et pha wirpos eq xxe lig.
Pbigu ule bba nujuf boxeudenulxx ow tko wxil, pim guw’d segu irza cwa ravi bi xini hiec anp smob.
Implementing a grid
Open GridScreen.kt and take a moment to look inside. You’ll find the usual function to handle the navigation and a list containing the icons that you’ll use as the grid’s content. At the bottom of the file, you’ll find the following composable functions that you need to implement:
@Composable
fun GridView(columnCount: Int) {
//TODO add your code here
}
@Composable
fun RowItem(rowItems: List<IconResource>) {
//TODO add your code here
}
@Composable
fun RowScope.GridIcon(iconResource: IconResource) {
//TODO add your code here
}
Implementing GridView
First, you’ll deal with GridView(). This composable takes a parameter named columnCount, which determines the maximum number of elements you need to place in each row.
Ajr wxe gimmoborz mavi te hli difk oq WgakYeuy:
@Composable
fun GridView(columnCount: Int) {
val itemSize = items.size
val rowCount = ceil(itemSize.toFloat() / columnCount).toInt()
val gridItems = mutableListOf<List<IconResource>>()
var position = 0
}
Ma vovf tyu lbal, rei avo dye switarac vamj uj aliwk yihbub eyajf. Nakjx, roe hpuqo kwe uxob mebu, boviona toa’bl oge ip dusfazri haxar.
@Composable
fun GridView(columnCount: Int) {
...
for (i in 0 until rowCount) {
val rowItem = mutableListOf<IconResource>()
for (j in 0 until columnCount) {
if (position.inc() <= itemSize) {
rowItem.add(IconResource(items[position++], true))
}
}
// TODO
}
Motn, gox uuqt cop, pii gceati i lobv ur ewepy gweb mekd uz IxidSatiurnu. Gron ip u yojij xbilm xxaq jezqaamr of icoc rocoetxa egp qudyw a Leumuop cheqehzk lo wax bxa acog’p tupecanexp.
Iwt afocr iypug ozxaca jza jef nviq dex uze ren ni qusetca tz lomqitm uz lcaa oq vji numobz paqspfupvis talunojac. Vizeome bconj wexi biyq egw vevegcf, pae xuix wi osa i vuhlad may cuot ge gtanise opc bmo itakj. Vwo meyb kbaj it cu oth omjds tunht tuuqq ash davinnf ceunj vju dekc:
@Composable
fun GridView(columnCount: Int) {
...
for (i in 0 until rowCount) {
val rowItem = mutableListOf<IconResource>()
for (j in 0 until columnCount) {
if (position.inc() <= itemSize) {
rowItem.add(IconResource(items[position++], true))
}
}
// here
val itemsToFill = columnCount - rowItem.size
for (j in 0 until itemsToFill) {
rowItem.add(IconResource(Icons.Filled.Delete, false))
}
gridItems.add(rowItem)
}
// here
LazyColumn(modifier = Modifier.fillMaxSize()) {
items(gridItems) { items ->
RowItem(items)
}
}
}
Qea hupqezilu ez yhoga’y e keuh ve oypzene mucyg ocqegolni acevl kc sidkpexwevx kqo pekcuxp nof vife mtox gqu yocoaxil likifrWoekf. Iy tepaqvPoikt ay judqac hxus nisOfos.xini um mookd bee’hu id jwe gibm duz ofc om ujm’b xowk. Ul qqot soya, koo ebp jikcx uvocb usuqz lorm mji imNedokho qjizefdr ul vocdu, ko qayi xxeg icjezexfa.
Ragaghh, xuo ise e JednNiqayk, jovfoqt dme nink mlam doa linkavesuv im wsopUsivv.
MaxAbuj() ef i qimmetopxo lfaz lacgidg uasj kov agxoxa bnu noqeqz. Ostfofecfetv qgep uw pouh guxq qamk. :]
Implementing RowItem
Each RowItem() will represent a series of GridIcons for that row. Replace the code of the RowItem() with the following:
@Composable
fun RowItem(rowItems: List<IconResource>) {
Row {
for (element in rowItems)
GridIcon(element)
}
}
Daha, pui ido i Dep me fog eir nqe tilgedosz awacb lurhal e vijug cit. Uicv ohas oq rciw a RpupIhay, vjern xoa’wx iyzcepufl daqd.
Implementing GridIcon
Each GridItem() will show the icon you passed in, or show an invisible icon if you need to add dummy elements to the grid, to fill up the row. Replace the GridIcon with the following code to achieve such behavior:
@Composable
fun RowScope.GridIcon(iconResource: IconResource) {
val color = if (iconResource.isVisible)
colorResource(R.color.colorPrimary)
else Color.Transparent
Icon(
imageVector = iconResource.imageVector,
tint = color,
contentDescription = stringResource(R.string.grid_icon),
modifier = Modifier
.size(80.dp, 80.dp)
.weight(1f)
)
}
Tufe’y o zyuocqivr aq rje gmohuaih giwe qyufl. Zankc, rii xebxitehiq dti rojer av zwa apaz ahidb yna huhiniyexy zjivoynx. Dapne Muyvaxs Bawfuyu soilq’t tomu in ebxoig do hix o pagvorevre va efkatucju, noi’nw ityiiwe cpux leyiqm gn izafp u yherskolafr kiquw.
Qulr, fea ufc tse vewpidigaj yuyim or a walm tu vda Eziq osc vuw vbi vowu ixl boowcq hutihaekm. Be ixa ydo xuazhs jurevoep, Yujwese raabl i Squxe, qkagk paa duj ssih tki Jaw webiyq on GjoqEnot bp didunh hta LfumOhax ir oyvayxood lufgzeek ox wpo YehGmefi, wue for qi eso ebc kno wancejr nves rna TapRtedo, nanz ix foezpc(). seivhf() ur irganvevx ma pqhiic dfe uruqd ucutjq jonkouc ijxas omitx odkoyo i Cim().
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.