Talking Tabs - Communicating Across Browsing Contexts
This is a modal window.
Das Video konnte nicht geladen werden, da entweder ein Server- oder Netzwerkfehler auftrat oder das Format nicht unterstützt wird.
Formale Metadaten
Titel |
| |
Untertitel |
| |
Serientitel | ||
Anzahl der Teile | 637 | |
Autor | ||
Mitwirkende | ||
Lizenz | CC-Namensnennung 2.0 Belgien: Sie dürfen das Werk bzw. den Inhalt zu jedem legalen Zweck nutzen, verändern und in unveränderter oder veränderter Form vervielfältigen, verbreiten und öffentlich zugänglich machen, sofern Sie den Namen des Autors/Rechteinhabers in der von ihm festgelegten Weise nennen. | |
Identifikatoren | 10.5446/53572 (DOI) | |
Herausgeber | ||
Erscheinungsjahr | ||
Sprache | ||
Produktionsjahr | 2021 |
Inhaltliche Metadaten
Fachgebiet | ||
Genre | ||
Abstract |
|
FOSDEM 2021552 / 637
1
2
7
8
10
11
12
17
29
33
35
38
40
44
48
50
54
59
63
65
85
87
91
95
97
105
108
114
115
119
120
122
126
127
129
130
133
137
140
142
143
147
149
151
156
159
160
161
168
169
170
175
176
177
178
179
182
183
184
187
189
191
193
197
198
204
206
209
212
220
222
224
227
230
233
235
238
242
243
245
247
252
253
255
258
260
261
262
263
264
265
272
273
278
281
282
285
286
287
288
289
294
295
296
302
304
305
308
310
316
320
323
324
328
330
332
335
338
342
343
347
348
349
350
351
360
361
365
368
370
372
374
377
378
380
381
382
383
386
390
392
395
398
402
405
407
408
409
414
419
420
422
425
427
430
439
451
452
453
458
460
461
464
468
470
471
472
473
475
478
485
486
487
491
492
493
495
496
498
509
510
511
512
516
532
534
538
543
548
550
551
554
556
557
559
563
568
570
572
574
575
577
583
585
588
591
593
595
597
601
602
603
604
605
606
607
610
611
617
627
633
634
00:00
Überlagerung <Mathematik>Computeranimation
00:37
BestimmtheitsmaßMereologieSoftware EngineeringSystemaufrufOpen SourceKontextbezogenes SystemTelekommunikationBildschirmfensterXMLUMLComputeranimation
01:05
SoftwareOpen SourceSoftware EngineeringRelativitätstheorieOpen SourceMereologieRISCAdditionDelisches Problemt-TestGesetz <Physik>XML
01:39
TelekommunikationHalbleiterspeicherCookie <Internet>TermObjekt <Kategorie>Kontextbezogenes SystemProgrammierumgebungZeitbereichNummernsystemProtokoll <Datenverarbeitungssystem>AppletSkriptspracheAbstraktionsebeneCodeDatensichtgerätUmwandlungsenthalpieSchaltnetzMereologieNummernsystemKontextbezogenes SystemProgrammierumgebungMessage-PassingDifferenteProzess <Informatik>Quick-SortViewerMatchingKonstruktor <Informatik>BildverstehenAbstraktionsebeneGemeinsamer SpeicherProtokoll <Datenverarbeitungssystem>CASE <Informatik>WhiteboardCodeMinkowski-MetrikHalbleiterspeicherDomain <Netzwerk>ATMTermBrowserWeb-SeiteBildschirmfensterBroadcastingverfahrenURLXML
03:44
Gemeinsamer SpeicherMultiplikationsoperatorSpeicher <Informatik>BeobachtungsstudieKontextbezogenes SystemKategorie <Mathematik>Stellenring
04:13
BrowserSchnittmengeMatchingAggregatzustandSpeicher <Informatik>StellenringMathematikPhysikalisches SystemBildschirmfensterNummernsystemDezimalzahlComputerarchitekturKontextbezogenes SystemQuick-SortWhiteboardSchlüsselverwaltungBootenJSONXML
04:39
Architektur <Informatik>TelekommunikationDemo <Programm>Speicher <Informatik>MathematikKontextbezogenes SystemMailing-ListeBitrateComputeranimation
05:11
Quick-SortMultifunktionBenutzerbeteiligungQuaderBenutzeroberflächeBrowserWeb-SeiteGemeinsamer SpeicherSpeicher <Informatik>Kontextbezogenes SystemComputeranimation
05:55
EntscheidungsmodellToken-RingNotepad-ComputerZeichenketteHasard <Digitaltechnik>ComputersicherheitKonditionszahlMechanismus-Design-TheorieDifferenteBrowserATMGemeinsamer SpeicherKontextbezogenes SystemSpeicher <Informatik>RechenschieberQuick-SortCASE <Informatik>Demo <Programm>SkriptspracheMultiplikationsoperatorEinfügungsdämpfungZeichenketteMechanismus-Design-TheorieBrowserInverser LimesProdukt <Mathematik>FunktionalWeb SiteStellenringComputersicherheitInformationHasard <Digitaltechnik>DatentypApp <Programm>Nichtlinearer OperatorSynchronisierungEinflussgrößeSerielle SchnittstelleKonditionszahlCookie <Internet>Formation <Mathematik>Exogene VariableQuelle <Physik>Brennen <Datenverarbeitung>HackerWellenpaketBestimmtheitsmaßAdditionMereologieAggregatzustandComputeranimationJSONXMLUML
08:09
Cookie <Internet>ZeichenketteBrowserExogene VariableCookie <Internet>ComputerarchitekturDateiformatZeichenketteGarbentheorieServerE-MailBrowserExogene VariableEindeutigkeitTypentheorieMereologieBenutzerbeteiligungBildschirmmaskeQuick-SortTotal <Mathematik>JSONXML
08:55
TelekommunikationArchitektur <Informatik>Cookie <Internet>Kontextbezogenes SystemFunktionalGruppenoperationBildschirmfensterAggregatzustandCASE <Informatik>MultiplikationsoperatorDemo <Programm>SynchronisierungMultiplikationSchnittmengeBenutzerbeteiligungSchlüsselverwaltungComputeranimation
09:36
Cookie <Internet>FunktionalQuellcodeSpeicher <Informatik>Cookie <Internet>BitQuick-SortMathematikSchnittmengeTablet PCSpieltheorieKonditionszahlWort <Informatik>DifferenteComputeranimation
10:20
AuthentifikationEINKAUF <Programm>ObjektverfolgungEntscheidungsmodellNotepad-ComputerCookie <Internet>Gemeinsamer SpeicherKartesische KoordinatenToken-RingOverhead <Kommunikationstechnik>CASE <Informatik>Cookie <Internet>Komplex <Algebra>AuthentifikationTypentheorieQuick-SortHalbleiterspeicherMailing-ListeJSONXML
11:05
BroadcastingverfahrenMechanismus-Design-TheorieBrowserRahmenproblemBroadcastingverfahrenMessage-PassingTelekommunikationQuick-SortAdditionInformationSoftwaretestKontextbezogenes SystemBildschirmfensterPunktProzess <Informatik>Gebäude <Mathematik>Figurierte ZahlPhysikalisches SystemCross-site scriptingBrowserComputerarchitekturDienst <Informatik>Wort <Informatik>BenutzerbeteiligungJSONXMLUML
12:06
TelekommunikationArchitektur <Informatik>Konvexe HülleComputervirusBroadcastingverfahrenMessage-PassingFigurierte ZahlSoftwaretestEreignishorizontDemo <Programm>MereologieGebäude <Mathematik>Quick-SortKontextbezogenes SystemBrowserComputeranimation
12:49
BroadcastingverfahrenGruppenoperationWeb logDigitale PhotographieNotepad-ComputerBroadcastingverfahrenPhysikalisches SystemGruppenoperationWeb SiteCASE <Informatik>MultiplikationSynchronisierungInstantiierungEinfache GenauigkeitSkriptspracheArithmetisches MittelOrdnung <Mathematik>ComputeranimationXML
13:41
ThreadKontextbezogenes SystemMessage-PassingTypentheorieDienst <Informatik>BenutzerbeteiligungSkriptspracheTypentheorieThreadWeb-ApplikationMessage-PassingArithmetische FolgePunktCodeQuick-SortDienst <Informatik>Inhalt <Mathematik>GruppenoperationArithmetisches MittelNichtlinearer OperatorEin-AusgabeFunktion <Mathematik>VerkehrsinformationAusnahmebehandlungZustandsdichteWasserdampftafelForcingComputeranimation
15:03
SkriptspracheProzess <Informatik>ThreadTelekommunikationArchitektur <Informatik>SkriptspracheQuick-SortBenutzerbeteiligungKontextbezogenes SystemPunktSpiraleMessage-PassingElektronische PublikationProzess <Informatik>Demo <Programm>ThreadDiagrammXMLUMLComputeranimation
16:00
Demo <Programm>TelekommunikationBildschirmmaskeExogene VariableQuick-SortArithmetisches MittelThreadComputeranimation
16:26
VisualisierungTaskRechnernetzRechenbuchBefehlsprozessorNotepad-ComputerBildverarbeitungNichtlinearer OperatorBildverarbeitungSoftwaret-TestCASE <Informatik>Speicher <Informatik>StellenringBildgebendes VerfahrenVisualisierungAutomatische IndexierungXMLUML
16:55
BildschirmfensterDifferenteSkriptspracheJSONXMLUML
17:26
SkriptspracheEindeutigkeitProzess <Informatik>Message-PassingArchitektur <Informatik>TelekommunikationDemo <Programm>PunktSkriptspracheWhiteboardQuick-SortDifferenteTelekommunikationDrahtloses lokales NetzKontextbezogenes SystemGesetz <Physik>Objekt <Kategorie>ARM <Computerarchitektur>MereologieComputerarchitekturThreadMessage-PassingKlasse <Mathematik>DiagrammComputeranimation
18:40
Gemeinsamer SpeicherWurm <Informatik>ComputervirusDemo <Programm>ParametersystemBroadcastingverfahrenQuick-SortBasis <Mathematik>Elektronische PublikationProfil <Aerodynamik>StellenringComputerspielForcingRahmenproblem
19:48
Funktion <Mathematik>EreignishorizontMessage-PassingComputervirusIndexberechnungMessage-PassingWhiteboardEinfach zusammenhängender RaumQuick-SortGesetz <Physik>MathematikStellenringCASE <Informatik>Digitale PhotographieRechter WinkelThreadBroadcastingverfahrenRahmenproblemEreignishorizont
20:32
SocketNotepad-ComputerBrowserLipschitz-StetigkeitEinfach zusammenhängender RaumWort <Informatik>Gemeinsamer SpeicherSocketQuick-SortCASE <Informatik>AggregatzustandBenutzerbeteiligungMobiles InternetBrowserTypentheorieSpeicher <Informatik>Puffer <Netzplantechnik>DatenstrukturZahlenbereichSynchronisierungKugelkappeStellenringAssoziativgesetzFacebookAutomatische IndexierungTeilbarkeitJSONXML
21:26
FacebookJSONXMLUMLComputeranimation
21:49
Element <Gruppentheorie>MereologieComputeranimation
23:40
StellenringUmwandlungsenthalpieKonditionszahlSpeicher <Informatik>ForcingMathematische LogikCASE <Informatik>Cookie <Internet>Quick-SortProgrammiergerätComputervirusSchnittmengeRechter WinkelBroadcastingverfahrenTelekommunikationBesprechung/Interview
29:30
HardwareSkriptspracheAppletComputeranimation
30:05
Element <Gruppentheorie>Computeranimation
Transkript: Englisch(automatisch erzeugt)
00:40
Hello everyone, hope everyone is doing good and are safe. Today I will be presenting a talk titled Talking Tabs, Communicating across browsing context. By the end of this talk, we can expect to understand the different ways of communicating across tabs or windows. This is the main agenda of this topic.
01:02
Before we move forward, I will quickly introduce myself. I am Akshat and I am based out of India. I am working as a software engineer with Uber as a part of the RISC team. I have been associated with open source for the last 5 years now. It all started with me making contributions to orgs during my college days like Mozilla, Firefox etc.
01:25
Since then, my love for the community has been ever growing. In my free time, I love to read about technology and related topics. Without any further delay, let us move into the main agenda.
01:41
As the topic reads, Communicating across browsing context. Let us see the primary modes of communicating here. The first one is the shared memory approach. In this case, we have a shared memory space where different browsing contexts can read or write data from. Enabling in a way how to communicate right.
02:00
The second way is to communicate via messaging. Two different messaging styles like post message style messaging, broadcast message etc. We will be discussing some of them in details in the latter half of the session. Before we go into the specifics, here are some related terms used across this talk.
02:22
Firstly, browsing context. By browsing context, we actually mean the environment in which a browser displays a document. In modern browser, it usually is a tab but it can definitely be a window or even parts of a page like an iframe. Next is origin.
02:40
Origin is defined as a combination of the scheme which is the protocol, host which is the domain and the port of the URL used to identify a URL. When we say things to be of same origin, what we mean in that case is that the scheme, host and the port all of them match for a URL.
03:06
To give a very simple example. For example, one of the URL is http example.com slash app1 and second is http example.com slash app2. Here the scheme is http, the domain is example.com and the port is 80.
03:22
All three of them matches for these two URLs and we can hence say that they are of same origin. Lastly, explain the execution context. It is an abstract concept of an environment where the JavaScript code is actually evaluated and executed.
03:43
Moving on, without wasting any time, let us move on to the shared memory approach. The first one in this category is the local storage. Most of us might be familiar with it and might have used local storage sometime, somewhere.
04:01
I mean the set item method and the get item method, so we must be familiar with that. Now, let us look at it and see how we can communicate via this method across browsing context. Firstly, the features. Local storage is a key value store and the data is shared between all tabs and windows from the same origin.
04:23
Again, by same origin, we mean that the scheme, the hostname and the port of the URL should match. Lastly, the data does not expire even if we restart the browser or do an OS reboot. In a sense, it is persisted.
04:41
Let us now see the architecture. In this figure, we can see that one browsing context sets a value in the local storage via the set item method. On the other hand, the other browsing contexts are listening for any change in the storage. As soon as the value is updated in the storage, the other tab receives it in the listener callback and updates can be made based on the newer value.
05:08
Let us quickly see a demo of it. Here in this web page, we can see there are 5 counter UIs with an increment button.
05:23
The first one at the top corresponds to the button and the counter in the main document. 4 of the other boxes are actually iframes loaded onto this web page. We will click on the increment in the document. We can see that all the corresponding counters are immediately reflecting the updated value.
05:47
When we do it from the iframe, we can see the same. Let us try to open it in a new tab and then see. Let us increment from this tab and see it here. We can see that we can communicate across the browsing context via a shared memory that is local storage.
06:11
Let us go back to the slides. We saw a demo of it. Now, let us look at some use cases. One of them is storing shopping cart items, user preferences like themes and sometimes auth tokens as well.
06:28
Although, it is not safe to do that. Here in this case, we added listener on the storage which enables us to sync the information across browsing context.
06:41
Some gotchas to look out for. It is prone to security hazards. For example, if a site is vulnerable to accesses attacks, local storage is not safe in that way since any script can access local storage. Also, people many times tend to clear cache and that might lead to loss of data.
07:01
In a way, we can say that it has very limited data production measures. Next is it is prone to race condition as there is no locking mechanism on data. Next is that it can only store string data. This makes it pretty useless for storing data that is even slightly more complex than a string.
07:22
I am sure we can definitely serialize everything including data types into string and then store it. It is sort of a hack and also adds time for that serialization step. Next is that it is synchronous and that means that each of the operation in local storage happens one at a time.
07:41
For a complex application, it will definitely slow down our app's runtime. The last one is that it limits the size of data that we can store. It is around 5MB across all major browsers. This is fairly a low limit for people building apps.
08:00
There are data intensive and nowadays people also build offline functionalities. So that might need even more space. Next one is cookies. Let us quickly have a look at it as well. Cookies are small strings of data that are stored directly in the browser. The unique part is that it can be set by web servers as well using a response type set cookie http header.
08:29
The servers can set the set cookie http header and via that method set the cookie value as well. The value of the cookie consists of in the format name equal to value pairs delimited by a semicolon.
08:46
Each of that section of name equal to value pair is actually a separate individual cookie. We will have a look at the architecture now. Here we can actually see how the cookie looks like.
09:00
In this case there are two cookies. One with the key name underscore GA and other with the key name counter. Here one of the browsing contexts sets the cookie via the document dot cookie api. The other browsing context have a function called after every interval through the set interval web api.
09:22
To sync the cookie data cross browsing context. What it does is basically it calls the function multiple times to check whether the cookie has been updated. If yes then it can take appropriate action. Let us look at a demo at it as well.
09:42
Here the UI is pretty similar to the local storage just that the functionality inbuilt is using cookies rather than local storage. We will again click on the increment and we can see that again it is working and reflecting the values in both the ways.
10:01
Also you might have noticed that it is a bit slower compared to local storage. The reason is because we are using the set interval which sort of polls for any data change and that is the reason. It looks a bit laggy.
10:21
Moving on. Regarding the use cases. It is commonly used for authentication for storing tokens. Some of the other use cases are storing user preferences like themes or sometimes even cart items. Gotchas to look out for. It can store only 4kb of data which is comparingly very very less based on the increasing complexity of applications day by day.
10:49
Another overhead it comes is that we need to ask explicitly permission from the users to use cookies to comply with the GDPR. We had looked at the two types of shared memory approach.
11:06
Now we will be looking at the messaging approach. Firstly we will discuss about the broadcast channel method. By the word itself means that we are broadcasting some information right.
11:22
The broadcast channel API is a simple API that makes communicating between browsers context easier. I mean that is communicating between windows, tabs, iframes, web workers and service workers. Messages which are posted to a given channel are delivered to all listeners of that channel.
11:41
It is applicable for communication on same origin. This is one important point that for broadcast channel it is applicable for communication only in the same origin. Compared to a post message style communication where it can be done cross site as well. So in this we just broadcast a message to the channel and then it is
12:01
the browser's job to send it to the other browsing context listening to that channel. Looking at the architecture here. Here we can look at the figures. The broadcast channel named test is created and a hello message is broadcasted through the channel. The message can then be received in all the other tabs via the on message event listener.
12:22
This is how it works. Here is a demo of it. So here we can see again there are four iframes and one button as a part of this document. So we click on the say hi to all button and we can see that hi is being sort of broadcasted to all of the other sort of iframes that is browsing context.
12:44
And the vice versa is also true. And we can actually open a new tab and also see the same. So we say hello to all from this tab and we can see it getting reflected in this tab as well. So this is how the broadcast channel method works.
13:03
Moving on. So regarding the use cases. So I mean there are multiple use cases of it. So one of two few of them are for example we need to sync UI across tabs based on some user action. So basically if a user takes action in one of the tab and we need to update it across all tabs.
13:22
So this is one approach or one use case. And another example might be for example if a user logs out from a single tab and for example multiple instances of that website is opened. So we actually want the user to be logged on from all of them. So again broadcast channel can be used in this case.
13:42
So workers. So now let us come to the workers now. So web workers are I mean simple means to actually for web content to run scripts in the background thread. So it's usually done to offload some heavy lifting to the background thread without interfering the main thread that is the UI thread.
14:03
And it can perform sort of input output operations as well as sort of use XML HTTP request as well as sort of use the fetch API. And once created a worker can send message to the JavaScript code that I mean that created it. So for example it can sort of send messages to the JavaScript code that actually spawned the worker itself.
14:27
And one more point here is that the data is copied rather than being shared. So that means the reference of the data is separate in the main thread and the worker thread. So there are mainly three types of workers.
14:41
So dedicated workers, shared workers and service workers. So we will have a look at the first two in details. And regarding service workers. So these are mainly used to do background actions for example like push messaging and etc. And nowadays it is commonly used in the PWAs that is the progressive web apps as well.
15:03
So let us talk about dedicated workers. So it is sort of the most basic kind of web worker and its access is limited to only the script which is spawning it. So as I said it is accessible by the script which actually spawned the worker. It runs as a separate thread within the same process as the main script.
15:24
So this is one important point. And as well as one document can have multiple dedicated workers. So for example one worker is dedicated to one document but a single document can have multiple dedicated workers. So in this diagram we spawn a worker by passing in the worker.js file path.
15:47
Which contains the sort of the on message handler as well. And the sort of browsing context sends the message to the worker. And the worker can respond back to the script file which actually spawned it.
16:01
Let us look at the demo of it. So here we have the worker kind and we have a button called say hi to worker. So as soon as we click on this button we will get a response from the worker back. So the worker responds with hello from worker. So this is sort of a communication from the main thread to the worker thread.
16:27
Moving on. So regarding the use cases of it. So as I said it is used in heavy operations for example image processing, CPU intensive calculations, network intensive tasks, rendering optimizations, animations and visualizations.
16:44
So these are some of the use cases of dedicated workers. The gotchas here are that it does not have access to local storage. So sometimes we might want to sort of adapt to some hybrid solutions like we want to use local storage along with dedicated workers. But with it, it will not be possible with it.
17:03
And but it still has I mean it can access index.db so that is one thing. So lastly we will be talking about shared workers. So a shared worker is I mean compared to the dedicated worker it can be accessed by multiple scripts.
17:21
Even if they are being accessed I mean across different windows, iframes or even workers. So the difference mainly as I said is the ability to be accessed with I mean with different browsing context. So creating a shared worker is very similar to how we create a dedicated worker. But instead of the straight forward communication between the main thread and the worker thread.
17:44
We essentially have to communicate via a port object. I mean that is I mean an explicit port has to be opened to communicate to be opened so that multiple scripts can use it to communicate via the same sort of channel that is created. And also the point to be noted that I mean dedicated workers do this port creation and communication via this port implicitly.
18:07
And we do not have to sort of mention that. So looking at the architecture diagram. So similar to a dedicated worker we can spawn a shared worker using its class and passing in the path to the worker script.
18:22
And the document sort of communicates to the port that is there. So we can see shared worker dot port dot post message. We can post a message called hi. And again it can the shared worker it can respond back to the same port as hello here right.
18:41
So let us look at the demo. So here we have four iframes and one main document sort of here. So here we have a button for say hi to worker. So it will sort of say hi to the workers which is in the four iframes.
19:02
Say hello to all is kind of a broadcast we are seeing here. And say bonjour to alternate iframes so it will do it in an alternate basis. And we will also have a look at the worker file for this. So we click on say hi to worker. So we can see that basically it is saying hi to it is responding back hi from worker.
19:25
So we are saying hi and it is responding hi from worker. We say say hello to all and it is sort of a broadcast that we can see here. And next is we say say bonjour to alternate iframes. And we can see that this is being sort of printed in the alternate iframes here.
19:43
So let us quickly look at the js file as well for this. So yeah now we can see the worker js file right here. So here we can see different cases that we saw in the UI.
20:00
So in the first case when the event data was high that high was received from the main thread. We saw that it posted back a message hi from worker. In case of a hello it sort of looped through each of the port connection whichever ports were connected. And it replied back similar to a broadcast. And in case when bonjour was sort of sent through the data.
20:23
It sort of did a simple math and sort of sent it to the alternate frames. This is how it works. So moving back. So I think regards to the use cases of it. So it's generally useful whenever you want.
20:40
So we have use case to share web socket connections. Sort of maintain some kind of centralized state. Limiting active tabs. So this is one interesting use case where we can actually sort of have a sort of number of cap on the number of active tabs. That is useful. And coordinating among different tabs. For example yeah we can sync sort of UI states and other states across tabs.
21:05
And regarding the gotcha. So yeah it's not supported in Safari and mobile browsers. It does not have access to local storage. It can access IndexedDB and it does not cannot access shared array buffer. Which is again another type of data structure I would say.
21:24
So yeah this is what I wanted to cover in this talk. I hope it was pretty useful for each one of us here. And maybe you will take back some learnings from this talk. So and you can connect with me on GitHub, LinkedIn and Facebook.
21:43
And yeah now I am open for any questions now. Yeah thank you.
22:58
Hello everyone I mean feel free to ask any questions if you have any regarding any part of it.
23:02
I'll be happy to answer.
23:50
Yeah hi. Hi Ludovic. Hello. Thanks a lot for your talk. It was very interesting. Thank you.
24:02
Don't hesitate people to ask questions.
24:57
Yeah thanks for asking that question. So I mean to answer that question for you.
25:01
I mean recommended. So there is no strict recommended way for communicating. So it all depends on use to use I mean use by use cases. So I mean if you're looking for sort of a broadcast kind of a sort of logic. So in that case you might want to go with a specific set. But yeah it all depends on a specific user. Thanks for asking that question.
26:11
We still have five minutes. If you want to ask questions. Four minutes now. Don't hesitate guys.
26:49
Do you have some recommendation? Or something to add?
27:51
Yeah programmer I saw your question. So what what I meant to answer is basically it all depends on our use case. So we can we can use local storage cookies and whatnot right.
28:01
But it all depends on the use case that we're trying to solve for. And each of them has their own pros and cons. So for most of the use cases I think for simpler. Yeah programmer I saw your question. So whatever what I meant to answer is basically it.