Events for the Uninitiated
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 | 287 | |
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/56889 (DOI) | |
Herausgeber | ||
Erscheinungsjahr | ||
Sprache |
Inhaltliche Metadaten
Fachgebiet | ||
Genre | ||
Abstract |
|
FOSDEM 2022124 / 287
2
4
6
8
12
17
21
23
31
35
37
41
44
45
46
47
50
62
65
66
67
68
71
73
81
84
85
86
90
92
94
100
102
105
111
114
115
116
117
118
121
122
124
127
131
133
135
137
139
140
141
142
145
149
150
156
164
165
167
169
170
171
172
174
176
178
180
183
184
189
190
192
194
198
205
206
207
208
210
218
220
224
225
229
230
232
235
236
238
239
240
242
243
244
245
246
249
250
253
260
262
264
267
273
274
277
282
283
287
00:00
Diskrete-Elemente-MethodeEreignishorizontMatrizenrechnungVirtuelle MaschineDatensatzMatrizenrechnungImplementierungInformationEreignishorizontEndliche ModelltheorieServerComputervirusMultiplikationsoperatorDatenstrukturUmwandlungsenthalpieElektronischer ProgrammführerQuick-SortElement <Gruppentheorie>SoftwareentwicklerKartesische KoordinatenEnergiedichteOrtsoperatorSoftwareZweiFunktionalBitKontrollstrukturKontextbezogenes SystemFitnessfunktionAbstraktionsebeneWinkelFormale SpracheSoftware EngineeringBildschirmmaskeProzess <Informatik>PunktGeradeStellenringMeterVersionsverwaltungTechnische Zeichnung
03:17
FAQWeb logMatrizenrechnungServerKontrollstrukturInternetworkingTelekommunikationBasis <Mathematik>MereologieMathematikClientDienst <Informatik>IdentitätsverwaltungGatewayBaum <Mathematik>VersionsverwaltungKanal <Bildverarbeitung>InformationWeb-SeiteArchitektur <Informatik>Message-PassingEreignishorizontVirtuelle RealitätGraphPartielle DifferentiationWiderspruchsfreiheitProzess <Informatik>Objekt <Kategorie>DatenmodellTheoremKugelkappeDatenstrukturZeitstempelSpannungsmessung <Mechanik>ComputerarchitekturQuick-SortGarbentheorieMatrizenrechnungDifferenteInformationFokalpunktKartesische KoordinatenLanding PageIdentitätsverwaltungVersionsverwaltungServerDienst <Informatik>Protokoll <Datenverarbeitungssystem>ClientBitVerschlingungGrenzschichtablösungComputeranimation
04:29
EreignishorizontMatrizenrechnungImplementierungObjekt <Kategorie>DatenfeldTypentheorieVersionsverwaltungBitMAPQuick-SortDifferenteObjekt <Kategorie>ImplementierungElement <Gruppentheorie>Kartesische KoordinatenMatrizenrechnungEreignishorizontTeilbarkeitSystemverwaltungKontextbezogenes SystemFunktionalServerClientUmwandlungsenthalpieCodeOpen SourceDatenfeldTypentheorieVersionsverwaltungMessage-PassingSchlussregelZentralisatorProzess <Informatik>MeterGamecontrollerSuite <Programmpaket>StatistikEinsDemoszene <Programmierung>BildschirmmaskeMagnetbandlaufwerkComputeranimation
07:51
ZeitbereichBaum <Mathematik>KontrollstrukturEreignishorizontMatrizenrechnungZentralisatorPunktSoftwareentwicklerIdentifizierbarkeitQuick-SortZeichenketteMatrizenrechnungGamecontrollerServerDomain <Netzwerk>Wort <Informatik>Arithmetisches Mittel
09:11
Baum <Mathematik>Message-PassingEreignishorizontInhalt <Mathematik>MatrizenrechnungZeiger <Informatik>AggregatzustandServerMetadatenPublic-Key-InfrastrukturE-MailMatrizenrechnungQuick-SortEreignishorizontDifferenteRechter WinkelZweiMathematikElektronische UnterschriftBitHyperbelverfahrenServerInhalt <Mathematik>Protokoll <Datenverarbeitungssystem>Spezifisches VolumenMessage-PassingInformationZeiger <Informatik>GraphSichtenkonzeptGüte der AnpassungPublic-Key-InfrastrukturMailing-ListeObjekt <Kategorie>Kontextbezogenes SystemAuthentifikationClientTypentheorieMagnetbandlaufwerkZahlenbereichSystemaufrufMixed RealityBenutzerfreundlichkeitMeterBitrateTermDatenverwaltungBildgebendes VerfahrenXMLFlussdiagramm
13:46
Message-PassingLoginEreignishorizontTypentheorieEreignishorizontTypentheorieMatrizenrechnungUmwandlungsenthalpieQuick-SortSingle Sign-OnInformationSchlüsselverwaltungKartesische KoordinatenChiffrierungProgrammverifikationKontextbezogenes SystemServerMessage-PassingLoginMathematikArithmetisches MittelMeterInhalt <Mathematik>Dienst <Informatik>t-TestDatenfeldComputeranimation
15:40
Ganze ZahlEreignishorizontZeichenketteSynchronisierungClientService providerDatentypInformationDatenfeldEindeutigkeitÄhnlichkeitsgeometrieAppletInhalt <Mathematik>Baum <Mathematik>Message-PassingMatrizenrechnungDateiformatQuick-SortFunktionalMetrisches SystemDatenfeldInhalt <Mathematik>EindeutigkeitServerBitEreignishorizontTypentheorieClientInformationMultiplikationsoperatorBildschirmmaskeBestimmtheitsmaßZeitstempelIdentifizierbarkeitDifferenteEinsTransaktionRauschenOrtsoperatorBildgebendes VerfahrenDivergente ReiheHilfesystemObjekt <Kategorie>Konfiguration <Informatik>DatensatzPeer-to-Peer-NetzShape <Informatik>Physikalisches SystemComputeranimation
19:40
EreignishorizontElektronische PublikationServerClientServerClientVertauschungsrelationEreignishorizontDatenstrukturDatensatzBitQuick-SortMetrisches SystemFunktionalRohdatenURLComputeranimation
20:31
ServerEreignishorizontMessage-PassingMaß <Mathematik>EreignishorizontGraphBitDifferenteAggregatzustandRechenwerkServerMessage-PassingMultigraphBenutzerfreundlichkeitUmwandlungsenthalpieComputeranimation
21:34
Message-PassingVersionsverwaltungAlgorithmusGraphOrdnung <Mathematik>Baum <Mathematik>Auflösung <Mathematik>AlgorithmusBitGraphServerMessage-PassingQuick-SortAuflösung <Mathematik>AggregatzustandTeilmengeEreignishorizontMultiplikationsoperatorMinimalgradNeuroinformatikDifferenteVersionsverwaltungDreiecksfreier GraphPunktZahlenbereichSchnittmengeSchlussregelRaum-ZeitDatenstrukturMeterInformationsmanagementRichtungSystemaufrufInformatikMetropolitan area networkKoroutineComputeranimation
25:48
SystemaufrufMathematikAggregatzustandMultiplikationsoperatorEreignishorizontMatrizenrechnungComputeranimationBesprechung/Interview
26:21
TypentheorieSpeicherabzugUmwandlungsenthalpieProzess <Informatik>MatrizenrechnungEreignishorizontMathematikRechter WinkelBesprechung/Interview
27:15
Gebäude <Mathematik>MathematikPunktInstant MessagingFIESTA <Programm>VideokonferenzMatrizenrechnungGeradeBesprechung/Interview
27:44
MultiplikationsoperatorBesprechung/Interview
28:07
Computeranimation
Transkript: Englisch(automatisch erzeugt)
00:12
Hello. Hi. Welcome to my talk. My name is Shay. And this is Events for the Uninitiated, a junior guides
00:21
junior's guide to events in matrix. So I have never done one of these pre-recorded talks before. I'm working with some new technology. So please just bear with me. Hopefully I'll make it through. But anyways, welcome. And I just want to say a few things about myself. My name is Shay.
00:40
I am a junior engineer at Element. I mostly work on Synapse, which is a matrix home server implementation. I've been at Element for about three months and this is my first software engineering job. So I'm sort of new and I thought I would use sort of my new curious energy to
01:01
share some of the most recent information I've learned with anybody who's interested. Hence this talk. So I decided to do this talk for a couple reasons. The first one is I'm curious and I found the best way to learn something is to put yourself in a position to have to explain it to somebody else. The second was I wanted to make the spec, the matrix specification, more approachable.
01:26
I found it very intimidating when I first started. It is a large document with a lot of information. But as I sort of got to know it, I found that actually it's very useful. There's a lot of really cool info in there and it's really worth digging into. So I thought I'd sort of set myself up as a friendly guide.
01:44
And events are central to matrix applications. So it's a good idea to just have some understanding of what they are and how they function in a matrix application. So this talk is for the curious. It's for newer, junior developers or sort of anybody who has an interest in hacking
02:03
on the matrix, hacking on applications in the matrix ecosystem. Hopefully it'll just give you a better idea of what's going on. And so what I hope you walk away from this with is a better mental model of how matrix applications function and a greater willingness to engage with the spec.
02:22
One thing I will say is that software can be a little bit tricky to talk about. It's sometimes very hard to know sort of what layer of abstraction to talk about it at. And it's very difficult to talk about, use language that's very precise without falling into jargon and obtuseness. So I'm really gonna do my best to be precise, but
02:46
be accessible. And so I'm gonna give it my best shot. And when talking about events, the way that I want to sort of break that down is that I want to talk about them sort of in the micro. So we'll just take a look at how they're structured and how they function. And
03:02
then we'll look at where they sort of fit into the larger context of the matrix application. A little bit less time on that, more just a little bit more on form and structure. So the first thing I'd like to do is I'm gonna introduce the spec, which is the matrix specification. You can see and there's a couple things that I want to talk about with this. First off is
03:26
you know, make sure that you're looking at version 1.1, which is the newest version. Second, there's a couple different APIs here. So there's a client-server API, there's a server-server API,
03:42
application service, identity service, push gateway, etc. So we're gonna focus mostly on the client-server API, but just be aware that there's more information in here. And the second thing I wanted to highlight was before you, if you go on the landing page and you go to the third section,
04:05
there's a talk on architecture. It sort of talks about the overall architecture of the matrix protocol, and it's really very useful. I found myself referring to it a lot. It's a good thing to just take a look at this whole
04:22
sort of beginning really this section 3 is very useful. So that's just just showing a little bit of how what's so exciting about, or not exciting, but like what's interesting about the spec and just taking a first look at it. So
04:41
okay so the matrix defines APIs for synchronizing JSON objects known as events, which is basically sort of a fancy way of saying it is a bunch of rules and definitions on how, from which you can derive a matrix application. So you just sort of add implementation and stir. So like I said, I work on
05:04
Synapse, which is an implementation of a home server. There are other implementations of home servers. I think Conduit is one of them. There's many implementations of clients. So FluffyChat, Element, and because they adhere to the specification, they're all able to communicate with each other.
05:24
So a Conduit home server and a matrix home server can talk to each other, and the client, you know, at Element can talk to any of those home servers. This is one of the things that's very cool about the matrix specification. And one of the other things that I really
05:41
encourage people to do is to look at the specification and then look at how it's implemented in a specific implementation. I use Synapse. You can use Synapse. It is open source. You can go to GitHub. You can look at the code. You can kind of toggle back and forth between the specification and the code, and
06:03
it's a really great way to sort of get familiar with the code and what it's trying to do and also helps the two sort of inform each other. And I've learned a lot from doing that. So that's enough about the spec. Let's move on to
06:20
events. So events, the events you've been waiting for. So all data exchanged over a matrix is expressed as an event. So you can see obviously events are very important. Most of what we're doing is exchanging data. So that's what events are doing at their sort of at the sort of base level. It's a JSON object.
06:42
And so there's many many different types of events. What fields an event has is determined by the type of the event and may also be affected by room version. But they all are JSON objects. So it's just most of what's different between different types is what fields they have and what function they provide in the ecosystem. And so most events are exchanged in the context of a room.
07:08
So as I said, several different factors determine form, including what type of event it is and what version the room is. And the type sort of determines function. So we'll take a look at one
07:21
at an event very soon. But basically many, you know, there are most things that happen in the matrix application are spurred by an event. So an event could be anything from sending a message into a room. It could be events create rooms, events they, you know, could change the who's the admin of a room, you know, all sorts of things like that.
07:47
And so let's talk a little bit, so we talked about events, let's talk about rooms. So rooms are a conceptual place where users can send and receive events. So they exist on a home server and they exist across home servers. So
08:02
these rooms have no central point of control. So if I create a room on matrix.org and another home server joins that room, if the room, if matrix.org goes down, that room still exists. There's no central point of control.
08:21
And these rooms are shared across the home servers who participate in them, which is one of the main sort of decentralized aspects of matrix. And again, one of the things that I found that it's very cool. So you can see a room identifier usually has an exclamation point at the beginning, and then there's a room ID and then domain, and the domain is the home server in which the room was created on. So an example is you see this
08:47
non-human readable string here, exclamation point, that's on matrix.org or synapse dash tab matrix.org, which is the room where we discuss development on synapse. And I encourage people, if you're interested in this, to join that room and start asking questions.
09:05
People are generally pretty friendly there. This is sort of a general overview. It's not, I would say it's lacking in detail, but it's a good sort of view of sort of what happens when an event is sent.
09:27
We have a user, Alice at matrix.org. This user makes a HTTP request to a home server. So it makes, they send, you know, I want to make this request,
09:40
I have this room ID, and I want to send an m.room.message event into the home server, and the content is encapsulated in this JSON object. So sends it to the home server at matrix.org. There's some authentication and some checks that happen there, just to make sure that this person is allowed to send this message. You know, there's
10:06
they're a member of the room, you know, things like that. The home server then persists the event. So it takes, and we'll talk about this a little bit more later, but it takes the event and puts it into its room graph
10:20
and adds it to sort of the list or the list of events that have happened in the context of that room. And then it creates a another HTTP request to another home server that is a member of this room. So you can see we have, once again,
10:42
important information in the room ID. We have the event type, m.room.message. We have the content, once again, encapsulated in that JSON object. As I said, when an event is persisted in the room graph, one of the things that's added to it is a pointer to the preceding message in the room. So there's usually a
11:03
list of the most recent messages in a room, and that next event then references either one or several messages that immediately precede it. And that's where it gets its place in the room graph, which we'll talk a little bit about that more later. You'll see here, we also have a public key infrastructure signature from matrix.work, this home server. So that's just a
11:27
fancy way of saying it uses some fancy math to mathematically verify to this other home server that it is matrix.org and not some random malicious sender.
11:40
And you see we have this shared data that ends up being shared between both home servers. So we have the room ID. Each server is aware that the other server is a member of that room. So that's shared data. Each server is aware that Alice is a member of the room and is aware that Bob is a member of the room.
12:02
And so we have that shared data, and also the content is shared and it's persisted on both home servers. So then we, you know, it gets to the second home server. A bunch of checks happen here too,
12:20
which we'll talk a little bit more in detail later, but the home server, the receiving home server basically authenticates that A, the message, the event is valid, and B, that this person has the right to send this event. There's a couple different things that happen there.
12:40
And then if it's, you know, if that's all good, that event is persisted in the second home servers graph and then the event is then sent to onto Bob at, you know, whatever client they're using. So that's just sort of a basic, I would say for this level, I didn't go too deep into detail,
13:04
but like a little sort of overview of what exactly is happening. And so this is, you know, one of the things to sort of kind of keep in mind is that, you know, this is a fairly toy example, but if you can imagine there's hundreds or hundreds of thousands of requests coming to a home server
13:21
every minute and then home servers are then exchanging those between each other. So the volume can get very high and it's something to think about in terms of like, how do you manage, you know, managing something like this is different versus managing, you know, thousands and thousands of requests. And that's sort of the magic of the math behind the matrix protocol that it's able to handle that.
13:46
So there's many types of events, you know, there's m.room.message, there's m.room.name, there's m.call.answer, there's m.typing, there's m.receits, there's m.presence, m.tag, m.login, ssso. So all of these events basically do different things in the context
14:05
of a matrix application. So m.room.message sends a message into a room, m.room.name changes the name of the room, m.typing sends a typing receipt into a room that other people on other home servers can see.
14:22
The key verification request has to do with requesting encryption keys, the login is logging in with ssso, a single sign-on. So there's, you know, basically kind of, as we said, since all data exchanged over a matrix is an event, all sort of requests to do something or
14:44
change something or alter data in a home server comes from an event. The other thing you may notice if you are astute is that there, you know, this m.here. And that just means that this type of event was outlined in the matrix specification.
15:06
But there are types of events. You can create your own type of event and the matrix specification has information on how to do that. So that m designation just means this is an event that is actually specified in the specification, but it does not preclude other events. And only events that are specified in the spec are allowed to use that sort of m.
15:31
That m.beginner. Let's see, what else did I wanted to say? So let's talk about a room event.
15:43
So I just wanted to give an example of, you know, when we talk about fields, what are the fields? So we have the content, which is, you know, and it also has the type here. So that's helpful for, you know, if you're trying to implement it or if you're debugging
16:01
you can look at the spec and say, hey, what should this be? Is this the correct thing? Is it not? Is this the best way to implement this? Okay. So we have content, which is an object. This is required field. Lots of different things could go into the content. We have an event ID,
16:22
which is a globally unique event identifier. So when a request is accepted and an event is generated, there is a unique ID that is assigned to that event. So that means that no other events will have that ID. And that ID can be uniquely identified by that string.
16:42
We have an origin server timestamp. So that's a timestamp in milliseconds in the originating home server when this event was sent. So the first home server from which this event comes has the timestamp. And then we have a room ID, so which you've seen. It's the room associated with the event.
17:02
I'm sorry, that's my dog in the background making noise. And then we have the sender. And that refers to the person who, or the user who sent the request in. And then we have the type. So we've talked about this, the type of event.
17:24
So events have different types. Their form or their type sort of basically refers to their functionality, and there's lots of different ones. You can create your own, as I said before. Then we have this field unsigned data, and it contains optional extra information about the event. So the unsigned data is not required.
17:41
All of those other fields are required. If you send an event without those required fields, somebody very soon will reject it. It'll get lost in the ether. And in unsigned data you have age, which is the time a millisecond has elapsed since the event was sent.
18:01
You have this field redacted because, so events can be redacted so that the content can't be seen. Sometimes that happens, sometimes that what doesn't. And then you have a transaction ID. So that sort of gives you sort of like a little bit of an overview of sort of all events
18:21
have different fields. Once you start looking at a bunch of them, you'll see that some of the fields are very consistent. Obviously, all of them have an event ID. Most of them, I think, have room IDs, that sort of thing. But they do vary, but this is sort of a good way to sort of get a base sense of it.
18:41
And this is what an event actually looks like. So this is the JSON. And we have content, you know, we have, and if we toggle back and forth, you'll see, you know, all of the fields that we said are required are here. So we have the event ID, we have the origin server timestamp, we have the room ID,
19:03
we have the sender, we have the type, we have the unsigned field. So that's just sort of what an event looks like. It gives you a sense of sort of what's the, what is the sort of underlying fabric of a metrics ecosystem, and it is those
19:26
events flying around, all referring to, you know, different functions that they want to achieve and carrying little bits of data that relate to the function that they're trying to achieve. So this is an important thing to know. Don't ever trust an event as a client.
19:44
You can't require, you can't basically assume that the server is verifying and validating, that the server will validate for you. There is more on this at this at this
20:01
URL here that you can read more about it. There's actually a very great write-up on why events can't be trusted. So that just means don't rot, don't ingest data raw from an event if you're a client. Okay, and so then we'll talk a little bit more, so we've talked about sort of like the structure and
20:23
function of events, and then I want to talk a little bit more about how they are sort of put into the overall structure of a metrics application. So there are server-server events. So we've talked mostly about client-server, we talked a little bit about server-server. Server-server events are a little bit different. They're called persistent data units, or PDUs, or EDUs, which are ephemeral data units.
20:48
Persistent data units are exchanged between home servers in the same room. Things like message and state events and are stored in the home servers, and they reference the most recent past events. Ephemeral data units are exchanged,
21:02
but they're not stored. And so when we talk about stored, I spoke about this a little bit when I was going over the graph, but we're talking about them being persisted in the events, in the room's event graph. And so I want to talk a little bit more about graphs. So you've heard this, you probably see it if you read more in the specification, but
21:27
rooms are structured by they basically are put into a directed acyclic graph. So a directed acyclic graph, if you were not unfortunate enough to get a degree in computer science, you probably have not heard this,
21:44
but a directed acyclic graph is basically a graph whose nodes, so you know these could be considered the nodes, have edges which are directed. So they basically point in one direction, and it is a graph that doesn't have a cycle. So a cycle is, can I start at one node,
22:03
follow the edges, and then end back up at the same node? You can't do this. If there for some reason were a directed edge from this node here to this one, that would be a cyclical graph. So it's very important that there's not a cycle. There's a definite,
22:24
there's a definite structure to it. And one of the things that is sort of important about this is basically the ordering determines the state of the room.
22:41
So if you consider that there are events that can do things like add users or ban users or things like that, the overall state of the room very much depends on which event came before the event, you know how events sort of
23:01
came in time, which is a little bit difficult when you're considering that events are going to different home servers, home servers are exchanging events amongst each other. This is all sort of happening at once. So the way that Major sort of deals with this is to put events into a DAG and
23:21
when necessary will order the DAG very specifically. And there's an algorithm for resolving the state of the room. And this algorithm depends on the room versions. So there's been a number of different versions of sort of the room space and different rules are outlined in different versions of rooms.
23:43
So it's a little bit complicated, but it's actually when you start reading about it, it kind of makes a lot of sense. It's basically how do we, what set of rules do we use to determine strictly which event became, came before which event. And so you can see in this one this little sort of pseudo
24:01
room graph that I have here, we have the very first event, which is an m.room.create event. And then we have this m.room.message. We'll skip, you know, servers joining and things like that. So assume people have joined, assume it's okay that they're in the room. So they send a message into the room and they reference that most recent
24:23
event. And so then we have, you know, these two other messages. And both are sent into the room, but one is sent to one home server and one is sent to another home server and they're sent at basically sort of the same time. So they both reference this last message as the most recent event. And that's acceptable.
24:46
And this is why you can, this sort of situation where, okay, both of these events have reference, you know, they reference the past event. That's totally acceptable. How do we strictly determine which one comes before the other one? That's where the room state resolution sort of comes in.
25:02
I think I'm running a little bit out of time, but hopefully this will give you sort of, it gets a little bit, the room, you know, the room state resolution algorithms in particular are a little bit hairy to get into, but I think I'll save those.
25:21
Those are, they're interesting to look at and it's a cool thing, you know, if you want to talk about it, come in to Synapse Dev, start asking questions. I'd be happy to answer whatever questions that I can. Yeah, so hopefully that's pretty much it for me. Hopefully this was useful. Like I said, please feel free to ask questions and
25:45
yeah, thanks for coming to my talk. Cool tip.
26:02
Which is, can I send any kind of event in a matrix room? Do they need to exist in the spec? Can I experiment with my own events? And once I'm done developing something with those new events, what can I do so that everyone knows what to do with them?
26:21
Yeah, so you can send your own experimental events into a matrix room. They don't need to exist in the spec. And so you can play around with that and if you, you know, you can work to do some experiments and if you come up with something that you think is really useful and could benefit the
26:40
matrix community, you can make a request to have that event type added to the matrix core specification or the MSC. So there's a whole process for adding and, you know, you make a proposal and the spec core team takes a look at it, there's usually some back and forth and then, you know,
27:02
if all goes well your event type or any other actual change to the spec that you might want to suggest gets merged into the spec and your work lives on. Great. Yeah, flexibility is definitely one of the one of matrix's main points.
27:21
Document matrix, it's very well known currently for instant messaging, but can it be used for something else? Mm-hmm. Yeah, so I think it can be used, it can be used for video, it can be used for, you know, like sensors talking to each other. I heard that there is somebody who's working on building
27:40
MMO on top of matrix. Yeah, we actually have a line in talk about that right later today at 1.10 p.m. European time. Looks like it lists Che.