<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<link href="https://rust.code-maven.com/atom" rel="self" />
<title>Rust programming language</title>
<id>https://rust.code-maven.com</id>
<updated>2026-09-11T09:30:01</updated>

  <entry>
    <title>Miscompilation in Rust 1.97</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2026-09-11T09:30:01Z</updated>
    <pubDate>2026-09-11T09:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/miscompilation-in-rust-1-97" />
    <id>https://rust.code-maven.com/miscompilation-in-rust-1-97</id>
    <content type="html"><![CDATA[<h2 class="title is-4">Description</h2>
<p>I reported a miscompilation in Rust 1.97. In this presentation, I'll go through the juicy details of the bug, walk through the investigation as it <a href="https://rust-lang.zulipchat.com/#narrow/channel/131828-t-compiler/topic/Miscompilation.20in.201.2E97.2E0.20with.20new.20Option.3A.3ANone.20discrimi.2E.2E.2E/with/609853461">unfolded in the Zulip chat</a> with the Rust team, and share my takeaways and conclusions.
<a href="https://github.com/rust-lang/rust/issues/159035">segfault on Rust 1.97.0</a></p>
<h2 class="title is-4">Bio</h2>
<p><a href="https://www.linkedin.com/in/yoni-peleg/">Yoni Peleg</a> Software engineer with 10 years of experience (6 in Rust).</p>
<h2 class="title is-4">Length</h2>
<p>45 minutes</p>
<p><a class="button is-primary" href="https://luma.com/2qfai4a8">register</a></p>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

  <entry>
    <title>Facts: Curated Knowledge for Humans and Agents</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2026-09-08T09:30:01Z</updated>
    <pubDate>2026-09-08T09:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/facts-curated-knowledge-for-humans-and-agents" />
    <id>https://rust.code-maven.com/facts-curated-knowledge-for-humans-and-agents</id>
    <content type="html"><![CDATA[<h2 class="title is-4">Description</h2>
<p><a href="https://alnewkirk.com/projects/facts/">Facts</a> is like Git for knowledge. It's an open-source protocol, SDK, and CLI for managing shared knowledge between humans and AI agents. Instead of treating everything written or remembered as true, Facts lets participants propose, review, revise, accept, and reject claims, creating a trusted, versioned record of what a team actually knows.</p>
<h2 class="title is-4">Bio</h2>
<p><a href="https://www.linkedin.com/in/alnewkirk/">Al Newkirk</a> is a technology leader with more than 30 years in software engineering. He builds systems and frameworks for improving how people and AI agents work, make decisions, and share knowledge.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/eL5HQLdmht8" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
<h2 class="title is-4">Transcript</h2>
<p>1
00:00:01.970 --&gt; 00:00:15.599
Gabor Szabo: So, hello, and welcome to the Code Maven YouTube channel, and to this presentation by Al Newkirk. I'm really happy that you… I hope that you pronounced your name correctly, but anyway, I'm really happy that you… that… that we…</p>
<p>2
00:00:15.650 --&gt; 00:00:24.389
Gabor Szabo: I've seen each other the first time, I think, even though we have been… we had some conversations for, I don't know, 10, 20 years? I don't remember.</p>
<p>3
00:00:24.390 --&gt; 00:00:25.120
Al Newkirk: Yeah.</p>
<p>4
00:00:25.120 --&gt; 00:00:31.339
Gabor Szabo: My name is Gabor Szabo, I'm organizing these, these sessions, these online sessions.</p>
<p>5
00:00:31.340 --&gt; 00:00:50.790
Gabor Szabo: We have some guests who might ask some questions, so it might become a conversation. That's the perks for those people who actually joined the event, that they can ask questions, and we had a nice conversation before the video, and we might have another one after then, if time permits.</p>
<p>6
00:00:52.060 --&gt; 00:01:07.459
Gabor Szabo: And if you're watching the video, then please like it, and follow the channel, and below the video, you will find links to the links that all provides, and to the future events. And I think that's it for now, and</p>
<p>7
00:01:07.680 --&gt; 00:01:12.579
Gabor Szabo: The stage is yours, yeah? Okay. Go ahead.</p>
<p>8
00:01:12.580 --&gt; 00:01:13.310
Al Newkirk: Hello, everyone.</p>
<p>9
00:01:13.310 --&gt; 00:01:14.440
Gabor Szabo: Thanks so much for coming on.</p>
<p>10
00:01:14.810 --&gt; 00:01:31.389
Al Newkirk: No problem at all. Hello, everyone. My name is Al Newkirk, and, been in the tech industry for about 30 years, since the mid-90s. My, I guess my first language was Perl. I love Perl. I still write a ton of Perl. But,</p>
<p>11
00:01:31.600 --&gt; 00:01:40.870
Al Newkirk: I've also spent most of my career in software as a service, and web, technologies, and,</p>
<p>12
00:01:42.050 --&gt; 00:01:53.180
Al Newkirk: After, sort of, spending half my career as an engineer, I switched into leadership, And consulting, managing projects.</p>
<p>13
00:01:53.400 --&gt; 00:01:55.019
Al Newkirk: And that is…</p>
<p>14
00:01:56.290 --&gt; 00:02:02.950
Al Newkirk: a great, like, segue into this particular project. So, I'm now working on a project that I call</p>
<p>15
00:02:03.560 --&gt; 00:02:08.590
Al Newkirk: A, C, T, S, And,</p>
<p>16
00:02:08.699 --&gt; 00:02:11.430
Al Newkirk: And the plural, so the…</p>
<p>17
00:02:11.850 --&gt; 00:02:18.239
Al Newkirk: I want to have a more, like, a kind of a conversation about what led me to the…</p>
<p>18
00:02:18.970 --&gt; 00:02:22.640
Al Newkirk: project that I'm working on, and why I think it's important.</p>
<p>19
00:02:22.860 --&gt; 00:02:29.250
Al Newkirk: And then I'll sort of do, like, a demo of the current implementation of the project, and…</p>
<p>20
00:02:29.540 --&gt; 00:02:34.210
Al Newkirk: you know, happy to answer any questions, but I want to first start</p>
<p>21
00:02:34.350 --&gt; 00:02:41.970
Al Newkirk: talking about how I got here, and I'll be brief, and feel free to ask questions or interrupt.</p>
<p>22
00:02:42.350 --&gt; 00:02:44.279
Al Newkirk: If, if you need to.</p>
<p>23
00:02:44.550 --&gt; 00:02:59.570
Al Newkirk: So… I, I launched a software-as-a-service product called AllSign. It's, All Sign, A-L-L… DN dot F.</p>
<p>24
00:02:59.870 --&gt; 00:03:07.650
Al Newkirk: So, Balsign is a product that lets you Elaborate and negotiate on agreements.</p>
<p>25
00:03:07.890 --&gt; 00:03:17.020
Al Newkirk: I am a big fan of the peer review process, so think RFDs, OKRs, PRDs, that kind of thing.</p>
<p>26
00:03:17.240 --&gt; 00:03:23.019
Al Newkirk: ARDs, TDDs, so, you know, documents that,</p>
<p>27
00:03:23.370 --&gt; 00:03:34.640
Al Newkirk: multiple people collaborate on to capture decisions, and to deliberate, and to sign off on. I'm a big fan of the peer review process. I think that</p>
<p>28
00:03:34.800 --&gt; 00:03:41.630
Al Newkirk: I mean… That is… the future.</p>
<p>29
00:03:41.840 --&gt; 00:03:45.239
Al Newkirk: And, you can see a version of that</p>
<p>30
00:03:45.460 --&gt; 00:03:52.929
Al Newkirk: in how people use AI, a lot of people talk about spec-driven development, creating…</p>
<p>31
00:03:53.980 --&gt; 00:04:05.820
Al Newkirk: engineering specifications to give to the AI agent. So these are all forms of… During context and decisions, And…</p>
<p>32
00:04:06.570 --&gt; 00:04:13.440
Al Newkirk: And a project with multiple people, that's gonna be, like, collaborating on those decisions, so the whole peer review process.</p>
<p>33
00:04:13.560 --&gt; 00:04:19.600
Al Newkirk: So anyway, that is all signed, and I'll share my screen just quickly, so that you can…</p>
<p>34
00:04:19.709 --&gt; 00:04:22.679
Al Newkirk: I see all sign, I'm not gonna do a demo,</p>
<p>35
00:04:22.930 --&gt; 00:04:25.929
Al Newkirk: Of all sign, because this conversation is not about all sign.</p>
<p>36
00:04:26.460 --&gt; 00:04:31.149
Al Newkirk: But this is, AllSign, and this is what the UI looks like.</p>
<p>37
00:04:31.410 --&gt; 00:04:38.500
Al Newkirk: As you can maybe infer from the UI, you can create agreements that represent</p>
<p>38
00:04:39.060 --&gt; 00:04:53.730
Al Newkirk: decisions or projects. You can invite people to negotiate those decisions. These agreements can be legally binding or non-binding. So you can sign off on the agreements and</p>
<p>39
00:04:54.540 --&gt; 00:05:04.260
Al Newkirk: Digitally sign, digitally sign those agreements, and, and they are, like, They have the appropriate…</p>
<p>40
00:05:04.500 --&gt; 00:05:12.409
Al Newkirk: distribution, so they can be used as legal documents if you decided to use it that way.</p>
<p>41
00:05:12.530 --&gt; 00:05:23.340
Al Newkirk: But, I just want to kind of show you some of the screenshots, just to familiarize you with the ideas that led to the project that I want to talk to you about today.</p>
<p>42
00:05:24.180 --&gt; 00:05:31.899
Al Newkirk: So fundamentally, like, what we're talking about is negotiation. So you have multiple people, and…</p>
<p>43
00:05:32.200 --&gt; 00:05:37.800
Al Newkirk: In my experience, and in companies that I… where I've worked, where there's a healthy peer review process.</p>
<p>44
00:05:38.340 --&gt; 00:05:46.790
Al Newkirk: Typically, we're using something like Google Docs, and people are commenting on, like, maybe a migration project.</p>
<p>45
00:05:46.930 --&gt; 00:05:52.909
Al Newkirk: And… maybe there's, like, a table in the Google Doc where people</p>
<p>46
00:05:53.970 --&gt; 00:06:01.590
Al Newkirk: sign their name, or add pills or labels that represent their sign-off. And that's how you decide when</p>
<p>47
00:06:03.410 --&gt; 00:06:07.340
Al Newkirk: The idea has been sort of settled or signed off on.</p>
<p>48
00:06:07.460 --&gt; 00:06:13.400
Al Newkirk: But because it's Google Docs, and it's not designed for that, workflow.</p>
<p>49
00:06:13.590 --&gt; 00:06:23.880
Al Newkirk: there's no real way to lock an agreement, make it immutable. There's… like, comments commonly get suppressed, you know, if you comment on a particular part of an agreement.</p>
<p>50
00:06:24.220 --&gt; 00:06:29.489
Al Newkirk: And… and someone changes it, your comments get suppressed, etc.</p>
<p>51
00:06:29.600 --&gt; 00:06:37.349
Al Newkirk: So, so that's what… that's how people are using Google Docs and other… and other technologies to</p>
<p>52
00:06:37.660 --&gt; 00:06:41.960
Al Newkirk: facilitate this peer review process. I basically just built a SaaS product to do it.</p>
<p>53
00:06:42.460 --&gt; 00:06:49.410
Al Newkirk: Now, this product actually, even though, the…</p>
<p>54
00:06:50.220 --&gt; 00:06:54.079
Al Newkirk: the documentation for the API and the MCP server are…</p>
<p>55
00:06:54.210 --&gt; 00:07:13.040
Al Newkirk: you have to find them, but it does have an API, it does have an MCP server, you can have an AI agent negotiate agreements for you. I've done it, it's actually quite fun to have two AIs, like, negotiating agreements and disagreeing with each other. So you can do that with this product, but</p>
<p>56
00:07:13.310 --&gt; 00:07:18.170
Al Newkirk: But again, like, this conversation is not about… All sign.</p>
<p>57
00:07:18.570 --&gt; 00:07:24.790
Al Newkirk: what I… what I found when I was developing this, product is that, that…</p>
<p>58
00:07:26.390 --&gt; 00:07:32.960
Al Newkirk: I think that the future will involve Version-controlling knowledge.</p>
<p>59
00:07:33.090 --&gt; 00:07:36.190
Al Newkirk: And… capturing decisions.</p>
<p>60
00:07:36.350 --&gt; 00:07:42.809
Al Newkirk: What a lot of people who are, who are really leveraging AI at a high level.</p>
<p>61
00:07:42.970 --&gt; 00:07:49.549
Al Newkirk: are stumbling upon is the idea that the implementation…</p>
<p>62
00:07:50.400 --&gt; 00:08:03.920
Al Newkirk: matters secondary to the context, the spec, if you will. But it's not just the spec. It's all the context around the spec. It's the thinking, the decisions that went into</p>
<p>63
00:08:06.150 --&gt; 00:08:09.309
Al Newkirk: the thing that you want to produce. And…</p>
<p>64
00:08:09.650 --&gt; 00:08:16.579
Al Newkirk: And it got me to thinking, because Allsign already does this, but Allsign takes a very opinionated approach.</p>
<p>65
00:08:18.200 --&gt; 00:08:26.260
Al Newkirk: Fundamentally, in all sign, you have to create an agreement. Let me maybe go to a product page to show you…</p>
<p>66
00:08:27.970 --&gt; 00:08:31.119
Al Newkirk: other screenshots. So you create an agreement.</p>
<p>67
00:08:31.190 --&gt; 00:08:44.079
Al Newkirk: And an agreement can have sections, and sections can have terms, and sometimes terms can live outside of sections. And so, this is an example of an agreement in its structure.</p>
<p>68
00:08:44.150 --&gt; 00:08:52.700
Al Newkirk: Scope of ownership is a section, it has multiple terms, and those terms have content that can be negotiated.</p>
<p>69
00:08:52.910 --&gt; 00:08:59.590
Al Newkirk: And you can see that here. So this is a particular term</p>
<p>70
00:08:59.670 --&gt; 00:09:16.789
Al Newkirk: weekly migration status inside of a section, payment methods, profile ownership, and obviously you can see the controls where you can accept or reject. If you reject it, you can propose new terms, and you can do this turn-based negotiation until there is consensus.</p>
<p>71
00:09:16.840 --&gt; 00:09:21.850
Al Newkirk: Alright, so I'm spending way too much time here, but here's the point.</p>
<p>72
00:09:24.530 --&gt; 00:09:28.769
Al Newkirk: Every decision is not necessarily an entire agreement.</p>
<p>73
00:09:29.560 --&gt; 00:09:34.460
Al Newkirk: Sometimes, a decision or a bit of knowledge is…</p>
<p>74
00:09:35.130 --&gt; 00:09:41.300
Al Newkirk: just an idea. And so you shouldn't have to force knowledge into</p>
<p>75
00:09:41.790 --&gt; 00:09:48.699
Al Newkirk: The shape of an agreement with sections and terms to capture it and to deliberate on it.</p>
<p>76
00:09:48.930 --&gt; 00:09:55.270
Al Newkirk: So, that led me to… The question, what if the…</p>
<p>77
00:09:55.440 --&gt; 00:10:08.019
Al Newkirk: fundamentals were open core? What if, what if… what if the core concept of… Versioning knowledge and negotiating</p>
<p>78
00:10:08.470 --&gt; 00:10:12.790
Al Newkirk: knowledge were sort of, like, open source. What if there was a Git</p>
<p>79
00:10:13.000 --&gt; 00:10:19.559
Al Newkirk: For knowledge management. So, Git is a software version control system.</p>
<p>80
00:10:19.750 --&gt; 00:10:31.680
Al Newkirk: that is distributed, and I was thinking, what if there was something like that, but for knowledge management? So, that's what led me to what I call the back system. Now,</p>
<p>81
00:10:32.390 --&gt; 00:10:35.519
Al Newkirk: the way… because I decided from the very start.</p>
<p>82
00:10:35.830 --&gt; 00:10:37.910
Al Newkirk: That this should be open source.</p>
<p>83
00:10:39.230 --&gt; 00:10:42.720
Al Newkirk: I split it into the protocol.</p>
<p>84
00:10:42.890 --&gt; 00:10:48.880
Al Newkirk: the SDK and the CLI, so the protocol is, the…</p>
<p>85
00:10:48.980 --&gt; 00:10:56.250
Al Newkirk: reasoning. It is… it is exactly the thing that I talked about earlier when I talked about</p>
<p>86
00:10:58.450 --&gt; 00:11:11.929
Al Newkirk: capturing the thinking and the implementation is secondary. It matters secondarily to the core ideas. So, the core ideas of facts is captured in the protocol. That exists, it's on GitHub.</p>
<p>87
00:11:12.030 --&gt; 00:11:20.089
Al Newkirk: And… The FACT CLI, is a Rust implementation</p>
<p>88
00:11:20.710 --&gt; 00:11:26.829
Al Newkirk: of the fax protocol as an SDK and a CLI that uses that SDK.</p>
<p>89
00:11:27.280 --&gt; 00:11:28.130
Al Newkirk: So…</p>
<p>90
00:11:28.310 --&gt; 00:11:39.690
Al Newkirk: the reason why I went with the name, Fast is because, and I know a little bit about philosophy, but I'm in no way an expert. But in philosophy,</p>
<p>91
00:11:40.060 --&gt; 00:11:45.729
Al Newkirk: You know, a fact is a true proposition, and a proposition is…</p>
<p>92
00:11:46.470 --&gt; 00:11:50.930
Al Newkirk: Statement or a claim that can be evaluated as true or false.</p>
<p>93
00:11:51.060 --&gt; 00:11:55.360
Al Newkirk: And it felt like it just fit Well,</p>
<p>94
00:11:55.490 --&gt; 00:12:04.660
Al Newkirk: So, what we're talking about is… when we're talking about knowledge, you know, we want to…</p>
<p>95
00:12:04.940 --&gt; 00:12:10.940
Al Newkirk: differentiate between, like, a claim and a truth, so…</p>
<p>96
00:12:12.430 --&gt; 00:12:19.360
Al Newkirk: So, for example, like, if you are using, the fax system.</p>
<p>97
00:12:19.980 --&gt; 00:12:23.750
Al Newkirk: And you capture an idea.</p>
<p>98
00:12:23.860 --&gt; 00:12:32.560
Al Newkirk: That idea is not necessarily a fact, and it shouldn't be made available to others that are also participating in this system.</p>
<p>99
00:12:32.930 --&gt; 00:12:45.850
Al Newkirk: maybe even agents. It shouldn't be made available immediately to agents until it becomes a fact. But on the fact system, the way something becomes a fact is, and let me switch to, sort of, like, a,</p>
<p>100
00:12:46.940 --&gt; 00:12:53.120
Al Newkirk: I guess I'll start the demo, because I can illustrate these concepts with the CLI.</p>
<p>101
00:12:53.490 --&gt; 00:12:58.279
Al Newkirk: And… and drive the point home, so let me just sort of share one of my terminals.</p>
<p>102
00:13:00.400 --&gt; 00:13:07.659
Al Newkirk: And, I'm gonna, like, increase the text, and let me know if there's something else I need to do to make this</p>
<p>103
00:13:09.290 --&gt; 00:13:17.300
Al Newkirk: clear. So we have the FACT CLI, and, in a lot of ways, it's meant to</p>
<p>104
00:13:17.630 --&gt; 00:13:34.069
Al Newkirk: be analogous to the Git CLI and the Git version control system. So, in the same way that Git manages repositories, the FAPS system manages ledgers. Ledgers are,</p>
<p>105
00:13:34.790 --&gt; 00:13:45.839
Al Newkirk: repositories of knowledge. They are stores of knowledge. So for example, I'll create a ledger here. So the first thing I'm going to do is I'm gonna initialize this directory.</p>
<p>106
00:13:46.600 --&gt; 00:13:58.219
Al Newkirk: if I… if I didn't do this, then the CLI would use the system-wide Configuration for organizing ledgers.</p>
<p>107
00:13:58.620 --&gt; 00:14:04.540
Al Newkirk: But I want to localize the ledger to this particular directory, and so I'm gonna initialize…</p>
<p>108
00:14:05.110 --&gt; 00:14:07.869
Al Newkirk: The space, and it's gonna create a default ledger.</p>
<p>109
00:14:08.350 --&gt; 00:14:10.060
Al Newkirk: And, if I do…</p>
<p>110
00:14:10.400 --&gt; 00:14:17.609
Al Newkirk: act as, it'll show that I am currently the ledger admin, I can create additional actors.</p>
<p>111
00:14:17.900 --&gt; 00:14:25.300
Al Newkirk: and create an actor that is, Claude or Codex, or I could just have Claude or Codex.</p>
<p>112
00:14:29.090 --&gt; 00:14:34.059
Al Newkirk: That's me. So… and I'm gonna… I'm gonna demonstrate all of that.</p>
<p>113
00:14:34.530 --&gt; 00:14:35.490
Al Newkirk: So…</p>
<p>114
00:14:37.080 --&gt; 00:14:45.120
Al Newkirk: If I do a fact list, obviously it's an empty ledger, so there's no propositions here. And</p>
<p>115
00:14:45.540 --&gt; 00:14:52.780
Al Newkirk: Fact pending is where you would go to see propositions that you've created that have not yet become</p>
<p>116
00:14:53.900 --&gt; 00:15:01.579
Al Newkirk: facts. And if, it's not obvious, Other actors in the system</p>
<p>117
00:15:03.070 --&gt; 00:15:15.389
Al Newkirk: they don't see propositions that haven't become factor. And there's also a protocol for, like, deliberating on facts before there is a</p>
<p>118
00:15:15.560 --&gt; 00:15:19.390
Al Newkirk: To create a consensus. And once a consensus is reached.</p>
<p>119
00:15:20.100 --&gt; 00:15:37.839
Al Newkirk: that fact automatically gets ex… sorry, that proposition automatically gets accepted as a fact. But I'm just gonna, like, do a couple of commands to create… so FactPropose launches the editor. There's other ways to do this, but it launches the editor, and you can start describing a proposition. So you could say…</p>
<p>120
00:15:38.220 --&gt; 00:15:38.920
Al Newkirk: Hmm.</p>
<p>121
00:15:42.950 --&gt; 00:15:48.249
Al Newkirk: Guess I'll just use voice. Brush programming language… And… I'm fine.</p>
<p>122
00:15:49.600 --&gt; 00:15:50.490
Al Newkirk: Alright, let's…</p>
<p>123
00:15:52.540 --&gt; 00:16:00.449
Al Newkirk: And I'm just gonna create that. So that created a, position. If I do, like, fact the list.</p>
<p>124
00:16:01.280 --&gt; 00:16:06.840
Al Newkirk: you won't see the proposition, because it hasn't been accepted yet. If I go Fact Pending…</p>
<p>125
00:16:07.080 --&gt; 00:16:11.519
Al Newkirk: you'll see the proposition, and I can accept it, good.</p>
<p>126
00:16:12.390 --&gt; 00:16:14.630
Al Newkirk: I could accept it by ID,</p>
<p>127
00:16:18.510 --&gt; 00:16:22.579
Al Newkirk: And as you can see, it says accept a proposition, effective revision.</p>
<p>128
00:16:22.950 --&gt; 00:16:31.260
Al Newkirk: And, the current summary. So, it's keeping… it's versioning, like, your knowledge as you're creating these.</p>
<p>129
00:16:31.730 --&gt; 00:16:38.359
Al Newkirk: I could also, and if I do fact list, now that proposition that was created is available as a</p>
<p>130
00:16:38.930 --&gt; 00:16:42.490
Al Newkirk: as a fact to whoever's using the system.</p>
<p>131
00:16:42.780 --&gt; 00:16:46.860
Al Newkirk: So let me, show you what this looks like with,</p>
<p>132
00:16:47.450 --&gt; 00:16:50.439
Al Newkirk: and AI. And… and this is,</p>
<p>133
00:16:51.610 --&gt; 00:16:59.539
Al Newkirk: This is where you really get to see, like, the protocol and the… approach, like, unlocked. So…</p>
<p>134
00:16:59.990 --&gt; 00:17:07.959
Al Newkirk: To make it easy, let me show… Another screen.</p>
<p>135
00:17:17.030 --&gt; 00:17:22.460
Al Newkirk: I'm just sort of, pulling up the, gitHub.</p>
<p>136
00:17:22.869 --&gt; 00:17:25.350
Al Newkirk: Share my screen so you can see that as well.</p>
<p>137
00:17:26.589 --&gt; 00:17:39.990
Al Newkirk: Okay, so this is the GitHub organization. There's several projects in this organization. There's the CLI, the SDK, there's the, particular architecture that the,</p>
<p>138
00:17:40.740 --&gt; 00:17:47.830
Al Newkirk: that the Rust implementation uses. And then there's the spec. This is the actual protocol that,</p>
<p>139
00:17:49.020 --&gt; 00:17:55.200
Al Newkirk: Is the same no matter what implementation, it's, it's implemented with.</p>
<p>140
00:17:55.400 --&gt; 00:18:02.420
Al Newkirk: But skills is also, this is how you use the fact system with the,</p>
<p>141
00:18:03.040 --&gt; 00:18:07.700
Al Newkirk: with your agents. So, I'm gonna open this up, but I also wanna…</p>
<p>142
00:18:07.930 --&gt; 00:18:16.039
Al Newkirk: In order to use it, you need to have the CLI, you can go to releases, and you can download, like, the latest,</p>
<p>143
00:18:16.410 --&gt; 00:18:20.029
Al Newkirk: you can download the latest CLI for your</p>
<p>144
00:18:20.440 --&gt; 00:18:28.450
Al Newkirk: operating system. It's, you know, between 5 to, 8 megabytes, at, at present.</p>
<p>145
00:18:28.640 --&gt; 00:18:31.640
Al Newkirk: So, if you go to skills,</p>
<p>146
00:18:31.860 --&gt; 00:18:35.729
Al Newkirk: It's really easy to install this, I'm gonna show you now,</p>
<p>147
00:18:35.890 --&gt; 00:18:38.790
Al Newkirk: I'm gonna clone this here,</p>
<p>148
00:18:43.530 --&gt; 00:18:46.649
Al Newkirk: And there is an install,</p>
<p>149
00:18:50.110 --&gt; 00:18:56.700
Al Newkirk: Okay, sorry. I usually call it the CLI, I usually call it install, but it's called spills here.</p>
<p>150
00:18:56.830 --&gt; 00:19:01.399
Al Newkirk: So, if you… If you execute the skills, CLI,</p>
<p>151
00:19:02.220 --&gt; 00:19:10.459
Al Newkirk: you know, it's just a Bash CLI, and it has a help menu, and you can, depending on, like, the agent that you have, you can,</p>
<p>152
00:19:10.740 --&gt; 00:19:13.010
Al Newkirk: You can link, you know, Claude.</p>
<p>153
00:19:13.170 --&gt; 00:19:16.430
Al Newkirk: And it skipped it because it's already linked.</p>
<p>154
00:19:16.620 --&gt; 00:19:19.999
Al Newkirk: Because I'm already using it, you could, if you want to do it for codecs.</p>
<p>155
00:19:20.140 --&gt; 00:19:29.349
Al Newkirk: If you're using an agent harness that… supports the… dot agents,</p>
<p>156
00:19:30.030 --&gt; 00:19:35.680
Al Newkirk: directory, then you could just say, like, I think agents, yeah, so…</p>
<p>157
00:19:35.840 --&gt; 00:19:42.769
Al Newkirk: So anyway, that's… that's all you need to do to install it, and it… and now it's linked up, and it just works.</p>
<p>158
00:19:43.170 --&gt; 00:19:47.680
Al Newkirk: Just to… just to verify, like, if you… if you look at, like, let's say…</p>
<p>159
00:19:47.860 --&gt; 00:19:51.219
Al Newkirk: Codex skills, you can see that</p>
<p>160
00:19:51.960 --&gt; 00:19:54.700
Al Newkirk: it basically creates a SIM link to…</p>
<p>161
00:19:55.320 --&gt; 00:20:06.760
Al Newkirk: wherever you ran the install script from. I ran it from a different directory, so it's already sem-linked from a different directory, so I don't need to worry about that. So…</p>
<p>162
00:20:07.120 --&gt; 00:20:12.350
Al Newkirk: Let me, I'm gonna delete that, because it's already sort of configured now.</p>
<p>163
00:20:12.640 --&gt; 00:20:18.360
Al Newkirk: And I'm gonna start… Codex, and then I'll start Claude later.</p>
<p>164
00:20:18.620 --&gt; 00:20:21.700
Al Newkirk: Okay.</p>
<p>165
00:20:23.760 --&gt; 00:20:36.170
Al Newkirk: So… Now, it's… pre-configure, to… Check the FATS system.</p>
<p>166
00:20:37.390 --&gt; 00:20:42.489
Al Newkirk: for memories. So you could… you could do something… oh, I'm not… actually, I'm sorry, I'm not…</p>
<p>167
00:20:42.850 --&gt; 00:20:47.140
Al Newkirk: I thought I was sharing the screen, but I'm not. Let me just share the screen.</p>
<p>168
00:20:51.820 --&gt; 00:20:52.630
Al Newkirk: Hmm.</p>
<p>169
00:20:58.050 --&gt; 00:20:59.689
Al Newkirk: I find the terminal, really.</p>
<p>170
00:21:01.730 --&gt; 00:21:05.189
Al Newkirk: I think this is it. Let me know if,</p>
<p>171
00:21:13.010 --&gt; 00:21:18.059
Al Newkirk: I think I'm… I think I'm sharing it, but let me know if you're having trouble seeing it. But anyway,</p>
<p>172
00:21:20.880 --&gt; 00:21:21.980
Al Newkirk: I just saw the…</p>
<p>173
00:21:22.550 --&gt; 00:21:30.990
Al Newkirk: just all the comments here. So, okay. Alright, so I started, Codex, and now, because,</p>
<p>174
00:21:31.830 --&gt; 00:21:34.740
Al Newkirk: Because the skills are configured to…</p>
<p>175
00:21:34.740 --&gt; 00:21:35.570
Gabor Szabo: Fingers crossed.</p>
<p>176
00:21:36.450 --&gt; 00:21:37.490
Al Newkirk: Good, good.</p>
<p>177
00:21:37.870 --&gt; 00:21:45.300
Al Newkirk: Okay, yeah, because the, because the AI agent is configured to…</p>
<p>178
00:21:45.640 --&gt; 00:21:51.210
Al Newkirk: reference the fact system for memories, I can… I can say something like,</p>
<p>179
00:21:53.380 --&gt; 00:21:56.589
Al Newkirk: What do you recall about the Rust programming language?</p>
<p>180
00:21:58.550 --&gt; 00:22:04.219
Al Newkirk: And… It should check the FATS system, and</p>
<p>181
00:22:07.210 --&gt; 00:22:14.649
Al Newkirk: Okay, well, this did a more, like, generic, this did sort of a more generic…</p>
<p>182
00:22:16.610 --&gt; 00:22:20.199
Al Newkirk: recollection, but I could be more specific and say, okay.</p>
<p>183
00:22:20.580 --&gt; 00:22:26.900
Uri Bruck: from the facts you entered into the system, or from what the agent knows from somewhere else, from its own?</p>
<p>184
00:22:27.690 --&gt; 00:22:36.500
Al Newkirk: Yeah, this came from its own knowledge, what it knows from somewhere else, so I'm going to… I'm going to specifically nudge it to use the facts system, so I'm gonna say, using facts.</p>
<p>185
00:22:37.400 --&gt; 00:22:39.880
Al Newkirk: What do you recall about…</p>
<p>186
00:22:41.010 --&gt; 00:22:51.010
Al Newkirk: the, Rush programming learning. So now it's gonna… with that nudge, it should… typically, you don't need that nudge, but with that nudge, it'll… it'll…</p>
<p>187
00:22:51.590 --&gt; 00:23:05.299
Al Newkirk: As you can see, it's loading the different skills related to the fact system, and now it's going to search for Russ, and it's going to, it found the proposition, there's only one proposition, because the ledger is empty.</p>
<p>188
00:23:05.740 --&gt; 00:23:07.080
Al Newkirk: And,</p>
<p>189
00:23:07.640 --&gt; 00:23:17.490
Al Newkirk: And now it's going to, there's nothing there. So, using FAFTS, I found one accepted proposition, whatever. So, here's what I want to do. I want to say.</p>
<p>190
00:23:19.090 --&gt; 00:23:23.729
Al Newkirk: the generic… explanation you gave of Rust.</p>
<p>191
00:23:24.290 --&gt; 00:23:26.680
Al Newkirk: Distill that into a set of facts.</p>
<p>192
00:23:32.650 --&gt; 00:23:41.819
Al Newkirk: So, actually, let me, I got the language wrong, but, so… so this should…</p>
<p>193
00:23:41.980 --&gt; 00:23:46.829
Al Newkirk: break down what… What it initially replied with.</p>
<p>194
00:23:46.960 --&gt; 00:23:50.790
Al Newkirk: And break that into a set of atomized fat.</p>
<p>195
00:23:51.100 --&gt; 00:23:56.779
Al Newkirk: And commit them, to the, the fax memory system.</p>
<p>196
00:23:57.420 --&gt; 00:24:03.200
Al Newkirk: And then I'm gonna show you… So, distilled fats,</p>
<p>197
00:24:04.680 --&gt; 00:24:08.340
Al Newkirk: Were these committed to the default ledger?</p>
<p>198
00:24:12.530 --&gt; 00:24:19.430
Al Newkirk: And then I'm going to check the ledger by saying list… sorry, I'm gonna say, like, list…</p>
<p>199
00:24:21.610 --&gt; 00:24:26.990
Al Newkirk: ending… though there… so it was not. No, I only distilled them…</p>
<p>200
00:24:27.540 --&gt; 00:24:30.939
Al Newkirk: did not run FactorFlow or whatever, so, okay.</p>
<p>201
00:24:32.720 --&gt; 00:24:35.620
Al Newkirk: Commit these facts to the ledger.</p>
<p>202
00:24:40.400 --&gt; 00:24:49.289
Al Newkirk: Now, it's gonna commit… it's gonna… so, the distillation process is actually a really interesting process, because</p>
<p>203
00:24:49.480 --&gt; 00:24:57.029
Al Newkirk: It does what… It does a crude version of what is considered knowledge compression.</p>
<p>204
00:24:57.280 --&gt; 00:25:02.690
Al Newkirk: And this is something that I think only people in the memory space pay attention to, but it's…</p>
<p>205
00:25:02.810 --&gt; 00:25:09.300
Al Newkirk: How do you take, contents, and distill it down to just the fact.</p>
<p>206
00:25:09.870 --&gt; 00:25:11.180
Al Newkirk: such that…</p>
<p>207
00:25:12.660 --&gt; 00:25:20.799
Al Newkirk: A completely separate process could reconstruct the entire idea from those facts, so that where you haven't lost</p>
<p>208
00:25:20.930 --&gt; 00:25:31.290
Al Newkirk: any… any… any requisite information. But you don't, you know, maybe you don't need all of the filler content, so you're distilling</p>
<p>209
00:25:31.400 --&gt; 00:25:37.950
Al Newkirk: context down to, like, precise atoms of information that…</p>
<p>210
00:25:38.130 --&gt; 00:25:51.860
Al Newkirk: are necessary to reproduce, like, the big idea in another process. So, anyway, that's… that's… that's, distillation slash compression, and</p>
<p>211
00:25:52.120 --&gt; 00:25:58.840
Al Newkirk: That's what's happened here, so… I committed to the… to the ledger, so if I do pending.</p>
<p>212
00:25:58.950 --&gt; 00:26:05.440
Al Newkirk: I think it auto-accepted the facts, which I like, that's good. So if I do fact list…</p>
<p>213
00:26:07.460 --&gt; 00:26:09.780
Al Newkirk: Sorry, give me a second here.</p>
<p>214
00:26:11.180 --&gt; 00:26:13.810
Al Newkirk: I revised… oh, it revised the existing…</p>
<p>215
00:26:15.910 --&gt; 00:26:18.169
Al Newkirk: They revised the existing, fact.</p>
<p>216
00:26:18.460 --&gt; 00:26:23.139
Al Newkirk: Okay, so what I want to show you here is if I do fact show, this…</p>
<p>217
00:26:23.360 --&gt; 00:26:28.109
Al Newkirk: As you can see, right, there are two revisions. One was superseded.</p>
<p>218
00:26:28.510 --&gt; 00:26:40.420
Al Newkirk: And they both have different identifiers, so you could see… so you can see it's being version controlled. And if you say, like, facts open, and you give it the identifier, it'll… it'll launch your editor.</p>
<p>219
00:26:40.580 --&gt; 00:26:50.520
Al Newkirk: with the content. So it basically, like, took the content and distilled it down into… Into this,</p>
<p>220
00:26:52.270 --&gt; 00:26:53.369
Al Newkirk: It's a dispatch.</p>
<p>221
00:26:53.530 --&gt; 00:27:00.150
Al Newkirk: But, so here's the interesting thing that you can do. I'm gonna… I'm gonna open up another terminal, and I'm gonna launch, Claude.</p>
<p>222
00:27:01.620 --&gt; 00:27:06.090
Al Newkirk: And… plot is also configured, because the skills…</p>
<p>223
00:27:06.650 --&gt; 00:27:10.009
Al Newkirk: I installed the skills across Cloud and codec, so…</p>
<p>224
00:27:10.810 --&gt; 00:27:21.840
Al Newkirk: So now they're both sharing the same memory. They're both pointed at the same ledger, and they can recall the same information, and they can sort of, like, add information to the ledger. So I'm gonna say.</p>
<p>225
00:27:21.960 --&gt; 00:27:23.900
Al Newkirk: Okay.</p>
<p>226
00:27:28.330 --&gt; 00:27:32.109
Al Newkirk: What do you recall I've written about the Rust programming language?</p>
<p>227
00:27:35.750 --&gt; 00:27:41.670
Al Newkirk: Alright, so, checking memory,</p>
<p>228
00:27:42.710 --&gt; 00:27:45.699
Al Newkirk: It's saying nothing in my memory, okay. So…</p>
<p>229
00:27:46.020 --&gt; 00:27:58.270
Al Newkirk: This is what's called, like, a bootstrapping problem. So, every… most AI agent harnesses have their own memory system, and it defaults to that, and you have to…</p>
<p>230
00:27:58.390 --&gt; 00:28:07.630
Al Newkirk: push it out of that if you want to use another memory system. And there are different ways to do that. So, I'm gonna say, like, the same that I did before. I'm gonna say, like, using…</p>
<p>231
00:28:08.150 --&gt; 00:28:12.550
Al Newkirk: that's… What do you recall about the respiratory enemies?</p>
<p>232
00:28:13.260 --&gt; 00:28:16.590
Al Newkirk: So now, as you can see, it loaded the skill.</p>
<p>233
00:28:16.730 --&gt; 00:28:23.589
Al Newkirk: And now it's using the fax system, and it's gonna use the same ledger, and the same,</p>
<p>234
00:28:24.080 --&gt; 00:28:26.460
Al Newkirk: And all the same information is in the ledger.</p>
<p>235
00:28:26.790 --&gt; 00:28:27.550
Al Newkirk: I'm sorry.</p>
<p>236
00:28:28.300 --&gt; 00:28:29.220
Al Newkirk: Okay.</p>
<p>237
00:28:32.710 --&gt; 00:28:41.180
Al Newkirk: Okay. So, without reading, like, the particulars, as you can see, it found the proposition.</p>
<p>238
00:28:42.100 --&gt; 00:28:50.910
Al Newkirk: 202A0, and that is the… are accepted…</p>
<p>239
00:28:51.630 --&gt; 00:28:53.690
Al Newkirk: So, I'm gonna jump back over to…</p>
<p>240
00:28:53.960 --&gt; 00:28:56.509
Al Newkirk: Codex. I'm gonna say, like,</p>
<p>241
00:28:59.180 --&gt; 00:29:05.310
Al Newkirk: Create a new proposition… I'm sorry. Actually, because you can use the fact</p>
<p>242
00:29:05.450 --&gt; 00:29:19.019
Al Newkirk: language, but you don't have to. Like, you can… you can use regular common with parlance, talking about, like, memories, or committing things, and it should do the right thing. So, I want to say,</p>
<p>243
00:29:26.760 --&gt; 00:29:33.410
Al Newkirk: add to memory that the Rust programming language Typically results in…</p>
<p>244
00:29:33.750 --&gt; 00:29:40.000
Al Newkirk: Very large workspaces in terms of… Bites on disk.</p>
<p>245
00:29:42.210 --&gt; 00:29:45.510
Al Newkirk: I mean… But I also want to add,</p>
<p>246
00:29:48.720 --&gt; 00:29:50.799
Al Newkirk: Do not accept this stack.</p>
<p>247
00:29:51.830 --&gt; 00:29:55.420
Al Newkirk: Or, actually, you know, I don't want to lead it too much, so I'm just gonna…</p>
<p>248
00:29:56.260 --&gt; 00:30:02.119
Al Newkirk: typically in my… in my day-to-day work, where I'm working on different projects, and</p>
<p>249
00:30:02.460 --&gt; 00:30:07.209
Al Newkirk: Using different, ledgers and memories,</p>
<p>250
00:30:07.350 --&gt; 00:30:16.070
Al Newkirk: I will, like, tell it what I want it to auto-accept and what I want it to leave as pending. But as you can see, it is,</p>
<p>251
00:30:16.470 --&gt; 00:30:25.539
Al Newkirk: It first checked that there's nothing… there's no pre-existing knowledge that it needs to revise, and now it's gonna sort of, like, add a revision, so…</p>
<p>252
00:30:25.670 --&gt; 00:30:30.550
Al Newkirk: It said it created a review, the revision pending</p>
<p>253
00:30:30.690 --&gt; 00:30:36.230
Al Newkirk: So if I go back over here to the terminal, and I go, like, pending…</p>
<p>254
00:30:36.770 --&gt; 00:30:40.129
Al Newkirk: I guess it auto-accepted it. Oh, wait, sorry, give me a sec.</p>
<p>255
00:30:45.190 --&gt; 00:30:49.970
Al Newkirk: Okay, so it added it… it sort of added it to the existing</p>
<p>256
00:30:50.270 --&gt; 00:30:53.720
Al Newkirk: position, but that's actually not what I want, so I'm gonna correct it and say…</p>
<p>257
00:30:55.350 --&gt; 00:31:02.630
Al Newkirk: I didn't want you to revise… the existing fact. Instead.</p>
<p>258
00:31:03.610 --&gt; 00:31:07.880
Al Newkirk: Retract that and add that as a separate fact.</p>
<p>259
00:31:09.330 --&gt; 00:31:15.850
Al Newkirk: Okay. And then I'm gonna come over to… flawed, I'm gonna say, like,</p>
<p>260
00:31:19.820 --&gt; 00:31:21.730
Al Newkirk: Do I have any memories about…</p>
<p>261
00:31:26.090 --&gt; 00:31:29.200
Al Newkirk: Rust workspace, sizes.</p>
<p>262
00:31:31.930 --&gt; 00:31:34.969
Al Newkirk: So… It's still…</p>
<p>263
00:31:35.440 --&gt; 00:31:45.339
Al Newkirk: Codex is still making the changes to the ledger, so it created a new revision because the… all ledgers are append-only.</p>
<p>264
00:31:49.090 --&gt; 00:31:56.070
Al Newkirk: ledgers, literal ledgers, append-only data stores. So it… it sort of…</p>
<p>265
00:31:56.380 --&gt; 00:32:06.279
Al Newkirk: up… it sort of created a new revision, removing that bullet point, adding it to another revision, so… so again, if I go back list, now I see two, facts.</p>
<p>266
00:32:06.810 --&gt; 00:32:16.890
Al Newkirk: And, there are no, pending, pending propositions. So, if I go over to, Flawed, I can say, like,</p>
<p>267
00:32:18.360 --&gt; 00:32:28.199
Al Newkirk: Do I have any memories about Rust workspace sizes? It's now going to… well, it's gonna find it because it didn't create it as pending.</p>
<p>268
00:32:29.310 --&gt; 00:32:39.899
Al Newkirk: So, I think I have another ledger that I sort of play around with that has a bunch of propositions that I'll sort of switch to. But as you can see, it found the other workspace, and</p>
<p>269
00:32:40.580 --&gt; 00:32:54.329
Al Newkirk: Now, the way that I want you to think about this is, imagine that you had different ledgers for different purposes. Maybe you had a ledger about a project, maybe you had a ledger about your, like, engineering practices. So, you don't have to tell the agent</p>
<p>270
00:32:55.270 --&gt; 00:33:01.649
Al Newkirk: every time you work on a new API, that you prefer versioning in the headers and not in the path.</p>
<p>271
00:33:01.790 --&gt; 00:33:07.870
Al Newkirk: Or that you prefer a maximum or path…</p>
<p>272
00:33:08.370 --&gt; 00:33:14.539
Al Newkirk: when constructing… when designing URLs. Like, you can have those preferences as</p>
<p>273
00:33:14.850 --&gt; 00:33:20.379
Al Newkirk: And the agent can just sort of find them, and you can share them across AI agent harnesses.</p>
<p>274
00:33:21.270 --&gt; 00:33:29.989
Al Newkirk: So, let's see, I'm gonna open up another terminal, and I'm just gonna see… I gotta get out of this directory so that I can… so I'm back in the global space.</p>
<p>275
00:33:30.700 --&gt; 00:33:33.170
Al Newkirk: And I'm gonna look at the ledgers that I have.</p>
<p>276
00:33:33.920 --&gt; 00:33:35.420
Al Newkirk: on this machine.</p>
<p>277
00:33:35.620 --&gt; 00:33:45.629
Al Newkirk: D here, what's in the default?</p>
<p>278
00:33:45.800 --&gt; 00:33:50.960
Al Newkirk: So I'm gonna go to Fact Use, so this is how you switch, ledgers, so Fact Use Default.</p>
<p>279
00:33:51.160 --&gt; 00:34:02.799
Al Newkirk: I'm going to look at what's in this ledger. It's a random notes… maybe… And I'm gonna switch to…</p>
<p>280
00:34:04.190 --&gt; 00:34:05.209
Al Newkirk: I said, no.</p>
<p>281
00:34:05.800 --&gt; 00:34:07.280
Al Newkirk: And… okay.</p>
<p>282
00:34:07.800 --&gt; 00:34:11.509
Al Newkirk: Yeah, this is, I think, is like a throwaway,</p>
<p>283
00:34:12.130 --&gt; 00:34:16.920
Al Newkirk: Not throwaway, but this is sort of like a, random…</p>
<p>284
00:34:18.870 --&gt; 00:34:25.270
Al Newkirk: ledger that I, that I'll use sometimes. Now, this actually highlights an interesting</p>
<p>285
00:34:25.790 --&gt; 00:34:42.490
Al Newkirk: parallel with Git. It is a distributed version control system, so it has… it also supports the notion of remotes, and you can push and pull to ledgers on other machines. But this is called default remote because</p>
<p>286
00:34:42.550 --&gt; 00:34:47.580
Al Newkirk: the origin ledger is actually on an iMac that,</p>
<p>287
00:34:47.880 --&gt; 00:34:51.670
Al Newkirk: that I… I connect to, and I can… Think?</p>
<p>288
00:34:51.889 --&gt; 00:34:55.059
Al Newkirk: Let me just see if the remote is wired up.</p>
<p>289
00:34:55.440 --&gt; 00:34:59.579
Al Newkirk: ready, because I think I might be able to push and pull from it, so…</p>
<p>290
00:35:00.210 --&gt; 00:35:03.779
Al Newkirk: So the remote is here… let me try to pull…</p>
<p>291
00:35:04.990 --&gt; 00:35:11.429
Al Newkirk: Okay, well, I'll… you know, but needless to say that you can push and pull to remotes, and</p>
<p>292
00:35:11.860 --&gt; 00:35:16.330
Al Newkirk: That way, the knowledge is not only versioned, but distributed.</p>
<p>293
00:35:16.450 --&gt; 00:35:26.380
Al Newkirk: Okay, so now that I'm… So…</p>
<p>294
00:35:27.240 --&gt; 00:35:33.090
Al Newkirk: So when you do, for example, Sorry.</p>
<p>295
00:35:34.840 --&gt; 00:35:38.299
Al Newkirk: In the normative, like, use of this.</p>
<p>296
00:35:39.080 --&gt; 00:35:44.250
Al Newkirk: It uses a globe, your ledgers are stored in a, like.</p>
<p>297
00:35:44.940 --&gt; 00:35:50.400
Al Newkirk: Neutral place where the current logged-in user And…</p>
<p>298
00:35:51.950 --&gt; 00:35:54.799
Al Newkirk: That's the ledgers from any directory.</p>
<p>299
00:35:55.160 --&gt; 00:35:56.560
Al Newkirk: on the system.</p>
<p>300
00:35:56.920 --&gt; 00:36:00.650
Al Newkirk: So, for example, like, if I'm… if I'm here.</p>
<p>301
00:36:01.480 --&gt; 00:36:04.969
Al Newkirk: I do, like, fact ledgers, ledger lists.</p>
<p>302
00:36:05.180 --&gt; 00:36:11.500
Al Newkirk: I can see the ledgers. If I move into, like, downloads, and I do the same command, I can see the same ledgers.</p>
<p>303
00:36:11.670 --&gt; 00:36:16.399
Al Newkirk: But if I go back to,</p>
<p>304
00:36:16.960 --&gt; 00:36:21.730
Al Newkirk: I'm just gonna create a temporary directory. If I, if I say fact here.</p>
<p>305
00:36:22.010 --&gt; 00:36:32.070
Al Newkirk: it basically creates a localized… same if you did, like, Git init. It creates a localized, directory-specific, notice.</p>
<p>306
00:36:33.240 --&gt; 00:36:37.469
Al Newkirk: workspace for FAST. So if I did, like, FAST ledger list.</p>
<p>307
00:36:38.370 --&gt; 00:36:46.280
Al Newkirk: this thing is empty, so there's nothing here. It's gonna say there's no ledgers, and if I do, like, fact init, it's gonna create the default ledger.</p>
<p>308
00:36:47.470 --&gt; 00:36:53.550
Al Newkirk: And so, you'll just see the one ledger, and it's all, like, very unique to this. And if you inspect the .factor</p>
<p>309
00:36:56.230 --&gt; 00:37:09.830
Al Newkirk: directory, you'll see, like, there's no remotes, but here's the catalog. The C file is your private key, because you… because every event that you cause is signed cryptographically, and</p>
<p>310
00:37:10.010 --&gt; 00:37:12.620
Al Newkirk: That's…</p>
<p>311
00:37:12.820 --&gt; 00:37:27.209
Al Newkirk: how the, end-only ledger is validated, etc, etc. All this stuff is, oh, and the ledgers are in the Rust implementation, SQLite databases.</p>
<p>312
00:37:28.490 --&gt; 00:37:34.239
Al Newkirk: that's the private key. Okay, so…</p>
<p>313
00:37:35.040 --&gt; 00:37:42.249
Al Newkirk: What I want to do, for demonstration purposes is I want to get out of this…</p>
<p>314
00:37:43.080 --&gt; 00:37:47.819
Al Newkirk: directory, I want to use the global, like, stores, I want to switch to…</p>
<p>315
00:37:52.140 --&gt; 00:37:55.829
Al Newkirk: I think, personal is interesting.</p>
<p>316
00:38:01.830 --&gt; 00:38:02.520
Al Newkirk: Huh.</p>
<p>317
00:38:02.680 --&gt; 00:38:05.089
Al Newkirk: Okay, I'll use,</p>
<p>318
00:38:12.890 --&gt; 00:38:20.770
Al Newkirk: Just give me one second. I'm just gonna use memory research. I mean, it's… It's actually a,</p>
<p>319
00:38:22.950 --&gt; 00:38:28.560
Al Newkirk: It's actually a ledger that I do use. It's a real ledger that I use, and…</p>
<p>320
00:38:28.790 --&gt; 00:38:33.389
Al Newkirk: Every time… okay, so this actually might be a good example of…</p>
<p>321
00:38:33.560 --&gt; 00:38:36.519
Al Newkirk: why and how you might use a ledger, so…</p>
<p>322
00:38:36.700 --&gt; 00:38:46.689
Al Newkirk: The Memory Research Ledger is all of the knowledge and research and information that I find important in learning about</p>
<p>323
00:38:49.550 --&gt; 00:38:52.479
Al Newkirk: memory management is being done with AI.</p>
<p>324
00:38:54.290 --&gt; 00:38:56.890
Al Newkirk: And… you know.</p>
<p>325
00:38:57.250 --&gt; 00:39:14.430
Al Newkirk: it's… having it as its own ledger is a way of sort of segmenting that knowledge. I don't want to have to fish through, like, you know, my professional development ideas and, you know, my Pearl ideas and memory management ideas. I want, like.</p>
<p>326
00:39:14.480 --&gt; 00:39:20.790
Al Newkirk: I want a repository of knowledge specific to, like, memory research. So, if I were to, like,</p>
<p>327
00:39:21.550 --&gt; 00:39:25.829
Al Newkirk: I don't know, like, I like Flawed, so let's… if I were to launch Vlad…</p>
<p>328
00:39:26.370 --&gt; 00:39:44.759
Al Newkirk: Now, the difference between, for example, this, this instance of Claude is… this instance of Claude is running an attempt directory where the fax… where, like, a directory-specific version of FACTS was created with, like, fact here.</p>
<p>329
00:39:45.050 --&gt; 00:39:53.499
Al Newkirk: So… So this is only gonna see, like, the ledgers that were created in this directory.</p>
<p>330
00:39:55.110 --&gt; 00:39:58.209
Al Newkirk: But I launched this other process.</p>
<p>331
00:40:00.430 --&gt; 00:40:06.200
Al Newkirk: like, from the home directory. So this has access to all of the…</p>
<p>332
00:40:06.550 --&gt; 00:40:11.250
Al Newkirk: a global ledger. So if I were to do, like, that as…</p>
<p>333
00:40:11.710 --&gt; 00:40:14.270
Al Newkirk: It's gonna… you know, it's…</p>
<p>334
00:40:14.580 --&gt; 00:40:27.050
Al Newkirk: I'm currently… I'm… I am Al Newkirk on the Memory Research Ledger. So, so now, this… so Claude is using the memory research ledger, and if I were to say something like,</p>
<p>335
00:40:32.570 --&gt; 00:40:42.760
Al Newkirk: Provide a simple bullet list of the… companies… that provide… memory for agents.</p>
<p>336
00:40:49.160 --&gt; 00:40:51.920
Al Newkirk: Okay, so I'm gonna say recall and provide.</p>
<p>337
00:40:52.210 --&gt; 00:40:54.010
Al Newkirk: Recall is kind of like a…</p>
<p>338
00:40:54.310 --&gt; 00:41:07.160
Al Newkirk: a trigger word in the memory space, it usually indicates that you're trying to look something up from memory. This should use the fax system, but again, that bootstrapping problem might rear its head.</p>
<p>339
00:41:07.930 --&gt; 00:41:12.930
Al Newkirk: Where it might look to its own memory first. Okay, so look, it used, fact…</p>
<p>340
00:41:13.540 --&gt; 00:41:25.439
Al Newkirk: So it's… it's using the fact system. I didn't… I didn't have to nudge it in this session to do so. So it's gonna look through the… all of the memories in the memory research ledger.</p>
<p>341
00:41:25.560 --&gt; 00:41:33.250
Al Newkirk: And it's gonna, like, it's gonna create a mapping and pull out a list of companies that are…</p>
<p>342
00:41:33.520 --&gt; 00:41:35.769
Al Newkirk: memory management for AI agents.</p>
<p>343
00:41:39.710 --&gt; 00:41:44.879
Al Newkirk: Any questions or thoughts about any of this before I, like, continue? Let's see, I just wanna…</p>
<p>344
00:41:45.720 --&gt; 00:41:51.480
Al Newkirk: Okay, so here's what it came back with, and this is all from the…</p>
<p>345
00:41:53.060 --&gt; 00:42:01.509
Al Newkirk: from the ledger. Like, if I were to… so, Memzero is one, ZEP, Leta, SuperMemory, Cogni is one,</p>
<p>346
00:42:01.880 --&gt; 00:42:15.879
Al Newkirk: open source projects without a company behind them, and the same ledger is useful, beads, membrane, Memento. So these are all, from this, ledger. So if I were to… if I were to open up a,</p>
<p>347
00:42:17.040 --&gt; 00:42:27.829
Al Newkirk: open up a terminal, go to the home directory. You don't have to be in the home directory, but I do just do fax as. Okay, I'm still on the memory research ledger. If I were to do, like, fact search.</p>
<p>348
00:42:28.070 --&gt; 00:42:31.400
Al Newkirk: And I would've do, like.</p>
<p>349
00:42:32.570 --&gt; 00:42:42.480
Al Newkirk: MIM0, so these are all the facts that reference MIM0. It is using vector searching, so… Hmm.</p>
<p>350
00:42:43.150 --&gt; 00:42:48.350
Al Newkirk: And so that's how it's ranking and returning search results.</p>
<p>351
00:42:50.260 --&gt; 00:42:56.579
Al Newkirk: There's also a command called FactFind, and it allows you… it just does kind of, like, it allows…</p>
<p>352
00:42:56.940 --&gt; 00:43:04.149
Al Newkirk: like, piping in a way, where you can do something with the search results. So, for example, say, like, fact find and zero.</p>
<p>353
00:43:04.910 --&gt; 00:43:08.390
Al Newkirk: And then I can, like, pick Number one.</p>
<p>354
00:43:08.900 --&gt; 00:43:18.199
Al Newkirk: And and then I can give it… tell it… tell it where I want to pipe that proposition, so I can say, like, with open. And so it's going to open that first one.</p>
<p>355
00:43:18.590 --&gt; 00:43:24.209
Al Newkirk: And this is what's actually in the content. It's marked down. If I, if I did, like, pick two.</p>
<p>356
00:43:24.340 --&gt; 00:43:28.509
Al Newkirk: It's gonna open up, like, this other thing, but they're, like, big three.</p>
<p>357
00:43:29.570 --&gt; 00:43:33.069
Al Newkirk: It's gonna open up the third result in the editor.</p>
<p>358
00:43:33.550 --&gt; 00:43:42.579
Al Newkirk: Now you can't, because… Because you're forced to go through… A revision and deliberation process.</p>
<p>359
00:43:42.890 --&gt; 00:43:47.990
Al Newkirk: To register a revision, like, changing the text here won't…</p>
<p>360
00:43:48.880 --&gt; 00:43:55.469
Al Newkirk: will not be persistent. So, it's opening the proposition in an editor for viewing purposes only.</p>
<p>361
00:43:55.600 --&gt; 00:44:10.749
Al Newkirk: But I could… you could pipe it to, like, revise. I don't want to, but I'm… you could pipe it to revise as a command, and you would be able to, like, create a revision from it, because revise is one of the commands.</p>
<p>362
00:44:12.520 --&gt; 00:44:26.029
Al Newkirk: So, let's see, one other thing. I want to go back here, and I want to say, like, and this is… this is actually, with this particular ledger, this is stuff that I… I do when I'm not presenting, so I might want to say…</p>
<p>363
00:44:26.290 --&gt; 00:44:30.350
Al Newkirk: I mean… This is a real thing, actually.</p>
<p>364
00:44:33.910 --&gt; 00:44:40.940
Al Newkirk: There were two thefts that contained… blood, artifact.</p>
<p>365
00:44:42.800 --&gt; 00:44:43.820
Al Newkirk: about…</p>
<p>366
00:44:48.250 --&gt; 00:44:51.420
Al Newkirk: memory, product, analysis.</p>
<p>367
00:44:52.080 --&gt; 00:44:54.750
Al Newkirk: cross… providers.</p>
<p>368
00:44:58.060 --&gt; 00:44:59.879
Al Newkirk: Surface those facts.</p>
<p>369
00:45:02.870 --&gt; 00:45:03.650
Al Newkirk: Okay.</p>
<p>370
00:45:03.950 --&gt; 00:45:11.110
Al Newkirk: And so… the voice recognition is not working like it should, so there are two facts that contain</p>
<p>371
00:45:11.480 --&gt; 00:45:13.030
Al Newkirk: flawed.</p>
<p>372
00:45:17.560 --&gt; 00:45:19.200
Al Newkirk: Clawed artifact.</p>
<p>373
00:45:19.670 --&gt; 00:45:23.269
Al Newkirk: About memory product analyses across providers,</p>
<p>374
00:45:23.640 --&gt; 00:45:29.120
Al Newkirk: So this is actually a real thing, and this is an example of, oh, I forgot where…</p>
<p>375
00:45:29.350 --&gt; 00:45:40.459
Al Newkirk: So, if you were using Markdown files, you might have to grep across a bunch of directories, like, and try to remember, like, what specific kinds of text were in</p>
<p>376
00:45:40.950 --&gt; 00:45:43.210
Al Newkirk: the markdown files,</p>
<p>377
00:45:44.420 --&gt; 00:46:01.920
Al Newkirk: But instead of that, you could just, like, put your… your knowledge into ledgers, and you could lean on the vector searching to surface. And you can use AI to automate the vector searching to recall those. So this is actually correct. So there were two artifacts that…</p>
<p>378
00:46:03.580 --&gt; 00:46:13.470
Al Newkirk: what, what, what Claude calls artifacts, I think, I think are, like, HTML pages, That represent, like, some…</p>
<p>379
00:46:13.840 --&gt; 00:46:20.479
Al Newkirk: research or whatever. So these are actually the URLs that I was looking for, and in fact,</p>
<p>380
00:46:20.710 --&gt; 00:46:26.529
Al Newkirk: Let me just, like, share my entire screen, that way you can see me go from the links to…</p>
<p>381
00:46:27.710 --&gt; 00:46:32.919
Al Newkirk: Okay, so this one was, Agent Memory Feature Mat. I was doing some research about</p>
<p>382
00:46:33.280 --&gt; 00:46:37.850
Al Newkirk: What are the things that I'm providing in this open source,</p>
<p>383
00:46:40.690 --&gt; 00:46:47.730
Al Newkirk: software system, and what are some of the features that are provided from these other players that have SaaS products? And so…</p>
<p>384
00:46:49.440 --&gt; 00:46:55.769
Al Newkirk: And so, this is, and so, this was something that Claude did, and…</p>
<p>385
00:46:57.400 --&gt; 00:47:05.670
Al Newkirk: It lists out all the different players, and at the bottom, it's like a feature matrix of the things that it does, and</p>
<p>386
00:47:05.960 --&gt; 00:47:11.010
Al Newkirk: And fax actually does some things that these other</p>
<p>387
00:47:11.250 --&gt; 00:47:17.430
Al Newkirk: solutions don't do. One of the… one of the big things that FACT is based on</p>
<p>388
00:47:17.640 --&gt; 00:47:24.680
Al Newkirk: That these other systems don't really do, they don't actually do, is differentiate between</p>
<p>389
00:47:24.860 --&gt; 00:47:35.819
Al Newkirk: oppositions and facts. They don't differentiate between Like, accepted, consensus-based knowledge, and…</p>
<p>390
00:47:36.560 --&gt; 00:47:50.049
Al Newkirk: something being proposed to become accepted knowledge. So, you know, you might be thinking, if I just had Markdown files in a Git repository, and I had all my agents share that.</p>
<p>391
00:47:50.640 --&gt; 00:47:57.940
Al Newkirk: why wouldn't that suffice? Well, there's a couple of flaws with that strategy, but…</p>
<p>392
00:47:58.720 --&gt; 00:48:04.019
Al Newkirk: A big one is that, you know, just because an agent writes something.</p>
<p>393
00:48:04.600 --&gt; 00:48:23.600
Al Newkirk: or a person writes something, doesn't mean that every other agent using that concept should automatically pick it up and accept it as truth. I mean, this is how you allow, like, poison pill… poison messages to, like… you could… this is an attack vector, it's… you know, you don't want,</p>
<p>394
00:48:23.780 --&gt; 00:48:36.920
Al Newkirk: And even when you have, like, agents writing back to their own knowledge systems, you want to have a process where there's checks and balances, or it just gets accepted and propagated across a fleet of AI agents.</p>
<p>395
00:48:37.010 --&gt; 00:48:44.959
Al Newkirk: And so, most of these systems haven't solved that yet, but that's one of the fundamental underpinnings of the fact system.</p>
<p>396
00:48:45.250 --&gt; 00:48:51.309
Al Newkirk: is the differentiate… differentiating between, propositions and knowledge. Anyway,</p>
<p>397
00:48:52.710 --&gt; 00:48:56.530
Al Newkirk: If I wanted to, like, open this, I could…</p>
<p>398
00:48:56.650 --&gt; 00:49:03.280
Al Newkirk: Let me do it in another terminal, but I'll just say, like, open that identifier…</p>
<p>399
00:49:04.230 --&gt; 00:49:12.030
Al Newkirk: And, this is where it found and pulled the URL when I asked the AI agent to find me the sub.</p>
<p>400
00:49:12.580 --&gt; 00:49:20.050
Al Newkirk: It had an artifact with, like, analyses, so it found, like, analyses, it found, like, term artifact.</p>
<p>401
00:49:20.270 --&gt; 00:49:22.680
Al Newkirk: And that's how I was able to recall.</p>
<p>402
00:49:26.310 --&gt; 00:49:30.780
Al Newkirk: That's how I was able to recall. So I'm gonna, like,</p>
<p>403
00:49:30.970 --&gt; 00:49:33.490
Al Newkirk: I'm gonna pause there and sort of, like.</p>
<p>404
00:49:35.360 --&gt; 00:49:38.580
Al Newkirk: Open it up for questions, if any of you have any</p>
<p>405
00:49:39.670 --&gt; 00:49:49.809
Al Newkirk: demos you want me to try to perform, I'm happy to do that. If you have questions about… or feedback about the project so far, I'd love to hear what you think.</p>
<p>406
00:49:53.270 --&gt; 00:50:01.839
Gabor Szabo: Well, first of all, thank you very much for this presentation. It was very interesting. It seems that the audience is very silent now, today.</p>
<p>407
00:50:02.280 --&gt; 00:50:05.549
Gabor Szabo: And if you have any questions, that you forgot to…</p>
<p>408
00:50:05.550 --&gt; 00:50:11.150
Uri Bruck: Okay. I'm not really familiar with systems like this, but when you chat with… when you…</p>
<p>409
00:50:11.210 --&gt; 00:50:26.280
Uri Bruck: share memory with documents with the AI. The demos I've seen so far were for Notebook LM, where you stick a lot… upload a bunch of documents, and then you have a chat with… you can ask about the AI about what's in the documents.</p>
<p>410
00:50:26.280 --&gt; 00:50:31.689
Uri Bruck: So, how is this similar? How, can you give me sort of, like,</p>
<p>411
00:50:33.060 --&gt; 00:50:36.389
Al Newkirk: Yeah, so, I think that, I don't…</p>
<p>412
00:50:36.540 --&gt; 00:50:43.270
Al Newkirk: I am familiar with, people using Notebook LM, to…</p>
<p>413
00:50:43.820 --&gt; 00:50:47.730
Al Newkirk: To be able to… so, okay.</p>
<p>414
00:50:48.610 --&gt; 00:50:52.049
Al Newkirk: I don't think that… Most people are…</p>
<p>415
00:50:52.300 --&gt; 00:50:58.210
Al Newkirk: connecting their production AI agents to Notebook LM, like…</p>
<p>416
00:50:58.630 --&gt; 00:51:07.030
Al Newkirk: for business purposes, I think that individuals might use, like, Claude locally and connect it to Notebook LM.</p>
<p>417
00:51:07.860 --&gt; 00:51:14.309
Al Newkirk: But the… let me explain, like, what Notebook LM… It's designed to do.</p>
<p>418
00:51:14.550 --&gt; 00:51:25.040
Al Newkirk: And it is useful. It is useful. So, Notebook LM is designed to… silo, the…</p>
<p>419
00:51:27.450 --&gt; 00:51:34.780
Al Newkirk: the inference. So, instead of… so, for example, in the… earlier in this demo, when I asked about Rust.</p>
<p>420
00:51:35.090 --&gt; 00:51:43.170
Al Newkirk: It… and it pulled from… like, it's trained knowledge. Notebook LM is specifically designed to not do that.</p>
<p>421
00:51:43.420 --&gt; 00:51:51.569
Al Newkirk: So it's designed to only reference the information that you give it, so to not pull from</p>
<p>422
00:51:51.800 --&gt; 00:52:05.380
Al Newkirk: it's training data. And so this is good. So this is good because you know that the answers that it's giving you are specific to the source material that you gave it, and that it's not, sort of.</p>
<p>423
00:52:05.540 --&gt; 00:52:16.469
Al Newkirk: hallucinating or, like, pulling from other sources that are not in the set that you gave it. That's the main… that's why Notebook LM, like.</p>
<p>424
00:52:16.630 --&gt; 00:52:24.519
Al Newkirk: exists. And… and so, you would give it a bunch of, information, and…</p>
<p>425
00:52:24.650 --&gt; 00:52:27.290
Al Newkirk: Including, like, PDFs and spreadsheets and…</p>
<p>426
00:52:27.470 --&gt; 00:52:32.589
Al Newkirk: And it will be able to, like, reference that, reference that in…</p>
<p>427
00:52:34.390 --&gt; 00:52:39.770
Al Newkirk: in, like, whatever questions you ask it. This system cannot do that. This system…</p>
<p>428
00:52:40.160 --&gt; 00:52:45.170
Al Newkirk: It's designed to capture, like, atomized knowledge.</p>
<p>429
00:52:45.370 --&gt; 00:52:48.009
Al Newkirk: So you, you wouldn't, you wouldn't point…</p>
<p>430
00:52:48.120 --&gt; 00:53:01.540
Al Newkirk: This system at files that it's going to parse for information, like PDFs, spreadsheets, etc. You would… Oof.</p>
<p>431
00:53:02.380 --&gt; 00:53:09.250
Al Newkirk: This system is designed for contextual… demise.</p>
<p>432
00:53:09.480 --&gt; 00:53:12.620
Al Newkirk: units of information. So, think, for example.</p>
<p>433
00:53:15.940 --&gt; 00:53:27.189
Al Newkirk: AI agents, like, Making conclusions… and then filing them for later reflection. Or humans, like.</p>
<p>434
00:53:28.940 --&gt; 00:53:37.180
Al Newkirk: being very precise about instructions, even in the, even in, like, I mean…</p>
<p>435
00:53:37.530 --&gt; 00:53:42.269
Al Newkirk: what I've created in this memory ledger is indicative of the kinds of</p>
<p>436
00:53:44.440 --&gt; 00:53:50.180
Al Newkirk: like, atomized knowledge that you would want, or… for example, like, if I were to open up this,</p>
<p>437
00:53:50.550 --&gt; 00:53:52.510
Al Newkirk: memory poisoning.</p>
<p>438
00:53:54.090 --&gt; 00:53:58.839
Al Newkirk: You know, this is the kind of thing you would expect in this system.</p>
<p>439
00:53:59.870 --&gt; 00:54:05.670
Al Newkirk: Now, you could use… they're not mutually exclusive, like, if you wanted to… if I, today.</p>
<p>440
00:54:05.880 --&gt; 00:54:11.150
Al Newkirk: being the author of the system. If I wanted to take a… Thank you.</p>
<p>441
00:54:11.880 --&gt; 00:54:13.859
Al Newkirk: under-page PDF.</p>
<p>442
00:54:14.230 --&gt; 00:54:18.239
Al Newkirk: And… I wanted to, like.</p>
<p>443
00:54:18.860 --&gt; 00:54:22.259
Al Newkirk: questions about it, I would use Nobelzella. Like, absolutely.</p>
<p>444
00:54:22.620 --&gt; 00:54:24.419
Al Newkirk: But,</p>
<p>445
00:54:24.920 --&gt; 00:54:30.020
Al Newkirk: But what I will… but what I would absolutely… and I have done this, actually, I can show you examples of it.</p>
<p>446
00:54:30.530 --&gt; 00:54:38.000
Al Newkirk: In fact, I could tell by the formatting, because Nobook LM formats things like this. Like, the bullet points are… the bullet points in the…</p>
<p>447
00:54:38.840 --&gt; 00:54:48.289
Al Newkirk: bolding. But anyway, facts is about, like, like, the decisions and the…</p>
<p>448
00:54:48.740 --&gt; 00:54:51.500
Al Newkirk: Capturing the thinking and the knowledge.</p>
<p>449
00:54:51.740 --&gt; 00:54:57.670
Al Newkirk: So, I wouldn't put the whole PDF into this system. I would put my conclusions</p>
<p>450
00:54:58.000 --&gt; 00:55:01.310
Al Newkirk: about the PDF in this system, if that makes sense.</p>
<p>451
00:55:02.300 --&gt; 00:55:07.959
Uri Bruck: I think it makes sense, yeah, sure. So we're dealing with lots of much smaller units for facts and conclusions.</p>
<p>452
00:55:08.080 --&gt; 00:55:08.580
Uri Bruck: And</p>
<p>453
00:55:08.580 --&gt; 00:55:09.290
Al Newkirk: Yes.</p>
<p>454
00:55:09.520 --&gt; 00:55:11.720
Uri Bruck: Yeah, so it makes influences from that, and…</p>
<p>455
00:55:12.520 --&gt; 00:55:14.969
Al Newkirk: Exactly. That's right, yeah, yeah, that's right.</p>
<p>456
00:55:15.310 --&gt; 00:55:15.860
Uri Bruck: Yeah.</p>
<p>457
00:55:17.180 --&gt; 00:55:25.610
Al Newkirk: So one of the things that I wanted to demonstrate in this demo that I think is very useful is that,</p>
<p>458
00:55:25.860 --&gt; 00:55:30.809
Al Newkirk: You can use… you're not locked into… this is the biggest, unlock.</p>
<p>459
00:55:32.660 --&gt; 00:55:39.529
Al Newkirk: That, if you don't take away anything else, from, from this demo,</p>
<p>460
00:55:41.510 --&gt; 00:55:49.009
Al Newkirk: If you spend a lot of time with an AI agent, You're building up… memory and knowledge.</p>
<p>461
00:55:49.300 --&gt; 00:55:55.940
Al Newkirk: And… And the AI will become more effective</p>
<p>462
00:55:56.050 --&gt; 00:55:58.489
Al Newkirk: Based on how much context it had.</p>
<p>463
00:56:00.640 --&gt; 00:56:06.409
Al Newkirk: But unless you're intentional about using… about having a…</p>
<p>464
00:56:06.540 --&gt; 00:56:11.249
Al Newkirk: vendor-neutral memory system, you're gonna be locked into</p>
<p>465
00:56:12.280 --&gt; 00:56:17.009
Al Newkirk: a particular vendor. This happened to me, this is a real thing that happened to me,</p>
<p>466
00:56:17.870 --&gt; 00:56:24.579
Al Newkirk: I was using, Claude. I started with Claude, and I was… I became a big fan of Claude.</p>
<p>467
00:56:24.950 --&gt; 00:56:30.970
Al Newkirk: And… I wanted to upgrade to a higher-priced plan.</p>
<p>468
00:56:31.180 --&gt; 00:56:39.369
Al Newkirk: And for whatever reason, the fact that I wanted to upgrade to, like, a $200 a month… $200 a month plan.</p>
<p>469
00:56:39.730 --&gt; 00:56:42.760
Al Newkirk: It triggered them to want to…</p>
<p>470
00:56:43.830 --&gt; 00:56:54.850
Al Newkirk: verify my identity. Now, the short story, short story is, I had trouble with my passport, and because I couldn't verify my identity, they actually locked me out of my account.</p>
<p>471
00:56:55.230 --&gt; 00:57:06.250
Al Newkirk: And all of the memories, all of the… like, all of the projects that I had in progress, I couldn't continue working on, because all of the… I could have tried to use another agent.</p>
<p>472
00:57:06.250 --&gt; 00:57:15.450
Al Newkirk: But all of the, like, knowledge of where I was in the project, and what I was planning to do, all that knowledge was trapped in that particular agent.</p>
<p>473
00:57:15.560 --&gt; 00:57:27.940
Al Newkirk: So I ended up, because I couldn't get a hold of Anthropic, I ended up switching to Codex and just starting from scratch, but I guess that also led me on a journey of…</p>
<p>474
00:57:28.060 --&gt; 00:57:32.680
Al Newkirk: Not wanting to be locked into a particular vendor's memory system.</p>
<p>475
00:57:34.890 --&gt; 00:57:36.570
Al Newkirk: So, yeah, you could…</p>
<p>476
00:57:37.120 --&gt; 00:57:40.850
Uri Bruck: You just stop all knowledge, and you can just take it to another agent, and…</p>
<p>477
00:57:41.900 --&gt; 00:57:47.289
Al Newkirk: Yeah, and I'm gonna, I'm gonna do… so I already did that with, with Claude and…</p>
<p>478
00:57:47.650 --&gt; 00:57:57.090
Al Newkirk: Codex. There's another open source, AI agent harness called Pi, and if I, like, launch PI,</p>
<p>479
00:57:58.060 --&gt; 00:58:04.680
Al Newkirk: you know, because I had the skills that work across agents, I could, I could just say,</p>
<p>480
00:58:05.450 --&gt; 00:58:08.350
Al Newkirk: Let's see… so I'm using Pi right now.</p>
<p>481
00:58:08.930 --&gt; 00:58:18.030
Al Newkirk: And for some reason… oh, okay, sorry, give me a second, because I'm still in that folder, so if I go here, and I relaunch Pi…</p>
<p>482
00:58:19.570 --&gt; 00:58:20.900
Al Newkirk: do, like…</p>
<p>483
00:58:21.060 --&gt; 00:58:27.409
Al Newkirk: act as… okay, I'm in the memory research, so now I could ask Papa the same thing. I could say, like,</p>
<p>484
00:58:28.150 --&gt; 00:58:33.980
Al Newkirk: What do I… what did I bid?</p>
<p>485
00:58:34.820 --&gt; 00:58:41.890
Al Newkirk: Okay, yeah, I'll answer the same thing. This is a whole completely separate, like, like, harness.</p>
<p>486
00:58:42.060 --&gt; 00:58:46.979
Al Newkirk: That there are two facts that contained clawed artifacts about memory products, blah blah blah.</p>
<p>487
00:58:47.320 --&gt; 00:58:49.210
Al Newkirk: There's a whole different,</p>
<p>488
00:58:51.290 --&gt; 00:58:55.450
Al Newkirk: And as you can see, it's doing its thing, it's using the fax memory system.</p>
<p>489
00:58:55.850 --&gt; 00:59:04.470
Al Newkirk: It's, it's using the current ledger, which is the memory research ledger, and it found that that was actually pretty quick. I think that was actually quicker than…</p>
<p>490
00:59:04.640 --&gt; 00:59:08.960
Al Newkirk: flawed, but… But it found it, so it went through.</p>
<p>491
00:59:09.110 --&gt; 00:59:11.630
Al Newkirk: So as you can see.</p>
<p>492
00:59:11.830 --&gt; 00:59:14.359
Al Newkirk: Like, I'm using a completely different AI agent.</p>
<p>493
00:59:14.520 --&gt; 00:59:18.860
Al Newkirk: And… it's using the same memory, so the memory is now portable.</p>
<p>494
00:59:20.320 --&gt; 00:59:27.629
Al Newkirk: And if I were to, yeah, if I were to… because it's, distributed, because you can push and pull, like, get…</p>
<p>495
00:59:28.200 --&gt; 00:59:35.699
Al Newkirk: if I were to, like, launch an AI as a product, like, you know, like an API, but an AI agent.</p>
<p>496
00:59:35.880 --&gt; 00:59:45.870
Al Newkirk: I could have it push and pull memory, and… And all of the… Un- unlike…</p>
<p>497
00:59:47.490 --&gt; 00:59:53.879
Al Newkirk: which will require, I guess, like, network-attached storage, or maybe, maybe, maybe?</p>
<p>498
00:59:54.190 --&gt; 01:00:01.129
Al Newkirk: Unlike that, like, different agents would be able to share the… The memories and… yeah, stuff.</p>
<p>499
01:00:02.120 --&gt; 01:00:02.980
Al Newkirk: Yup.</p>
<p>500
01:00:04.150 --&gt; 01:00:04.570
Uri Bruck: Okay.</p>
<p>501
01:00:04.570 --&gt; 01:00:07.859
Al Newkirk: I think we… I think we lost, Paul? Powell?</p>
<p>502
01:00:08.180 --&gt; 01:00:10.200
Uri Bruck: He left at some point, he still left a message on the chat.</p>
<p>503
01:00:10.200 --&gt; 01:00:11.650
Al Newkirk: Okay, okay, okay.</p>
<p>504
01:00:13.230 --&gt; 01:00:18.210
Uri Bruck: Yeah, okay, well, that's great, that's… I'd love to look into that, you know, this, you know…</p>
<p>505
01:00:18.320 --&gt; 01:00:19.850
Uri Bruck: This is a very nice introduction.</p>
<p>506
01:00:20.150 --&gt; 01:00:20.969
Uri Bruck: Yeah, thank you.</p>
<p>507
01:00:21.610 --&gt; 01:00:27.510
Uri Bruck: And I like the philosophy behind it, when you said you didn't… you said you didn't know much about philosophy, but you have a very nice philosophy behind it, so…</p>
<p>508
01:00:27.970 --&gt; 01:00:29.999
Al Newkirk: Oh, thank you, thank you, I appreciate that.</p>
<p>509
01:00:31.990 --&gt; 01:00:38.449
Al Newkirk: I guess, I guess now that we've sort of… oh, should we, should we leave it there, Gabor?</p>
<p>510
01:00:38.450 --&gt; 01:00:43.559
Gabor Szabo: Yeah, I mean, I think we are… we are done. I mean, we can turn off the camera now, if you like.</p>
<p>511
01:00:43.560 --&gt; 01:00:44.080
Al Newkirk: Okay, okay.</p>
<p>512
01:00:44.080 --&gt; 01:00:46.090
Gabor Szabo: I'll continue talking about other things.</p>
<p>513
01:00:46.740 --&gt; 01:00:49.339
Al Newkirk: Yeah, yeah, so I wanted to ask about…</p>
<p>514
01:00:49.680 --&gt; 01:01:05.330
Gabor Szabo: Wait a second, let me just finish, say a few words for those people who are also in the video. So just remember to like the video again, and follow the channel, and below the video, you will find the link to the… to… to…</p>
<p>515
01:01:05.370 --&gt; 01:01:13.620
Gabor Szabo: various things about this presentation and to the future events. And thank you very much again for this presentation, it was very interesting.</p>
<p>516
01:01:13.680 --&gt; 01:01:14.270
Gabor Szabo: Bye-bye.</p>
<p>517
01:01:14.270 --&gt; 01:01:14.970
Al Newkirk: No problem.</p>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

  <entry>
    <title>No Python was harmed: teaching a tiny MCU to learn as it goes</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2026-09-08T07:30:01Z</updated>
    <pubDate>2026-09-08T07:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/no-python-was-harmed-teaching-a-tiny-mcu-to-learn-as-it-goes" />
    <id>https://rust.code-maven.com/no-python-was-harmed-teaching-a-tiny-mcu-to-learn-as-it-goes</id>
    <content type="html"><![CDATA[<h2 class="title is-4">Description</h2>
<p>An embedded session showing how to deploy a useful hand-written neural network made with Rust supporting on-chip training on a tiny MCU.</p>
<h2 class="title is-4">Bio</h2>
<p><a href="https://www.linkedin.com/in/leon-vak-24445922/">Leon Vak</a></p>
<p>As CTO of Embedded at abra R&amp;D Solutions, I lead the technical architecture and engineering for highly customized, non-standard client projects. My daily work spans hands-on board bring-ups, custom silicon (ARM, RISC-V, ARC), Embedded Linux BSPs (specializing in Yocto project), and RTOS platforms. I work across the full software stack: from complex bare-metal layers and kernel drivers up to higher-level applications, everything primarily in C, C++, and Rust. Alongside running R&amp;D POCs and solving low-level integration issues, I prepare and conduct technical trainings and meetups, while mentoring our development teams and representing the company at presales meetings.</p>
<h2 class="title is-4">Length</h2>
<p><a class="button is-primary" href="https://luma.com/1byfc495">register</a></p>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

  <entry>
    <title>Rust and the GPU from Native to Web: An Introduction to `wgpu` by Liam Rust</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2026-09-04T09:30:01Z</updated>
    <pubDate>2026-09-04T09:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/rust-and-the-gpu-from-native-to-web-an-introduction-to-wgpu" />
    <id>https://rust.code-maven.com/rust-and-the-gpu-from-native-to-web-an-introduction-to-wgpu</id>
    <content type="html"><![CDATA[<h2 class="title is-4">Description</h2>
<p>The GPU can be one of the most powerful pieces of hardware in a device, and they are in almost every personal device with a screen. Despite this, it's usually quite difficult to actually utilize them, requiring platform and hardware-specific considerations. Enter <code>wgpu</code>: Rust's low-level, yet platform-agnostic and safe GPU library. This talk will cover what <code>wgpu</code> is and does, how you can use it for everything from parallel computations to rendering, and walk you through how to use it starting from scratch. Additionally, we'll cover how you can compile it for use in the browser!</p>
<h2 class="title is-4">Bio</h2>
<p><a href="https://www.linkedin.com/in/liam-rust/">Liam Rust</a> is a recent masters graduate of computer science from Stevens Institute of Technology. Liam is currently an embedded software engineering intern at Persistent Systems. Liam has many interests, but include all things Rust, full-stack web development, free and open source software, and Linux. Outside of programming, Liam enjoys singing, music, design, urbanism, and modeling.</p>
<h2 class="title is-4">Length</h2>
<p>30 min</p>
<p><a class="button is-primary" href="https://luma.com/k1978ath">register</a></p>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

  <entry>
    <title>Tauri: Cross-Platform desktop applications with Rust and web technologies</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2026-09-02T10:30:01Z</updated>
    <pubDate>2026-09-02T10:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/tauri-cross-platform-desktop-applications-with-rust-and-web-technologies" />
    <id>https://rust.code-maven.com/tauri-cross-platform-desktop-applications-with-rust-and-web-technologies</id>
    <content type="html"><![CDATA[<h2 class="title is-4">Description:</h2>
<p>Developing desktop applications with web technologies has been the norm for quite some time (at least for non-realtime applications). Slack, VS Code, Discord, Figma, 1Password, and more apps have been built this way. While Electron was, and still remains, a great choice for doing this, there is a new contender in town. Meet <a href="https://tauri.app/">Tauri</a>, designed for secure and lightweight desktop applications, without sacrificing on user experience, and while still using the mature web technologies we know and love.
In this session, I will introduce Tauri, and we will build a simple application using it together.</p>
<h2 class="title is-4">Bio:</h2>
<p><a href="https://www.linkedin.com/in/lielfr/">Liel Friedman</a> has been into open source for years, beginning with some translation work, and also contributing code to a few projects.
Professionally, he has about 4.5 years of experience in full-stack web development.</p>
<h2 class="title is-4">Links and Notes</h2>
<ul>
<li>
<p><a href="https://github.com/lielfr/tauri-clipboard-manager-demo">Tauri clipboard manager demo</a></p>
</li>
<li>
<p><a href="https://media.code-maven.com/slides/TauriSlideshow.pdf">Tauri Slides</a></p>
</li>
</ul>
<iframe width="560" height="315" src="https://www.youtube.com/embed/DQwu0F-xdS0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
<h2 class="title is-4">Transcript</h2>
<p>1
00:00:01.940 --&gt; 00:00:14.360
Gabor Szabo: So, hello and welcome to this new episode of the Code Maven YouTube channel, if you are watching on YouTube, and the Rust Maven session, that's a soft session of the Code Maven thingy.</p>
<p>2
00:00:14.510 --&gt; 00:00:26.789
Gabor Szabo: Below the video, if you are there, you will find links to where the further sessions are going to be, and where details about this session can be found, links, and</p>
<p>3
00:00:26.790 --&gt; 00:00:49.439
Gabor Szabo: I don't know if we all have code examples, whatever. You will be able to find links below the video. I'm going to also share them here in the meeting. If you are in the meeting, then welcome, I'm really happy. It's very… it's always fun to present in front of people. And you have the opportunity to ask questions while we have</p>
<p>4
00:00:49.440 --&gt; 00:01:06.799
Gabor Szabo: the presentation, and even after that, as I mentioned earlier, we can… you can stay around, and then we can have free chat about anything, whatever Leah does, or doesn't do, or about the cat, or… I don't know. So, we can discuss anything.</p>
<p>5
00:01:06.810 --&gt; 00:01:12.590
Gabor Szabo: My name is Gabor Szabo, I run this channel, I run these, events,</p>
<p>6
00:01:13.260 --&gt; 00:01:32.779
Gabor Szabo: And I think with this… that said, I can give you the floor, Liel. I'm really happy that you agreed to give this presentation. We already did this, or an earlier version of these ones, but now we can do it into the international community in English, so…</p>
<p>7
00:01:32.840 --&gt; 00:01:38.769
Gabor Szabo: Let's get started. Liel. The floor is yours, please. Introduce yourself, whatever you like.</p>
<p>8
00:01:39.570 --&gt; 00:01:40.280
Liel: Okay.</p>
<p>9
00:01:40.620 --&gt; 00:01:41.729
Gabor Szabo: So I'm thinking that before.</p>
<p>10
00:01:42.060 --&gt; 00:01:46.919
Gabor Szabo: Sorry, sorry, one second. How long do you feel… do you expect this is going to be… take?</p>
<p>11
00:01:47.520 --&gt; 00:01:49.429
Gabor Szabo: The session, the whole thing.</p>
<p>12
00:01:49.430 --&gt; 00:01:53.979
Liel: So… I think it will be less than the allocated 2 hours.</p>
<p>13
00:01:54.330 --&gt; 00:01:56.060
Gabor Szabo: Okay, okay, good.</p>
<p>14
00:01:56.240 --&gt; 00:02:03.750
Gabor Szabo: I just wanted to make sure that, so people will allow, we might, if it takes a long time, then we might have a break in the middle, if you like, okay?</p>
<p>15
00:02:04.020 --&gt; 00:02:05.129
Gabor Szabo: Are you a short report.</p>
<p>16
00:02:05.130 --&gt; 00:02:12.430
Liel: Last time we did go over time, but I, like, scaled down the second demo, so hopefully it won't happen this time.</p>
<p>17
00:02:12.430 --&gt; 00:02:13.200
Gabor Szabo: Okay.</p>
<p>18
00:02:14.610 --&gt; 00:02:15.760
Gabor Szabo: Go ahead, sorry.</p>
<p>19
00:02:16.290 --&gt; 00:02:26.760
Liel: Okay, so as Gabor said, welcome, hi everyone, I'm really glad you either joined live, or that you're watching this video on YouTube.</p>
<p>20
00:02:27.230 --&gt; 00:02:33.420
Liel: My name is Liel. I've been a professional software developer for about 4.5 years.</p>
<p>21
00:02:34.130 --&gt; 00:02:36.399
Liel: Mostly full stack.</p>
<p>22
00:02:37.300 --&gt; 00:02:40.940
Liel: More on the back end, to be honest, but also front-end as well.</p>
<p>23
00:02:41.760 --&gt; 00:02:44.210
Liel: And, for the cat.</p>
<p>24
00:02:44.460 --&gt; 00:02:49.129
Liel: This is Sasha, she is my assistant, and also an avidos station.</p>
<p>25
00:02:50.870 --&gt; 00:02:56.879
Liel: And, yeah, she will be here as she has been with me for… since COVID days.</p>
<p>26
00:02:59.940 --&gt; 00:03:09.389
Liel: This presentation will be about Tori, which is… cross-platform application development in Rust.</p>
<p>27
00:03:10.150 --&gt; 00:03:11.760
Liel: And let's begin!</p>
<p>28
00:03:15.540 --&gt; 00:03:23.920
Liel: Let's use… Presentation… Or maybe Advanced?</p>
<p>29
00:03:24.540 --&gt; 00:03:31.920
Liel: And… Slides… Like that?</p>
<p>30
00:03:49.520 --&gt; 00:03:58.010
Liel: Let's do this… Yeah. Let's just do a portion of screen, probably. We'll be fine.</p>
<p>31
00:03:59.640 --&gt; 00:04:04.310
Liel: Okay, so now we see a personal screen, and… yeah.</p>
<p>32
00:04:04.660 --&gt; 00:04:06.969
Liel: This one needs to go away.</p>
<p>33
00:04:07.570 --&gt; 00:04:12.979
Liel: And I can actually resize this to be just the… the presentation.</p>
<p>34
00:04:13.820 --&gt; 00:04:17.329
Liel: One second… Great.</p>
<p>35
00:04:19.690 --&gt; 00:04:22.849
Liel: Okay, so totally in a nutshell.</p>
<p>36
00:04:23.310 --&gt; 00:04:28.239
Liel: It's a library for graphical user interface application development.</p>
<p>37
00:04:28.650 --&gt; 00:04:33.539
Liel: Mainly for desktop, but since version 2.0, it also supports mobile.</p>
<p>38
00:04:34.010 --&gt; 00:04:38.249
Liel: We won't focus on the mobile side too much.</p>
<p>39
00:04:39.020 --&gt; 00:04:46.390
Liel: But, in general, it works the same way, and also note that unlike React Native and Flutter.</p>
<p>40
00:04:46.570 --&gt; 00:04:50.610
Liel: It just functions… it just opens a web view.</p>
<p>41
00:04:51.460 --&gt; 00:04:55.649
Liel: It's not like rendering native components whatsoever.</p>
<p>42
00:04:57.560 --&gt; 00:05:00.289
Liel: And it uses web technologies.</p>
<p>43
00:05:01.530 --&gt; 00:05:13.149
Liel: So, yeah, inside the WebView browser, basically, you can use any front-end framework you like, whether it's Rust-based, like Dioxus, Leptos, Vue.</p>
<p>44
00:05:13.290 --&gt; 00:05:18.980
Liel: or more traditional ones, like React, Angular overview.</p>
<p>45
00:05:19.400 --&gt; 00:05:21.540
Liel: The backend code is in Rust.</p>
<p>46
00:05:22.570 --&gt; 00:05:25.169
Liel: But you can also embed…</p>
<p>47
00:05:25.350 --&gt; 00:05:37.399
Liel: like, additional binaries, if you need, as what's called a sidecar. You have, like, a link. We'll add a PDF of the presentation after that, so you can…</p>
<p>48
00:05:38.090 --&gt; 00:05:41.229
Liel: Use all the links. It's written in Rust.</p>
<p>49
00:05:41.430 --&gt; 00:05:51.450
Liel: And what's nice is that there are so many plugins that come with Tori that you don't really have to mess with the Rust code so much.</p>
<p>50
00:05:51.710 --&gt; 00:05:52.930
Liel: If you want.</p>
<p>51
00:05:53.370 --&gt; 00:06:00.110
Liel: But, you can, and this is a Rust talk, so I will be focusing on that part.</p>
<p>52
00:06:02.540 --&gt; 00:06:07.050
Liel: So, there are two nice applications. I'm not affiliated with any of them.</p>
<p>53
00:06:07.250 --&gt; 00:06:10.450
Liel: But, I think they show quite a nice.</p>
<p>54
00:06:11.800 --&gt; 00:06:15.540
Liel: like, example of what you can do with Tori.</p>
<p>55
00:06:16.300 --&gt; 00:06:20.930
Liel: Let's see… oh, it opened it through Lara Dufre.</p>
<p>56
00:06:21.580 --&gt; 00:06:26.260
Liel: So, it's basically, like, chatting with Postgres.</p>
<p>57
00:06:26.950 --&gt; 00:06:31.520
Liel: with the native language, so probably LLM-based.</p>
<p>58
00:06:32.390 --&gt; 00:06:35.750
Liel: Based… And… yeah.</p>
<p>59
00:06:41.320 --&gt; 00:06:51.909
Liel: That's one, and the other is RustDesk, which is basically an AnyDesk alternative, which is open source for remote desktop.</p>
<p>60
00:06:54.670 --&gt; 00:07:01.869
Liel: So, yeah, that's, like, how it looks, and I think… It's also a nice example.</p>
<p>61
00:07:03.900 --&gt; 00:07:20.079
Liel: Yeah, I probably wouldn't use Tori for, like, low-latency stuff. If you need, like, real-time display for DSP applications and so on, I wouldn't use it, but for most other applications, I think it's fine, and it's a great</p>
<p>62
00:07:20.570 --&gt; 00:07:24.760
Liel: Solution, especially if you're already familiar with web technologies.</p>
<p>63
00:07:26.540 --&gt; 00:07:31.929
Liel: So… Yeah, one other very popular</p>
<p>64
00:07:32.180 --&gt; 00:07:38.779
Liel: solution for desktop applications based with web technologies is Electron.</p>
<p>65
00:07:39.410 --&gt; 00:07:47.120
Liel: And we will compare and talk a little bit about the difference, because… okay, so first of all.</p>
<p>66
00:07:48.280 --&gt; 00:07:50.710
Liel: Electron is Node.js-based.</p>
<p>67
00:07:52.490 --&gt; 00:08:02.450
Liel: And Tory is Rust-based, but even beyond that, they are, like, using a little bit of different philosophies.</p>
<p>68
00:08:02.880 --&gt; 00:08:04.699
Liel: regarding using a browser.</p>
<p>69
00:08:05.030 --&gt; 00:08:13.069
Liel: While electron bundles chromium, Tori tries to use the OS web view.</p>
<p>70
00:08:13.380 --&gt; 00:08:18.370
Liel: Which is… Usually WebKid-based.</p>
<p>71
00:08:18.480 --&gt; 00:08:21.729
Liel: On Linux, it's WebKit GTK.</p>
<p>72
00:08:23.540 --&gt; 00:08:27.739
Liel: On Windows, it's Edge WebView.</p>
<p>73
00:08:28.030 --&gt; 00:08:32.600
Liel: And macOS, it's… yeah, it's WebKit as well, probably based on Safari.</p>
<p>74
00:08:33.140 --&gt; 00:08:38.230
Liel: It has the advantage of being light, and potentially.</p>
<p>75
00:08:38.590 --&gt; 00:08:44.949
Liel: It can, or… it can be more beneficial security-wise, because</p>
<p>76
00:08:45.220 --&gt; 00:08:49.990
Liel: You kind of get the browser updates for free without needing to update your own app.</p>
<p>77
00:08:52.460 --&gt; 00:08:59.460
Liel: But, the disadvantage is that you need to account for that, and, like, don't use</p>
<p>78
00:09:00.600 --&gt; 00:09:04.170
Liel: Features that may not be supported.</p>
<p>79
00:09:06.460 --&gt; 00:09:12.229
Liel: Regarding the file size, it's about a minimum of 600 kilobytes.</p>
<p>80
00:09:12.980 --&gt; 00:09:17.950
Liel: Which is, like, way lighter than Electron apps, which are, like.</p>
<p>81
00:09:18.270 --&gt; 00:09:20.829
Liel: placed a few hundred megabytes, I guess?</p>
<p>82
00:09:22.240 --&gt; 00:09:25.780
Liel: Haven't done this in a while, but they are very large.</p>
<p>83
00:09:29.290 --&gt; 00:09:36.160
Liel: And… In the future, it might be possible to embed the browser engine if you would like.</p>
<p>84
00:09:36.580 --&gt; 00:09:43.830
Liel: But right now, it's like… you can technically fork Tory and try to do it, but… Broly.</p>
<p>85
00:09:44.630 --&gt; 00:09:46.489
Liel: Quite a bit of work.</p>
<p>86
00:09:49.670 --&gt; 00:09:57.900
Liel: And also, regarding security, while Electron apps can be very secure, the link here is the… I think it's the…</p>
<p>87
00:09:58.530 --&gt; 00:10:03.389
Liel: guidelines for security in Electron, but TORI is built</p>
<p>88
00:10:03.940 --&gt; 00:10:08.259
Liel: So, that it's both harder to misuse, and…</p>
<p>89
00:10:08.640 --&gt; 00:10:14.420
Liel: It can be, in some cases, less vulnerable to supply chain attacks.</p>
<p>90
00:10:15.130 --&gt; 00:10:21.709
Liel: So we'll talk a little bit about how the frontend communicates with the Rust part, but</p>
<p>91
00:10:21.840 --&gt; 00:10:34.539
Liel: If you build it right, the front end, even if you have, like, a malicious code inside of it, can do as much damage as it potentially can</p>
<p>92
00:10:35.660 --&gt; 00:10:36.870
Liel: in electron.</p>
<p>93
00:10:38.350 --&gt; 00:10:45.200
Liel: But the caveat is that the Rust code is not isolated, so…</p>
<p>94
00:10:45.480 --&gt; 00:10:50.880
Liel: And as we saw, the Rosa supply chain attack.</p>
<p>95
00:10:51.360 --&gt; 00:10:53.460
Liel: A few weeks ago, I think.</p>
<p>96
00:10:57.630 --&gt; 00:11:03.240
Liel: So, yeah. It's not perfect, but I think it's a step in the right direction.</p>
<p>97
00:11:05.010 --&gt; 00:11:09.120
Liel: Oh, I also forgot to… To tell that…</p>
<p>98
00:11:09.260 --&gt; 00:11:15.969
Liel: the front end only communicates with the backend via message passing, so there is no, like, FFI between the front end and</p>
<p>99
00:11:16.740 --&gt; 00:11:17.720
Liel: there.</p>
<p>100
00:11:18.460 --&gt; 00:11:20.879
Liel: The core process, as it's called.</p>
<p>101
00:11:21.070 --&gt; 00:11:22.559
Liel: Which is the arrest.</p>
<p>102
00:11:22.810 --&gt; 00:11:24.549
Liel: Part of the app.</p>
<p>103
00:11:28.870 --&gt; 00:11:33.570
Liel: Let's… See if we have any questions…</p>
<p>104
00:11:35.410 --&gt; 00:11:38.330
Liel: I don't know, not so far, so let's continue.</p>
<p>105
00:11:38.780 --&gt; 00:11:42.470
Liel: Alright, yeah, feel free to write questions on the chat.</p>
<p>106
00:11:42.640 --&gt; 00:11:48.690
Liel: And, I'll stop every once in a while and… see them.</p>
<p>107
00:11:49.950 --&gt; 00:11:51.030
Liel: Oh, sorry.</p>
<p>108
00:11:51.810 --&gt; 00:11:59.480
Liel: So, we have two primary CLI tools, Creatoria App for, like, scaffolding projects from scratch.</p>
<p>109
00:12:00.000 --&gt; 00:12:02.870
Liel: And we have the Tori CLI.</p>
<p>110
00:12:03.010 --&gt; 00:12:05.359
Liel: Which can be used to, like.</p>
<p>111
00:12:05.510 --&gt; 00:12:08.540
Liel: Introduce story to an existing front-end app.</p>
<p>112
00:12:08.960 --&gt; 00:12:13.019
Liel: And it can be also used for other stuff, like</p>
<p>113
00:12:13.310 --&gt; 00:12:17.630
Liel: Building the app, bundling it for distribution, and so on.</p>
<p>114
00:12:18.330 --&gt; 00:12:27.530
Liel: And we need Rust, as well as Node.js, and their favorite build tool, which is, like, NPM, BAN, PNPM, YARN,</p>
<p>115
00:12:27.650 --&gt; 00:12:31.620
Liel: Oh, the .NET equivalent, if you're… you can also use .NET.</p>
<p>116
00:12:31.980 --&gt; 00:12:36.430
Liel: as… For the front end, using Blazor.</p>
<p>117
00:12:36.900 --&gt; 00:12:39.059
Liel: But I haven't tried that, to be honest.</p>
<p>118
00:12:39.530 --&gt; 00:12:43.979
Liel: So, you can try that, see the documentation, it's really good.</p>
<p>119
00:12:48.240 --&gt; 00:12:52.730
Liel: And… okay. So, regarding project structure…</p>
<p>120
00:12:53.470 --&gt; 00:13:01.169
Liel: as I told you before, you can kind of inject Tory into an existing front-end project.</p>
<p>121
00:13:01.620 --&gt; 00:13:06.020
Liel: the way it does all, it's, like, we have SRC-story.</p>
<p>122
00:13:06.560 --&gt; 00:13:11.169
Liel: file, folder for the Rust code and the toggle configuration.</p>
<p>123
00:13:14.410 --&gt; 00:13:18.550
Liel: And we can also run the frontend separately if we'd like to.</p>
<p>124
00:13:23.970 --&gt; 00:13:29.660
Liel: Regarding the process model, we have the core, which is, like, the mandatory process.</p>
<p>125
00:13:30.280 --&gt; 00:13:34.549
Liel: It's the only thing with full operating system access.</p>
<p>126
00:13:36.810 --&gt; 00:13:39.740
Liel: So, like, every Rust code runs here.</p>
<p>127
00:13:41.990 --&gt; 00:13:48.979
Liel: And it opens one or more WebView processes, which each has one WebView.</p>
<p>128
00:13:49.380 --&gt; 00:13:53.100
Liel: Which is, like, what's rendering the front end.</p>
<p>129
00:13:56.220 --&gt; 00:14:09.400
Liel: Regarding security, when you are, like, doing message passing, it's best practice to treat the web view as, like, an actual browser, meaning that you don't trust</p>
<p>130
00:14:09.840 --&gt; 00:14:11.929
Liel: Like, the inputs.</p>
<p>131
00:14:12.280 --&gt; 00:14:22.289
Liel: From the web view blindly, but you do, like, do validations and sanitize it, whatever you do, if it was, like, an actual web app and</p>
<p>132
00:14:22.720 --&gt; 00:14:27.970
Liel: you'd want… To secure it from potentially malicious inputs.</p>
<p>133
00:14:30.850 --&gt; 00:14:39.070
Liel: It's also recommended to write the logic in Rust, but yeah, you can reuse plugins if you want, and…</p>
<p>134
00:14:39.370 --&gt; 00:14:40.770
Liel: many.</p>
<p>135
00:14:46.810 --&gt; 00:14:49.550
Liel: Okay, so we talked about method passing.</p>
<p>136
00:14:49.660 --&gt; 00:14:53.959
Liel: And the core of message passing is called commands.</p>
<p>137
00:14:54.130 --&gt; 00:15:03.870
Liel: So, basically, You can have, like, commands that… which are, like, which simulate</p>
<p>138
00:15:04.350 --&gt; 00:15:10.829
Liel: RPC, remote procedural call, but are actually Just messages passing me around?</p>
<p>139
00:15:13.720 --&gt; 00:15:23.809
Liel: And… yeah, you define them in the Rust, and you can call them from the front end. We'll see that soon. You can also, like.</p>
<p>140
00:15:23.940 --&gt; 00:15:26.200
Liel: Restrict the inputs.</p>
<p>141
00:15:27.260 --&gt; 00:15:29.999
Liel: That, it allows.</p>
<p>142
00:15:30.410 --&gt; 00:15:33.449
Liel: Via, what's called the permission system.</p>
<p>143
00:15:34.170 --&gt; 00:15:38.880
Liel: So you can, like, make sure that some out… some inputs are</p>
<p>144
00:15:39.390 --&gt; 00:15:43.300
Liel: Yeah, restricted even before they go into the call.</p>
<p>145
00:15:44.470 --&gt; 00:15:50.890
Liel: And, you can also have pretty much everything that you can deserialize with ZRD.</p>
<p>146
00:15:51.940 --&gt; 00:15:54.860
Liel: So, behind the scenes, it probably uses JSON.</p>
<p>147
00:15:57.180 --&gt; 00:16:09.209
Liel: And… yeah, it's a really nice mechanism, we'll see it in the next slide. Just a reminder that the Rust code is not isolated, so you'll need to treat that as</p>
<p>148
00:16:10.210 --&gt; 00:16:15.040
Liel: Code that has elevated privileges, and so on.</p>
<p>149
00:16:15.890 --&gt; 00:16:23.190
Liel: So the way you define commands is that you have the attribute macro of ToriCommand.</p>
<p>150
00:16:23.720 --&gt; 00:16:35.750
Liel: And yeah, it's a little… yeah, it's honestly a silly example, because it wouldn't validate password and user like that, but for example, it would work.</p>
<p>151
00:16:36.320 --&gt; 00:16:39.970
Liel: So, you can… optionally have.</p>
<p>152
00:16:40.690 --&gt; 00:16:44.510
Liel: As many params as you'd like, or you can have none.</p>
<p>153
00:16:45.890 --&gt; 00:16:50.150
Liel: And you can also… Return a result type.</p>
<p>154
00:16:50.700 --&gt; 00:16:55.429
Liel: So, if you have, like, an error, in this case.</p>
<p>155
00:16:55.740 --&gt; 00:17:09.180
Liel: We just return the error, and what happens in the JavaScript side is that it returns a promise. So if we return OK, then the promise resolves with our output.</p>
<p>156
00:17:09.329 --&gt; 00:17:14.420
Liel: But if we're down… An error, it rejects.</p>
<p>157
00:17:15.890 --&gt; 00:17:21.240
Liel: We can also use the async keyword, as Tori uses Tokyo.</p>
<p>158
00:17:21.410 --&gt; 00:17:28.280
Liel: So if we want something that doesn't run in the main thread, we can… like, Ed Essing?</p>
<p>159
00:17:28.550 --&gt; 00:17:33.339
Liel: function login. From the JavaScript side, it's actually the same, it was a promise.</p>
<p>160
00:17:36.030 --&gt; 00:17:39.399
Liel: By the way, if you're interested on how this works.</p>
<p>161
00:17:39.580 --&gt; 00:17:43.249
Liel: Basically, a web view allows you to register a custom protocol.</p>
<p>162
00:17:43.450 --&gt; 00:17:50.820
Liel: So… a command from Tauri is actually just… a fetch call.</p>
<p>163
00:17:51.190 --&gt; 00:17:55.760
Liel: So, it's almost like an HTTP call, but instead of HTTP,</p>
<p>164
00:17:57.490 --&gt; 00:18:08.180
Liel: let me just… yeah, let me just have myself something I can write on. So instead of… http.slash-less. Something?</p>
<p>165
00:18:09.920 --&gt; 00:18:12.420
Liel: it calls, I think, IPC.</p>
<p>166
00:18:13.380 --&gt; 00:18:14.980
Liel: Colon slash slash.</p>
<p>167
00:18:15.220 --&gt; 00:18:16.130
Liel: Something.</p>
<p>168
00:18:16.280 --&gt; 00:18:25.360
Liel: And that is registered, so it doesn't actually go over the wire, but goes directly to the toll record responsible for handling.</p>
<p>169
00:18:26.780 --&gt; 00:18:28.330
Liel: Nicole's.</p>
<p>170
00:18:33.470 --&gt; 00:18:41.399
Liel: Also, another tip, if you have, like, a large array, You'd like to return?</p>
<p>171
00:18:41.820 --&gt; 00:18:48.929
Liel: You can return a type called the Tory… Happy to see your response.</p>
<p>172
00:18:49.100 --&gt; 00:18:57.500
Liel: Which… is optimized for this kind of thing, so if you, like, if you're, like.</p>
<p>173
00:18:57.670 --&gt; 00:19:07.579
Liel: pass a large image, or a sound, or an audio file, so that would be a use case for that IPC response type.</p>
<p>174
00:19:10.190 --&gt; 00:19:18.350
Liel: We also have… A mechanism for small events, so we can, like, Post an event, and…</p>
<p>175
00:19:22.080 --&gt; 00:19:24.940
Liel: And listen to events?</p>
<p>176
00:19:25.260 --&gt; 00:19:27.299
Liel: There are simpler than commands.</p>
<p>177
00:19:27.420 --&gt; 00:19:33.450
Liel: So, they only use JSON, And… there aren't.</p>
<p>178
00:19:34.110 --&gt; 00:19:37.720
Liel: Any type checks, and no permissions or capabilities.</p>
<p>179
00:19:38.460 --&gt; 00:19:44.000
Liel: But they are flexible, so you can have as many producers and as many consumers as you like.</p>
<p>180
00:19:45.260 --&gt; 00:19:50.900
Liel: There is also a similar mechanism called channels, which is low latency.</p>
<p>181
00:19:52.560 --&gt; 00:19:57.910
Liel: And, yeah, let's see an example. We can have global events.</p>
<p>182
00:19:58.040 --&gt; 00:20:02.170
Liel: So, let's say we have a command for download a file.</p>
<p>183
00:20:02.610 --&gt; 00:20:06.009
Liel: We can emit an event. Download started…</p>
<p>184
00:20:06.230 --&gt; 00:20:09.930
Liel: And we can omit the process… the progress, and when it's finished.</p>
<p>185
00:20:10.100 --&gt; 00:20:19.459
Liel: And we can also… emit to a specific screen, so it's specific… it's for one specific web view.</p>
<p>186
00:20:22.780 --&gt; 00:20:29.759
Liel: We can also have something called an emit filter, which allows us to, like, allow</p>
<p>187
00:20:30.250 --&gt; 00:20:31.659
Liel: A bunch of web views.</p>
<p>188
00:20:35.580 --&gt; 00:20:41.640
Liel: But, yeah, it can be anything that's serializable.</p>
<p>189
00:20:45.480 --&gt; 00:20:50.240
Liel: And how we listen to events in TypeScript is… looks like that.</p>
<p>190
00:20:50.880 --&gt; 00:20:59.249
Liel: So we define a type for download started, and we listen to an event, and we have our callback, which in this case is just a</p>
<p>191
00:20:59.390 --&gt; 00:21:00.650
Liel: Console log.</p>
<p>192
00:21:01.800 --&gt; 00:21:03.910
Liel: Note that the type isn't, like.</p>
<p>193
00:21:04.090 --&gt; 00:21:12.620
Liel: actually checked, so it's only for, like, developer experience, but it doesn't actually check that all these fields exist.</p>
<p>194
00:21:18.960 --&gt; 00:21:23.489
Liel: for WorkView-specific events, this is how we'll listen to them.</p>
<p>195
00:21:24.310 --&gt; 00:21:30.600
Liel: We first get the WorkView window, and then… We do, like, listen.</p>
<p>196
00:21:31.280 --&gt; 00:21:36.530
Liel: And yeah, in this case, we just set a session token. Again, please don't do that.</p>
<p>197
00:21:36.950 --&gt; 00:21:38.700
Liel: In a real app.</p>
<p>198
00:21:42.110 --&gt; 00:21:49.799
Liel: And finally, for cleanup, every listen, also every call to listen, also returns</p>
<p>199
00:21:50.480 --&gt; 00:21:58.449
Liel: A function, which can be used to deregister the Listener. But…</p>
<p>200
00:21:58.860 --&gt; 00:22:04.520
Liel: Unless you're doing, like, single-page applications, You can, like.</p>
<p>201
00:22:05.760 --&gt; 00:22:11.969
Liel: ignore that part. But if you're using, like, React, whenever you are switching components and so on.</p>
<p>202
00:22:12.790 --&gt; 00:22:16.720
Liel: Please, do and listen to… like, clean up.</p>
<p>203
00:22:17.060 --&gt; 00:22:19.669
Liel: Any event listeners you don't use.</p>
<p>204
00:22:22.250 --&gt; 00:22:33.670
Liel: And behind the scenes, events work, like, really similarly to commands. It's also, like, IPC call, just an internal one tutorial.</p>
<p>205
00:22:34.200 --&gt; 00:22:41.339
Liel: And what it does, it basically runs the event listeners, so, like, it keeps some kind of a map.</p>
<p>206
00:22:41.990 --&gt; 00:22:50.070
Liel: Between every event and its listeners, and it just runs the listener code every time,</p>
<p>207
00:22:50.390 --&gt; 00:22:54.120
Liel: the actual event happens. So, let's say I logged in.</p>
<p>208
00:22:54.400 --&gt; 00:23:02.800
Liel: There is, like, a map with the name logged in as a key, And… Like, all the handlers.</p>
<p>209
00:23:03.530 --&gt; 00:23:08.290
Liel: inside it, so it calls the JavaScript via the web view.</p>
<p>210
00:23:09.880 --&gt; 00:23:16.700
Liel: to run each one of these listeners. If you're interested, you can check out the source code</p>
<p>211
00:23:17.950 --&gt; 00:23:21.420
Liel: It's in the Tory… Runtime.</p>
<p>212
00:23:22.020 --&gt; 00:23:25.989
Liel: Great, I think. Or the Tory runtime WRY.</p>
<p>213
00:23:26.170 --&gt; 00:23:29.469
Liel: Just, like, picked at it before</p>
<p>214
00:23:30.050 --&gt; 00:23:33.309
Liel: So I remember how that works.</p>
<p>215
00:23:34.650 --&gt; 00:23:40.160
Liel: There's also a utility function that's not listed That's not listed here.</p>
<p>216
00:23:41.190 --&gt; 00:23:48.750
Liel: that allows to listen to an event exactly once. So it's similar to, like, a one-shot channel.</p>
<p>217
00:23:50.820 --&gt; 00:23:57.389
Liel: And… Yeah, that's that. Sorry, I accidentally…</p>
<p>218
00:24:00.070 --&gt; 00:24:08.189
Liel: Is Tory ready for a mobile app? I'll answer that once we are, done with events and channels.</p>
<p>219
00:24:12.990 --&gt; 00:24:17.630
Liel: So that's that, and let's do… Damn.</p>
<p>220
00:24:17.910 --&gt; 00:24:19.680
Liel: Longer example.</p>
<p>221
00:24:20.410 --&gt; 00:24:24.160
Liel: So, we have a download event, we serialize it.</p>
<p>222
00:24:25.030 --&gt; 00:24:31.830
Liel: It's all the nice derived attributes, so, like, it… the camel case, and so on.</p>
<p>223
00:24:34.460 --&gt; 00:24:44.640
Liel: And we define a command. Once again, download, because that's the example they got at the official documentation. We'll do another one in the demos.</p>
<p>224
00:24:47.250 --&gt; 00:24:51.679
Liel: So, we have the app handle… which is injected.</p>
<p>225
00:24:53.800 --&gt; 00:24:56.649
Liel: We have URL and unevent.</p>
<p>226
00:24:56.980 --&gt; 00:25:03.390
Liel: So, we can basically send Any, like, progress event or whatever.</p>
<p>227
00:25:03.760 --&gt; 00:25:07.210
Liel: On the channel, and it's faster.</p>
<p>228
00:25:07.950 --&gt; 00:25:11.820
Liel: then… Just using the events.</p>
<p>229
00:25:13.570 --&gt; 00:25:14.700
Liel: And…</p>
<p>230
00:25:18.780 --&gt; 00:25:24.160
Liel: Yeah, it's a… it's kind of similar to a command, but…</p>
<p>231
00:25:25.290 --&gt; 00:25:30.660
Liel: It also allows you to send multiple messages.</p>
<p>232
00:25:33.770 --&gt; 00:25:37.919
Liel: On the front-end side, how it looks is that we define the channel.</p>
<p>233
00:25:38.330 --&gt; 00:25:39.359
Liel: From here…</p>
<p>234
00:25:39.780 --&gt; 00:25:46.999
Liel: And also note that the channels are only created on the front-end side. You cannot create them from Rust. That's, like, how they're designed.</p>
<p>235
00:25:50.820 --&gt; 00:26:00.610
Liel: And, yeah, they're useful when we have, like, a command, and we want, instead of just one, output?</p>
<p>236
00:26:01.770 --&gt; 00:26:04.729
Liel: We can return, like, a bunch of outputs.</p>
<p>237
00:26:04.970 --&gt; 00:26:11.700
Liel: And, yeah, again, these are ordered, so… That can be.</p>
<p>238
00:26:12.100 --&gt; 00:26:13.589
Liel: Really nice as well.</p>
<p>239
00:26:18.620 --&gt; 00:26:20.750
Liel: We can also listen to events.</p>
<p>240
00:26:21.400 --&gt; 00:26:22.540
Liel: in Rust.</p>
<p>241
00:26:23.770 --&gt; 00:26:30.160
Liel: So we do, in the setup, we have the app handle, and we listen to the event like that.</p>
<p>242
00:26:33.310 --&gt; 00:26:38.259
Liel: It can also be done in a WebView-specific version as well, but…</p>
<p>243
00:26:38.970 --&gt; 00:26:43.689
Liel: Yeah, we won't show that, at least in here. We might show that in the second demo.</p>
<p>244
00:26:45.150 --&gt; 00:26:52.309
Liel: We also have unlisten and a way to send events only once, or listen to just one message.</p>
<p>245
00:26:56.020 --&gt; 00:27:01.039
Liel: Okay, so… Before we go to the first demo.</p>
<p>246
00:27:01.700 --&gt; 00:27:05.210
Liel: I see a question from Raw.</p>
<p>247
00:27:05.840 --&gt; 00:27:09.039
Liel: I hope I didn't butcher your name.</p>
<p>248
00:27:11.670 --&gt; 00:27:14.049
Liel: Is store ready for mobile app?</p>
<p>249
00:27:15.290 --&gt; 00:27:16.470
Liel: So…</p>
<p>250
00:27:17.650 --&gt; 00:27:29.039
Liel: It is in a stable state, but the caveat is that you only have a web view, so it's like having one giant browser window which shows your app.</p>
<p>251
00:27:32.460 --&gt; 00:27:36.979
Liel: So, personally, I wouldn't use it for a mobile app unless to</p>
<p>252
00:27:37.390 --&gt; 00:27:44.220
Liel: I'm like, okay, and you already have, like, a fantastic and responsive web app. You'd just like to…</p>
<p>253
00:27:44.520 --&gt; 00:27:45.790
Liel: Have a mobile?</p>
<p>254
00:27:46.810 --&gt; 00:27:48.480
Liel: But you can use that.</p>
<p>255
00:27:48.660 --&gt; 00:27:53.889
Liel: In my opinion, a better approach would be, like, to have some crate</p>
<p>256
00:27:54.010 --&gt; 00:28:01.330
Liel: as, like, a shared Rust core, and use… Like, either native, or…</p>
<p>257
00:28:01.450 --&gt; 00:28:06.610
Liel: any of the other solutions, like React Native or Flutter, which…</p>
<p>258
00:28:07.000 --&gt; 00:28:10.450
Liel: Flutter has nice support for Rust as well.</p>
<p>259
00:28:18.780 --&gt; 00:28:21.769
Liel: Yeah, I hope that answered the question.</p>
<p>260
00:28:22.770 --&gt; 00:28:25.889
Liel: Anything else before we move on to the first demo?</p>
<p>261
00:28:39.610 --&gt; 00:28:41.490
Gabor Szabo: Nice again, we can, we can go ahead.</p>
<p>262
00:28:42.620 --&gt; 00:28:45.060
Liel: Okay, so for the first demo.</p>
<p>263
00:28:45.570 --&gt; 00:28:53.299
Liel: what I'll do is I… I'll stop the share, and… We'll switch to Gabor.</p>
<p>264
00:28:53.470 --&gt; 00:28:57.350
Liel: And I'll kinda instruct him.</p>
<p>265
00:28:57.470 --&gt; 00:29:02.049
Liel: how we can basically bootstrap Tori app from scratch.</p>
<p>266
00:29:17.930 --&gt; 00:29:19.629
Gabor Szabo: Something is broken here.</p>
<p>267
00:29:25.570 --&gt; 00:29:26.480
Gabor Szabo: Okay.</p>
<p>268
00:29:26.480 --&gt; 00:29:27.710
Liel: Oh, great.</p>
<p>269
00:29:29.190 --&gt; 00:29:34.529
Liel: Okay, so you probably have Rust installed, and you have NPM as well.</p>
<p>270
00:29:35.400 --&gt; 00:29:44.830
Gabor Szabo: Probably… probably from the previous time, I still have NPM. I don't… Rust, I keep upgrading. NPM, probably not.</p>
<p>271
00:29:45.450 --&gt; 00:29:49.299
Gabor Szabo: So, whatever we have. Tell me what to do.</p>
<p>272
00:29:49.700 --&gt; 00:29:50.300
Gabor Szabo: Okay.</p>
<p>273
00:29:50.300 --&gt; 00:29:56.390
Liel: Okay, so first, we need to, like, run… And…</p>
<p>274
00:29:56.840 --&gt; 00:30:03.790
Liel: the command to create the Tory app. So, what we'll do is npm space Create.</p>
<p>275
00:30:04.170 --&gt; 00:30:07.079
Gabor Szabo: Is it going to create a… is it going to create a folder?</p>
<p>276
00:30:07.480 --&gt; 00:30:09.219
Liel: Yeah, it is.</p>
<p>277
00:30:13.430 --&gt; 00:30:15.840
Liel: I'll just paste that.</p>
<p>278
00:30:16.860 --&gt; 00:30:18.080
Liel: Into the chat.</p>
<p>279
00:30:19.450 --&gt; 00:30:23.960
Liel: Let's hope that the version is okay. If not, I will do it.</p>
<p>280
00:30:24.900 --&gt; 00:30:26.029
Liel: On my machine.</p>
<p>281
00:30:38.700 --&gt; 00:30:41.660
Liel: Yeah, we need the creator reactor.</p>
<p>282
00:30:46.530 --&gt; 00:30:52.509
Liel: Okay, so product name, it will be the folder, let's say Tory Demo, or whatever you'd like.</p>
<p>283
00:30:53.130 --&gt; 00:30:56.000
Gabor Szabo: Yeah, I just verified that it doesn't exist here.</p>
<p>284
00:30:56.750 --&gt; 00:30:58.810
Gabor Szabo: Double up is good, or…</p>
<p>285
00:31:00.210 --&gt; 00:31:02.139
Liel: Yeah, that could be good as well.</p>
<p>286
00:31:03.030 --&gt; 00:31:03.850
Gabor Szabo: Okay.</p>
<p>287
00:31:04.890 --&gt; 00:31:12.280
Liel: identifier, yeah, it could be… it probably makes more sense for mobile, because in, like.</p>
<p>288
00:31:12.500 --&gt; 00:31:17.049
Liel: at least in iOS and Android, you do have that convention of.</p>
<p>289
00:31:17.420 --&gt; 00:31:19.760
Gabor Szabo: It's like my domain name should be, right? So…</p>
<p>290
00:31:25.380 --&gt; 00:31:25.840
Liel: Yeah.</p>
<p>291
00:31:25.840 --&gt; 00:31:31.350
Gabor Szabo: That… that would be… because SubGov.com is my personal domain, or whatever.</p>
<p>292
00:31:32.270 --&gt; 00:31:32.890
Gabor Szabo: Okay.</p>
<p>293
00:31:32.890 --&gt; 00:31:33.500
Liel: Yeah.</p>
<p>294
00:31:33.760 --&gt; 00:31:36.919
Liel: Let's do TypeScript or JavaScript.</p>
<p>295
00:31:37.470 --&gt; 00:31:41.509
Gabor Szabo: Okay, so I can move here, but I just skip the first one.</p>
<p>296
00:31:42.090 --&gt; 00:31:45.419
Liel: Yeah, package manager, let's just do 1PM.</p>
<p>297
00:31:45.950 --&gt; 00:31:49.400
Liel: Because I'm not sure if you have anything.</p>
<p>298
00:31:49.760 --&gt; 00:31:53.959
Liel: And for the UI template, it doesn't really matter, let's do vanilla.</p>
<p>299
00:31:54.100 --&gt; 00:31:55.200
Liel: So it's…</p>
<p>300
00:31:55.500 --&gt; 00:31:57.700
Gabor Szabo: Okay, so YouTube, I keep it.</p>
<p>301
00:31:57.850 --&gt; 00:31:58.830
Gabor Szabo: Like this.</p>
<p>302
00:32:00.660 --&gt; 00:32:06.090
Liel: Yeah, UI flavor… It can be whatever, the default is fine.</p>
<p>303
00:32:09.500 --&gt; 00:32:13.389
Liel: Okay, and now we have a folder called ToriApp.</p>
<p>304
00:32:20.370 --&gt; 00:32:20.850
Gabor Szabo: Okay.</p>
<p>305
00:32:20.850 --&gt; 00:32:25.230
Liel: And, we need to do, like, npm install. It says, so,</p>
<p>306
00:32:27.770 --&gt; 00:32:29.739
Gabor Szabo: Just wanted to see what's in here.</p>
<p>307
00:32:30.150 --&gt; 00:32:36.440
Liel: Okay, so as you can see, that's great. We have the SRC, which is the front end, we have SRC Tory.</p>
<p>308
00:32:38.150 --&gt; 00:32:39.009
Gabor Szabo: This one.</p>
<p>309
00:32:39.820 --&gt; 00:32:40.410
Liel: Yeah.</p>
<p>310
00:32:41.860 --&gt; 00:32:42.690
Gabor Szabo: Okay.</p>
<p>311
00:32:43.360 --&gt; 00:32:45.050
Gabor Szabo: So, NPM?</p>
<p>312
00:32:45.760 --&gt; 00:32:49.579
Liel: Yeah, npm installed, because we need to get all the dependencies.</p>
<p>313
00:32:57.500 --&gt; 00:33:01.919
Gabor Szabo: Go ahead, ask a question, or whoever wants to ask a question, just type in the question.</p>
<p>314
00:33:09.050 --&gt; 00:33:13.019
Gabor Szabo: If that's… that's why you… you raised your hand for… I don't know.</p>
<p>315
00:33:13.260 --&gt; 00:33:19.970
Gabor Szabo: Anyway, if anyone has questions, just type them in the chat, we are both looking at it once in a while.</p>
<p>316
00:33:22.150 --&gt; 00:33:23.200
Gabor Szabo: Okay.</p>
<p>317
00:33:25.740 --&gt; 00:33:26.690
Gabor Szabo: Done.</p>
<p>318
00:33:27.390 --&gt; 00:33:32.950
Liel: Okay, and now there is… it's NPM… Random.</p>
<p>319
00:33:33.400 --&gt; 00:33:37.789
Gabor Szabo: Actually, before that, maybe I should start a Git repository here, right?</p>
<p>320
00:33:39.480 --&gt; 00:33:40.580
Liel: Sure.</p>
<p>321
00:33:42.650 --&gt; 00:33:46.000
Gabor Szabo: And git add… Everything?</p>
<p>322
00:33:47.550 --&gt; 00:33:53.050
Liel: Yeah, it also includes a gitignore, so… We should be fine.</p>
<p>323
00:33:54.910 --&gt; 00:33:55.600
Gabor Szabo: Yeah.</p>
<p>324
00:33:58.630 --&gt; 00:33:59.670
Gabor Szabo: Okay.</p>
<p>325
00:34:01.290 --&gt; 00:34:06.439
Gabor Szabo: So it has this VS Code folder. Why do I need the VS Code folder in the report?</p>
<p>326
00:34:06.440 --&gt; 00:34:08.790
Liel: Probably don't, unless you use VS Code.</p>
<p>327
00:34:09.560 --&gt; 00:34:12.310
Gabor Szabo: I mean, we might, we might use, but, okay.</p>
<p>328
00:34:12.679 --&gt; 00:34:15.870
Gabor Szabo: So, git… let's just git add.</p>
<p>329
00:34:17.530 --&gt; 00:34:18.530
Gabor Szabo: Okay.</p>
<p>330
00:34:23.280 --&gt; 00:34:24.190
Gabor Szabo: Okay.</p>
<p>331
00:34:24.449 --&gt; 00:34:29.920
Gabor Szabo: then I'm going to push it out, everything to a repository later on, okay? But for now… Okay.</p>
<p>332
00:34:30.100 --&gt; 00:34:30.730
Gabor Szabo: We are not…</p>
<p>333
00:34:30.739 --&gt; 00:34:33.609
Liel: Probably won't be changing that much, but, sure.</p>
<p>334
00:34:34.199 --&gt; 00:34:34.989
Gabor Szabo: Okay.</p>
<p>335
00:34:36.260 --&gt; 00:34:41.829
Liel: now it's npm run dev, so space between every word.</p>
<p>336
00:34:44.400 --&gt; 00:34:48.100
Liel: Oh, that just runs the front end.</p>
<p>337
00:34:50.360 --&gt; 00:34:51.250
Gabor Szabo: Okay.</p>
<p>338
00:34:52.239 --&gt; 00:34:53.469
Gabor Szabo: Should I visit it?</p>
<p>339
00:34:54.530 --&gt; 00:34:58.359
Liel: Sure, let's visit it, just to see what it looks like.</p>
<p>340
00:34:58.360 --&gt; 00:34:59.989
Gabor Szabo: The one for…</p>
<p>341
00:35:08.970 --&gt; 00:35:09.950
Gabor Szabo: Okay.</p>
<p>342
00:35:10.630 --&gt; 00:35:15.410
Liel: Yeah, that's, like, a simple app. The grid won't work.</p>
<p>343
00:35:15.990 --&gt; 00:35:21.689
Liel: But now let's return to the terminal, and and actually run the…</p>
<p>344
00:35:21.860 --&gt; 00:35:27.129
Liel: Yeah, it won't work, and you will probably see an error in the console if you open it.</p>
<p>345
00:35:29.410 --&gt; 00:35:31.219
Liel: Here, the browser console.</p>
<p>346
00:35:31.220 --&gt; 00:35:32.410
Gabor Szabo: Yeah. Okay.</p>
<p>347
00:35:32.410 --&gt; 00:35:46.670
Liel: cannot access because you don't have that. So, yeah, that's, like, a nice tip, too. You can check for that window.underscore underscore tori internals underscore underscore. If you have an app that you'd like to work</p>
<p>348
00:35:47.000 --&gt; 00:35:50.260
Liel: Either in the browser or in Tori, so you can…</p>
<p>349
00:35:50.490 --&gt; 00:35:53.619
Liel: Like, have the best of both worlds, and have called that…</p>
<p>350
00:35:56.880 --&gt; 00:35:57.620
Gabor Szabo: Okay?</p>
<p>351
00:35:58.080 --&gt; 00:36:01.320
Liel: And do that. Let's go back to the terminal, and…</p>
<p>352
00:36:02.290 --&gt; 00:36:04.949
Liel: Yeah, let's scale the process.</p>
<p>353
00:36:05.600 --&gt; 00:36:09.069
Gabor Szabo: Will it not restart, reload, restart, if I make a change?</p>
<p>354
00:36:09.070 --&gt; 00:36:13.429
Liel: We will just, Ctrl-C it, because we need a different one, so…</p>
<p>355
00:36:13.840 --&gt; 00:36:18.300
Liel: Instead of npm run dev, we need just the word Tory between run and dev.</p>
<p>356
00:36:24.130 --&gt; 00:36:24.740
Gabor Szabo: This?</p>
<p>357
00:36:24.950 --&gt; 00:36:25.580
Liel: Yeah.</p>
<p>358
00:36:25.890 --&gt; 00:36:29.100
Liel: That should… Ron Tory.</p>
<p>359
00:36:32.250 --&gt; 00:36:33.190
Liel: Okay, so…</p>
<p>360
00:36:33.190 --&gt; 00:36:33.850
Gabor Szabo: Hmm?</p>
<p>361
00:36:33.850 --&gt; 00:36:36.039
Liel: It built it, now it builds.</p>
<p>362
00:36:40.100 --&gt; 00:36:41.040
Liel: the app.</p>
<p>363
00:36:47.050 --&gt; 00:36:48.170
Gabor Szabo: It takes time.</p>
<p>364
00:36:51.380 --&gt; 00:36:54.979
Liel: Oh, so apparently some packages are missing?</p>
<p>365
00:36:54.980 --&gt; 00:36:55.910
Gabor Szabo: Oh, sorry.</p>
<p>366
00:36:56.260 --&gt; 00:37:01.630
Gabor Szabo: Just wanted to see how much it takes, how long… how much…</p>
<p>367
00:37:03.450 --&gt; 00:37:06.900
Gabor Szabo: Okay, whatever. Just wanted to look at my CPUs. Okay.</p>
<p>368
00:37:07.090 --&gt; 00:37:07.670
Liel: Oh.</p>
<p>369
00:37:08.850 --&gt; 00:37:11.920
Liel: Oh, okay, so on Ubuntu, it…</p>
<p>370
00:37:11.920 --&gt; 00:37:12.730
Gabor Szabo: Yeah.</p>
<p>371
00:37:12.730 --&gt; 00:37:14.000
Liel: How you're running it?</p>
<p>372
00:37:14.430 --&gt; 00:37:15.550
Liel: Ubuntu?</p>
<p>373
00:37:15.550 --&gt; 00:37:16.140
Gabor Szabo: Yeah.</p>
<p>374
00:37:16.520 --&gt; 00:37:18.339
Liel: So please install this.</p>
<p>375
00:37:32.640 --&gt; 00:37:36.209
Liel: Okay, that's great, and now let's try that again.</p>
<p>376
00:37:36.590 --&gt; 00:37:39.070
Liel: Hopefully, it will build this time.</p>
<p>377
00:37:45.480 --&gt; 00:37:47.499
Liel: Yeah, quite a bit of dependencies.</p>
<p>378
00:37:49.870 --&gt; 00:37:50.840
Gabor Szabo: Yeah.</p>
<p>379
00:38:01.640 --&gt; 00:38:03.499
Gabor Szabo: Okay, something is still missing.</p>
<p>380
00:38:03.500 --&gt; 00:38:04.069
Liel: Another one.</p>
<p>381
00:38:04.070 --&gt; 00:38:04.630
Gabor Szabo: grip.</p>
<p>382
00:38:06.330 --&gt; 00:38:09.079
Gabor Szabo: GLIPC… GLIP 2.0.</p>
<p>383
00:38:10.690 --&gt; 00:38:16.390
Liel: Yeah, it probably has… That…</p>
<p>384
00:38:16.700 --&gt; 00:38:21.289
Liel: Wait, it has it in prerequisites… Linux.</p>
<p>385
00:38:25.360 --&gt; 00:38:30.650
Liel: So, I'll post the entire install from the documentation.</p>
<p>386
00:38:32.060 --&gt; 00:38:33.990
Liel: Feels like everything it needs.</p>
<p>387
00:38:35.120 --&gt; 00:38:37.980
Liel: Most of which are probably existing, but</p>
<p>388
00:38:44.040 --&gt; 00:38:48.159
Liel: Yeah, and in general, please don't, like, copy and paste</p>
<p>389
00:38:48.890 --&gt; 00:38:51.330
Liel: Like that, but in this case…</p>
<p>390
00:38:51.330 --&gt; 00:38:52.330
Gabor Szabo: I looked at it.</p>
<p>391
00:38:53.080 --&gt; 00:38:57.049
Gabor Szabo: I mean, if, if… unless there are hidden characters there.</p>
<p>392
00:38:57.360 --&gt; 00:39:02.020
Gabor Szabo: It looked, it looked right, I mean… It's just installing stuff.</p>
<p>393
00:39:05.550 --&gt; 00:39:08.130
Liel: Yeah, I did install JLib, which is nice.</p>
<p>394
00:39:12.910 --&gt; 00:39:15.920
Gabor Szabo: Can you link to where you copied this from?</p>
<p>395
00:39:16.990 --&gt; 00:39:20.440
Gabor Szabo: Yeah, sure, can you insert the link as well? Share the link in the chat?</p>
<p>396
00:39:20.440 --&gt; 00:39:25.129
Liel: It's from the official documentation, I just got… went to work, because it's…</p>
<p>397
00:39:25.700 --&gt; 00:39:29.970
Gabor Szabo: But it's better if I then include that in the final notes.</p>
<p>398
00:39:30.410 --&gt; 00:39:32.049
Gabor Szabo: The link there.</p>
<p>399
00:39:33.590 --&gt; 00:39:37.939
Gabor Szabo: Okay, looks better. Oh, no, actually, that's just the information.</p>
<p>400
00:39:37.940 --&gt; 00:39:48.000
Liel: about creating the app, what is the difference between the command cargo creator app? It's the same thing, just you are using cargo instead of NPM.</p>
<p>401
00:39:49.290 --&gt; 00:39:52.549
Liel: So, you can absolutely use that as well, it's…</p>
<p>402
00:39:53.050 --&gt; 00:39:56.409
Liel: It's essentially the same, whatever you are more comfortable with.</p>
<p>403
00:39:59.960 --&gt; 00:40:02.859
Gabor Szabo: You're responding to this question in the chat, right?</p>
<p>404
00:40:02.860 --&gt; 00:40:04.500
Liel: Yeah, stefano's question.</p>
<p>405
00:40:05.730 --&gt; 00:40:06.350
Gabor Szabo: Yeah.</p>
<p>406
00:40:23.090 --&gt; 00:40:24.260
Liel: Yeah, only.</p>
<p>407
00:40:25.050 --&gt; 00:40:25.970
Liel: demand.</p>
<p>408
00:40:35.310 --&gt; 00:40:41.610
Gabor Szabo: So I wonder what happened since the last time when we ran this. Did I replace my computer? No.</p>
<p>409
00:40:42.930 --&gt; 00:40:44.690
Gabor Szabo: I mean, back then.</p>
<p>410
00:40:44.690 --&gt; 00:40:47.519
Liel: Yeah, it has been a while, so I'm not sure.</p>
<p>411
00:40:48.710 --&gt; 00:40:49.820
Gabor Szabo: Yeah, I don't remember.</p>
<p>412
00:40:49.820 --&gt; 00:41:01.029
Liel: Yeah, now we can see this, and now please type something in the name, and once we go to the grid, it will say… it will actually run the command. Hello for you, you have been greeted.</p>
<p>413
00:41:01.340 --&gt; 00:41:08.509
Liel: from Rust. Now, can you please leave that window, or that tab on the terminal open and open a new one?</p>
<p>414
00:41:08.690 --&gt; 00:41:11.139
Liel: So we can, like, try to edit.</p>
<p>415
00:41:15.030 --&gt; 00:41:16.299
Gabor Szabo: Yeah, you're here.</p>
<p>416
00:41:16.300 --&gt; 00:41:19.469
Liel: Okay, so now, let's go to…</p>
<p>417
00:41:21.240 --&gt; 00:41:23.959
Gabor Szabo: This is just… sorry, just checking this one, yeah?</p>
<p>418
00:41:24.210 --&gt; 00:41:25.290
Liel: Yeah, that's okay.</p>
<p>419
00:41:25.650 --&gt; 00:41:30.540
Liel: I think it's in SRC. Let's first change something in the front end.</p>
<p>420
00:41:35.490 --&gt; 00:41:37.570
Liel: Yeah, let's go to main dot.</p>
<p>421
00:41:37.730 --&gt; 00:41:39.780
Liel: TS, I guess?</p>
<p>422
00:41:40.750 --&gt; 00:41:43.639
Gabor Szabo: Okay? Is it okay if I open it with Vim?</p>
<p>423
00:41:45.060 --&gt; 00:41:46.090
Liel: Yeah, sure.</p>
<p>424
00:41:49.190 --&gt; 00:41:57.540
Liel: Okay, so now we have… that, so you see we defined grid, and on DOMContentLoaded.</p>
<p>425
00:41:57.940 --&gt; 00:41:59.489
Liel: It just does that.</p>
<p>426
00:42:04.530 --&gt; 00:42:12.129
Liel: So… You know what? Let's actually close that file and change something in the HTML.</p>
<p>427
00:42:13.640 --&gt; 00:42:15.330
Gabor Szabo: Okay, which is… which file?</p>
<p>428
00:42:16.840 --&gt; 00:42:20.239
Liel: I think it's in SRC slash assets?</p>
<p>429
00:42:22.190 --&gt; 00:42:25.020
Liel: Haven't done a vanilla one in a while.</p>
<p>430
00:42:26.430 --&gt; 00:42:29.120
Liel: No. So, maybe it's in the root?</p>
<p>431
00:42:33.870 --&gt; 00:42:34.680
Liel: Yeah.</p>
<p>432
00:42:34.680 --&gt; 00:42:36.229
Gabor Szabo: There's an index extremely.</p>
<p>433
00:42:36.230 --&gt; 00:42:37.950
Liel: edit index.html.</p>
<p>434
00:42:45.120 --&gt; 00:42:47.340
Gabor Szabo: So this is going to be this window, right?</p>
<p>435
00:42:47.340 --&gt; 00:42:57.370
Liel: I just checked the capstone… Yeah, so there is a hot reload, so yeah, you can change… Whatever.</p>
<p>436
00:43:02.890 --&gt; 00:43:08.000
Gabor Szabo: Okay, and I didn't do anything reload, any reloading, it automatically reloaded, nice.</p>
<p>437
00:43:09.470 --&gt; 00:43:21.989
Liel: Yeah, that's very nice. A really great developer experience. Now let's go and change something in the RAS code. So, let's close that, and it's in the SRC-tower.</p>
<p>438
00:43:30.410 --&gt; 00:43:32.560
Gabor Szabo: Which file shall I open? The main orderly?</p>
<p>439
00:43:37.050 --&gt; 00:43:42.399
Liel: Lib. Main is just like a thin wrapper. The code is actually in Lib RS.</p>
<p>440
00:43:51.040 --&gt; 00:43:53.139
Gabor Szabo: Hmm. Why did it come up?</p>
<p>441
00:43:53.610 --&gt; 00:43:54.970
Gabor Szabo: What happened to it?</p>
<p>442
00:43:59.570 --&gt; 00:44:00.799
Gabor Szabo: It's suddenly showing down.</p>
<p>443
00:44:00.800 --&gt; 00:44:02.630
Liel: We've done the squad.</p>
<p>444
00:44:05.100 --&gt; 00:44:06.169
Gabor Szabo: Okay, what should I do?</p>
<p>445
00:44:10.440 --&gt; 00:44:16.989
Liel: Let's change the message on line 4 to something. Greeted from Rasmans, let's say, yeah.</p>
<p>446
00:44:17.500 --&gt; 00:44:21.340
Liel: And note that when he saved, it.</p>
<p>447
00:44:23.170 --&gt; 00:44:23.820
Gabor Szabo: Group?</p>
<p>448
00:44:24.790 --&gt; 00:44:25.380
Liel: Yeah.</p>
<p>449
00:44:25.540 --&gt; 00:44:26.370
Liel: What?</p>
<p>450
00:44:26.910 --&gt; 00:44:28.230
Liel: Let's try it.</p>
<p>451
00:44:30.790 --&gt; 00:44:31.880
Gabor Szabo: Let's do this one.</p>
<p>452
00:44:31.880 --&gt; 00:44:34.810
Liel: Okay, so you didn't save it yet. Note.</p>
<p>453
00:44:34.810 --&gt; 00:44:37.610
Gabor Szabo: Oh, I think it's… oh, I didn't save it, sorry, yeah.</p>
<p>454
00:44:38.060 --&gt; 00:44:38.780
Liel: Yeah, please.</p>
<p>455
00:44:41.220 --&gt; 00:44:42.100
Gabor Szabo: Sorry.</p>
<p>456
00:44:43.140 --&gt; 00:44:43.460
Liel: Yeah.</p>
<p>457
00:44:43.460 --&gt; 00:44:44.339
Gabor Szabo: There is a little bit.</p>
<p>458
00:44:44.340 --&gt; 00:44:45.300
Liel: But,</p>
<p>459
00:44:45.590 --&gt; 00:44:56.230
Liel: Whenever you change the last code, it triggers a rebuild, and yeah, now it reopened the window, so it's a slightly less nice developer experience.</p>
<p>460
00:44:57.460 --&gt; 00:44:58.070
Gabor Szabo: Yeah.</p>
<p>461
00:44:58.430 --&gt; 00:45:00.290
Gabor Szabo: But it's here. Okay.</p>
<p>462
00:45:00.580 --&gt; 00:45:01.529
Liel: Yeah, it's true.</p>
<p>463
00:45:02.010 --&gt; 00:45:04.760
Liel: So, that's the demo.</p>
<p>464
00:45:05.760 --&gt; 00:45:16.939
Liel: And yeah, with a few additional steps, and the… you can also do that for mobile, but we won't do that in here, because it's… it can be quite heavy, whereas either</p>
<p>465
00:45:18.620 --&gt; 00:45:21.419
Liel: iOS we can do on Linux, and</p>
<p>466
00:45:22.170 --&gt; 00:45:29.040
Liel: Android, it requires all the SDK stuff, which I don't want to waste time downloading.</p>
<p>467
00:45:31.370 --&gt; 00:45:32.820
Liel: So, that's that.</p>
<p>468
00:45:33.250 --&gt; 00:45:41.180
Liel: And I think that's, like, the basic demo, and that would be it. Thanks.</p>
<p>469
00:45:41.620 --&gt; 00:45:43.839
Gabor Szabo: Okay. Shall I close everything?</p>
<p>470
00:45:44.840 --&gt; 00:45:45.430
Liel: Yep.</p>
<p>471
00:45:53.850 --&gt; 00:45:55.649
Gabor Szabo: Stop the sharing?</p>
<p>472
00:45:56.960 --&gt; 00:45:57.620
Liel: No.</p>
<p>473
00:45:58.220 --&gt; 00:45:58.910
Gabor Szabo: Okay, alright.</p>
<p>474
00:45:59.140 --&gt; 00:46:00.230
Liel: Hooray.</p>
<p>475
00:46:00.530 --&gt; 00:46:01.400
Liel: Yeah.</p>
<p>476
00:46:01.540 --&gt; 00:46:08.080
Liel: I'll just share again, where is it? Portion of screen, and it stopped your very long.</p>
<p>477
00:46:08.080 --&gt; 00:46:11.949
Gabor Szabo: You can look, you can… you can steal my sharing! Oh, I didn't know that.</p>
<p>478
00:46:13.190 --&gt; 00:46:14.280
Gabor Szabo: Okay.</p>
<p>479
00:46:14.280 --&gt; 00:46:14.930
Liel: Yeah.</p>
<p>480
00:46:15.120 --&gt; 00:46:16.730
Liel: So that's the basics.</p>
<p>481
00:46:17.660 --&gt; 00:46:26.539
Liel: And… As a product, the only way to communicate from the UI to the application core is via</p>
<p>482
00:46:27.980 --&gt; 00:46:32.020
Liel: Or, it should be message passing.</p>
<p>483
00:46:32.260 --&gt; 00:46:39.800
Liel: It isn't, like, actual… Actual, function call between the two.</p>
<p>484
00:46:40.320 --&gt; 00:46:45.120
Liel: From the front-end perspective, all it does is a fetch call.</p>
<p>485
00:46:46.240 --&gt; 00:46:53.930
Liel: like, the window.underscore underscore internals. What it does, you can also see it in the WorkPro, is, like, must fetch.</p>
<p>486
00:46:59.750 --&gt; 00:47:04.899
Liel: So… Sorry, I did say it here, so it's done.</p>
<p>487
00:47:05.170 --&gt; 00:47:15.049
Liel: Message pressing, and each message is also known as a command, as we say. Permissions allow us to filter what we can and cannot do.</p>
<p>488
00:47:15.350 --&gt; 00:47:16.830
Liel: in each command.</p>
<p>489
00:47:19.330 --&gt; 00:47:26.129
Liel: And we also can scope them. For example, if we have a file system plugin, and we don't want it to…</p>
<p>490
00:47:26.300 --&gt; 00:47:29.630
Liel: Access anything beyond the home folder, we can do that.</p>
<p>491
00:47:30.330 --&gt; 00:47:34.610
Liel: So, how it's done is we have, like, a TOML file.</p>
<p>492
00:47:36.690 --&gt; 00:47:41.309
Liel: And, yeah. In here, let's say the identifier.</p>
<p>493
00:47:41.580 --&gt; 00:47:44.109
Liel: is my identifier.</p>
<p>494
00:47:44.270 --&gt; 00:47:59.460
Liel: The commands that are allowed for this particular plugin are read file, and it only allows home, and we can also say, like, we don't want home secret, or that could be your home slash dot SSH</p>
<p>495
00:47:59.970 --&gt; 00:48:04.329
Liel: Folder, since you don't want the app to read your private key.</p>
<p>496
00:48:06.170 --&gt; 00:48:18.999
Liel: And regarding the dollar home, I also found, like, unfortunately, I haven't found it in the documentation yet, but I found where it comes from.</p>
<p>497
00:48:19.380 --&gt; 00:48:21.019
Liel: in the…</p>
<p>498
00:48:22.260 --&gt; 00:48:35.050
Liel: code itself. So, yeah, it's in here, you have many, like, audio cache config, some of which are platform-specific, or some of which aren't available in Android, for example.</p>
<p>499
00:48:35.510 --&gt; 00:48:36.620
Liel: Those ones?</p>
<p>500
00:48:40.980 --&gt; 00:48:44.130
Liel: And in case it doesn't find…</p>
<p>501
00:48:44.840 --&gt; 00:48:48.960
Liel: Then… it just doesn't substitute, so it…</p>
<p>502
00:48:49.250 --&gt; 00:48:53.309
Liel: Just, let's say, Dollar Gabor Gabor, or Dollar Liel.</p>
<p>503
00:48:53.420 --&gt; 00:48:57.969
Liel: It won't find it here, so it just will leave it at all real.</p>
<p>504
00:49:04.610 --&gt; 00:49:09.170
Liel: That's that, and on top of permissions, we have capabilities.</p>
<p>505
00:49:10.340 --&gt; 00:49:15.419
Liel: Which… Allow us to, like, set permissions?</p>
<p>506
00:49:16.180 --&gt; 00:49:18.569
Liel: Per window label.</p>
<p>507
00:49:19.310 --&gt; 00:49:21.870
Liel: So, label isn't the window writer?</p>
<p>508
00:49:25.460 --&gt; 00:49:29.150
Liel: But… It's…</p>
<p>509
00:49:30.280 --&gt; 00:49:38.920
Liel: something else you can tell, like, in this case, I don't think… or we just tell it to be specifically for main.</p>
<p>510
00:49:39.280 --&gt; 00:49:41.680
Liel: We can also restrict it by platform.</p>
<p>511
00:49:43.550 --&gt; 00:49:50.839
Liel: And so on. So at this point, you might ask, okay, so… but what does it protect against? Why do we need it?</p>
<p>512
00:49:51.290 --&gt; 00:49:54.729
Liel: So, it depends on which permission capability, but…</p>
<p>513
00:49:55.450 --&gt; 00:49:59.720
Liel: In case the front end is compromised, so let's say…</p>
<p>514
00:50:00.640 --&gt; 00:50:03.720
Liel: let's say I, as an adversarial.</p>
<p>515
00:50:04.790 --&gt; 00:50:07.790
Liel: Somehow managed to take over the front end?</p>
<p>516
00:50:10.070 --&gt; 00:50:14.030
Liel: it allows to limit how much damage I can do.</p>
<p>517
00:50:16.250 --&gt; 00:50:21.850
Liel: Or the file system is a great example, because if we read files.</p>
<p>518
00:50:22.060 --&gt; 00:50:30.079
Liel: We might just want to make sure that the application cannot read anything it's not supposed to, even</p>
<p>519
00:50:30.500 --&gt; 00:50:35.350
Liel: If, like, we control the code, I would still like to have that.</p>
<p>520
00:50:36.590 --&gt; 00:50:40.230
Liel: Additional filter, in case someone takes over.</p>
<p>521
00:50:45.780 --&gt; 00:50:53.729
Liel: Unfortunately, it doesn't protect us against code that's malicious inside the RAT.</p>
<p>522
00:50:55.420 --&gt; 00:50:59.900
Liel: portion of our office, because that runs directly the core process.</p>
<p>523
00:51:08.240 --&gt; 00:51:16.680
Liel: And also, it doesn't protect us from anything else, like, if we don't define the permissions correctly, or if we don't…</p>
<p>524
00:51:16.850 --&gt; 00:51:19.769
Liel: like… Make sure to check them.</p>
<p>525
00:51:20.610 --&gt; 00:51:26.080
Liel: then… Or we bypass their checks somewhere?</p>
<p>526
00:51:26.340 --&gt; 00:51:29.850
Liel: then, tori want.</p>
<p>527
00:51:30.130 --&gt; 00:51:31.739
Liel: won't protect us.</p>
<p>528
00:51:32.640 --&gt; 00:51:38.760
Liel: The capabilities can be also defined in JSON, but permissions are… Strictly tunnel.</p>
<p>529
00:51:43.290 --&gt; 00:51:57.950
Liel: There is also one more… Possibility for filtering commands before they reach the core process, And we'll…</p>
<p>530
00:51:58.790 --&gt; 00:52:01.620
Liel: We'll take, like, a little look at that.</p>
<p>531
00:52:01.740 --&gt; 00:52:08.669
Liel: So, what we've discussed… we've discussed so far is called the brownfield pattern for communication.</p>
<p>532
00:52:08.920 --&gt; 00:52:18.530
Liel: And, yeah, it basically just forwards the… each command we send to the core, and then the core handles it.</p>
<p>533
00:52:19.680 --&gt; 00:52:23.919
Liel: It still limits misuse, but we can do better if we want to.</p>
<p>534
00:52:24.920 --&gt; 00:52:31.159
Liel: there is an isolation pattern, which is basically yet another JavaScript program we run.</p>
<p>535
00:52:32.360 --&gt; 00:52:36.730
Liel: that… Does introduce some overhead.</p>
<p>536
00:52:38.010 --&gt; 00:52:41.630
Liel: But it allows us to filter</p>
<p>537
00:52:42.790 --&gt; 00:52:46.939
Liel: Before it even reaches the Rust core, if you wish to.</p>
<p>538
00:52:48.900 --&gt; 00:52:57.019
Liel: So, it's basically another layer that… Sits between the… Webflow and the core.</p>
<p>539
00:53:06.840 --&gt; 00:53:14.850
Liel: So, I think I talked about it a little bit before, but there are quite a lot of plugins that allow us to</p>
<p>540
00:53:15.000 --&gt; 00:53:16.940
Liel: have… sound function.</p>
<p>541
00:53:24.780 --&gt; 00:53:27.550
Gabor Szabo: Your voice disappeared? Yeah?</p>
<p>542
00:53:32.590 --&gt; 00:53:35.790
Gabor Szabo: Okay… Something happened?</p>
<p>543
00:53:40.530 --&gt; 00:53:41.680
Gabor Szabo: Clear?</p>
<p>544
00:53:47.450 --&gt; 00:53:51.970
Gabor Szabo: Europe… Okay, you seem to be back now?</p>
<p>545
00:53:51.970 --&gt; 00:53:57.200
Liel: Yeah, but I was mute, I was sound… Yeah.</p>
<p>546
00:53:57.420 --&gt; 00:53:58.820
Liel: Oh, wow, thanks.</p>
<p>547
00:53:59.100 --&gt; 00:54:01.780
Liel: Now… Now, do you hear me?</p>
<p>548
00:54:02.090 --&gt; 00:54:03.529
Gabor Szabo: Yeah, I can hear you now.</p>
<p>549
00:54:03.910 --&gt; 00:54:05.860
Liel: Okay, that's great.</p>
<p>550
00:54:06.630 --&gt; 00:54:07.859
Liel: So, yeah.</p>
<p>551
00:54:08.020 --&gt; 00:54:11.239
Liel: Plugins provide some functionality.</p>
<p>552
00:54:11.770 --&gt; 00:54:13.030
Liel: Out of the box.</p>
<p>553
00:54:13.140 --&gt; 00:54:16.200
Liel: So you don't need to, like, write it yourself.</p>
<p>554
00:54:17.100 --&gt; 00:54:20.289
Liel: Some of them can be used from Rust as well.</p>
<p>555
00:54:20.400 --&gt; 00:54:25.090
Liel: And some examples are for logging, and some deep links.</p>
<p>556
00:54:26.020 --&gt; 00:54:34.210
Liel: So, DeepLinks allows us to set the app as a default handler for some protocol. So, let's say,</p>
<p>557
00:54:35.380 --&gt; 00:54:37.330
Liel: Code Mavens.</p>
<p>558
00:54:37.990 --&gt; 00:54:45.400
Liel: Or, yeah, call Mavens.com slash. If we want that, we can make sure that</p>
<p>559
00:54:46.280 --&gt; 00:54:48.639
Liel: It opens those links in our app.</p>
<p>560
00:54:50.340 --&gt; 00:54:53.240
Liel: Oh, and yeah.</p>
<p>561
00:54:56.320 --&gt; 00:54:59.769
Liel: Sorry, there was a little question in the chat, I'll answer that shortly.</p>
<p>562
00:55:01.550 --&gt; 00:55:09.439
Liel: And, yeah, so that's what DeepLink is for. Of course, the operating system just,</p>
<p>563
00:55:09.980 --&gt; 00:55:15.319
Liel: Or it asks if we are okay with opening these links in our app.</p>
<p>564
00:55:17.110 --&gt; 00:55:25.789
Liel: And there is the dialog plugin, and there's a lot more. So there is a list of all official plugins, and there's awesome directory for other links.</p>
<p>565
00:55:26.100 --&gt; 00:55:27.180
Liel: we can use.</p>
<p>566
00:55:35.310 --&gt; 00:55:45.610
Liel: We can also warp an existing project, so… For the second demo, What we'll do… is…</p>
<p>567
00:55:46.380 --&gt; 00:55:50.870
Liel: I have a little app which I have done the front end for.</p>
<p>568
00:55:51.020 --&gt; 00:55:53.569
Liel: And I'll extend it as a Tory app.</p>
<p>569
00:56:00.330 --&gt; 00:56:03.129
Liel: For distribution and packaging.</p>
<p>570
00:56:03.380 --&gt; 00:56:08.159
Liel: That's, like, the only thing before the demo.</p>
<p>571
00:56:09.660 --&gt; 00:56:16.390
Liel: I'd like to point out that it does support generating packages, but you can do, like.</p>
<p>572
00:56:17.040 --&gt; 00:56:20.590
Liel: You know, generate for different platforms.</p>
<p>573
00:56:22.710 --&gt; 00:56:27.599
Liel: So, for example, if I'm on a Mac, I can generate for a Mac.</p>
<p>574
00:56:28.940 --&gt; 00:56:35.249
Liel: And that's it. Or maybe if I spawn a virtual machine, then I can</p>
<p>575
00:56:35.630 --&gt; 00:56:39.349
Liel: do, like, Linux, and potentially Windows.</p>
<p>576
00:56:39.560 --&gt; 00:56:45.639
Liel: But I need, like, A native runner to do for each platform.</p>
<p>577
00:56:46.070 --&gt; 00:56:52.509
Liel: So you can get around that with CI. There is, like, an official Tory tab auction, which does that.</p>
<p>578
00:56:53.780 --&gt; 00:57:03.740
Liel: And again, there is the documentation for following AVIs. I think there is one experimental use case that allows</p>
<p>579
00:57:04.680 --&gt; 00:57:07.860
Liel: from, I think, Mac to Linux?</p>
<p>580
00:57:10.330 --&gt; 00:57:14.210
Liel: But, you know, that's not stable, at least.</p>
<p>581
00:57:14.780 --&gt; 00:57:15.890
Liel: right now.</p>
<p>582
00:57:19.010 --&gt; 00:57:19.940
Liel: Okay.</p>
<p>583
00:57:20.540 --&gt; 00:57:24.149
Liel: And… now we have the demo!</p>
<p>584
00:57:26.230 --&gt; 00:57:33.140
Liel: So, let me enlarge the… Screen a little bit…</p>
<p>585
00:57:33.790 --&gt; 00:57:37.960
Liel: And, yeah, let's do it like that, and… Like that.</p>
<p>586
00:57:39.660 --&gt; 00:57:46.610
Liel: So, let me first open… Z, which is my editor first.</p>
<p>587
00:57:49.190 --&gt; 00:57:53.539
Liel: I've prepared a little app, in this case it will be a little clipboard manager.</p>
<p>588
00:57:55.790 --&gt; 00:58:02.410
Liel: So, let's see how it looks. It will look a little bit differently, because…</p>
<p>589
00:58:02.600 --&gt; 00:58:10.089
Liel: what happens is that I want it to be a little transparent, and it's not possible in the web browser, but in Tori it is.</p>
<p>590
00:58:10.560 --&gt; 00:58:12.879
Liel: So what we'll do is npm run them.</p>
<p>591
00:58:14.940 --&gt; 00:58:17.170
Liel: And once we go to that…</p>
<p>592
00:58:17.760 --&gt; 00:58:31.279
Liel: We see that we have, like, two objects. These are, like, mock data. I will replace that with data we'll receive from an event. And once I click on something, I'd like it to be copied.</p>
<p>593
00:58:36.570 --&gt; 00:58:38.660
Liel: Okay, so that's that.</p>
<p>594
00:58:39.660 --&gt; 00:58:42.660
Liel: I'll leave their web browser just in case.</p>
<p>595
00:58:43.970 --&gt; 00:58:47.430
Liel: I will… Poppy.</p>
<p>596
00:58:48.560 --&gt; 00:58:49.850
Liel: this folder.</p>
<p>597
00:58:50.500 --&gt; 00:58:52.670
Liel: into another…</p>
<p>598
00:58:57.550 --&gt; 00:58:58.350
Liel: Peace.</p>
<p>599
00:58:58.720 --&gt; 00:59:02.390
Liel: In my products folder, with my colleague.</p>
<p>600
00:59:07.220 --&gt; 00:59:08.819
Liel: Let's copy that.</p>
<p>601
00:59:09.400 --&gt; 00:59:13.730
Liel: And let's… Move to that folder.</p>
<p>602
00:59:18.750 --&gt; 00:59:19.560
Liel: Yeah.</p>
<p>603
00:59:19.880 --&gt; 00:59:23.450
Liel: That's that, and… Sorry?</p>
<p>604
00:59:23.570 --&gt; 00:59:28.699
Liel: Trust. Trust and continue, and now… We have that folder.</p>
<p>605
00:59:29.060 --&gt; 00:59:35.350
Liel: And here… So, one caveat I did notice is that sometimes the node modules</p>
<p>606
00:59:35.980 --&gt; 00:59:41.210
Liel: isn't working right, so… let's do our… mode. Module?</p>
<p>607
00:59:42.070 --&gt; 00:59:45.279
Liel: and NPMI to install.</p>
<p>608
00:59:45.780 --&gt; 00:59:46.940
Liel: Everything, yeah.</p>
<p>609
00:59:47.850 --&gt; 00:59:51.110
Liel: So it's 5173, we need that.</p>
<p>610
01:00:04.430 --&gt; 01:00:11.410
Liel: For… yeah. Okay, so we did that, which is great. Now, I think it's cargo authority in it.</p>
<p>611
01:00:13.320 --&gt; 01:00:16.140
Liel: And the app name is Clipman, that's right.</p>
<p>612
01:00:16.690 --&gt; 01:00:19.180
Liel: Let's do a capital letter.</p>
<p>613
01:00:19.660 --&gt; 01:00:26.300
Liel: web assets, it's correctly in this. And the fourth… 5173.</p>
<p>614
01:00:26.630 --&gt; 01:00:27.959
Liel: That's for him.</p>
<p>615
01:00:29.310 --&gt; 01:00:31.769
Liel: NPM run dev, npm run build…</p>
<p>616
01:00:32.210 --&gt; 01:00:36.370
Liel: Everything is right, now we can see we have SRC total.</p>
<p>617
01:00:36.880 --&gt; 01:00:43.070
Liel: which has the Torikov JSON, And the Libaris, as we saw earlier.</p>
<p>618
01:00:44.020 --&gt; 01:00:48.420
Liel: Just, like, it doesn't register a command in here right now.</p>
<p>619
01:00:52.540 --&gt; 01:00:55.390
Liel: So now I can run to Dev.</p>
<p>620
01:01:00.870 --&gt; 01:01:03.579
Liel: Cargo, then, in this case?</p>
<p>621
01:01:11.080 --&gt; 01:01:11.820
Liel: Yeah.</p>
<p>622
01:01:12.830 --&gt; 01:01:15.250
Liel: Now, it's running.</p>
<p>623
01:01:17.070 --&gt; 01:01:18.380
Liel: everything here…</p>
<p>624
01:01:23.920 --&gt; 01:01:25.760
Liel: It will take a little while.</p>
<p>625
01:01:26.890 --&gt; 01:01:36.179
Liel: And while it does that, let's add some settings so we can… Have it transparent.</p>
<p>626
01:01:37.480 --&gt; 01:01:41.579
Liel: Sure, there is another setting specifically for Mac.</p>
<p>627
01:01:42.160 --&gt; 01:01:44.910
Liel: Mac OS Private API, true.</p>
<p>628
01:01:45.030 --&gt; 01:01:50.680
Liel: Note that, in this case, you can't upload it to the App Store, because… FO.</p>
<p>629
01:01:51.020 --&gt; 01:01:52.640
Liel: Kinda hates devs.</p>
<p>630
01:01:52.780 --&gt; 01:01:57.740
Liel: I guess… Sorry, I had to grab the tissue.</p>
<p>631
01:02:05.650 --&gt; 01:02:10.010
Liel: Yeah, that build, and now you can see it is transparent.</p>
<p>632
01:02:10.460 --&gt; 01:02:12.010
Liel: Which isn't nice.</p>
<p>633
01:02:16.270 --&gt; 01:02:20.399
Liel: Yeah, I thought it would look nicer, but</p>
<p>634
01:02:20.960 --&gt; 01:02:23.379
Liel: Yeah, that's okay for the demo.</p>
<p>635
01:02:27.890 --&gt; 01:02:30.520
Liel: We can always tweak it later.</p>
<p>636
01:02:32.880 --&gt; 01:02:42.309
Liel: Now… For an actual clipboard to function, we need a library that accesses the clipboard.</p>
<p>637
01:02:42.700 --&gt; 01:02:45.209
Liel: So, there is one called Our Board.</p>
<p>638
01:02:45.920 --&gt; 01:02:47.819
Liel: Which is nice.</p>
<p>639
01:02:49.270 --&gt; 01:02:59.700
Liel: But, also wrapped in… Or Cargo Tari ad, yeah, in a plug called Clipboard Manager.</p>
<p>640
01:03:00.390 --&gt; 01:03:13.550
Liel: it uses our board internally, and I'd just like to show you how easy it is to install any plugin. And if you check out the Libra S, you see that it already</p>
<p>641
01:03:13.760 --&gt; 01:03:17.089
Liel: edit that. So, it's really nice.</p>
<p>642
01:03:18.030 --&gt; 01:03:20.950
Liel: Let's now do a cargo. Dev?</p>
<p>643
01:03:22.300 --&gt; 01:03:27.389
Liel: So we can have Vlad in place.</p>
<p>644
01:03:31.830 --&gt; 01:03:34.899
Liel: Yeah, by the way, this is a live demo, so…</p>
<p>645
01:03:35.580 --&gt; 01:03:43.639
Liel: Hopefully, everything goes right, but it can go wrong, and hopefully, in this case, you could learn from that too.</p>
<p>646
01:03:45.880 --&gt; 01:03:56.090
Liel: Okay, so inside the setup, Debug assertions, that's okay, that's… That just allows us to… Long?</p>
<p>647
01:03:58.690 --&gt; 01:04:02.000
Liel: And in here, Elm… app.</p>
<p>648
01:04:02.490 --&gt; 01:04:03.340
Liel: Don't.</p>
<p>649
01:04:06.680 --&gt; 01:04:13.499
Liel: handle… that will be the app handle, and what we need is storage, yeah.</p>
<p>650
01:04:13.740 --&gt; 01:04:16.740
Liel: A sync runtime, which is okay.</p>
<p>651
01:04:18.180 --&gt; 01:04:19.190
Liel: Spawn?</p>
<p>652
01:04:21.710 --&gt; 01:04:23.130
Liel: And…</p>
<p>653
01:04:28.240 --&gt; 01:04:35.790
Liel: Let's do… no, let's do spawn blocking, because we might block the executor. Unfortunately, the…</p>
<p>654
01:04:36.080 --&gt; 01:04:41.880
Liel: The way the people library works is that we listen for an event, and it might block.</p>
<p>655
01:04:42.180 --&gt; 01:04:50.480
Liel: So… I want to… With that…</p>
<p>656
01:05:01.990 --&gt; 01:05:04.139
Liel: Spawn blocking…</p>
<p>657
01:05:13.370 --&gt; 01:05:16.480
Liel: Maybe just that. Yeah, broadly just that.</p>
<p>658
01:05:17.100 --&gt; 01:05:20.649
Liel: So, in this case, we want… To run in a loop.</p>
<p>659
01:05:21.880 --&gt; 01:05:28.820
Liel: And we need the app handle, so let's… handle?</p>
<p>660
01:05:29.300 --&gt; 01:05:32.920
Liel: app.handle, and we can also clone it.</p>
<p>661
01:05:33.120 --&gt; 01:05:42.920
Liel: Internally, it uses an arc, an atomic reference counter, so that's relatively cheap. It's not free, but it should be okay.</p>
<p>662
01:05:45.440 --&gt; 01:05:49.690
Liel: app. Handle.clip.</p>
<p>663
01:05:50.390 --&gt; 01:05:51.370
Liel: Bird?</p>
<p>664
01:05:52.330 --&gt; 01:05:53.290
Liel: dot.</p>
<p>665
01:05:53.520 --&gt; 01:05:55.130
Liel: Read text.</p>
<p>666
01:05:59.820 --&gt; 01:06:02.520
Liel: So, this returns a result.</p>
<p>667
01:06:06.030 --&gt; 01:06:08.290
Liel: Let's match on that.</p>
<p>668
01:06:11.560 --&gt; 01:06:12.780
Liel: Okay.</p>
<p>669
01:06:14.080 --&gt; 01:06:16.069
Liel: Text.</p>
<p>670
01:06:16.920 --&gt; 01:06:17.969
Liel: Do that.</p>
<p>671
01:06:18.170 --&gt; 01:06:19.270
Liel: Error…</p>
<p>672
01:06:24.540 --&gt; 01:06:30.979
Liel: Let's just do, or… Sorry. Login. Login?</p>
<p>673
01:06:39.290 --&gt; 01:06:40.599
Liel: Love it done.</p>
<p>674
01:06:42.660 --&gt; 01:06:43.530
Liel: Sure.</p>
<p>675
01:06:49.150 --&gt; 01:06:51.620
Liel: And this is probably tracing.</p>
<p>676
01:06:55.040 --&gt; 01:07:00.110
Liel: So, let's do… Who is not.</p>
<p>677
01:07:01.920 --&gt; 01:07:03.309
Liel: Pick text.</p>
<p>678
01:07:03.580 --&gt; 01:07:12.639
Liel: Or, you know what? I'm not sure that's a good idea, because that can potentially just flood our laws with</p>
<p>679
01:07:13.230 --&gt; 01:07:17.350
Liel: That, so let's… Put that in a comment for now.</p>
<p>680
01:07:17.500 --&gt; 01:07:20.130
Liel: And in here, let's do app.</p>
<p>681
01:07:20.650 --&gt; 01:07:21.680
Liel: Candle?</p>
<p>682
01:07:23.340 --&gt; 01:07:24.070
Liel: Oh.</p>
<p>683
01:07:24.380 --&gt; 01:07:26.590
Liel: That needs to go to the side.</p>
<p>684
01:07:26.930 --&gt; 01:07:28.510
Liel: Handle. Dot.</p>
<p>685
01:07:29.500 --&gt; 01:07:30.550
Liel: Commit.</p>
<p>686
01:07:32.120 --&gt; 01:07:33.689
Liel: And… yeah.</p>
<p>687
01:07:34.520 --&gt; 01:07:35.480
Liel: Text.</p>
<p>688
01:07:37.750 --&gt; 01:07:38.860
Liel: profit?</p>
<p>689
01:07:39.530 --&gt; 01:07:42.629
Liel: And the payload, we are just our text.</p>
<p>690
01:07:49.740 --&gt; 01:07:51.350
Liel: Okay, apparently.</p>
<p>691
01:07:52.030 --&gt; 01:07:54.550
Liel: It also leads to a result.</p>
<p>692
01:07:54.960 --&gt; 01:07:58.229
Liel: But I can ignore that for the sake of the demo.</p>
<p>693
01:08:00.320 --&gt; 01:08:05.870
Liel: And yeah, it's quite annoying that… It…</p>
<p>694
01:08:06.080 --&gt; 01:08:10.090
Liel: Restartes every time, but, yeah.</p>
<p>695
01:08:11.350 --&gt; 01:08:14.340
Liel: At least there is some kind of utter loading.</p>
<p>696
01:08:14.570 --&gt; 01:08:18.429
Liel: Hopefully, they make that even better in the future.</p>
<p>697
01:08:19.100 --&gt; 01:08:21.340
Liel: So, in rapp.</p>
<p>698
01:08:21.830 --&gt; 01:08:24.330
Liel: View what we need. Next.</p>
<p>699
01:08:24.810 --&gt; 01:08:26.400
Liel: Is we need to.</p>
<p>700
01:08:28.410 --&gt; 01:08:30.040
Liel: Remove this.</p>
<p>701
01:08:33.740 --&gt; 01:08:41.460
Liel: Yeah, let's just add any in here, because… Oh.</p>
<p>702
01:08:41.760 --&gt; 01:08:43.929
Liel: It can't add that.</p>
<p>703
01:08:49.330 --&gt; 01:08:50.830
Liel: Or… yeah.</p>
<p>704
01:08:51.700 --&gt; 01:08:55.569
Liel: Let's see what… It does.</p>
<p>705
01:08:58.930 --&gt; 01:09:00.120
Liel: Where is it?</p>
<p>706
01:09:01.779 --&gt; 01:09:06.400
Liel: Oh, it's just empty, so it doesn't show anything right now.</p>
<p>707
01:09:06.930 --&gt; 01:09:08.479
Liel: So I missed it.</p>
<p>708
01:09:09.609 --&gt; 01:09:18.880
Liel: Let's do… where is Tory? I'm sorry, I have to consult the documentation, because I don't remember the exact syntax for that.</p>
<p>709
01:09:20.600 --&gt; 01:09:23.280
Liel: No, it's nothing learned, it's developed.</p>
<p>710
01:09:28.060 --&gt; 01:09:29.950
Liel: It is process clean.</p>
<p>711
01:09:35.580 --&gt; 01:09:39.090
Liel: Because I need to find how the event</p>
<p>712
01:09:43.979 --&gt; 01:09:44.770
Liel: Oop.</p>
<p>713
01:09:45.950 --&gt; 01:09:47.180
Liel: That's that.</p>
<p>714
01:09:47.319 --&gt; 01:09:53.380
Liel: And also, in the… In the presentation.</p>
<p>715
01:09:53.819 --&gt; 01:09:55.510
Liel: Sorry. That.</p>
<p>716
01:09:59.400 --&gt; 01:10:03.440
Liel: That, and yeah, so we can import the…</p>
<p>717
01:10:03.860 --&gt; 01:10:09.460
Liel: No, not in Vogue, but probably the… Listen.</p>
<p>718
01:10:09.700 --&gt; 01:10:10.430
Liel: Fine.</p>
<p>719
01:10:11.480 --&gt; 01:10:13.900
Liel: Yeah, global events, and yeah.</p>
<p>720
01:10:14.390 --&gt; 01:10:18.349
Liel: Okay, so we need to import that, and we need to use that.</p>
<p>721
01:10:18.630 --&gt; 01:10:21.900
Liel: So… listen…</p>
<p>722
01:10:34.610 --&gt; 01:10:36.540
Liel: story apps.</p>
<p>723
01:10:36.660 --&gt; 01:10:38.119
Liel: slash API.</p>
<p>724
01:10:41.870 --&gt; 01:10:43.730
Liel: That's that.</p>
<p>725
01:10:45.180 --&gt; 01:10:53.800
Liel: Yeah, it complains because I didn't listen to an event. Listen to… How did we call it?</p>
<p>726
01:10:53.950 --&gt; 01:10:55.480
Liel: Text copied.</p>
<p>727
01:11:00.220 --&gt; 01:11:04.579
Liel: And the second argument is the</p>
<p>728
01:11:08.340 --&gt; 01:11:11.410
Liel: event. So, event.</p>
<p>729
01:11:16.480 --&gt; 01:11:18.029
Liel: Let's do that.</p>
<p>730
01:11:25.520 --&gt; 01:11:31.459
Liel: And, yeah, we should probably… Import it, in case it doesn't…</p>
<p>731
01:11:44.640 --&gt; 01:11:50.149
Liel: Let's import it like that, so it doesn't clash with anything.</p>
<p>732
01:11:51.340 --&gt; 01:11:54.319
Liel: And in this case, we just have a string, so…</p>
<p>733
01:11:54.580 --&gt; 01:11:57.839
Liel: In any case, we have text copied.</p>
<p>734
01:11:59.660 --&gt; 01:12:05.100
Liel: What we can do is items.push, Okay.</p>
<p>735
01:12:05.300 --&gt; 01:12:07.090
Liel: items.value.</p>
<p>736
01:12:09.270 --&gt; 01:12:10.779
Liel: Alright, let's do it.</p>
<p>737
01:12:15.310 --&gt; 01:12:18.469
Liel: Yeah, I'm just not sure.</p>
<p>738
01:12:18.960 --&gt; 01:12:24.360
Liel: it will work with views reactivity, but let's try it.</p>
<p>739
01:12:28.550 --&gt; 01:12:29.870
Liel: ID.</p>
<p>740
01:12:32.810 --&gt; 01:12:36.909
Liel: random UUID, we can just use that.</p>
<p>741
01:12:38.980 --&gt; 01:12:39.780
Liel: Time.</p>
<p>742
01:12:40.140 --&gt; 01:12:45.739
Liel: just a student for text. We have some support for images, but…</p>
<p>743
01:12:47.260 --&gt; 01:12:55.609
Liel: It's not implemented yet. Let's see if we have time for that. And content will just be event.payload.</p>
<p>744
01:12:56.110 --&gt; 01:12:58.380
Liel: Which is correctly string.</p>
<p>745
01:12:59.610 --&gt; 01:13:01.420
Liel: And we have that.</p>
<p>746
01:13:01.990 --&gt; 01:13:05.359
Liel: Now, let's see if that actually works.</p>
<p>747
01:13:06.810 --&gt; 01:13:10.450
Liel: But yeah, one thing I don't like is that…</p>
<p>748
01:13:10.820 --&gt; 01:13:14.860
Liel: We don't have any sleep, so what we can do?</p>
<p>749
01:13:18.160 --&gt; 01:13:19.549
Liel: He asleep?</p>
<p>750
01:13:22.560 --&gt; 01:13:24.530
Liel: Here, we can do sleep.</p>
<p>751
01:13:25.040 --&gt; 01:13:33.470
Liel: Like that, because… Oz… We are in a blocking thread, duration. Done.</p>
<p>752
01:13:33.800 --&gt; 01:13:35.440
Liel: Error 4.</p>
<p>753
01:13:37.570 --&gt; 01:13:38.930
Liel: Mail is?</p>
<p>754
01:13:39.220 --&gt; 01:13:41.600
Liel: Let's do, like, 2?</p>
<p>755
01:13:46.090 --&gt; 01:13:47.980
Liel: mismatched types.</p>
<p>756
01:13:49.000 --&gt; 01:13:51.739
Liel: Okay, so you're 64, so…</p>
<p>757
01:13:59.440 --&gt; 01:14:05.420
Liel: Okay, now… Oh, sorry, I just wanted to copy something.</p>
<p>758
01:14:07.610 --&gt; 01:14:10.470
Liel: And, apparently, it doesn't work.</p>
<p>759
01:14:13.120 --&gt; 01:14:16.589
Liel: Import binding name is not found.</p>
<p>760
01:14:18.040 --&gt; 01:14:19.060
Liel: Okay.</p>
<p>761
01:14:20.240 --&gt; 01:14:21.360
Liel: Oh.</p>
<p>762
01:14:22.760 --&gt; 01:14:26.849
Liel: So we should do something like that, import.</p>
<p>763
01:14:27.020 --&gt; 01:14:27.810
Liel: Type?</p>
<p>764
01:14:29.320 --&gt; 01:14:30.130
Liel: That.</p>
<p>765
01:14:38.130 --&gt; 01:14:40.530
Liel: Okay. That didn't work.</p>
<p>766
01:14:41.430 --&gt; 01:14:45.579
Liel: Which I suspect is related to that.</p>
<p>767
01:14:51.130 --&gt; 01:14:55.960
Liel: Back to the activity thing I mentioned earlier, so let's do that.</p>
<p>768
01:14:56.590 --&gt; 01:14:58.699
Liel: I know it's a rust step.</p>
<p>769
01:15:06.580 --&gt; 01:15:15.020
Liel: It's the worst thing, but… Unfortunately, this can be complex to debug.</p>
<p>770
01:15:16.620 --&gt; 01:15:18.210
Liel: Let's do that together.</p>
<p>771
01:15:19.450 --&gt; 01:15:26.500
Liel: In the case of that… I'd like to have… Some kind of error.</p>
<p>772
01:15:26.790 --&gt; 01:15:35.619
Liel: or some kind of that. So, what I have here is… That, or let's do info.</p>
<p>773
01:15:38.130 --&gt; 01:15:38.950
Liel: Fantastic.</p>
<p>774
01:15:41.220 --&gt; 01:15:43.710
Liel: Just to see if that works.</p>
<p>775
01:15:47.700 --&gt; 01:15:49.990
Liel: Yeah, it runs.</p>
<p>776
01:15:50.370 --&gt; 01:15:56.340
Liel: That's that, yeah. As you can see, it does spam me quite often.</p>
<p>777
01:15:58.590 --&gt; 01:15:59.869
Liel: Let's do that.</p>
<p>778
01:16:00.870 --&gt; 01:16:03.810
Liel: Successfully grab the text.</p>
<p>779
01:16:11.000 --&gt; 01:16:13.380
Liel: Okay, so he does that as well.</p>
<p>780
01:16:18.650 --&gt; 01:16:19.969
Liel: Remove that.</p>
<p>781
01:16:22.590 --&gt; 01:16:25.759
Liel: Oh, maybe I just need to eliminate it.</p>
<p>782
01:16:29.450 --&gt; 01:16:30.750
Liel: Oh, let's see.</p>
<p>783
01:16:35.320 --&gt; 01:16:40.520
Liel: Okay, let's… dot meet…</p>
<p>784
01:16:45.210 --&gt; 01:16:49.390
Liel: It's actually bad, that result.</p>
<p>785
01:17:03.950 --&gt; 01:17:06.030
Liel: So, it does succeed.</p>
<p>786
01:17:31.750 --&gt; 01:17:37.890
Liel: Oh, so the ID is a problem, so let's have… Last idea.</p>
<p>787
01:17:47.680 --&gt; 01:17:51.190
Liel: And here… Rusty.</p>
<p>788
01:17:53.430 --&gt; 01:17:55.650
Liel: And do that.</p>
<p>789
01:18:04.160 --&gt; 01:18:07.170
Liel: So, it's converted to a string.</p>
<p>790
01:18:10.520 --&gt; 01:18:12.699
Liel: But even that didn't work.</p>
<p>791
01:18:14.160 --&gt; 01:18:17.800
Liel: So let's… That's… oh.</p>
<p>792
01:18:24.810 --&gt; 01:18:26.680
Liel: That's worth…</p>
<p>793
01:18:41.620 --&gt; 01:18:43.050
Liel: That's unfortunate.</p>
<p>794
01:18:43.810 --&gt; 01:18:46.500
Liel: Let's see, listen…</p>
<p>795
01:18:52.480 --&gt; 01:18:52.885
Liel: What?</p>
<p>796
01:18:58.400 --&gt; 01:19:05.170
Liel: Okay, so… Technically, it should work, but I'm not sure why it doesn't.</p>
<p>797
01:19:07.630 --&gt; 01:19:12.660
Liel: Let's, first of all… Do… sleep.</p>
<p>798
01:19:13.100 --&gt; 01:19:14.250
Liel: Seconds.</p>
<p>799
01:19:15.330 --&gt; 01:19:16.780
Liel: Maybe 10 seconds?</p>
<p>800
01:19:32.710 --&gt; 01:19:33.540
Liel: Oh.</p>
<p>801
01:19:43.410 --&gt; 01:19:50.860
Liel: Yeah, so as you can see now, I can see the text copy fired, so maybe I was just flooding it too much.</p>
<p>802
01:19:56.370 --&gt; 01:19:58.649
Liel: So, if you can see, I will just copy</p>
<p>803
01:20:00.790 --&gt; 01:20:03.530
Liel: That, the Congo book, for example.</p>
<p>804
01:20:05.940 --&gt; 01:20:08.450
Liel: Just so you can see it's not…</p>
<p>805
01:20:12.360 --&gt; 01:20:14.959
Liel: Yeah, you can see it's the cargo book.</p>
<p>806
01:20:16.370 --&gt; 01:20:24.100
Liel: And if I look at the dev tools, Let's check the upstate.</p>
<p>807
01:20:24.410 --&gt; 01:20:28.880
Liel: Yeah. We now probably have some reactivity issue.</p>
<p>808
01:20:29.100 --&gt; 01:20:30.739
Liel: in that,</p>
<p>809
01:20:57.730 --&gt; 01:21:05.759
Liel: So, let's see… And default console lob items.</p>
<p>810
01:21:05.980 --&gt; 01:21:10.549
Liel: Liel? Yes, so… We can see it.</p>
<p>811
01:21:11.490 --&gt; 01:21:14.459
Liel: Let's remove that, and inspect elementary.</p>
<p>812
01:21:21.340 --&gt; 01:21:23.350
Liel: Okay, so it's a proxy.</p>
<p>813
01:21:23.490 --&gt; 01:21:26.289
Liel: So, technically, it should.</p>
<p>814
01:21:33.970 --&gt; 01:21:35.030
Liel: Show it?</p>
<p>815
01:21:37.450 --&gt; 01:21:41.479
Liel: And also, let's make sure we aren't copying the same thing.</p>
<p>816
01:21:41.960 --&gt; 01:21:48.400
Liel: So, what we can do… is just… if… Items.</p>
<p>817
01:21:49.080 --&gt; 01:21:53.450
Liel: dot add, or items.value.ad equals 1.</p>
<p>818
01:21:53.750 --&gt; 01:21:55.990
Liel: dot content.</p>
<p>819
01:21:57.090 --&gt; 01:22:01.309
Liel: is equal to event payload, just for an example.</p>
<p>820
01:22:08.160 --&gt; 01:22:09.779
Liel: Yeah, yeah.</p>
<p>821
01:22:12.450 --&gt; 01:22:14.919
Liel: Let's add that so it doesn't complain.</p>
<p>822
01:22:15.170 --&gt; 01:22:17.100
Liel: If it's undefined…</p>
<p>823
01:22:22.600 --&gt; 01:22:25.440
Liel: Okay, so now we have that.</p>
<p>824
01:22:25.940 --&gt; 01:22:33.549
Liel: And inside app.view, Item of items…</p>
<p>825
01:22:36.160 --&gt; 01:22:39.400
Liel: Type is text, which is correct.</p>
<p>826
01:22:52.220 --&gt; 01:22:54.449
Liel: Okay, so, yeah.</p>
<p>827
01:23:02.990 --&gt; 01:23:05.230
Liel: It doesn't like the async.</p>
<p>828
01:23:08.590 --&gt; 01:23:12.700
Liel: So how can I do that? Let's do…</p>
<p>829
01:23:28.100 --&gt; 01:23:37.770
Liel: How can I do that? Let me just, like, copy the file, duplicate, and let's call it… Bye.</p>
<p>830
01:23:38.320 --&gt; 01:23:41.169
Liel: Or, no, but it isn't a great name.</p>
<p>831
01:23:41.830 --&gt; 01:23:42.590
Liel: Hmm.</p>
<p>832
01:23:49.420 --&gt; 01:23:56.159
Liel: In here… Yeah, the import can go there, and I can remove the styling.</p>
<p>833
01:23:56.560 --&gt; 01:24:04.370
Liel: But in app… What I'll need to do is, first of all, remove all this setup from here.</p>
<p>834
01:24:05.220 --&gt; 01:24:09.040
Liel: Substance… And, up, and up.</p>
<p>835
01:24:14.230 --&gt; 01:24:18.140
Liel: See, we're… Is that in here?</p>
<p>836
01:24:25.980 --&gt; 01:24:33.810
Liel: Okay, so if I clear all filters… Maybe it needs some reload?</p>
<p>837
01:24:41.580 --&gt; 01:24:42.990
Liel: Okay.</p>
<p>838
01:24:47.460 --&gt; 01:24:53.190
Liel: That's just… Add a suspense.</p>
<p>839
01:24:53.290 --&gt; 01:24:55.220
Liel: Again, this is not a view.</p>
<p>840
01:25:05.030 --&gt; 01:25:08.210
Liel: So, yeah, let's try that a little bit.</p>
<p>841
01:25:25.950 --&gt; 01:25:32.140
Liel: Okay, async setup. That's right… Let me add…</p>
<p>842
01:25:33.220 --&gt; 01:25:38.080
Liel: One item to that. So, we'll do… Post.</p>
<p>843
01:25:38.490 --&gt; 01:25:41.050
Liel: One ending here.</p>
<p>844
01:25:42.140 --&gt; 01:25:44.300
Liel: Next Indeed.</p>
<p>845
01:25:44.740 --&gt; 01:25:47.879
Liel: Is just zero content.</p>
<p>846
01:25:50.150 --&gt; 01:25:53.510
Liel: Let's just add that, so we have something…</p>
<p>847
01:25:59.330 --&gt; 01:26:00.330
Liel: Yeah.</p>
<p>848
01:26:00.650 --&gt; 01:26:07.469
Liel: Okay, let's also remove the transparency, because that… that looks nicer.</p>
<p>849
01:26:07.750 --&gt; 01:26:12.060
Liel: But… Can make it harder to debug.</p>
<p>850
01:26:17.730 --&gt; 01:26:19.410
Liel: We have that…</p>
<p>851
01:26:25.110 --&gt; 01:26:26.729
Liel: And it still complains.</p>
<p>852
01:26:37.470 --&gt; 01:26:39.810
Liel: Oh. I.</p>
<p>853
01:26:40.670 --&gt; 01:26:43.300
Liel: I made a really stupid mistake.</p>
<p>854
01:26:51.630 --&gt; 01:26:54.970
Liel: I want that in the inner component.</p>
<p>855
01:26:55.360 --&gt; 01:27:01.250
Liel: And I want to, like, remove All of the rest…</p>
<p>856
01:27:03.500 --&gt; 01:27:09.850
Liel: Yeah, here in the root component, first of all, I don't want All this setup.</p>
<p>857
01:27:10.750 --&gt; 01:27:17.099
Liel: And in the template… All I want is to have a suspense.</p>
<p>858
01:27:19.500 --&gt; 01:27:21.239
Liel: And up, you know.</p>
<p>859
01:27:28.390 --&gt; 01:27:29.870
Liel: Where is our app?</p>
<p>860
01:27:30.100 --&gt; 01:27:31.010
Liel: Here.</p>
<p>861
01:27:32.860 --&gt; 01:27:38.769
Liel: Oh, fail to resolve component, or I just need in the…</p>
<p>862
01:27:42.570 --&gt; 01:27:48.309
Liel: Airport… Look at that.</p>
<p>863
01:27:53.580 --&gt; 01:27:54.810
Liel: Okay.</p>
<p>864
01:27:57.930 --&gt; 01:28:05.200
Liel: And now, if I, let's say, copy VIT, You see, I have it.</p>
<p>865
01:28:05.950 --&gt; 01:28:10.640
Liel: Yeah, sorry it took a little bit of time, but hopefully you got something from it.</p>
<p>866
01:28:11.760 --&gt; 01:28:13.190
Liel: And yeah, the…</p>
<p>867
01:28:13.190 --&gt; 01:28:13.930
Gabor Szabo: Nice.</p>
<p>868
01:28:16.740 --&gt; 01:28:21.129
Liel: The view DevTools, I… yeah, I just removed that.</p>
<p>869
01:28:21.700 --&gt; 01:28:23.369
Liel: We have that.</p>
<p>870
01:28:25.070 --&gt; 01:28:30.409
Liel: And let's do one command, because we actually want to use that.</p>
<p>871
01:28:31.080 --&gt; 01:28:37.300
Liel: So… what we need to do first. Oh, okay, time.</p>
<p>872
01:28:37.440 --&gt; 01:28:38.660
Liel: ESTMS?</p>
<p>873
01:28:38.770 --&gt; 01:28:40.679
Liel: Just so he doesn't complain.</p>
<p>874
01:28:41.740 --&gt; 01:28:45.820
Liel: And what we can do is first register a command.</p>
<p>875
01:28:47.700 --&gt; 01:28:50.870
Liel: So, in here… It can do.</p>
<p>876
01:28:51.340 --&gt; 01:28:52.290
Liel: Commando?</p>
<p>877
01:28:53.670 --&gt; 01:28:54.390
Liel: Wow.</p>
<p>878
01:28:58.120 --&gt; 01:28:58.790
Liel: Sweet.</p>
<p>879
01:29:03.430 --&gt; 01:29:06.349
Liel: And in here, let's do text string.</p>
<p>880
01:29:10.090 --&gt; 01:29:16.349
Liel: Result… Well, let's not do a result in here. Let's just do it vanilla.</p>
<p>881
01:29:17.240 --&gt; 01:29:27.369
Liel: And, we also need the app handle to get the clipboard, so what we can do is…</p>
<p>882
01:29:31.400 --&gt; 01:29:37.529
Liel: And just… We just need to add that.</p>
<p>883
01:29:38.670 --&gt; 01:29:44.640
Liel: In here… Importory app handle, that's great.</p>
<p>884
01:29:47.120 --&gt; 01:29:50.300
Liel: And why is it defined?</p>
<p>885
01:29:50.410 --&gt; 01:29:52.540
Liel: Multiple times…</p>
<p>886
01:29:57.560 --&gt; 01:30:01.830
Liel: Oh, maybe I just don't need the… We pop.</p>
<p>887
01:30:02.300 --&gt; 01:30:05.570
Liel: Yeah, I don't need the popcorn.</p>
<p>888
01:30:06.770 --&gt; 01:30:10.989
Liel: So, next… Yeah, it reopened.</p>
<p>889
01:30:14.100 --&gt; 01:30:18.500
Liel: and handle. Click. Bird.</p>
<p>890
01:30:19.210 --&gt; 01:30:20.260
Liel: Right.</p>
<p>891
01:30:20.660 --&gt; 01:30:21.680
Liel: Text?</p>
<p>892
01:30:21.880 --&gt; 01:30:22.780
Liel: Next.</p>
<p>893
01:30:23.280 --&gt; 01:30:27.390
Liel: So… for… this. I don't want this to be…</p>
<p>894
01:30:29.430 --&gt; 01:30:33.540
Liel: much longer, so I'll just support text right now.</p>
<p>895
01:30:35.060 --&gt; 01:30:38.960
Liel: So, okay, one last, or… Yeah.</p>
<p>896
01:30:39.730 --&gt; 01:30:46.449
Liel: Let's ignore the warning here, that I don't… Really care about, for now.</p>
<p>897
01:30:50.460 --&gt; 01:30:55.350
Liel: So, what I need to do next is actually call the command.</p>
<p>898
01:30:55.790 --&gt; 01:30:59.380
Liel: So, first of all, I need to, like, register it.</p>
<p>899
01:31:02.400 --&gt; 01:31:03.930
Liel: I think…</p>
<p>900
01:31:09.180 --&gt; 01:31:12.229
Liel: Yeah, I actually need to edit in the setup.</p>
<p>901
01:31:13.010 --&gt; 01:31:15.350
Liel: Let me quickly reference.</p>
<p>902
01:31:15.830 --&gt; 01:31:16.570
Liel: Where?</p>
<p>903
01:31:17.220 --&gt; 01:31:18.220
Liel: that.</p>
<p>904
01:31:18.440 --&gt; 01:31:19.580
Liel: Should go.</p>
<p>905
01:31:25.490 --&gt; 01:31:32.070
Liel: Commands, okay, custom command… And yeah, we need to add the invoke handler.</p>
<p>906
01:31:32.590 --&gt; 01:31:33.620
Liel: Okay.</p>
<p>907
01:31:34.170 --&gt; 01:31:38.620
Liel: So, in here.invokeHandler, generate.</p>
<p>908
01:31:39.050 --&gt; 01:31:40.760
Liel: Headdler!</p>
<p>909
01:31:41.520 --&gt; 01:31:44.380
Liel: And copy will be done.</p>
<p>910
01:31:52.400 --&gt; 01:31:53.749
Liel: Now we can.</p>
<p>911
01:31:55.330 --&gt; 01:31:56.460
Liel: Do that.</p>
<p>912
01:31:57.670 --&gt; 01:32:10.610
Liel: And… In our app… So here, we can have… we have clicked… And event is… Just…</p>
<p>913
01:32:10.920 --&gt; 01:32:15.360
Liel: item.ai, so we need to find the item.</p>
<p>914
01:32:27.310 --&gt; 01:32:30.510
Liel: If we don't find it, I don't really care.</p>
<p>915
01:32:37.280 --&gt; 01:32:44.130
Liel: Now, we need… keyboard in Vogue.</p>
<p>916
01:32:46.740 --&gt; 01:32:50.809
Liel: Which will allow us to… Invoke the command.</p>
<p>917
01:32:51.730 --&gt; 01:33:03.310
Liel: Now let's… I think it needs to be a sync as well, because it returns a promise whatsoever, or… yeah, whatsoever isn't the right word, but you get the point.</p>
<p>918
01:33:05.570 --&gt; 01:33:14.030
Liel: Let's… Do that, so invoke… And… How did I call it?</p>
<p>919
01:33:14.930 --&gt; 01:33:16.519
Liel: Copy the clipboard.</p>
<p>920
01:33:20.250 --&gt; 01:33:30.299
Liel: I think it's dashes instead of underscores, and… The argument is item.</p>
<p>921
01:33:37.220 --&gt; 01:33:42.790
Liel: So it should be string… Let's just use the screen. Again, don't…</p>
<p>922
01:33:51.630 --&gt; 01:33:59.880
Liel: Yeah, okay, so copycat label. We have that. Now I copied dependencies, so we'll have that as well in a few seconds.</p>
<p>923
01:34:01.320 --&gt; 01:34:02.350
Liel: Yes.</p>
<p>924
01:34:02.900 --&gt; 01:34:16.169
Liel: And now, let's check if that works. So, the way we do that is, let's say I open a new terminal. Now, the thing I have is dependencies, which is okay. And now, if I click it.</p>
<p>925
01:34:16.950 --&gt; 01:34:18.369
Liel: I did not work.</p>
<p>926
01:34:18.520 --&gt; 01:34:20.669
Liel: Okay, so another…</p>
<p>927
01:34:24.560 --&gt; 01:34:30.130
Liel: Command, copy to clipboard, not found. Maybe it is with under… scores?</p>
<p>928
01:34:37.550 --&gt; 01:34:39.090
Liel: Let's check now.</p>
<p>929
01:34:39.330 --&gt; 01:34:45.250
Liel: Now we have dependencies, which is okay, but I want something else. Let's say the name of the folder.</p>
<p>930
01:34:51.850 --&gt; 01:34:52.770
Liel: Yes.</p>
<p>931
01:34:53.380 --&gt; 01:34:59.640
Liel: Now, I have that in Clickboard. Once I type dependencies, that still doesn't work.</p>
<p>932
01:35:00.820 --&gt; 01:35:02.540
Liel: Okay, what's next?</p>
<p>933
01:35:03.030 --&gt; 01:35:08.940
Liel: Invalid arguments… oh, so it requires me to have it.</p>
<p>934
01:35:10.390 --&gt; 01:35:11.670
Liel: Like that.</p>
<p>935
01:35:12.240 --&gt; 01:35:13.260
Liel: Text.</p>
<p>936
01:35:19.520 --&gt; 01:35:24.930
Liel: I think, let me just reference my own presentation once again.</p>
<p>937
01:35:31.080 --&gt; 01:35:35.119
Liel: I don't have it in here, but I have it here.</p>
<p>938
01:35:35.470 --&gt; 01:35:41.160
Liel: Invoke command… Passing ordinance. That's what they need.</p>
<p>939
01:35:41.650 --&gt; 01:35:43.669
Liel: Yeah, exactly, Isaia.</p>
<p>940
01:35:44.940 --&gt; 01:35:47.120
Liel: Try to do. Text.</p>
<p>941
01:35:47.590 --&gt; 01:35:51.820
Liel: Not that, but item.content.</p>
<p>942
01:35:54.260 --&gt; 01:35:57.789
Liel: And let's ignore item.</p>
<p>943
01:36:04.600 --&gt; 01:36:05.320
Liel: Yeah.</p>
<p>944
01:36:05.420 --&gt; 01:36:07.980
Liel: Let's ignore anything that isn't a string.</p>
<p>945
01:36:10.520 --&gt; 01:36:16.089
Liel: Now, let's see… yeah, I populated that, and let's copy dependencies as well.</p>
<p>946
01:36:21.460 --&gt; 01:36:22.480
Liel: Great.</p>
<p>947
01:36:22.880 --&gt; 01:36:25.609
Liel: Now we have dependencies, once I do that…</p>
<p>948
01:36:26.400 --&gt; 01:36:30.340
Liel: And we have a working little clipboard manager.</p>
<p>949
01:36:31.050 --&gt; 01:36:38.709
Liel: Of course, it doesn't actually have, like, that smart of a… brain or state.</p>
<p>950
01:36:39.100 --&gt; 01:36:45.470
Liel: But… At least it works, and I think that's enough for a demo right now.</p>
<p>951
01:36:48.390 --&gt; 01:36:50.070
Liel: So let's close that.</p>
<p>952
01:36:52.830 --&gt; 01:36:59.260
Liel: Would you, if you'd like, I could also upload this demo afterwards to Git?</p>
<p>953
01:37:01.010 --&gt; 01:37:05.269
Gabor Szabo: Yeah, I think it has probably more value than what we did in the first demo.</p>
<p>954
01:37:07.670 --&gt; 01:37:08.320
Liel: Yeah.</p>
<p>955
01:37:10.940 --&gt; 01:37:19.300
Liel: So, we were here… That's… do that.</p>
<p>956
01:37:20.230 --&gt; 01:37:27.460
Liel: So, you'll have some additional links here, documentation, Oscari, their GitHub, and their Discord.</p>
<p>957
01:37:27.690 --&gt; 01:37:35.059
Liel: There are some real nice people here, so in case you have any questions about Tori.</p>
<p>958
01:37:35.290 --&gt; 01:37:39.880
Liel: They're probably… much more skilled than I am.</p>
<p>959
01:37:42.050 --&gt; 01:37:44.840
Liel: So, feel free to use that.</p>
<p>960
01:37:45.840 --&gt; 01:37:47.630
Liel: And… yeah.</p>
<p>961
01:37:47.810 --&gt; 01:37:59.159
Liel: Thanks, that would be it for my contact info. You have my email, you have my links in here to GitHub and LinkedIn as well. And, yeah, I'll export the…</p>
<p>962
01:38:00.310 --&gt; 01:38:05.499
Liel: the presentation slides to PDF, so people can put that into…</p>
<p>963
01:38:07.330 --&gt; 01:38:08.210
Gabor Szabo: Excellent.</p>
<p>964
01:38:08.990 --&gt; 01:38:10.219
Gabor Szabo: Excellent. Okay.</p>
<p>965
01:38:10.630 --&gt; 01:38:12.609
Gabor Szabo: Any questions? Any of you?</p>
<p>966
01:38:12.610 --&gt; 01:38:13.240
Liel: Yeah.</p>
<p>967
01:38:16.410 --&gt; 01:38:19.420
Gabor Szabo: Okay, I think people got really tired already.</p>
<p>968
01:38:20.000 --&gt; 01:38:20.860
Gabor Szabo: This was a…</p>
<p>969
01:38:20.860 --&gt; 01:38:22.470
Liel: Yeah, that makes sense.</p>
<p>970
01:38:22.470 --&gt; 01:38:24.300
Gabor Szabo: Have you, have you watched 10 kids?</p>
<p>971
01:38:24.300 --&gt; 01:38:26.250
Liel: Thank you for, listening.</p>
<p>972
01:38:26.770 --&gt; 01:38:36.290
Gabor Szabo: Yeah, I would like to thank you for giving this presentation. It was, deep, and,</p>
<p>973
01:38:37.570 --&gt; 01:38:42.849
Gabor Szabo: I guess it seems that there are no more questions from the audience, so…</p>
<p>974
01:38:43.110 --&gt; 01:38:45.430
Gabor Szabo: We can finish this, right?</p>
<p>975
01:38:46.850 --&gt; 01:38:48.300
Gabor Szabo: What are you saying?</p>
<p>976
01:38:48.610 --&gt; 01:38:54.999
Liel: Yeah, yeah, we can stop the recording, and I'll stay for a little while in case someone wants to.</p>
<p>977
01:38:55.410 --&gt; 01:38:59.790
Gabor Szabo: Yeah, so again, thank you very much for, for doing this, for the.</p>
<p>978
01:38:59.790 --&gt; 01:39:00.549
Liel: Always a pleasure.</p>
<p>979
01:39:00.950 --&gt; 01:39:14.369
Gabor Szabo: Yeah, thank you. For the people watching it, please like the video, and follow the channel, and check out below the video, you will find links to… to the various things, that, probably the slides, and,</p>
<p>980
01:39:14.370 --&gt; 01:39:30.680
Gabor Szabo: to their LinkedIn profile of Liel, and you can contact him as well. So thank you, and thank you very much for all those people who were here in the audience. It's always good to have audience, instead of just…</p>
<p>981
01:39:30.790 --&gt; 01:39:33.059
Gabor Szabo: Speaking to a video.</p>
<p>982
01:39:33.520 --&gt; 01:39:44.000
Gabor Szabo: So, thank you very much, and you can stay around, and we can have an open mic session after I stop the video recording. So, thank you, and bye-bye.</p>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

  <entry>
    <title>Add tests to an open source Rust project - xmlem</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2026-09-01T07:30:01Z</updated>
    <pubDate>2026-09-01T07:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/add-tests-to-an-open-source-rust-project-xmlem" />
    <id>https://rust.code-maven.com/add-tests-to-an-open-source-rust-project-xmlem</id>
    <content type="html"><![CDATA[<h2 class="title is-4">Description</h2>
<p>Automated tests are a power multiplier as they help us make sure that changes to the code or to the environment don't have unintended changes in the results.</p>
<p>Therefore contributing tests to an open source project is very valuable.</p>
<p>It is usually also easier than contributing a feature or fixing a bug as you &quot;only&quot; need to know how to use the project, you don't have understand the code. At least not as deeply as you would need to make changes to the project.</p>
<p>During this hands on workshop you will learn how to find out what tests are missing, you will learn how to write a test and you will send a Pull-Request.</p>
<p>Prerequisite: You need to have an account on GitHub, you need to have your Rust tool-chain set up on your computer, you need to pick a crate, or other Rust project you'd like to contribute to.</p>
<p>We will do several steps. In each step:</p>
<ul>
<li>
<p>I'll demonstrate what to do.</p>
</li>
<li>
<p>You will try to follow the what I did.</p>
</li>
<li>
<p>I'll help you with any issues you might encounter.</p>
</li>
</ul>
<h2 class="title is-4">Links and Notes</h2>
<ul>
<li>
<p>We had some workshop elements in this session, but basically I ended up showing how to generate a test coverage report and a mutation testing report. Then I generated a test to cover some more lines of the code-base using Google Antigravity.</p>
</li>
<li>
<p>The <a href="https://osdc.code-maven.com/rust">OSDC Rust</a> page where I collect the ideas how to select a project, what to contribute, and what did we do during the previous sessions.</p>
</li>
<li>
<p>The <a href="https://github.com/xmlem/xmlem/pull/20">Pull Request</a></p>
</li>
</ul>
<iframe width="560" height="315" src="https://www.youtube.com/embed/KX9cGEJ1oZw" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
<h2 class="title is-4">Transcription</h2>
<p>1
00:00:00.720 --&gt; 00:00:02.840
Saile: Meeting is being recorded.</p>
<p>2
00:00:02.840 --&gt; 00:00:19.179
Gabor Szabo: So, hello, and welcome to the Code Maven YouTube channel, if you are watching this on YouTube, and welcome to the session, which is… either you call it Code Maven, that's the global name, or Rust Maven, because we are talking specifically about Rust.</p>
<p>3
00:00:19.310 --&gt; 00:00:21.230
Gabor Szabo: My name is Gabor Szabo.</p>
<p>4
00:00:21.850 --&gt; 00:00:40.729
Gabor Szabo: I am the host of this event, and in this time, we have lots of events. If you go to live… I'll share the screen, actually, and I'll explain. That's much easier than just speaking, so…</p>
<p>5
00:00:41.450 --&gt; 00:00:50.950
Gabor Szabo: Hopefully, you can see my screen now, yeah. Okay, so here there is this website, the Live Code Maven, and I turn on the beeps, so we won't…</p>
<p>6
00:00:51.310 --&gt; 00:00:53.130
Gabor Szabo: Play drone, okay.</p>
<p>7
00:00:53.170 --&gt; 00:00:55.260
Gabor Szabo: So, it won't bother us.</p>
<p>8
00:00:55.260 --&gt; 00:01:17.820
Gabor Szabo: Anyway, this is the Live Code Maven website, probably you're familiar with it. That's where we have the sessions. There are going to be this workshop and another workshop in Python I'm doing, and most of the others are guest speakers in various topics, so you are invited to look at them. I'll share it in the chat as well.</p>
<p>9
00:01:19.470 --&gt; 00:01:27.330
Gabor Szabo: this time it's going to be a workshop, and we are going to try to contribute to some open source Rust project, and I've done this</p>
<p>10
00:01:27.330 --&gt; 00:01:41.140
Gabor Szabo: quite a few of these already, and so I have this website called osdc.codemaven.com, and specifically this is the Rust page. I'm sharing this link as well in the</p>
<p>11
00:01:41.140 --&gt; 00:01:53.929
Gabor Szabo: in the… in the chat, so you can visit it. In general, this open source… OSDC stands for Open Source Developer Development Conference, or course, or community, or whatever club, whatever you name it.</p>
<p>12
00:01:54.350 --&gt; 00:01:57.370
Gabor Szabo: But the point here was that I had</p>
<p>13
00:01:57.510 --&gt; 00:02:11.750
Gabor Szabo: quite a few sessions in which we were contributing to some open source project, and we had sessions in Rust, in Python, in Ruby, in Perl. These are the languages that I covered.</p>
<p>14
00:02:12.140 --&gt; 00:02:14.150
Gabor Szabo: And here you can find notes.</p>
<p>15
00:02:14.150 --&gt; 00:02:35.830
Gabor Szabo: on how to select a Rust project to contribute to, if you don't have one that is already… you want to contribute to this one specifically. You just want to find something and contribute to that project. So, various ways to pick a project. Then, I have a bunch of links, and this is now highlighted. Let's…</p>
<p>16
00:02:35.830 --&gt; 00:02:49.509
Gabor Szabo: get rid of the search here. A bunch of things that you can contribute to. So, low level, low-hanging fruit, I would call, is, writing… configuring the CI.</p>
<p>17
00:02:50.290 --&gt; 00:02:52.780
Gabor Szabo: I don't know, there is someone who's trying to…</p>
<p>18
00:02:52.780 --&gt; 00:02:53.146
Saile: Oh, Mr.</p>
<p>19
00:02:53.330 --&gt; 00:02:54.070
Gabor Szabo: Trying to speak?</p>
<p>20
00:02:54.070 --&gt; 00:02:55.360
Saile: Take a time to speak!</p>
<p>21
00:02:55.720 --&gt; 00:02:57.310
Antonin Malzieu Ridolfi: What side is echoing?</p>
<p>22
00:02:57.650 --&gt; 00:02:59.069
Saile: What's savings and agreement.</p>
<p>23
00:03:00.830 --&gt; 00:03:20.509
Gabor Szabo: Okay, if you have some comments, and you don't want to have it recorded, that's fine. Write it in the chat, and then I'll see it, and I can comment on it, and I won't even say your name, so no one will have to know that… who asked it, or… well, besides the ones who are already here.</p>
<p>24
00:03:22.050 --&gt; 00:03:35.360
Gabor Szabo: So feel free to ask the questions in the chat. It's probably also better, especially if the voice is not that good, as we had some, but now. Anyway, so one of the things that you can…</p>
<p>25
00:03:35.360 --&gt; 00:03:43.889
Gabor Szabo: relatively easily contribute is configuring the CI, the continuous integration. So most of the projects, especially the Rust projects, are on GitHub.</p>
<p>26
00:03:43.890 --&gt; 00:04:08.219
Gabor Szabo: Because the crates I.O. is integrated with GitHub, for now, at least. You need an account on GitHub in order to upload something. So, most of the projects are on GitHub, or primarily on GitHub, and you can configure GitHub Actions, which basically will… what it will do is just run the tests whenever you put</p>
<p>27
00:04:08.220 --&gt; 00:04:17.279
Gabor Szabo: out, or the author pushes out some changes. And then, of course, it's a good idea to have tests for that project, and</p>
<p>28
00:04:17.279 --&gt; 00:04:26.640
Gabor Szabo: you, you won't believe how many projects are there on crates.io… on… yeah, so here.</p>
<p>29
00:04:27.150 --&gt; 00:04:32.899
Gabor Szabo: wait a second, why do I have this banner here? Can I get rid of it? Can I get… oops, or…</p>
<p>30
00:04:33.660 --&gt; 00:04:35.450
Gabor Szabo: I hate this when it happens.</p>
<p>31
00:04:36.860 --&gt; 00:04:39.380
Gabor Szabo: Do you still see my share?</p>
<p>32
00:04:39.620 --&gt; 00:04:46.250
Gabor Szabo: Or, stop share, I'll have to stop the share and share again.</p>
<p>33
00:04:48.090 --&gt; 00:04:51.279
Gabor Szabo: There is some strange behavior in…</p>
<p>34
00:04:52.010 --&gt; 00:04:59.070
Gabor Szabo: And then I minimize this so it won't bother us later. Okay, hopefully it's better now. So…</p>
<p>35
00:04:59.380 --&gt; 00:05:02.099
Gabor Szabo: If we go to craze.io,</p>
<p>36
00:05:03.540 --&gt; 00:05:20.189
Gabor Szabo: There are tons of crates here, and many of them are very good and well-tested and whatever, but there are also tons of them which are good beginner, good beginnings, without probably many tests, so you can encounter those.</p>
<p>37
00:05:20.190 --&gt; 00:05:33.939
Gabor Szabo: And you can also find just projects on GitHub, which weren't even uploaded to craze.io, because they are not major enough, or I don't know, whatever reason, without,</p>
<p>38
00:05:34.220 --&gt; 00:05:37.979
Gabor Szabo: without tests, or without enough tests.</p>
<p>39
00:05:38.010 --&gt; 00:05:55.260
Gabor Szabo: So I thought… oh, and one couple of more things. You can run, if you are… so you can set up CI, then you can write tests, and that's the major thing we are trying to… going to try to do now, that… write some tests, and…</p>
<p>40
00:05:55.410 --&gt; 00:06:12.259
Gabor Szabo: And here, Bill… and then, once you find the project that has already tests, you want to ask the question, what other tests you might want to write? So… and the way to find it out is that you can run… where is it?</p>
<p>41
00:06:14.900 --&gt; 00:06:17.419
Gabor Szabo: Where is it? I don't see it now.</p>
<p>42
00:06:18.550 --&gt; 00:06:21.180
Gabor Szabo: Yeah, it's here. Test coverage.</p>
<p>43
00:06:21.470 --&gt; 00:06:34.359
Gabor Szabo: generate test coverage report, okay? So you can generate a test coverage report, and then from there you can see which tests are… which areas of the code were not executed while testing.</p>
<p>44
00:06:34.360 --&gt; 00:06:52.169
Gabor Szabo: And that's a good idea to try to write a test to cover that area. So… and then if you have a good test coverage, then you can also go to something else which is called mutation testing, and I'm going to show you that as well, where what mutation test does</p>
<p>45
00:06:52.170 --&gt; 00:07:01.770
Gabor Szabo: is takes your codebase, runs your tests. The tests are passing, okay, hopefully. If the tests are not passing, then you already know what to fix, okay? Because something is broken.</p>
<p>46
00:07:01.980 --&gt; 00:07:17.209
Gabor Szabo: Either in the tests or in the code. But let's say the tests are passing, and let's say you have a very good test coverage. Now, you run the mutation test, what the mutation test does is changes your source code a little bit, maybe replacing,</p>
<p>47
00:07:17.450 --&gt; 00:07:20.660
Gabor Szabo: Yeah, I'm recording. Am I not? Yeah, I'm recording.</p>
<p>48
00:07:21.490 --&gt; 00:07:27.410
Gabor Szabo: Yeah, someone just right, kindly recorded. Okay, I'm recording, but when I said, I think, that I'm not…</p>
<p>49
00:07:27.870 --&gt; 00:07:31.680
Gabor Szabo: Sure, what I'm going to do is this. Anyway, if I'm going to upload it.</p>
<p>50
00:07:31.690 --&gt; 00:07:50.930
Gabor Szabo: Anyway, so you have the code base, and then the mutation testing changes your codebase a little bit. Let's say a plus sign replaces by the minus sign, okay? So everything is the same, except that in the computation, somewhere, a plus is replaced by the minus. And then runs the tests.</p>
<p>51
00:07:50.930 --&gt; 00:07:57.990
Gabor Szabo: And the test… are expected to fail, right? Because now the code base changed. If the tests don't</p>
<p>52
00:07:58.360 --&gt; 00:08:03.770
Gabor Szabo: didn't fail, okay? If the no test failed, that means that the test</p>
<p>53
00:08:03.940 --&gt; 00:08:22.399
Gabor Szabo: are not properly verifying that area of the code. It might be that they are not covering at all, that the test coverage should have found it, okay? Or it might be that, you know, I've seen a codebase or tests where you have a</p>
<p>54
00:08:22.450 --&gt; 00:08:25.580
Gabor Szabo: You run a tab, you run a function, You…</p>
<p>55
00:08:25.730 --&gt; 00:08:41.219
Gabor Szabo: compute the result, but then you're in the test, but then you're not comparing it to some expected, result. Now, how this happens, I have theories, but probably it's just a mistake that the,</p>
<p>56
00:08:41.559 --&gt; 00:08:48.489
Gabor Szabo: developer-made. Sometimes I saw code like this, that people, instead of verifying</p>
<p>57
00:08:48.530 --&gt; 00:09:03.659
Gabor Szabo: with an assert, comparing to an expected result, instead of that printing out the result, and eyeballing it. So, looking at it and saying, okay, it's a good value. And that's how they think tests are.</p>
<p>58
00:09:03.930 --&gt; 00:09:21.049
Gabor Szabo: this is… well, as long as they look at the value, it's good, but it means that they're not really verifying in the test that the value is correct. You have to compare it to some expected result. And so,</p>
<p>59
00:09:21.320 --&gt; 00:09:22.989
Gabor Szabo: the mutation tests.</p>
<p>60
00:09:23.160 --&gt; 00:09:30.960
Gabor Szabo: Can… will find these problems, because they will change the code, the code will still run, it will still generate some result.</p>
<p>61
00:09:31.000 --&gt; 00:09:47.000
Gabor Szabo: And the code and the test will pass, because no one is… because it's not comparing to some expected result, which is different from what is actually generated. And so, if you go further on this page, scroll further down, you will find…</p>
<p>62
00:09:47.360 --&gt; 00:09:55.660
Gabor Szabo: This… let's skip the Rust Digger for now, because I stopped running it. A bunch of projects that I hand… that I…</p>
<p>63
00:09:55.660 --&gt; 00:10:12.010
Gabor Szabo: dealt with, and then you can see the dates when I dealt with on what session was there, and the links to the issues I opened, and the status as I… as I updated it, because it's not automatically updated. So let's say this was a pull request.</p>
<p>64
00:10:12.010 --&gt; 00:10:26.189
Gabor Szabo: adding GitHub workflow, and it was merged. And this was an issue I opened, and it's still waiting for some response. And, there was a PR that I opened, and it was rejected without any comment.</p>
<p>65
00:10:26.190 --&gt; 00:10:42.880
Gabor Szabo: And so, for example, this project, I will probably not contribute anymore, because there were, like, 4 PRs, 3 PRs, and they were all rejected, closed, basically, without any comments. Now, maybe the author implemented the same thing.</p>
<p>66
00:10:43.690 --&gt; 00:10:48.389
Gabor Szabo: Himself, herself, whatever. But,</p>
<p>67
00:10:48.950 --&gt; 00:11:01.769
Gabor Szabo: my PR was sort of rejected, so I would say, okay, I don't want to contribute to this person and to this project anymore, because my contribution is not really valued, okay?</p>
<p>68
00:11:01.810 --&gt; 00:11:07.259
Gabor Szabo: Of course, not every rejection should</p>
<p>69
00:11:07.260 --&gt; 00:11:22.669
Gabor Szabo: generate this reaction, but if you feel… and there's even a video recording of that, okay? Of that session, when I was doing this. So you have plenty of video recordings you might find here.</p>
<p>70
00:11:22.840 --&gt; 00:11:37.720
Gabor Szabo: Anyway, there is a CSV create, which is a very… I don't know if it's popular, but it's, the author is a very well-known author, so it's a very good, create. And so…</p>
<p>71
00:11:37.720 --&gt; 00:11:50.609
Gabor Szabo: I have it locally, and I wanted to show that one. So these were the… because it's a big one, and I'm going to get stuck with this, and so I will just show</p>
<p>72
00:11:50.740 --&gt; 00:11:56.620
Gabor Szabo: That even there, we might have… even… even there, in such a,</p>
<p>73
00:11:57.100 --&gt; 00:12:09.550
Gabor Szabo: well-maintained project, you might find issues. Now, you can see that here, too, I have to check whether they are still waiting, or they were… what happened to these… all the other things.</p>
<p>74
00:12:10.020 --&gt; 00:12:12.280
Gabor Szabo: But you can see the comments I made.</p>
<p>75
00:12:12.840 --&gt; 00:12:21.750
Gabor Szabo: So, I have… here, the Rust CSV project cloned.</p>
<p>76
00:12:22.020 --&gt; 00:12:25.469
Gabor Szabo: So, I can come to this link.</p>
<p>77
00:12:25.740 --&gt; 00:12:28.330
Gabor Szabo: Just to go to a whole,</p>
<p>78
00:12:29.320 --&gt; 00:12:35.080
Gabor Szabo: I can close this one, I can close this one for now. This is the same thing.</p>
<p>79
00:12:35.570 --&gt; 00:12:49.500
Gabor Szabo: This is something that I don't need for now. Oh, and I have the clock. Okay, so this is where the crate is. Andrew Gallant, also known as Burned Sushi.</p>
<p>80
00:12:49.730 --&gt; 00:12:58.430
Gabor Szabo: is the author, or the maintainer, I don't know. I can click on the reposit… on the link to the repository. Most crates have that link.</p>
<p>81
00:12:59.070 --&gt; 00:13:10.720
Gabor Szabo: I think not all of them, but most of them have. And then I took this one, and I cloned it with git clone. And then, so now I have… if I run it Git…</p>
<p>82
00:13:10.750 --&gt; 00:13:27.110
Gabor Szabo: remote minus 3, I have the origin repo, which is from Burn Sushi, so that's the original one, and I have my own fork, this is my username on GitHub. And git pull…</p>
<p>83
00:13:27.140 --&gt; 00:13:37.749
Gabor Szabo: origin master will update from the origin… from the origin. I think it's up to date because I just ran this 5 minutes before we started the session.</p>
<p>84
00:13:37.890 --&gt; 00:13:56.020
Gabor Szabo: And now I can just basically run cargo test here, and it will run the test. And it's already compiled, because I read it earlier. And it was… it's pretty fast. Now, before I continue, I have this other window, and I wanted to run HTOP here.</p>
<p>85
00:13:56.290 --&gt; 00:14:03.729
Gabor Szabo: So, we'll see… how much of my CPU is used?</p>
<p>86
00:14:03.970 --&gt; 00:14:13.320
Gabor Szabo: So I have, like, 16 cores here, and it's not… not that bad. I mean, remember your Zoom used to take up a lot more. I think it's now…</p>
<p>87
00:14:13.570 --&gt; 00:14:28.529
Gabor Szabo: better. So it has a load average of 3, as you can see here, which is not that bad. So I can go now to this page, and</p>
<p>88
00:14:31.290 --&gt; 00:14:39.619
Gabor Szabo: find, try to find, because I never remember the commands, test coverage report using tarpaulin. Okay, so this is the link where</p>
<p>89
00:14:39.770 --&gt; 00:14:52.779
Gabor Szabo: I wrote a blog post, basically, or it's a book, or whatever, there, because I don't remember how the comments are, I just write them in books or blog posts, and then I can find them easier.</p>
<p>90
00:14:52.780 --&gt; 00:15:02.919
Gabor Szabo: So, cargo install, cargo tarpaulin would install this thing, this tool, which generates the test report.</p>
<p>91
00:15:03.570 --&gt; 00:15:18.749
Gabor Szabo: And then you can run it in various flags. So here, this one will run cargo tarpauline HTML, that will generate an HTML report, this is a standard output report, and this will do both.</p>
<p>92
00:15:19.340 --&gt; 00:15:26.129
Gabor Szabo: So… And there is a bug here in the slide. Anyway, I take this one.</p>
<p>93
00:15:26.420 --&gt; 00:15:41.349
Gabor Szabo: and copy it, and run this command, okay? So now what it does, it runs the tests again, but this time it will collect information, which,</p>
<p>94
00:15:42.170 --&gt; 00:15:45.800
Gabor Szabo: Lines of the code base.</p>
<p>95
00:15:46.080 --&gt; 00:15:50.180
Gabor Szabo: were executed while the tests were running, and</p>
<p>96
00:15:52.320 --&gt; 00:16:01.170
Gabor Szabo: Something, oh, broken? Test error? Test failed during run? What does that mean? Is this happening earlier?</p>
<p>97
00:16:01.540 --&gt; 00:16:03.750
Gabor Szabo: Oh, there was a failure already!</p>
<p>98
00:16:03.940 --&gt; 00:16:05.719
Gabor Szabo: Huh, I didn't notice.</p>
<p>99
00:16:08.370 --&gt; 00:16:16.460
Gabor Szabo: Okay, I think it's… it… Okay, now I'm getting confused. I think it was… it was passing earlier, no?</p>
<p>100
00:16:16.600 --&gt; 00:16:17.950
Gabor Szabo: Field, field?</p>
<p>101
00:16:30.130 --&gt; 00:16:34.230
Gabor Szabo: Okay, now I'm sorry, I'll get… I ran the Garbo test again.</p>
<p>102
00:16:37.880 --&gt; 00:16:40.339
Gabor Szabo: Wasn't it passing? Anyone remembers?</p>
<p>103
00:16:40.510 --&gt; 00:16:43.010
Gabor Szabo: This is what happens when you do live coding.</p>
<p>104
00:16:47.910 --&gt; 00:16:52.620
Gabor Szabo: So it… okay, I think I remember… I think specifically…</p>
<p>105
00:16:52.850 --&gt; 00:17:02.049
Gabor Szabo: Some modules… so, okay, the tests are passing, but if I run cargo tarpaulin with this, I hope I pronounced properly.</p>
<p>106
00:17:02.430 --&gt; 00:17:03.639
Gabor Szabo: First of all.</p>
<p>107
00:17:03.850 --&gt; 00:17:15.640
Gabor Szabo: you see that it needs to recompile it, because it's working in a different way, which is a pretty… a little bit annoying. And now we can see that while it's running.</p>
<p>108
00:17:16.730 --&gt; 00:17:30.909
Gabor Szabo: it has all kinds of things that are… get broken, okay? So, I know that tarpaulin doesn't work with every codebase, okay? There are issues. Now, on the other hand.</p>
<p>109
00:17:32.160 --&gt; 00:17:39.490
Gabor Szabo: I think… This might… I mean, I don't know if this worked. I can work… use this one.</p>
<p>110
00:17:39.660 --&gt; 00:17:41.619
Gabor Szabo: Let's try this one as well.</p>
<p>111
00:17:42.730 --&gt; 00:17:46.520
Gabor Szabo: So, I… usually, what I do is I…</p>
<p>112
00:17:46.740 --&gt; 00:18:00.930
Gabor Szabo: run everything inside a Docker container in order to make sure that whatever this random codebase, basically, does, okay, won't impact all of my computer.</p>
<p>113
00:18:00.940 --&gt; 00:18:09.630
Gabor Szabo: Now, what you can see is that I'm running them… running it on… natively on my computer, which is on one hand scary,</p>
<p>114
00:18:09.980 --&gt; 00:18:17.950
Gabor Szabo: On the other hand, it doesn't work either. So, bad example, okay, or one example that,</p>
<p>115
00:18:18.350 --&gt; 00:18:35.279
Gabor Szabo: I can't show you the result for now. I will pick another module, another example, another create another example, but for… while we are… before we do this, I wanted to show one more thing, and this is the mutation testing, so…</p>
<p>116
00:18:37.650 --&gt; 00:18:39.679
Gabor Szabo: No, this, not this one?</p>
<p>117
00:18:41.690 --&gt; 00:18:54.930
Gabor Szabo: This one is my article, okay? So here you can find that this is also… you install it with cargo install… not that tarpaulin… cargo install, cargo mutants, and then you run cargo mutants.</p>
<p>118
00:18:55.180 --&gt; 00:18:58.609
Gabor Szabo: That's it. There… you can find this article, I'll…</p>
<p>119
00:18:59.660 --&gt; 00:19:13.159
Gabor Szabo: Paste it there. So this one now generates the mutants. It found… it generated 758 mutants, meaning in 758 different ways, it changed the codebase.</p>
<p>120
00:19:13.500 --&gt; 00:19:20.509
Gabor Szabo: And it will run the tests on all Run all the tests, 758…</p>
<p>121
00:19:21.470 --&gt; 00:19:35.950
Gabor Szabo: times. If we… if I switch to this screen now, you can see that it's, like, all of the… all of my cores are fully used, almost fully used, okay? The load average is now 12 already.</p>
<p>122
00:19:36.230 --&gt; 00:19:39.450
Gabor Szabo: So… My computer is pretty, pretty busy.</p>
<p>123
00:19:39.570 --&gt; 00:19:43.799
Gabor Szabo: And… when I ran this before the…</p>
<p>124
00:19:44.140 --&gt; 00:19:57.340
Gabor Szabo: with the session, I actually stopped it pretty early, because I found this, what you can see also here. So, I found that there are syncs which are missed.</p>
<p>125
00:19:57.380 --&gt; 00:20:05.139
Gabor Szabo: So, I think when it says missed, it means that it found a case where if you make some changes.</p>
<p>126
00:20:05.620 --&gt; 00:20:09.560
Gabor Szabo: Then the still… the test will pass.</p>
<p>127
00:20:09.920 --&gt; 00:20:16.659
Gabor Szabo: Okay? Unfortunately, I couldn't find how to…</p>
<p>128
00:20:16.860 --&gt; 00:20:30.749
Gabor Szabo: limit the number… how to tell it to stop after the first missed one, okay? If anyone… so I'm going to stop it now, and what I promised is that I share this link as well, in case you…</p>
<p>129
00:20:30.790 --&gt; 00:20:38.099
Gabor Szabo: want to… want to find it easily, but, you can find it from the… from the OSDC page.</p>
<p>130
00:20:38.760 --&gt; 00:20:40.110
Gabor Szabo: Okay, so…</p>
<p>131
00:20:40.270 --&gt; 00:20:48.370
Gabor Szabo: So that's… that's it. Now let me try to find another crate, and hopefully there I will be able to show, better.</p>
<p>132
00:20:49.360 --&gt; 00:20:51.650
Gabor Szabo: what I wanted to… to show.</p>
<p>133
00:20:51.790 --&gt; 00:20:52.940
Gabor Szabo: Damn.</p>
<p>134
00:20:53.790 --&gt; 00:21:08.990
Gabor Szabo: But, wait a second, sorry, before that, I wanted to finish this one, this thought. So I said, let's get the help, and I even piped through less. I couldn't find a way to limit the number of mutants</p>
<p>135
00:21:08.990 --&gt; 00:21:19.790
Gabor Szabo: probably I need to read the documentation for this, or ask ChatGTP, or how to do this, so it will stop the first… on the first missed, mutant.</p>
<p>136
00:21:19.990 --&gt; 00:21:29.200
Gabor Szabo: Git status, mutants out, this is the…</p>
<p>137
00:21:29.390 --&gt; 00:21:49.200
Gabor Szabo: I think it's totally different than what I remember. In any case, in this article that I shared with you, you can find an example that I used on the XMLM rust grid, and we can look at it now, maybe it will work for us now as well, where,</p>
<p>138
00:21:49.820 --&gt; 00:21:58.780
Gabor Szabo: there were quite a few things that were missed, and then I made some improvements, so maybe we can do this again.</p>
<p>139
00:21:59.020 --&gt; 00:22:03.999
Gabor Szabo: X… Let's see what happens here.</p>
<p>140
00:22:08.820 --&gt; 00:22:10.920
Gabor Szabo: Okay, it's not here.</p>
<p>141
00:22:13.620 --&gt; 00:22:16.509
Gabor Szabo: It's here, okay, git status.</p>
<p>142
00:22:16.800 --&gt; 00:22:24.540
Gabor Szabo: Okay, so… I can remove all… everything from here. This is the other project out.</p>
<p>143
00:22:24.940 --&gt; 00:22:27.210
Gabor Szabo: And… Ode?</p>
<p>144
00:22:27.360 --&gt; 00:22:30.540
Gabor Szabo: And the tarpaulin report. Okay, let's clean this.</p>
<p>145
00:22:30.840 --&gt; 00:22:31.710
Gabor Szabo: Git?</p>
<p>146
00:22:33.430 --&gt; 00:22:35.500
Gabor Szabo: Remote?</p>
<p>147
00:22:35.670 --&gt; 00:22:45.000
Gabor Szabo: So here, too, I have two remotes, the origin, which is where it came from, and my fork. So let's see this kit.</p>
<p>148
00:22:45.260 --&gt; 00:22:47.200
Gabor Szabo: Pool Origin.</p>
<p>149
00:22:48.150 --&gt; 00:22:49.740
Gabor Szabo: main here.</p>
<p>150
00:22:51.730 --&gt; 00:22:56.729
Gabor Szabo: Just to make sure that it's up to date. Okay, so it's up to date, and now…</p>
<p>151
00:22:56.990 --&gt; 00:23:07.110
Gabor Szabo: Because, sort of, I say, okay, I trust less this crate, I'm going to show you the one with the docker. So I have this alias.</p>
<p>152
00:23:09.560 --&gt; 00:23:13.059
Gabor Szabo: DRROST, which is basically this command.</p>
<p>153
00:23:13.430 --&gt; 00:23:19.049
Gabor Szabo: And I'm copy-pasting it for you, so you can… in case you would like to use this.</p>
<p>154
00:23:21.470 --&gt; 00:23:27.670
Gabor Szabo: So I'm running this command. What it does, it runs, this, image.</p>
<p>155
00:23:28.210 --&gt; 00:23:33.939
Gabor Szabo: this Docker image, it runs Bash inside it, it maps my directories.</p>
<p>156
00:23:34.050 --&gt; 00:23:37.839
Gabor Szabo: And it also maps various other folders.</p>
<p>157
00:23:37.840 --&gt; 00:23:58.590
Gabor Szabo: Because this Docker image, this is an image I created, this Docker image also contains installations of Copilot, of Codex, of Gemini, Gemini, whatever, how you say it. So if you have a configuration, you can use Dolos, because the clients are installed. So I say DR Rust.</p>
<p>158
00:23:59.480 --&gt; 00:24:05.079
Gabor Szabo: And it copies it because I've removed the previous image.</p>
<p>159
00:24:06.240 --&gt; 00:24:12.690
Gabor Szabo: The idea here is that I can Run inside this,</p>
<p>160
00:24:13.000 --&gt; 00:24:27.709
Gabor Szabo: container, inside this Docker container, I can run any code, and it will only impact the folders that were mapped here, which is still too much, I think, because still these, they are mapping… all these folders are accessible to it.</p>
<p>161
00:24:27.710 --&gt; 00:24:36.500
Gabor Szabo: But, at least it won't be able to access all of my computer, just these few folders, and…</p>
<p>162
00:24:36.790 --&gt; 00:24:39.660
Gabor Szabo: The current folder of the current project.</p>
<p>163
00:24:40.040 --&gt; 00:24:45.600
Gabor Szabo: And that's good, because I can also run any of the…</p>
<p>164
00:24:46.450 --&gt; 00:25:03.819
Gabor Szabo: LM agents, LM coding agents, and I can let them do whatever they want, because they can, again, can't just randomly remove my hard disk or do all kinds of changes. They can only do this. So, okay, we are fine. Inside is this,</p>
<p>165
00:25:03.820 --&gt; 00:25:15.280
Gabor Szabo: container in the slash OPT folder, but if I look at what's here, this is the same project that we saw earlier. Now I can run cargo test.</p>
<p>166
00:25:15.350 --&gt; 00:25:19.460
Gabor Szabo: And, see what's going on, if it's a passive high.</p>
<p>167
00:25:24.600 --&gt; 00:25:30.460
Gabor Szabo: is… is Rust Analyzer also running in the Docker container? So I'm not using it,</p>
<p>168
00:25:30.590 --&gt; 00:25:50.080
Gabor Szabo: I mean, I don't think that I use Rust Analyzer here, and I'm not using an IDE. I think that's what you are going… referring to, that if I use StartCopilot, right, then… not cop… not Copilot, sorry, VS Code, or some IDE, that is using,</p>
<p>169
00:25:50.180 --&gt; 00:25:58.650
Gabor Szabo: the… no, so if I start now VS Code, it's not configured to use the Docker container. That's,</p>
<p>170
00:25:58.770 --&gt; 00:26:08.240
Gabor Szabo: something is lacking from my setup yet, okay? So that would use the… the… Run it on my computer.</p>
<p>171
00:26:08.880 --&gt; 00:26:17.079
Gabor Szabo: Which is problematic, again, because it runs the code. But, yeah, well, whatever.</p>
<p>172
00:26:17.210 --&gt; 00:26:18.670
Gabor Szabo: when I run…</p>
<p>173
00:26:19.010 --&gt; 00:26:29.520
Gabor Szabo: the agents, then I don't even open the IDE, looking at the source code. I'm just telling the agents… I'll show you, probably. Let's see if I can get there, but maybe…</p>
<p>174
00:26:29.820 --&gt; 00:26:36.629
Gabor Szabo: Well, what time is it? Anyway, test… the test passed. I want… I already want to… you to do something, so…</p>
<p>175
00:26:36.760 --&gt; 00:26:44.969
Gabor Szabo: I just… this managed to do, the test passed, okay, cargo test. Now I go back to this,</p>
<p>176
00:26:45.390 --&gt; 00:26:46.930
Gabor Szabo: The tarpauling?</p>
<p>177
00:26:47.460 --&gt; 00:26:49.500
Gabor Szabo: Darba-ulin?</p>
<p>178
00:26:49.800 --&gt; 00:26:51.700
Gabor Szabo: Command, this one…</p>
<p>179
00:26:51.990 --&gt; 00:27:05.689
Gabor Szabo: So, this one is running, the test coverage report, generating the test coverage report. Hopefully, this will work.</p>
<p>180
00:27:06.380 --&gt; 00:27:10.680
Gabor Szabo: In this crit. This is a much, much simpler crit, so…</p>
<p>181
00:27:11.540 --&gt; 00:27:29.830
Gabor Szabo: here… oh, okay, sorry. So this problem is what is described in… on this page, that I get this ASLR disable fail whatever error, and that's where I need to add this one. So basically, the tarpaulin has</p>
<p>182
00:27:29.830 --&gt; 00:27:34.199
Gabor Szabo: two, I think, two engines on how to,</p>
<p>183
00:27:34.620 --&gt; 00:27:42.779
Gabor Szabo: monitor the source code, basically, how to monitor the execution, and one of them doesn't work inside the container. And the other one, which is</p>
<p>184
00:27:44.260 --&gt; 00:27:49.879
Gabor Szabo: probably not so good, or I don't know what that's good, I don't… I'm not sure.</p>
<p>185
00:27:50.360 --&gt; 00:28:08.469
Gabor Szabo: uses this flag, and… and I need to use that when I'm using inside a container. Anyway, now, this, what you can see here, is the out… is the report to the standard output, which says on which… on the source code, which line of code,</p>
<p>186
00:28:10.980 --&gt; 00:28:30.650
Gabor Szabo: what is covered or uncovered, what is not covered. Okay, uncovered? Why is it uncovered? I don't know, it should be not covered, probably. But I'm not an English native, so I don't know. And it also created this file in OPT tarpaulin report. Now, this is, let me open another tab here.</p>
<p>187
00:28:32.400 --&gt; 00:28:51.080
Gabor Szabo: Though it's inside… inside the container, it says slash OPT, tarpaulin report, but the slash OPT is mapped to the outside folder, so if I visit the same folder outside its status, then you can find this page here, and then I can open it</p>
<p>188
00:28:51.680 --&gt; 00:28:56.960
Gabor Szabo: This X is just an alias for me to open a… whatever you open.</p>
<p>189
00:28:58.630 --&gt; 00:29:02.799
Gabor Szabo: And so this is the HTML file that I opened.</p>
<p>190
00:29:03.330 --&gt; 00:29:17.080
Gabor Szabo: And you can see, the source code, and you can see that the display file has a very… a rather good test coverage, 85%. It can be improved, but</p>
<p>191
00:29:17.080 --&gt; 00:29:24.870
Gabor Szabo: It is, as it is, and now you can see which functions were not covered by tests.</p>
<p>192
00:29:26.140 --&gt; 00:29:28.440
Gabor Szabo: Okay? So…</p>
<p>193
00:29:29.530 --&gt; 00:29:37.000
Gabor Szabo: So now, we could go and write a test, or read a little bit more of the source code, and write a test. If I go back here.</p>
<p>194
00:29:37.510 --&gt; 00:29:45.050
Gabor Szabo: back this one, and so there is… the other… other files are way less covered. The yellow… the yellow ones…</p>
<p>195
00:29:45.590 --&gt; 00:29:46.750
Gabor Szabo: I guess…</p>
<p>196
00:29:47.070 --&gt; 00:29:58.489
Gabor Szabo: different ranges, and then there is the select RS, which is really poorly tested, okay? Now, I… I don't know that well this crate, I…</p>
<p>197
00:29:58.560 --&gt; 00:30:03.530
Gabor Szabo: Basically found it in a random, more or less random way,</p>
<p>198
00:30:03.530 --&gt; 00:30:12.659
Gabor Szabo: a couple of months ago, when I dealt with it. But that's one thing that you can… you can do, and you should do.</p>
<p>199
00:30:12.660 --&gt; 00:30:24.670
Gabor Szabo: And I think that's it for now. Let's stop… let me stop here. Maybe I even stop the recording, for now, and then you,</p>
<p>200
00:30:26.370 --&gt; 00:30:45.600
Gabor Szabo: you need to do all these things, okay? So you can also do this, and I will be able to help you. And I'm not recording it so no one needs to worry about the recording. So you don't need to use the Docker container, you can use it locally. Before…</p>
<p>201
00:30:46.340 --&gt; 00:31:03.419
Gabor Szabo: I let you start doing it one more thing. So, either you already have some crate that you want to deal with, okay? You can go with some crate that you want to play with, but the… probably most of you will pick some big crate.</p>
<p>202
00:31:03.520 --&gt; 00:31:18.780
Gabor Szabo: well-known crate. I have another proposition. Go with a semi… here is what the… at the top of the OSDC page. I said, a semi-popular, recently updated Rust project. So if you click on this link.</p>
<p>203
00:31:19.140 --&gt; 00:31:27.670
Gabor Szabo: Well, I have to fix the link because it's an old link. It says it's a… it goes to GitHub, and it searches for</p>
<p>204
00:31:28.030 --&gt; 00:31:39.440
Gabor Szabo: projects where the language is Rust, as you can see. It has between a hundred and a thousand stars. This is an arbitrary</p>
<p>205
00:31:40.380 --&gt; 00:31:47.940
Gabor Szabo: range for saying semi-popular, okay? So it's not very popular, but it's not also not some beginner thing.</p>
<p>206
00:31:47.940 --&gt; 00:31:59.760
Gabor Szabo: And it was changed recently. Now, I updated that file, apparently, in October last year, so it's almost a year ago, so you can come here and change the date and say, okay, let's say</p>
<p>207
00:31:59.760 --&gt; 00:32:08.729
Gabor Szabo: 08, so it's a lot… it was changed in the last months, and let's say you say you want to between 10 and 100 stars.</p>
<p>208
00:32:08.730 --&gt; 00:32:19.450
Gabor Szabo: Okay? So you go here, and then you find a bunch of crates which are not totally… so on one hand, not totally,</p>
<p>209
00:32:23.580 --&gt; 00:32:35.240
Gabor Szabo: uninteresting, or un… or new, or whatever can I say on… so it has some stars, okay? It doesn't have a lot of stars, and the point of recently changed</p>
<p>210
00:32:35.380 --&gt; 00:32:39.270
Gabor Szabo: recently pushed here, is that if there is a</p>
<p>211
00:32:39.470 --&gt; 00:32:48.279
Gabor Szabo: project that hasn't been changed for, I don't know, half a year, that… very unlikely that any changes you make will</p>
<p>212
00:32:48.280 --&gt; 00:32:51.509
Gabor Szabo: Will be accepted and integrated.</p>
<p>213
00:32:51.510 --&gt; 00:33:16.380
Gabor Szabo: So if you are… if you care about the fact also that your work will be accepted, then probably it's a good idea, and you're not… you don't have a specific module that creates that you want to contribute to, then probably it's a good idea to pick one that has been changed recently, because then it… the likelihood that it will… that someone will look at your changes</p>
<p>214
00:33:18.530 --&gt; 00:33:28.459
Gabor Szabo: is higher. So, I can share this link as well, and we can try this one. Okay? So, I'm,</p>
<p>215
00:33:28.980 --&gt; 00:33:34.729
Gabor Szabo: Stopping the share now, and then posing the video, and then giving you…</p>
<p>216
00:33:34.980 --&gt; 00:33:46.419
Gabor Szabo: I don't know, 5 minutes, 10 minutes, maybe, I'll give you to do this, okay? So what your task is, is to find the crate.</p>
<p>217
00:33:46.940 --&gt; 00:33:50.400
Gabor Szabo: Whether you find it a random one, or one that you already</p>
<p>218
00:33:50.570 --&gt; 00:34:01.559
Gabor Szabo: came with, because you want to contribute to, clone it, okay, to your machine, and run the, run the tests, and run the,</p>
<p>219
00:34:01.840 --&gt; 00:34:07.370
Gabor Szabo: test coverage report, and then show it to us, okay? So we can see it.</p>
<p>220
00:34:07.720 --&gt; 00:34:13.979
Gabor Szabo: Emm… So, let me find the button to stop, pause the recording.</p>
<p>221
00:34:14.909 --&gt; 00:34:16.709
Gabor Szabo: Pause recording, okay.</p>
<p>222
00:34:19.100 --&gt; 00:34:33.349
Gabor Szabo: Okay, so now we continue. Hopefully, those who are watching the video might have stopped it and did some of the work already. And I would like to just run on the same codebase, the…</p>
<p>223
00:34:33.510 --&gt; 00:34:46.270
Gabor Szabo: the other tool, the mutation testing that I mentioned. So this is the cargo install mutant, and that's it. I… I don't remember how to run these things, even though they are so simple.</p>
<p>224
00:34:48.199 --&gt; 00:34:50.740
Gabor Szabo: Okay, that's not good.</p>
<p>225
00:34:52.010 --&gt; 00:34:56.419
Gabor Szabo: I thought it was installed in the container… in the image.</p>
<p>226
00:34:56.699 --&gt; 00:35:00.560
Gabor Szabo: But apparently not, so now I'm installing it.</p>
<p>227
00:35:07.160 --&gt; 00:35:10.430
Gabor Szabo: And then, let's use the opportunity.</p>
<p>228
00:35:12.350 --&gt; 00:35:15.700
Gabor Szabo: to go to… GitHub?</p>
<p>229
00:35:17.800 --&gt; 00:35:19.070
Gabor Szabo: Sub-gub?</p>
<p>230
00:35:20.720 --&gt; 00:35:22.590
Gabor Szabo: And, Rust…</p>
<p>231
00:35:27.450 --&gt; 00:35:30.089
Gabor Szabo: Docker on Ubuntu, okay.</p>
<p>232
00:35:31.780 --&gt; 00:35:36.300
Gabor Szabo: Dockerfile, okay, I'm going to enlarge the font, probably, it's a good idea.</p>
<p>233
00:35:36.550 --&gt; 00:35:38.100
Gabor Szabo: Dockerfile…</p>
<p>234
00:35:43.550 --&gt; 00:35:44.510
Gabor Szabo: Utah?</p>
<p>235
00:35:47.810 --&gt; 00:35:49.400
Gabor Szabo: Interesting, you see?</p>
<p>236
00:35:50.020 --&gt; 00:35:51.309
Gabor Szabo: It's not there.</p>
<p>237
00:35:53.350 --&gt; 00:36:04.439
Gabor Szabo: Okay, so this is the file, okay, just to explain you, nothing to do really with the project. This is the file, the Docker file, that generates that Docker image.</p>
<p>238
00:36:09.370 --&gt; 00:36:13.650
Gabor Szabo: And so I'm going to add… this one.</p>
<p>239
00:36:22.670 --&gt; 00:36:24.370
Gabor Szabo: That's it, right? Yeah.</p>
<p>240
00:36:27.450 --&gt; 00:36:37.000
Gabor Szabo: Strange, I thought that I already added it. Okay, so git add docker file, git… edit… mute.</p>
<p>241
00:36:40.320 --&gt; 00:36:42.350
Gabor Szabo: Mutant… okay.</p>
<p>242
00:36:43.770 --&gt; 00:36:47.009
Gabor Szabo: So… that's it, basically. Oh, no.</p>
<p>243
00:36:52.000 --&gt; 00:36:54.460
Gabor Szabo: It probably…</p>
<p>244
00:36:58.100 --&gt; 00:36:59.739
Gabor Szabo: I updated something there.</p>
<p>245
00:37:00.800 --&gt; 00:37:18.530
Gabor Szabo: I can even take a look at it. It was the dependable that updated something in the GitHub Actions, okay? That's why I had to pull it. Anyway, I updated the Docker configuration, so the next time it builds the image, which is now, and I will already have the</p>
<p>246
00:37:18.590 --&gt; 00:37:29.880
Gabor Szabo: this tool also inside, so the mutants, which apparently I didn't have. Okay, so now I'm supposed to be able to run this command as well inside the container.</p>
<p>247
00:37:30.610 --&gt; 00:37:36.020
Gabor Szabo: And because it's a very much smaller crate.</p>
<p>248
00:37:36.020 --&gt; 00:37:51.670
Gabor Szabo: It still found 350 mutants, but the tests are running, I think, much faster. But I still… there are a couple of missed things, so let me try to remember how it helped, how it was. So this is the…</p>
<p>249
00:37:54.020 --&gt; 00:38:01.070
Gabor Szabo: This was when… before I ran the… I contributed, I think. Then I com… after I…</p>
<p>250
00:38:01.490 --&gt; 00:38:07.420
Gabor Szabo: So I found this crate, and then I run these tools, and I found that there are, like.</p>
<p>251
00:38:07.710 --&gt; 00:38:14.159
Gabor Szabo: 600… 165… Mutants that were, failing.</p>
<p>252
00:38:14.330 --&gt; 00:38:23.280
Gabor Szabo: or missed, and that was exactly the story that I told you, that there were these, this,</p>
<p>253
00:38:23.600 --&gt; 00:38:35.659
Gabor Szabo: This is the change, so it had these print statements inside. Doing some calculation, or doing some work, generating this doc, whatever it is, doesn't matter, it's a string.</p>
<p>254
00:38:35.800 --&gt; 00:38:40.960
Gabor Szabo: And then just printing it out. That was the code, that was the test.</p>
<p>255
00:38:41.090 --&gt; 00:38:52.549
Gabor Szabo: And so I… I looked at what it prints out, I said, okay, hopefully, whatever it prints out is the right thing. I mean, I said, I mean, I don't really know, I don't…</p>
<p>256
00:38:52.780 --&gt; 00:39:06.159
Gabor Szabo: really know what it's supposed to be, but let's… let's assume that whatever it is does now works, is the correct one. So, I think I even commented in the… in the comment that I hadn't</p>
<p>257
00:39:06.160 --&gt; 00:39:15.670
Gabor Szabo: verified that whatever we are now testing is correct, I just… testing whatever it… so the regression part of it.</p>
<p>258
00:39:15.840 --&gt; 00:39:22.499
Gabor Szabo: So, I replace the print statement with an assert statement, saying, okay, this is what we are expecting</p>
<p>259
00:39:22.780 --&gt; 00:39:37.749
Gabor Szabo: this dock to be. And that's it. And then I ran the cargo mutants, and it went down from 165 missed to 141 missed, out of the 337 mutants. Now.</p>
<p>260
00:39:37.790 --&gt; 00:39:44.169
Gabor Szabo: I don't know what happened since then. There, I mean, since I made that pull request.</p>
<p>261
00:39:45.370 --&gt; 00:39:51.179
Gabor Szabo: Yeah, I made that pull request somewhere, probably there is a link here to the pull request.</p>
<p>262
00:39:53.030 --&gt; 00:39:56.629
Gabor Szabo: Since now that I run it, it found…</p>
<p>263
00:39:56.880 --&gt; 00:40:12.649
Gabor Szabo: It scripts… 350, mutants. It's saying at the bottom, last row, I don't know if you can see it, I hope that you can see it. It says it's now running the… which mutant it's testing, but it's,</p>
<p>264
00:40:13.400 --&gt; 00:40:17.550
Gabor Szabo: And so far, this is the result. Okay?</p>
<p>265
00:40:25.440 --&gt; 00:40:27.040
Gabor Szabo: So, I mean…</p>
<p>266
00:40:27.150 --&gt; 00:40:40.310
Gabor Szabo: This is not very surprising, okay? I probably… there is no… not a lot of point, not really good reason to run the mutation test on this grade, because we already know that there are so many</p>
<p>267
00:40:40.630 --&gt; 00:40:42.580
Gabor Szabo: There's…</p>
<p>268
00:40:42.660 --&gt; 00:40:52.099
Gabor Szabo: such a huge percentage of the codebase is not tested. That's what the tarpaulin, the tarpaulin, the test coverage report, revealed.</p>
<p>269
00:40:52.110 --&gt; 00:41:01.990
Gabor Szabo: So, obviously, if you make any changes in a code, part of the code that is not tested, the test, it won't impact the tests, okay? The test won't fail. So…</p>
<p>270
00:41:01.990 --&gt; 00:41:13.810
Gabor Szabo: Most of these things that we can see here are probably parts of the code that were never tested. So the first thing that we should do now is write some tests for those parts.</p>
<p>271
00:41:13.960 --&gt; 00:41:23.009
Gabor Szabo: Okay, so I think I'm going to even stop this, because, it's just running and doing…</p>
<p>272
00:41:23.490 --&gt; 00:41:26.109
Gabor Szabo: If you'll give us a report, okay, whatever.</p>
<p>273
00:41:26.300 --&gt; 00:41:33.190
Gabor Szabo: Instead of that, let me try to do some… let me try to do something else. I run…</p>
<p>274
00:41:33.720 --&gt; 00:41:36.539
Gabor Szabo: AGY, which is the…</p>
<p>275
00:41:40.240 --&gt; 00:41:48.040
Gabor Szabo: which is… what is it called? The anti-gravity, okay, so the Gemini tool.</p>
<p>276
00:41:54.040 --&gt; 00:41:57.790
Gabor Szabo: Okay, so there is a question. Some tests in this codebase</p>
<p>277
00:41:57.940 --&gt; 00:42:06.759
Gabor Szabo: are running for too long. Is there a way to ignore specific tests instead of just removing them?</p>
<p>278
00:42:07.190 --&gt; 00:42:25.900
Gabor Szabo: I think… I mean, yeah, running the normal test running, definitely, you have… you can filter out tests. I'm not sure if you're using tarpaulin or this tool, how to do this, but cargo mutants.</p>
<p>279
00:42:26.120 --&gt; 00:42:27.130
Gabor Szabo: Help?</p>
<p>280
00:42:27.630 --&gt; 00:42:28.640
Gabor Szabo: Bless?</p>
<p>281
00:42:28.950 --&gt; 00:42:33.710
Gabor Szabo: Exclude… here it is.</p>
<p>282
00:42:38.600 --&gt; 00:42:39.690
Gabor Szabo: Okay.</p>
<p>283
00:42:41.730 --&gt; 00:42:47.109
Gabor Szabo: I'm not sure if what the… what is it excluding, whether it's excluding the files.</p>
<p>284
00:42:49.240 --&gt; 00:42:58.350
Gabor Szabo: which ones to change, or excluding, tests from… I know, probably the… the…</p>
<p>285
00:43:00.130 --&gt; 00:43:03.479
Gabor Szabo: Wait a second. Time out. Time out.</p>
<p>286
00:43:03.620 --&gt; 00:43:13.720
Gabor Szabo: That I remember. So you can set, what are… what should be the timeout. Minimum test timeout, okay?</p>
<p>287
00:43:16.180 --&gt; 00:43:26.200
Gabor Szabo: or you can set a timeout, whatever, maximum runtime for all cargo commands. Okay, not minimum test time, I don't know. Timeout multiplier…</p>
<p>288
00:43:27.050 --&gt; 00:43:30.809
Gabor Szabo: I don't know, okay? Let's see, cargo test.</p>
<p>289
00:43:45.310 --&gt; 00:43:55.649
Gabor Szabo: So, here's exclude packages, and which test to run. So, with the test, you can configure which ones… you can tell it which one to run and which not.</p>
<p>290
00:43:58.190 --&gt; 00:44:13.890
Gabor Szabo: Yeah, I don't know… I don't know how to tell the other tools which test to run when you're running. And I'm not even sure that that's a good idea. I mean, if test coverage… if you care about test coverage, we want to know what is the general test coverage.</p>
<p>291
00:44:13.890 --&gt; 00:44:22.199
Gabor Szabo: I mean, depending on what you're testing. For example, I have a codebase where I have various subsystems.</p>
<p>292
00:44:22.410 --&gt; 00:44:24.209
Gabor Szabo: And I have passed.</p>
<p>293
00:44:24.360 --&gt; 00:44:31.239
Gabor Szabo: Specifically for those subsystems. And then there are generic, more integration tests, let's say.</p>
<p>294
00:44:31.300 --&gt; 00:44:35.230
Gabor Szabo: And so, sometimes I want to run test coverage report.</p>
<p>295
00:44:35.230 --&gt; 00:44:59.739
Gabor Szabo: running only the tests of the specific subsystem to see how well they are actually covering that subsystem, without the integration tests that are also covering those subsystems, and might cover some parts of it that are the more, like, unit tests are not covering. And let's say I want to make sure that the unit tests are covering. So, in that case, I run</p>
<p>296
00:44:59.740 --&gt; 00:45:05.100
Gabor Szabo: A test coverage report on the test of the subsystem, or whatever.</p>
<p>297
00:45:05.320 --&gt; 00:45:08.210
Gabor Szabo: Crate, or… so part of the code.</p>
<p>298
00:45:09.470 --&gt; 00:45:20.860
Gabor Szabo: So I wanted to do this, I think, run anti-gravity, which is Gemini, and I have a subscription, so hopefully it will, do some…</p>
<p>299
00:45:23.100 --&gt; 00:45:30.640
Gabor Szabo: okay, whatever, it's warning about me, good, whatever, good. So, I would like to,</p>
<p>300
00:45:31.240 --&gt; 00:45:34.929
Gabor Szabo: I don't know exactly the…</p>
<p>301
00:45:36.120 --&gt; 00:45:48.090
Gabor Szabo: we can go back to the report, okay? So, we can go back to this report, and find…</p>
<p>302
00:45:48.200 --&gt; 00:45:49.790
Gabor Szabo: something here.</p>
<p>303
00:45:53.400 --&gt; 00:45:56.120
Gabor Szabo: Here, there is a function here, indent.</p>
<p>304
00:45:56.270 --&gt; 00:45:57.310
Gabor Szabo: Okay?</p>
<p>305
00:45:57.550 --&gt; 00:46:03.450
Gabor Szabo: So, right… one test, Death.</p>
<p>306
00:46:03.580 --&gt; 00:46:07.180
Gabor Szabo: Real… Cool…</p>
<p>307
00:46:13.970 --&gt; 00:46:16.420
Gabor Szabo: It's called SRC Displays.</p>
<p>308
00:46:16.540 --&gt; 00:46:17.430
Gabor Szabo: Right?</p>
<p>309
00:46:18.380 --&gt; 00:46:21.420
Gabor Szabo: The… indent.</p>
<p>310
00:46:23.730 --&gt; 00:46:32.990
Gabor Szabo: Hmmelt… the… what is it? Config indent? Let's say this one, config indent.</p>
<p>311
00:46:34.100 --&gt; 00:46:42.250
Gabor Szabo: function in the SRC… display… File.</p>
<p>312
00:46:43.340 --&gt; 00:46:44.340
Gabor Szabo: Okay?</p>
<p>313
00:46:44.480 --&gt; 00:46:45.870
Gabor Szabo: I, I…</p>
<p>314
00:46:46.110 --&gt; 00:47:00.439
Gabor Szabo: just trying to, minimize it, okay? So I told it what to do. Let me see. We are seeing the test works fine with cargo test, but with cargo turbo, it takes forever. Well,</p>
<p>315
00:47:00.730 --&gt; 00:47:06.890
Gabor Szabo: So, the forever is way too long, obviously, but, it's,</p>
<p>316
00:47:07.120 --&gt; 00:47:19.629
Gabor Szabo: It's definitely a lot slower, because now, while the test is running, it's also recording things, so it added various things to the code base, to the compiled code.</p>
<p>317
00:47:20.440 --&gt; 00:47:25.289
Gabor Szabo: So you have a lot more code, inside your… your…</p>
<p>318
00:47:26.080 --&gt; 00:47:44.390
Gabor Szabo: code, right? Your application, and it's writing somewhere, so it will definitely take longer. Now, forever, it's a bit too much, okay? So, but I did see, like, a 10 times increase in time, and that seems like,</p>
<p>319
00:47:44.750 --&gt; 00:47:50.230
Gabor Szabo: I don't know, normal, shall I call it, but existing, at least. So…</p>
<p>320
00:47:54.010 --&gt; 00:48:08.839
Gabor Szabo: Yeah. Now, on the other hand, yeah, you can… you could take a look, I don't know if what operating system you're running. It still hasn't finished, so I feel it's stopped. Yeah, maybe it stopped. Yeah, that can also happen. But you could also take a look at the…</p>
<p>321
00:48:09.370 --&gt; 00:48:22.489
Gabor Szabo: So probably you can also set some logging on it, so you will see if it is progressing, and… and you could probably take a look at… because you're using Zoom, it might also take up some of your,</p>
<p>322
00:48:24.520 --&gt; 00:48:32.550
Gabor Szabo: CPU power, I had no idea what… you can take a look at that one, depending on your operating system, and the… how…</p>
<p>323
00:48:32.680 --&gt; 00:48:37.510
Gabor Szabo: bigger computer it is. So here it is, okay?</p>
<p>324
00:48:37.950 --&gt; 00:48:44.139
Gabor Szabo: So, there is a… Test for it.</p>
<p>325
00:48:44.660 --&gt; 00:48:53.600
Gabor Szabo: Okay? And now we can go to the… To the outside, git status.</p>
<p>326
00:48:55.060 --&gt; 00:49:07.530
Gabor Szabo: And this is what changed. So these are… this is the tarpaulin report, okay? Probably I should set a gitignore, so it won't be added by meme.</p>
<p>327
00:49:07.530 --&gt; 00:49:16.869
Gabor Szabo: by mistake, but it's not really my project, so… And so this is what the… the agent now changed, bit, diff, S-R-C,</p>
<p>328
00:49:17.080 --&gt; 00:49:18.010
Gabor Szabo: Leap.</p>
<p>329
00:49:19.240 --&gt; 00:49:24.439
Gabor Szabo: And, I don't know. Use create display config?</p>
<p>330
00:49:26.430 --&gt; 00:49:27.490
Gabor Szabo: Okay.</p>
<p>331
00:49:28.380 --&gt; 00:49:37.330
Gabor Szabo: document from, it takes the document, doc, okay? Config default pretty, indent, okay, this is what it does.</p>
<p>332
00:49:37.560 --&gt; 00:49:43.630
Gabor Szabo: So it… it creates some configuration, and then it runs two string prettes config.</p>
<p>333
00:49:43.780 --&gt; 00:49:47.220
Gabor Szabo: Okay, and now it needs to look at, like, this.</p>
<p>334
00:49:48.380 --&gt; 00:49:55.789
Gabor Szabo: Okay, let's, hope that it works, okay? So…</p>
<p>335
00:49:55.970 --&gt; 00:50:00.050
Gabor Szabo: I go back, and now probably,</p>
<p>336
00:50:03.260 --&gt; 00:50:16.079
Gabor Szabo: probably I need to… I should have two Docker sessions open, or I can run here, with an exclamation mark, I think. I can run cargo…</p>
<p>337
00:50:16.550 --&gt; 00:50:21.019
Gabor Szabo: cargo… How did I write a telephone pole in here?</p>
<p>338
00:50:25.970 --&gt; 00:50:27.959
Gabor Szabo: Test coverage, this one.</p>
<p>339
00:50:28.750 --&gt; 00:50:30.740
Gabor Szabo: Cargo tarpaulin?</p>
<p>340
00:50:34.620 --&gt; 00:50:36.959
Gabor Szabo: And then I also need this one.</p>
<p>341
00:50:40.670 --&gt; 00:50:54.260
Gabor Szabo: And before I do that, let me… move the tarpauline… A report, tarpaulin report… 1.</p>
<p>342
00:50:54.510 --&gt; 00:50:57.850
Gabor Szabo: Okay? And now I run this code again.</p>
<p>343
00:50:58.350 --&gt; 00:51:05.509
Gabor Szabo: And so I'm inside the agent, but I'm executing an external code, hopefully.</p>
<p>344
00:51:05.630 --&gt; 00:51:12.659
Gabor Szabo: So it's not the agent doing anything, it's just letting the… I don't need to leave the…</p>
<p>345
00:51:12.940 --&gt; 00:51:18.309
Gabor Szabo: the agent to run this, and I think it finished.</p>
<p>346
00:51:19.010 --&gt; 00:51:25.429
Gabor Szabo: Let me see its status. Okay, so it created a new report.</p>
<p>347
00:51:25.620 --&gt; 00:51:34.890
Gabor Szabo: And I can go back to this page, and now I'm going to reload it, and hopefully this part is going to be green.</p>
<p>348
00:51:36.110 --&gt; 00:51:42.160
Gabor Szabo: this part, okay? Good. So I… now I have a… new test.</p>
<p>349
00:51:43.170 --&gt; 00:51:49.549
Gabor Szabo: And I can get… check out, minus B.</p>
<p>350
00:51:50.410 --&gt; 00:51:51.360
Gabor Szabo: Ed.</p>
<p>351
00:51:51.490 --&gt; 00:51:52.430
Gabor Szabo: Dest?</p>
<p>352
00:51:52.880 --&gt; 00:51:55.589
Gabor Szabo: Give that SRC.</p>
<p>353
00:51:55.930 --&gt; 00:51:56.960
Gabor Szabo: bleep?</p>
<p>354
00:51:59.420 --&gt; 00:52:05.480
Gabor Szabo: Git status, git… And… nest?</p>
<p>355
00:52:22.160 --&gt; 00:52:23.030
Gabor Szabo: Beautiful.</p>
<p>356
00:52:23.360 --&gt; 00:52:24.160
Gabor Szabo: Oof.</p>
<p>357
00:52:24.380 --&gt; 00:52:27.510
Gabor Szabo: Minus… you…</p>
<p>358
00:52:33.840 --&gt; 00:52:34.690
Gabor Szabo: 4.</p>
<p>359
00:52:39.070 --&gt; 00:52:40.480
Gabor Szabo: It's this?</p>
<p>360
00:52:41.300 --&gt; 00:52:52.549
Gabor Szabo: Okay? So this one, you remember Git Remote minus 3. I have, in this project, I have two remotes. I cloned it originally from</p>
<p>361
00:52:52.730 --&gt; 00:53:02.119
Gabor Szabo: So I don't work the same way as many other people do. I don't… when I encounter an open source project, I don't fork and clone.</p>
<p>362
00:53:02.440 --&gt; 00:53:07.549
Gabor Szabo: from my own fork. Instead, I clone from the original one.</p>
<p>363
00:53:08.590 --&gt; 00:53:20.160
Gabor Szabo: that I'm going to contribute to, and then I play with it, and then if I really know how to contribute, then I create a fork, and I create a remote which is called fork.</p>
<p>364
00:53:20.170 --&gt; 00:53:34.910
Gabor Szabo: This makes more sense to me, okay? Instead of the other way around that many people recommend. And so now, I created a branch, and pushed out that branch to my fork.</p>
<p>365
00:53:35.160 --&gt; 00:53:43.289
Gabor Szabo: And I can go to… It's SubGov XML, okay?</p>
<p>366
00:53:43.590 --&gt; 00:53:48.619
Gabor Szabo: GitHub subgroup XMLEM, okay?</p>
<p>367
00:53:48.790 --&gt; 00:53:57.470
Gabor Szabo: So this is the fork, and it's here, and I think the actions are Running.</p>
<p>368
00:53:58.000 --&gt; 00:54:04.310
Gabor Szabo: Yeah, and the test passed, okay, so this was one minute ago, so this is the GitHub action.</p>
<p>369
00:54:04.510 --&gt; 00:54:07.059
Gabor Szabo: And I can go back to this one.</p>
<p>370
00:54:07.240 --&gt; 00:54:11.919
Gabor Szabo: And, send a pull request.</p>
<p>371
00:54:12.630 --&gt; 00:54:14.080
Gabor Szabo: Create a pull request.</p>
<p>372
00:54:18.000 --&gt; 00:54:19.049
Gabor Szabo: And that's it!</p>
<p>373
00:54:20.320 --&gt; 00:54:30.130
Gabor Szabo: Okay? Now, I'm going to… I think that's it. If you have any questions, any more comments, then…</p>
<p>374
00:54:30.260 --&gt; 00:54:43.430
Gabor Szabo: do it, then ask it now. If not, I can stop the recording, so people who are watching the video can click on the like button and follow the channel, okay, remember that one.</p>
<p>375
00:54:44.200 --&gt; 00:54:51.200
Gabor Szabo: And, and you can stay around and do a little bit more work, if you…</p>
<p>376
00:54:51.810 --&gt; 00:54:56.019
Gabor Szabo: would like to, those people who are around, and I can still help you.</p>
<p>377
00:54:56.460 --&gt; 00:55:04.400
Gabor Szabo: So, it seems… can you share the YouTube channel? Yes, yes, I don't… It's,</p>
<p>378
00:55:07.770 --&gt; 00:55:10.220
Gabor Szabo: How do I share it?</p>
<p>379
00:55:10.360 --&gt; 00:55:11.370
Gabor Szabo: Properly.</p>
<p>380
00:55:11.810 --&gt; 00:55:18.310
Gabor Szabo: Find new window… Without sharing all the… everything.</p>
<p>381
00:55:18.560 --&gt; 00:55:26.050
Gabor Szabo: YouTube at Google. Actually, I think if I just visit that URL, then it will only show those</p>
<p>382
00:55:26.290 --&gt; 00:55:33.889
Gabor Szabo: Not all of my… This is the YouTube channel. Okay, I put it in the chat.</p>
<p>383
00:55:34.750 --&gt; 00:55:35.860
Gabor Szabo: Boom.</p>
<p>384
00:55:37.690 --&gt; 00:55:49.630
Gabor Szabo: Surprisingly, it's called Code Mailer. Anyway, so thank you for, for being here, and asking questions and discussing things.</p>
<p>385
00:55:49.630 --&gt; 00:56:04.759
Gabor Szabo: And thank you for everyone who's watching the video, for watching it, and follow the channel. And below the video, you will find links to… I guess, to the video, and to the… to notes, and to all the things that I shared in the chat.</p>
<p>386
00:56:06.410 --&gt; 00:56:19.070
Gabor Szabo: And, sign up for upcoming events, both Rust and other languages that I also mentioned. And that's it for now. Thank you very much. Bye-bye.</p>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

  <entry>
    <title>Cursed Rust</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2026-08-30T17:30:01Z</updated>
    <pubDate>2026-08-30T17:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/cursed-rust" />
    <id>https://rust.code-maven.com/cursed-rust</id>
    <content type="html"><![CDATA[<h2 class="title is-4">Description</h2>
<p>A talk about abusing Rustlang's formal grammar rules.</p>
<p>Rust, chaos, and a chance to win your very own Ferris.</p>
<p>Come see what happens when programming is about fun, not clean code.</p>
<p>Programming isn’t always about writing the cleanest, most production-ready code. Sometimes, it’s about experimenting, breaking things, and making colleagues confused about what the heck you just wrote and why does it compile.</p>
<p>In this talk, we’ll take a playful look at what happens when you push Rust (and your brain cells) in unusual directions. Along the way, we’ll celebrate clever design choices in Rust, dabble in some esoteric examples, and remind ourselves that programming should be fun.</p>
<p>Come for the Rust, stay for the chaos.</p>
<p>Oh and throughout the presentation you will have a chance to win your very own Ferris the crab!</p>
<h2 class="title is-4">Bio</h2>
<p><a href="https://www.linkedin.com/in/milan-sedivy/">Milan Šedivý</a></p>
<p>I'm a chill software engineer who spends too much time at his computer :). I started programming early, took a detour into mathematics, and now I work professionally in software engineering. My interests range from low-level engineering and distributed systems to reverse engineering and analyzing how things work under the hood. I’ve had the opportunity to build production-grade systems in Rust, and in my spare time I mentor high school students and early career engineers, sharing both technical depth and a love for problem-solving.</p>
<h2 class="title is-4">Length</h2>
<p>60 min</p>
<p><a class="button is-primary" href="https://luma.com/omlooqv8">register</a></p>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

  <entry>
    <title>Creating a hexadecimal editor in Rust</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2026-08-27T20:30:01Z</updated>
    <pubDate>2026-08-27T20:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/creating-a-hexadecimal-editor-in-rust" />
    <id>https://rust.code-maven.com/creating-a-hexadecimal-editor-in-rust</id>
    <content type="html"><![CDATA[<h2 class="title is-4">Description</h2>
<p>In this talk, I'll tell a story involving the need of binary editing, how I tried to improve existing tools, and the outcome and challenges of my decision to build my own hex editor in Rust while learning the language. And no, I didn't ask a LLM to write it, for a variety of reasons I'll also cover in the presentation.</p>
<p>Next, I'll present the features my hex editor has and how it helps me (and hopefully others) to achieve my goals while working with security research on a daily basis.</p>
<h2 class="title is-4">Bio</h2>
<p><a href="https://github.com/merces/">Fernando Mercês</a> is a security researcher that spent more than 10 years analyzing malware and investigating cyberattacks and APTs. At <a href="https://binarly.io">Binarly</a>, he works with vulnerability detection in POSIX binaries as his primary focus, and broader ELF ecosystem support on the side. In his free time, he's a volunteer at <a href="https://mentebinaria.org.br/">Mente Binária</a>, the NPO that he founded with free educational programs in computing and security.</p>
<h2 class="title is-4">Length</h2>
<p>50 min</p>
<p><a class="button is-primary" href="https://luma.com/q8i3385k">register</a></p>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

  <entry>
    <title>Solving Real-World Planning Problems in Rust with SolverForge</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2026-08-09T15:30:01Z</updated>
    <pubDate>2026-08-09T15:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/solving-real-world-planning-problems-in-rust-with-solverforge" />
    <id>https://rust.code-maven.com/solving-real-world-planning-problems-in-rust-with-solverforge</id>
    <content type="html"><![CDATA[<h2 class="title is-4">Abstract</h2>
<p>Scheduling, routing, allocation, and dispatch problems appear everywhere, but their real-world constraints and competing objectives can quickly overwhelm hand-written rules.
In this practical talk, we will model and solve a planning problem end to end using SolverForge, an open-source planning optimization framework for Rust. We will explore how to represent the domain with ordinary Rust types, express hard constraints and softer business goals, run the solver, and inspect why one solution is better than another.
The emphasis will be on building a working planning application rather than explaining the entire architecture of the library. No previous experience with optimization algorithms is required; familiarity with Rust will be helpful.</p>
<h2 class="title is-4">Short bio</h2>
<p><a href="https://www.linkedin.com/in/vdistefano/">Vittorio Distefano</a> is the founder and lead developer of SolverForge, an open-source planning optimization framework for Rust. He is interested in decision-making software, constraint solving, and using Rust to build fast, inspectable systems for scheduling, routing, allocation, and dispatch.</p>
<h2 class="title is-4">Links</h2>
<ul>
<li><a href="https://solverforge.ai">solverforge.ai</a></li>
<li><a href="https://solverforge.org">solverforge.org</a></li>
<li><a href="https://solverforge.ai/use-cases">Use cases</a></li>
</ul>
<h2 class="title is-4">Length</h2>
<p>1.5 hours</p>
<p><a class="button is-primary" href="https://luma.com/rfbzk3ae">register</a></p>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

  <entry>
    <title>Mutation testing the xmlem Rust crate</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2026-06-23T21:30:01Z</updated>
    <pubDate>2026-06-23T21:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/mutant-testing-xmlem" />
    <id>https://rust.code-maven.com/mutant-testing-xmlem</id>
    <content type="html"><![CDATA[<p>As I am working on a project that generates HTML pages I wanted to prettify / beautify the files.
So far the best crate I found is the <a href="https://crates.io/crates/xmlem">xmlem</a>, however the generated
file are &quot;too pretty&quot;. That is, every HTML element is on it own line. I wanted to have an option
to keep the result a bit tighter. So I opened an <a href="https://github.com/xmlem/xmlem/issues/14">issue</a>
and <a href="https://github.com/Ltrlg">Ltrlg</a> basically gave his (her?) blessing for someone to work on it.</p>
<p>I thought to give it a try, but first I had to make myself familiar with the code and with the tests.</p>
<p>Side note: by the time I started to write this blog post <a href="https://github.com/bbqsrc">Brendan Molloy</a>,
who is apparently the original author of the crate, has already committed the change.
So maybe I won't have to do anything here. On the other hand I could contribute some of my expertise
to the project (GitHub Actions, testing etc.)</p>
<p>As I looked at the tests I noticed that in many cases the tests seem to only print the generated
HTML/XML and don't seem to verify the result. There were several <code>println!</code> calls instead of <code>assert_eq!</code> calls.</p>
<p>I figured it would be an interesting thing to see the test coverage report and the mutation testing report.</p>
<h2 class="title is-4">SHA</h2>
<p>I cloned the repository and got this sha: <code>89b9f9fa2f729f6e95ec79638c977dfecc3b6ec1</code>.
I keep it here so you can check it out too to reproduce this result.</p>
<h2 class="title is-4">Test coverage report</h2>
<p>Using <a href="https://crates.io/crates/cargo-tarpaulin">cargo-tarpaulin</a></p>
<pre><code>cargo install cargo-tarpaulin
</code></pre>
<pre><code>$ cargo tarpaulin --out Html --out Stdout

|| Uncovered Lines:
|| src/display.rs: 45-47, 50-52, 55-57, 60-62, 65-67, 135, 139, 293-294, 298, 342-343, 347, 392, 492-495, 497, 537
|| src/document.rs: 25, 49, 51-52, 57, 59-60, 73-74, 77-79, 82-84, 88-92, 99-107, 112-114, 118-125, 129, 175-177, 180, 182-190, 192-193, 197-198, 200-202, 204, 208-209, 214, 217-218, 220-224, 226, 228-229, 231, 234-237, 239, 242-244, 248-253, 257-258, 261-262, 265-269, 272-275, 281, 284-286, 294-297, 301, 318-321, 325-327, 357, 364, 369, 384, 422, 425, 431-433, 450-451, 466-468, 480, 487-489, 512, 527-529, 535-540, 542-544, 556, 563-564, 566-567, 569-570, 572, 574, 576-577, 601, 625-631, 633-634, 636-638, 645-650
|| src/element.rs: 93, 96, 119, 163, 168, 170, 206, 211, 220, 279-282, 284-287, 289, 440, 486, 549-550, 554-555, 558-560, 564-565, 568, 575-576, 578-579, 581, 583, 585-586, 589, 592-593, 595-596, 598, 601-602, 604, 606-607, 610, 617-619, 633
|| src/key.rs: 23-25, 33-35, 43-45, 68, 74-77, 88-91, 95-98, 102-105, 109-112, 116-123
|| src/select.rs: 48, 54-55, 69, 73, 78-79, 104, 108, 139-140, 143-144, 150, 154-155, 158, 162-165, 171-174, 180, 188-189, 192-193, 205, 209-210, 217, 221, 229, 237, 241, 245, 250-252, 256, 261-262, 264-265, 269, 273, 276, 280-281, 284-285, 288-290, 293, 295, 299, 301, 305, 316, 322-323, 346, 355-360, 364-366
|| src/value.rs: 27, 34, 41, 48, 52-55
|| Tested/Total Lines:
|| src/display.rs: 182/212
|| src/document.rs: 145/325
|| src/element.rs: 134/188
|| src/key.rs: 14/52
|| src/select.rs: 37/112
|| src/value.rs: 12/20
||
57.65% coverage, 524/909 lines covered
</code></pre>
<h2 class="title is-4">Mutation testing</h2>
<p>Using <a href="https://crates.io/crates/cargo-mutants">cargo-mutants</a></p>
<p>For documentation see the <a href="https://mutants.rs/">mutants</a> web site.</p>
<pre><code>cargo install cargo-mutants
</code></pre>
<pre><code>$ cargo mutants
Found 337 mutants to test
ok       Unmutated baseline in 8s build + 0s test
 INFO Auto-set test timeout to 20s
MISSED   src/display.rs:46:9: replace Config::indent -&gt; Self with Default::default() in 0s build + 0s test
MISSED   src/display.rs:51:9: replace Config::end_pad -&gt; Self with Default::default() in 0s build + 0s test
MISSED   src/display.rs:56:9: replace Config::max_line_length -&gt; Self with Default::default() in 0s build + 0s test
MISSED   src/display.rs:61:9: replace Config::entity_mode -&gt; Self with Default::default() in 0s build + 0s test
MISSED   src/display.rs:66:9: replace Config::indent_text_nodes -&gt; Self with Default::default() in 0s build + 0s test
MISSED   src/display.rs:128:9: replace &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for Declaration&gt;::print -&gt; std::io::Result&lt;()&gt; with Ok(()) in 0s build + 0s test
MISSED   src/display.rs:222:9: replace + with * in fmt_attrs in 0s build + 0s test
MISSED   src/display.rs:221:9: replace + with * in fmt_attrs in 0s build + 0s test
MISSED   src/display.rs:223:53: replace + with * in fmt_attrs in 0s build + 0s test
MISSED   src/display.rs:223:43: replace + with * in fmt_attrs in 0s build + 0s test
MISSED   src/display.rs:223:17: replace + with * in fmt_attrs in 0s build + 0s test
MISSED   src/display.rs:226:56: replace &gt; with == in fmt_attrs in 0s build + 0s test
MISSED   src/display.rs:226:56: replace &gt; with &lt; in fmt_attrs in 0s build + 0s test
MISSED   src/display.rs:226:56: replace &gt; with &gt;= in fmt_attrs in 0s build + 0s test
MISSED   src/display.rs:288:25: replace + with * in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:287:25: replace + with * in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 1s test
MISSED   src/display.rs:289:69: replace + with * in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 1s test
MISSED   src/display.rs:289:59: replace + with * in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:289:33: replace + with * in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:291:72: replace &gt; with == in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:291:72: replace &gt; with &lt; in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:291:72: replace &gt; with &gt;= in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:333:28: replace match guard !attrs.is_empty() with false in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:337:21: replace + with * in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:336:21: replace + with - in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:336:21: replace + with * in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:338:65: replace + with - in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 1s test
MISSED   src/display.rs:338:65: replace + with * in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 1s test
MISSED   src/display.rs:338:55: replace + with * in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:338:29: replace + with * in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:340:53: replace &amp;&amp; with || in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 1s test
MISSED   src/display.rs:340:68: replace &gt; with == in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:340:68: replace &gt; with &lt; in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:340:68: replace &gt; with &gt;= in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 1s test
MISSED   src/display.rs:354:60: replace &amp;&amp; with || in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:354:46: replace || with &amp;&amp; in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:354:49: delete ! in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:360:49: delete ! in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:379:38: replace || with &amp;&amp; in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:379:41: delete ! in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for ElementValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:412:41: replace &amp;&amp; with || in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for NodeValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:436:41: replace &amp;&amp; with || in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for NodeValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:442:41: replace &amp;&amp; with || in &lt;impl Print&lt;Config, State&lt;'_&gt;&gt; for NodeValue&gt;::print in 0s build + 0s test
MISSED   src/display.rs:482:53: replace || with &amp;&amp; in process_entities in 0s build + 0s test
MISSED   src/display.rs:486:28: replace || with &amp;&amp; in process_entities in 0s build + 0s test
MISSED   src/display.rs:492:49: replace match guard !is_text with true in process_entities in 0s build + 0s test
MISSED   src/display.rs:492:49: replace match guard !is_text with false in process_entities in 0s build + 0s test
MISSED   src/display.rs:493:48: replace match guard !is_text with true in process_entities in 0s build + 3s test
MISSED   src/display.rs:493:48: replace match guard !is_text with false in process_entities in 0s build + 0s test
MISSED   src/display.rs:500:28: replace match guard !ch.is_ascii_whitespace() &amp;&amp; ch.is_ascii_control() with false in process_entities in 0s build + 0s test
MISSED   src/display.rs:492:49: delete ! in process_entities in 0s build + 0s test
MISSED   src/display.rs:493:48: delete ! in process_entities in 0s build + 0s test
MISSED   src/display.rs:508:25: replace &amp;&amp; with || in process_entities in 0s build + 0s test
MISSED   src/display.rs:508:32: replace == with != in process_entities in 0s build + 0s test
MISSED   src/display.rs:510:33: replace &amp;&amp; with || in process_entities in 0s build + 0s test
MISSED   src/display.rs:511:61: replace || with &amp;&amp; in process_entities in 0s build + 0s test
MISSED   src/document.rs:83:8: delete ! in ord_elem in 0s build + 0s test
MISSED   src/document.rs:91:16: delete ! in ord_elem in 0s build + 0s test
MISSED   src/document.rs:106:12: delete ! in ord_elem in 0s build + 0s test
MISSED   src/document.rs:124:12: delete ! in ord_elem in 0s build + 0s test
MISSED   src/document.rs:176:9: replace Document::sort_nodes -&gt; Vec&lt;Node&gt; with vec![] in 0s build + 1s test
MISSED   src/document.rs:176:29: replace &lt; with == in Document::sort_nodes in 0s build + 0s test
MISSED   src/document.rs:176:29: replace &lt; with &gt; in Document::sort_nodes in 0s build + 0s test
MISSED   src/document.rs:176:29: replace &lt; with &lt;= in Document::sort_nodes in 0s build + 0s test
MISSED   src/document.rs:208:21: replace &amp;&amp; with || in Document::sort_nodes in 0s build + 0s test
MISSED   src/document.rs:208:24: delete ! in Document::sort_nodes in 0s build + 0s test
MISSED   src/document.rs:243:9: replace Document::sort_attrs with () in 0s build + 0s test
MISSED   src/document.rs:249:9: replace Document::sort with () in 0s build + 0s test
MISSED   src/document.rs:258:9: replace Document::set_declaration with () in 0s build + 0s test
MISSED   src/document.rs:262:9: replace Document::declaration -&gt; Option&lt;&amp;Declaration&gt; with None in 0s build + 0s test
MISSED   src/document.rs:266:9: replace Document::set_doctype with () in 0s build + 0s test
MISSED   src/document.rs:295:9: replace Document::doctype -&gt; Option&lt;&amp;str&gt; with None in 0s build + 0s test
MISSED   src/document.rs:295:9: replace Document::doctype -&gt; Option&lt;&amp;str&gt; with Some(&quot;&quot;) in 0s build + 0s test
MISSED   src/document.rs:295:9: replace Document::doctype -&gt; Option&lt;&amp;str&gt; with Some(&quot;xyzzy&quot;) in 0s build + 0s test
MISSED   src/document.rs:319:9: replace Document::to_string_pretty_with_config -&gt; String with String::new() in 0s build + 0s test
MISSED   src/document.rs:319:9: replace Document::to_string_pretty_with_config -&gt; String with &quot;xyzzy&quot;.into() in 0s build + 0s test
MISSED   src/document.rs:363:25: delete match arm Some(XML_VERSION_1_0) in Document::from_reader in 0s build + 0s test
MISSED   src/document.rs:366:25: delete match arm Some(XML_VERSION_1_1) in Document::from_reader in 0s build + 0s test
MISSED   src/document.rs:626:9: replace &lt;impl fmt::Display for ReadError&gt;::fmt -&gt; fmt::Result with Ok(Default::default()) in 2s build + 2s test
MISSED   src/document.rs:646:9: replace &lt;impl Error for ReadError&gt;::source -&gt; Option&lt;&amp;(dyn Error +'static)&gt; with None in 0s build + 0s test
MISSED   src/element.rs:214:18: replace &gt;= with &lt; in Element::append_new_element_after in 0s build + 0s test
MISSED   src/element.rs:559:9: replace Element::display -&gt; String with String::new() in 0s build + 0s test
MISSED   src/element.rs:559:9: replace Element::display -&gt; String with &quot;xyzzy&quot;.into() in 0s build + 1s test
MISSED   src/element.rs:576:9: replace Element::next_sibling_element -&gt; Option&lt;Element&gt; with None in 0s build + 1s test
MISSED   src/element.rs:581:29: replace == with != in Element::next_sibling_element in 0s build + 0s test
MISSED   src/element.rs:583:15: replace += with -= in Element::next_sibling_element in 0s build + 0s test
MISSED   src/element.rs:583:15: replace += with *= in Element::next_sibling_element in 0s build + 0s test
MISSED   src/element.rs:585:18: replace &lt; with == in Element::next_sibling_element in 0s build + 0s test
MISSED   src/element.rs:585:18: replace &lt; with &gt; in Element::next_sibling_element in 0s build + 0s test
MISSED   src/element.rs:585:18: replace &lt; with &lt;= in Element::next_sibling_element in 0s build + 0s test
MISSED   src/element.rs:593:9: replace Element::prev_sibling_element -&gt; Option&lt;Element&gt; with None in 0s build + 1s test
MISSED   src/element.rs:598:29: replace == with != in Element::prev_sibling_element in 0s build + 0s test
MISSED   src/element.rs:601:18: replace == with != in Element::prev_sibling_element in 0s build + 0s test
MISSED   src/element.rs:604:15: replace -= with += in Element::prev_sibling_element in 0s build + 0s test
MISSED   src/element.rs:604:15: replace -= with /= in Element::prev_sibling_element in 0s build + 0s test
MISSED   src/element.rs:606:18: replace == with != in Element::prev_sibling_element in 0s build + 0s test
MISSED   src/element.rs:618:9: replace Element::query_selector_all -&gt; Vec&lt;Element&gt; with vec![] in 0s build + 0s test
TIMEOUT  src/element.rs:644:15: replace += with *= in walk_tree in 0s build + 20s test
MISSED   src/key.rs:24:9: replace CDataSection::as_str -&gt; &amp;'d str with &quot;&quot; in 0s build + 0s test
MISSED   src/key.rs:24:9: replace CDataSection::as_str -&gt; &amp;'d str with &quot;xyzzy&quot; in 0s build + 0s test
MISSED   src/key.rs:34:9: replace ProcessingInstruction::as_str -&gt; &amp;'d str with &quot;&quot; in 0s build + 0s test
MISSED   src/key.rs:34:9: replace ProcessingInstruction::as_str -&gt; &amp;'d str with &quot;xyzzy&quot; in 0s build + 0s test
MISSED   src/key.rs:44:9: replace Comment::as_str -&gt; &amp;'d str with &quot;&quot; in 0s build + 0s test
MISSED   src/key.rs:44:9: replace Comment::as_str -&gt; &amp;'d str with &quot;xyzzy&quot; in 0s build + 0s test
MISSED   src/key.rs:75:9: replace Node::as_text -&gt; Option&lt;Text&gt; with None in 0s build + 0s test
MISSED   src/key.rs:76:13: delete match arm Node::Text(e) in Node::as_text in 0s build + 0s test
MISSED   src/key.rs:89:9: replace Node::as_document_type -&gt; Option&lt;DocumentType&gt; with None in 0s build + 0s test
MISSED   src/key.rs:90:13: delete match arm Node::DocumentType(e) in Node::as_document_type in 0s build + 0s test
MISSED   src/key.rs:96:9: replace Node::as_cdata -&gt; Option&lt;CDataSection&gt; with None in 0s build + 0s test
MISSED   src/key.rs:97:13: delete match arm Node::CDataSection(e) in Node::as_cdata in 0s build + 0s test
MISSED   src/key.rs:103:9: replace Node::as_comment -&gt; Option&lt;Comment&gt; with None in 0s build + 0s test
MISSED   src/key.rs:104:13: delete match arm Node::Comment(e) in Node::as_comment in 0s build + 0s test
MISSED   src/key.rs:110:9: replace Node::as_processing_instruction -&gt; Option&lt;ProcessingInstruction&gt; with None in 0s build + 0s test
MISSED   src/key.rs:111:13: delete match arm Node::ProcessingInstruction(e) in Node::as_processing_instruction in 0s build + 0s test
MISSED   src/key.rs:117:9: replace Node::to_ordinal -&gt; u8 with 0 in 0s build + 0s test
MISSED   src/key.rs:117:9: replace Node::to_ordinal -&gt; u8 with 1 in 0s build + 0s test
MISSED   src/select.rs:42:5: replace hash -&gt; u32 with 0 in 0s build + 0s test
MISSED   src/select.rs:42:5: replace hash -&gt; u32 with 1 in 0s build + 0s test
MISSED   src/select.rs:49:9: replace &lt;impl Borrow&lt;String&gt; for PrehashedString&gt;::borrow -&gt; &amp;String with Box::leak(Box::new(String::new())) in 0s build + 0s test
MISSED   src/select.rs:49:9: replace &lt;impl Borrow&lt;String&gt; for PrehashedString&gt;::borrow -&gt; &amp;String with Box::leak(Box::new(&quot;xyzzy&quot;.into())) in 0s build + 0s test
MISSED   src/select.rs:55:9: replace &lt;impl PrecomputedHash for PrehashedString&gt;::precomputed_hash -&gt; u32 with 0 in 0s build + 0s test
MISSED   src/select.rs:55:9: replace &lt;impl PrecomputedHash for PrehashedString&gt;::precomputed_hash -&gt; u32 with 1 in 0s build + 0s test
MISSED   src/select.rs:73:9: replace &lt;impl cssparser::ToCss for Value&gt;::to_css -&gt; std::fmt::Result with Ok(Default::default()) in 0s build + 0s test
MISSED   src/select.rs:79:9: replace &lt;impl PrecomputedHash for Value&gt;::precomputed_hash -&gt; u32 with 0 in 0s build + 0s test
MISSED   src/select.rs:79:9: replace &lt;impl PrecomputedHash for Value&gt;::precomputed_hash -&gt; u32 with 1 in 0s build + 0s test
MISSED   src/select.rs:105:9: replace &lt;impl NonTSPseudoClass for Value&gt;::is_active_or_hover -&gt; bool with true in 0s build + 0s test
MISSED   src/select.rs:109:9: replace &lt;impl NonTSPseudoClass for Value&gt;::is_user_action_state -&gt; bool with true in 0s build + 0s test
MISSED   src/select.rs:144:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::parent_element -&gt; Option&lt;Self&gt; with None in 0s build + 0s test
MISSED   src/select.rs:151:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::parent_node_is_shadow_root -&gt; bool with true in 0s build + 0s test
MISSED   src/select.rs:159:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::is_pseudo_element -&gt; bool with true in 0s build + 0s test
MISSED   src/select.rs:163:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::prev_sibling_element -&gt; Option&lt;Self&gt; with None in 0s build + 0s test
MISSED   src/select.rs:172:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::next_sibling_element -&gt; Option&lt;Self&gt; with None in 0s build + 0s test
MISSED   src/select.rs:181:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::is_html_element_in_html_document -&gt; bool with true in 0s build + 0s test
MISSED   src/select.rs:185:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::has_local_name -&gt; bool with true in 0s build + 0s test
MISSED   src/select.rs:189:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::has_namespace -&gt; bool with true in 0s build + 0s test
MISSED   src/select.rs:189:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::has_namespace -&gt; bool with false in 0s build + 0s test
MISSED   src/select.rs:189:44: replace == with != in &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::has_namespace in 0s build + 0s test
MISSED   src/select.rs:193:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::is_same_type -&gt; bool with true in 0s build + 0s test
MISSED   src/select.rs:193:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::is_same_type -&gt; bool with false in 0s build + 1s test
MISSED   src/select.rs:193:42: replace == with != in &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::is_same_type in 0s build + 0s test
MISSED   src/select.rs:202:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::attr_matches -&gt; bool with true in 0s build + 0s test
MISSED   src/select.rs:206:50: replace match guard ns.as_str() == &quot;&quot; with true in &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::attr_matches in 0s build + 0s test
MISSED   src/select.rs:226:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::match_non_ts_pseudo_class -&gt; bool with true in 0s build + 1s test
MISSED   src/select.rs:234:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::match_pseudo_element -&gt; bool with true in 0s build + 0s test
MISSED   src/select.rs:238:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::is_link -&gt; bool with true in 0s build + 0s test
MISSED   src/select.rs:242:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::is_html_slot_element -&gt; bool with true in 0s build + 0s test
MISSED   src/select.rs:250:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::has_id -&gt; bool with true in 0s build + 0s test
MISSED   src/select.rs:250:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::has_id -&gt; bool with false in 0s build + 0s test
MISSED   src/select.rs:261:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::has_class -&gt; bool with true in 0s build + 0s test
MISSED   src/select.rs:261:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::has_class -&gt; bool with false in 0s build + 0s test
MISSED   src/select.rs:273:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::imported_part -&gt; Option&lt;&lt;Self::Impl as SelectorImpl&gt;::Identifier&gt; with Some(Default::default()) in 0s build + 0s test
MISSED   src/select.rs:277:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::is_part -&gt; bool with true in 0s build + 0s test
MISSED   src/select.rs:281:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::is_empty -&gt; bool with true in 0s build + 0s test
MISSED   src/select.rs:281:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::is_empty -&gt; bool with false in 0s build + 0s test
MISSED   src/select.rs:285:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::is_root -&gt; bool with true in 0s build + 0s test
MISSED   src/select.rs:285:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::is_root -&gt; bool with false in 0s build + 0s test
MISSED   src/select.rs:285:30: replace == with != in &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::is_root in 0s build + 0s test
MISSED   src/select.rs:289:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::first_element_child -&gt; Option&lt;Self&gt; with None in 0s build + 0s test
MISSED   src/select.rs:302:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::has_custom_state -&gt; bool with true in 0s build + 0s test
MISSED   src/select.rs:306:9: replace &lt;impl selectors::Element for ElementRef&lt;'_&gt;&gt;::add_element_unique_hashes -&gt; bool with true in 0s build + 0s test
MISSED   src/select.rs:321:9: replace &lt;impl Parser&lt;'i&gt; for TheParser&gt;::parse_non_ts_pseudo_class -&gt; Result&lt;Value, ParseError&lt;'i, SelectorParseErrorKind&lt;'i&gt;&gt;&gt; with Ok(Default::default()) in 0s build + 0s test
MISSED   src/select.rs:353:9: replace Selector::matches -&gt; bool with true in 0s build + 0s test
MISSED   src/value.rs:53:9: replace NodeValue::as_document_type -&gt; Option&lt;&amp;str&gt; with None in 0s build + 0s test
MISSED   src/value.rs:53:9: replace NodeValue::as_document_type -&gt; Option&lt;&amp;str&gt; with Some(&quot;&quot;) in 0s build + 0s test
MISSED   src/value.rs:53:9: replace NodeValue::as_document_type -&gt; Option&lt;&amp;str&gt; with Some(&quot;xyzzy&quot;) in 0s build + 0s test
MISSED   src/value.rs:54:13: delete match arm NodeValue::DocumentType(e) in NodeValue::as_document_type in 0s build + 0s test
337 mutants tested in 6m: 165 missed, 118 caught, 53 unviable, 1 timeouts
</code></pre>
<p>The 165 missed mutants indicate that there are lots of places the code could be changed and the test would not catch the regression.</p>
<h2 class="title is-4">Convert <code>println!</code> to <code>assert_eq!</code></h2>
<p>As I mentioned, there were many test cases where at the end of the test the content of the generated document was printed,
but not verified. So I changed all those cases. I don't know much about this crate so I could not personally verify
the correctness of the results. So first I changed the <code>println</code> to compare the result to an empty string. This made the test
fail printing the actual result. Then I took the current actual result and set it as the expected string.</p>
<p>This will ensure that changes to the code don't lead to unplanned changes in the output.</p>
<p>Later someone who wants to manually verify the correctness of the tests can do so.</p>
<p>Here is an example of the changes I made. See the full <a href="https://github.com/xmlem/xmlem/commit/4b002fd4fd42b89649ba7ef01d059b3fab89e0f1">diff here</a>. It was merged into the code-base.</p>
<pre><code>-   println!(&quot;{:#}&quot;, doc);
+   assert_eq!(&quot;&lt;root&gt;\n  potato\n&lt;/root&gt;\n&quot;, format!(&quot;{:#}&quot;, doc));
</code></pre>
<h2 class="title is-4">Running mutation testing again</h2>
<pre><code>cargo mutants
...
337 mutants tested in 5m: 141 missed, 142 caught, 53 unviable, 1 timeouts
</code></pre>
<p>There are still 141 missed cases, but that's already 24 less than what we had earlier.</p>
<h2 class="title is-4">Conclusion</h2>
<p>Given that the test coverage is &quot;only&quot; 57.65% this might not be such a great example showing that &quot;high test coverage might not mean the code is really tested&quot;,
but still converting those <code>println!</code> macros to <code>assert_eq!</code> macros reduced the missed cases by 24.</p>
<p>We need to increase the test coverage in order to make sure the code does not accidently breaks in one place when some changes are introduced in another place.
At the same time we also need to monitor the reports from the mutant tests to make sure the tests indeed verify the behavior.</p>
<p>Unrelated note: What would be really nice if the two reports could be combined and it would emphasize the statements that were covered by the test coverage,
but still don't fail the tests if they are changed.</p>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

  <entry>
    <title>Access the process starting time everywhere</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2026-06-12T08:30:01Z</updated>
    <pubDate>2026-06-12T08:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/fixed-start-time" />
    <id>https://rust.code-maven.com/fixed-start-time</id>
    <content type="html"><![CDATA[<p>If you need to access the process starting time from several functions, then instead of passing it around or instead of using the <a href="/cache-the-result-of-a-function">caching</a>
we could use the <a href="https://doc.rust-lang.org/std/sync/struct.LazyLock.html">std::sync::LazyLock</a>.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/fixed-start-time/src/main.rs">examples/fixed-start-time/src/main.rs</a></strong></p>
<pre><code class="language-rust">use std::sync::LazyLock;
use std::time::SystemTime;

static START_TIME: LazyLock&lt;SystemTime&gt; = LazyLock::new(SystemTime::now);

fn main() {
    print_start_time();
    print_start_time();

}

fn print_start_time() {
    println!(&quot;{:?}&quot;, *START_TIME);
}

</code></pre>
<h2 class="title is-4">Output</h2>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/fixed-start-time/out.txt">examples/fixed-start-time/out.txt</a></strong></p>
<pre><code class="language-txt">SystemTime { tv_sec: 1781242831, tv_nsec: 637877888 }
SystemTime { tv_sec: 1781242831, tv_nsec: 637877888 }

</code></pre>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

  <entry>
    <title>Cached dispatch table</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2026-06-11T13:00:01Z</updated>
    <pubDate>2026-06-11T13:00:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/cached-dispatch-table" />
    <id>https://rust.code-maven.com/cached-dispatch-table</id>
    <content type="html"><![CDATA[<p>We have lots of functions handling various cases.
These are divided into multiple modules based on the types of the cases.</p>
<p>The nice thing seem to be is creating a dispatch table mapping strings to functions.</p>
<p>Each module is responsible for returning a DispatchTable. There is a central function that
combines them.</p>
<p>We could generate this up-front and then pass the DispatchTable to each function but it seemed
better to get the DispatchTable internally.</p>
<p>If we do that we'll recreate the DispatchTable in every call. Using the <a href="https://crates.io/crates/cached">cached crate</a>
allows us to eliminate all the calls but the first one.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/cache-dispatch-table/src/main.rs">examples/cache-dispatch-table/src/main.rs</a></strong></p>
<pre><code class="language-rust">use cached::macros::cached;

mod locations;
mod other;
mod types;

use crate::types::DispatchTable;

fn main() {
    for name in &amp;[&quot;city&quot;, &quot;state&quot;, &quot;country&quot;, &quot;language&quot;] {
        process(name);
    }
}

fn process(name: &amp;str) {
    let dispatch = get_dispatch();

    println!(&quot;Processing: {name}&quot;);
    if let Some(process_fn) = dispatch.get(name) {
        let result = process_fn();
        println!(&quot;{}&quot;, result);
    }
    println!();
}

#[cached]
fn get_dispatch() -&gt; DispatchTable {
    println!(&quot;get_dispatch called&quot;);

    let mut config = DispatchTable::new();

    let cfg = crate::locations::get_dispatch();
    for (key, value) in cfg {
        config.insert(key, value);
    }

    let cfg = crate::other::get_dispatch();
    for (key, value) in cfg {
        config.insert(key, value);
    }

    config
}

</code></pre>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/cache-dispatch-table/src/locations.rs">examples/cache-dispatch-table/src/locations.rs</a></strong></p>
<pre><code class="language-rust">use crate::types::DispatchTable;

fn process_city() -&gt; &amp;'static str {
    &quot;Processing city of Seoul&quot;
}

fn process_country() -&gt; &amp;'static str {
    &quot;Processing country of Korea&quot;
}

pub(crate) fn get_dispatch() -&gt; DispatchTable {
    println!(&quot;get_dispatch for locations called&quot;);

    let mut config = DispatchTable::new();
    config.insert(&quot;city&quot;, process_city);
    config.insert(&quot;country&quot;, process_country);
    config
}

</code></pre>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/cache-dispatch-table/src/other.rs">examples/cache-dispatch-table/src/other.rs</a></strong></p>
<pre><code class="language-rust">use crate::types::DispatchTable;

fn process_language() -&gt; &amp;'static str {
    &quot;Processing the Korean language&quot;
}

pub(crate) fn get_dispatch() -&gt; DispatchTable {
    println!(&quot;get_dispatch for locations called&quot;);

    let mut config = DispatchTable::new();
    config.insert(&quot;language&quot;, process_language);
    config
}

</code></pre>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/cache-dispatch-table/src/types.rs">examples/cache-dispatch-table/src/types.rs</a></strong></p>
<pre><code class="language-rust">use std::collections::HashMap;

pub(crate) type Handler = fn() -&gt; &amp;'static str;
pub(crate) type DispatchTable = HashMap&lt;&amp;'static str, Handler&gt;;

</code></pre>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/cache-dispatch-table/out.txt">examples/cache-dispatch-table/out.txt</a></strong></p>
<pre><code class="language-txt">get_dispatch called
get_dispatch for locations called
get_dispatch for locations called
Processing: city
Processing city of Seoul

Processing: state

Processing: country
Processing country of Korea

Processing: language
Processing the Korean language


</code></pre>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/cache-dispatch-table/Cargo.toml">examples/cache-dispatch-table/Cargo.toml</a></strong></p>
<pre><code class="language-toml">[package]
name = &quot;cache-dispatch-table&quot;
version = &quot;0.1.0&quot;
edition = &quot;2024&quot;

[dependencies]
cached = &quot;2.0.2&quot;

</code></pre>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

  <entry>
    <title>Cache the result of a function HashMap</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2026-06-11T12:30:01Z</updated>
    <pubDate>2026-06-11T12:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/cache-the-hashmap-result-of-a-function" />
    <id>https://rust.code-maven.com/cache-the-hashmap-result-of-a-function</id>
    <content type="html"><![CDATA[<p>Caching the result of a function using the <a href="https://crates.io/crates/cached">cached crate</a></p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/cache-hashmap-result-of-function/src/main.rs">examples/cache-hashmap-result-of-function/src/main.rs</a></strong></p>
<pre><code class="language-rust">use std::collections::HashMap;
use cached::macros::cached;

fn main() {
    let config = get_config();
    println!(&quot;Config: {:?}&quot;, config);

    let config = get_config();
    println!(&quot;Config: {:?}&quot;, config);
}


#[cached]
fn get_config() -&gt; HashMap&lt;&amp;'static str, String&gt; {
    println!(&quot;get_config called&quot;);

    let mut config = HashMap::new();
    config.insert(&quot;city&quot;, String::from(&quot;Seoul&quot;));
    config.insert(&quot;country&quot;, String::from(&quot;Korea&quot;));
    config
}




</code></pre>
<p>The function runs only once.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/cache-hashmap-result-of-function/out.txt">examples/cache-hashmap-result-of-function/out.txt</a></strong></p>
<pre><code class="language-txt">get_config called
Config: {&quot;country&quot;: &quot;Korea&quot;, &quot;city&quot;: &quot;Seoul&quot;}
Config: {&quot;country&quot;: &quot;Korea&quot;, &quot;city&quot;: &quot;Seoul&quot;}

</code></pre>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/cache-hashmap-result-of-function/Cargo.toml">examples/cache-hashmap-result-of-function/Cargo.toml</a></strong></p>
<pre><code class="language-toml">[package]
name = &quot;cache-hashmap-result-of-function&quot;
version = &quot;0.1.0&quot;
edition = &quot;2024&quot;

[dependencies]
cached = &quot;2.0.2&quot;

</code></pre>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

  <entry>
    <title>Cache the result of a function</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2026-06-11T11:30:01Z</updated>
    <pubDate>2026-06-11T11:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/cache-the-result-of-a-function" />
    <id>https://rust.code-maven.com/cache-the-result-of-a-function</id>
    <content type="html"><![CDATA[<p>I have some code where I wanted to cache the result of a function. I found the <a href="https://crates.io/crates/cached">cached crate</a> to be useful.</p>
<p>Here is the first experiment with it showing how it caches the value in one function, but not in the other.
The first 2 tv_nsec values differ, as time have elapsed between the calls.
The 3rd and 4th tv_nsec values are the same as the value got cached after the first call.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/cache-result-of-function/src/main.rs">examples/cache-result-of-function/src/main.rs</a></strong></p>
<pre><code class="language-rust">use std::time::SystemTime;
use cached::macros::cached;

fn main() {
    let time = get_current_time();
    println!(&quot;Current time: {:?}&quot;, time);
    let time = get_current_time();
    println!(&quot;Current time: {:?}&quot;, time);


    let time = get_cached_time();
    println!(&quot;Cacehed time: {:?}&quot;, time);
    let time = get_cached_time();
    println!(&quot;Cacehed time: {:?}&quot;, time);
}

fn get_current_time() -&gt; SystemTime {
    SystemTime::now()
}


#[cached]
fn get_cached_time() -&gt; SystemTime {
    SystemTime::now()
}

</code></pre>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/cache-result-of-function/out.txt">examples/cache-result-of-function/out.txt</a></strong></p>
<pre><code class="language-txt">Current time: SystemTime { tv_sec: 1781167332, tv_nsec: 68780987 }
Current time: SystemTime { tv_sec: 1781167332, tv_nsec: 68846651 }
Cacehed time: SystemTime { tv_sec: 1781167332, tv_nsec: 68882989 }
Cacehed time: SystemTime { tv_sec: 1781167332, tv_nsec: 68882989 }

</code></pre>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/cache-result-of-function/Cargo.toml">examples/cache-result-of-function/Cargo.toml</a></strong></p>
<pre><code class="language-toml">[package]
name = &quot;cache-result-of-function&quot;
version = &quot;0.1.0&quot;
edition = &quot;2024&quot;

[dependencies]
cached = &quot;2.0.2&quot;

</code></pre>
<p>If you only want to store a timestamp then there are better solutions as well. For example check out <a href="/fixed-start-time">the starting time of the process</a>.</p>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

  <entry>
    <title>Clippy: Multiple crate versions</title>
    <summary type="html"><![CDATA[Should we invest energy avoiding the same crate twice as our dependency?]]></summary>
    <updated>2026-04-18T09:30:01Z</updated>
    <pubDate>2026-04-18T09:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/multiple-crate-versions" />
    <id>https://rust.code-maven.com/multiple-crate-versions</id>
    <content type="html"><![CDATA[<p>Adding</p>
<pre><code class="language-toml">[lints.clippy]
cargo        = { priority = -1, level = &quot;deny&quot; }
</code></pre>
<p>to <code>Cargo.toml</code> will also turn on the <a href="https://rust-lang.github.io/rust-clippy/rust-1.95.0/index.html#multiple_crate_versions">multiple_crate_versions</a> rule.</p>
<p>It will them complain if the same create was added more than once (with different version numbers) to <code>Cargo.lock</code>.</p>
<h2 class="title is-4">How could this happen?</h2>
<h2 class="title is-4">What to do about it?</h2>
<ol>
<li>We can decide to disregard this rule. Add the following line to <code>Cargo.toml</code></li>
</ol>
<pre><code>[lints.clippy]
multiple_crate_versions = &quot;allow&quot;
</code></pre>
<ol start="2">
<li>Tell Clippy about the specific crates for which we allow the duplication:</li>
</ol>
<p>Create the <code>clippy.toml</code> file and add the following entry, with the names of the crates we allow to be duplicated:</p>
<pre><code class="language-toml">allowed-duplicate-crates = [
    &quot;async-channel&quot;,
    &quot;event-listener&quot;,
    &quot;foldhash&quot;,
    &quot;hashbrown&quot;,
    &quot;hashlink&quot;,
    &quot;wit-bindgen&quot;,
]
</code></pre>
<p>See <a href="https://doc.rust-lang.org/nightly/clippy/lint_configuration.html#allowed-duplicate-crates">allowed-duplicate-crates</a>.</p>
<ol start="3">
<li>
<p>Figure out which of our dependencies brought in these dependencies and either replace our own dependencies, or send a Pull-Request to our dependencies to allow for more flexibility.</p>
</li>
</ol>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

  <entry>
    <title>Zed - enable inlay type hints for Rust projects</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2026-02-12T11:30:01Z</updated>
    <pubDate>2026-02-12T11:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/zed-enable-inlay-type-hints-for-rust" />
    <id>https://rust.code-maven.com/zed-enable-inlay-type-hints-for-rust</id>
    <content type="html"><![CDATA[<p>Inlay hints or inline type hints allow you to see the derived types of a variable.</p>
<p>For example when you assign the return value of a function to a variable but you don't explicitely write the type of the variable,
Rust will derive (deduct) the type based on the function signature.</p>
<p>If you declare a variable <code>let x = 2;</code>, Rust will derived that it is an <code>i32</code> and the inlay type hints will show <code>let x: i32 = 2;</code>.</p>
<p>In another case if add together two variables holding numbers (that default to <code>i32</code>) and declare the resulting variable to be <code>i8</code>
then Rust will derived that the original two variables also must be <code>i8</code>.</p>
<p>So</p>
<pre><code class="language-rust">    let x = 2;
    let y = 3;
</code></pre>
<p>is understood as</p>
<pre><code class="language-rust">    let x: i32 = 2;
    let y: i32 = 3;
</code></pre>
<p>but</p>
<pre><code class="language-rust">    let x = 2;
    let y = 3;
    let z: i8 = x +y;
</code></pre>
<p>is understood as</p>
<pre><code class="language-rust">    let x: i8 = 2;
    let y: i8 = 3;
    let z: i8 = x +y;
</code></pre>
<p>The inlay type hints will help you understand this.</p>
<h2 class="title is-4">Inline (inlay) type hints:</h2>
<p>I configured the following to make it work. I am not sure everything is really needed.</p>
<ul>
<li>Installed rust-analyzers</li>
</ul>
<pre><code>rustup component add rust-analyzer
</code></pre>
<ul>
<li>settings.json</li>
</ul>
<p>In the <code>settings.json</code> file I added the following:</p>
<pre><code class="language-json">  &quot;inlay_hints&quot;: {
    &quot;enabled&quot;: true,
  },
  &quot;enable_language_server&quot;: true,
  &quot;lsp&quot;: {
    &quot;rust-analyzer&quot;: {
      &quot;binary&quot;: {
        &quot;path&quot;: &quot;/home/gabor/.cargo/bin/rust-analyzer&quot;
      },
      &quot;initialization_options&quot;: {
        &quot;inlayHints&quot;: {
          &quot;maxLength&quot;: null,
          &quot;lifetimeElisionHints&quot;: {
            &quot;enable&quot;: &quot;always&quot;,
            &quot;useParameterNames&quot;: true,
          },
          &quot;closureReturnTypeHints&quot;: {
            &quot;enable&quot;: &quot;always&quot;,
          },
        },
      },
    },
  },
</code></pre>
<ul>
<li>Trusted code</li>
</ul>
<p>Opened the crate I was working on as a &quot;project&quot; and then in the top-left corner of the IDE I clicked on &quot;Trusted project&quot;.</p>
<p>Then I could also use <code>Crtl-:</code> to toggle the inline hint.</p>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

  <entry>
    <title>Embed time of compilation and other build-time information in a rust binary</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2026-02-06T09:30:01Z</updated>
    <pubDate>2026-02-06T09:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/embed-compile-time-data" />
    <id>https://rust.code-maven.com/embed-compile-time-data</id>
    <content type="html"><![CDATA[<p>Sometimes it is useful to be able to show information about the compilation of a rust crate.</p>
<p>For example the date and time when it was compiled.</p>
<h2 class="title is-4">Cargo.toml</h2>
<p>We need to add the <a href="https://crates.io/crates/built">built</a> crate as a build-time dependency.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/embed-build-time-data/Cargo.toml">examples/embed-build-time-data/Cargo.toml</a></strong></p>
<pre><code class="language-toml">[package]
name = &quot;embed-build-time-data&quot;
version = &quot;0.1.0&quot;
edition = &quot;2024&quot;

[dependencies]

[build-dependencies]
built = { version = &quot;0.8&quot;, features = [&quot;cargo-lock&quot;, &quot;dependency-tree&quot;, &quot;chrono&quot;, &quot;git2&quot;, &quot;semver&quot;] }


</code></pre>
<h2 class="title is-4">build.rs</h2>
<p>We need to create <code>build.rs</code> in the root of the crate.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/embed-build-time-data/build.rs">examples/embed-build-time-data/build.rs</a></strong></p>
<pre><code class="language-rust">fn main() {
    built::write_built_file().expect(&quot;Failed to acquire build-time information&quot;)
}

</code></pre>
<h2 class="title is-4">main.rs</h2>
<p>We can then access the data in our code during run-time.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/embed-build-time-data/src/main.rs">examples/embed-build-time-data/src/main.rs</a></strong></p>
<pre><code class="language-rust">mod built_info {
    include!(concat!(env!(&quot;OUT_DIR&quot;), &quot;/built.rs&quot;));
}

fn main() {
    println!(&quot;TARGET                {:?}&quot;, built_info::TARGET);
    println!(&quot;PKG_VERSION           {:?}&quot;, built_info::PKG_VERSION);
    println!(&quot;RUSTC_VERSION         {:?}&quot;, built_info::RUSTC_VERSION);

    println!(&quot;GIT_VERSION           {:?}&quot;, built_info::GIT_VERSION);
    println!(&quot;GIT_DIRTY             {:?}&quot;, built_info::GIT_DIRTY);
    println!(&quot;GIT_COMMIT_HASH       {:?}&quot;, built_info::GIT_COMMIT_HASH);
    println!(
        &quot;GIT_COMMIT_HASH_SHORT {:?}&quot;,
        built_info::GIT_COMMIT_HASH_SHORT
    );

    println!(&quot;BUILT_TIME_UTC        {:?}&quot;, built_info::BUILT_TIME_UTC);

    println!(&quot;CI_PLATFORM           {:?}&quot;, built_info::CI_PLATFORM);
}

</code></pre>
<h2 class="title is-4">Output</h2>
<pre><code>$cargo run

TARGET                &quot;x86_64-unknown-linux-gnu&quot;
PKG_VERSION           &quot;0.1.0&quot;
RUSTC_VERSION         &quot;rustc 1.93.0 (254b59607 2026-01-19)&quot;
GIT_VERSION           Some(&quot;9c6447a&quot;)
GIT_DIRTY             Some(true)
GIT_COMMIT_HASH       Some(&quot;9c6447a01046142ccf471a597f21d2c08c67c2cd&quot;)
GIT_COMMIT_HASH_SHORT Some(&quot;9c6447a&quot;)
BUILT_TIME_UTC        &quot;Fri, 6 Feb 2026 10:42:50 +0000&quot;
CI_PLATFORM           None
</code></pre>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

  <entry>
    <title>Adding the repository field to Cargo.toml</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2026-01-27T08:30:01Z</updated>
    <pubDate>2026-01-27T08:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/adding-repository-to-cargo-toml-video" />
    <id>https://rust.code-maven.com/adding-repository-to-cargo-toml-video</id>
    <content type="html"><![CDATA[<ul>
<li><a href="https://osdc.code-maven.com/rust">OSDC Rust</a></li>
</ul>
<iframe width="560" height="315" src="https://www.youtube.com/embed/MPnaIxOTbLA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
<ul>
<li>00:00 Introduction</li>
<li>00:30 Open source contributors are volunteers</li>
<li>01:15 How to select an open source project to contribute to?</li>
<li>03:30 Select a recently updated project on GitHub.</li>
<li>05:08 <a href="https://rust-digger.code-maven.com/">Rust Digger</a></li>
<li>06:33 A crate that has no repository link... and one that has.</li>
<li>09:40 Check the <a href="https://github.com/hoodie/dvb-rs/pull/8">previous Pull-Request</a> adding the repository field to <a href="https://crates.io/crates/dvb">dvb</a></li>
<li>11:05 Picking the <a href="https://rust-digger.code-maven.com/crates/spyne-syntax">spyne-syntax</a> crate.</li>
<li>12:40 The GitHub account of <a href="https://github.com/ZA1815/">Zaid Ahmed</a>, finding the repository of spyne-syntax</li>
<li>15:45 Making the change to Cargo.toml, fork the repository</li>
<li>17:55 Commit the change, decide on the commit message.</li>
<li>20:50 Explain the change on the trailing line.</li>
<li>21:50 The <a href="https://github.com/szabgab/rust-digger/issues/89">issue</a> where I collect the PRs.</li>
<li>25:00 We finished the Pull-Request.</li>
<li>25:10 Some PRs take time to get accepted.</li>
<li>27:40 Offering driver-navigator pair-programming.</li>
<li>29:05 Radek: Is there some automatic evaluation of the PR?</li>
<li>30:00 GitHub Actions, tests, co-pilot integration.</li>
<li>34:45 Karol is volunteering to do a PR.</li>
<li>35:50 Karol start sharing his screen.</li>
<li>36:54 Picking the <a href="https://crates.io/crates/kftray-helper">kftray-helper</a> crate to work on.</li>
<li>38:50 A <a href="https://github.com/hcavarsan/kftray">repository</a> with multiple creates.</li>
<li>46:05 CodeRabbit skipped the review.</li>
<li>46:30 Google CLA - The legal issues.</li>
<li>51:10 Baby steps! <a href="https://osdc.code-maven.com/rust#chat">Chat with us</a></li>
</ul>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

  <entry>
    <title>Testing registration with email verification process</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2025-12-25T16:30:01Z</updated>
    <pubDate>2025-12-25T16:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/testing-registration-process" />
    <id>https://rust.code-maven.com/testing-registration-process</id>
    <content type="html"><![CDATA[<p>In many web-based application the process of registration includes a step of email verification.
The process is more or less this:</p>
<ol>
<li>The user types in an email address (and some other date)</li>
<li>The system checks that the looks ok, including the format of the email address. (e.g. that it is not empty)</li>
<li>Then it generates a unique code and stores all the received data and the unique code in the database.</li>
<li>Then it send an email to the given address containing a URL with the unique code.</li>
<li>When the user receives the email and clicks on the link the web system receives this verification request and can update the records marking the email as verified.</li>
</ol>
<p>There can and probably should be a number of extra things in the process.</p>
<ul>
<li>For example the database should contain an expiration date for the code.</li>
</ul>
<p>The question though, how do you test this code? Do you let the system send out real emails on every run? That would be slow and the test would need to rely an external service that will receive the email from where the test can download it for verification.</p>
<p>One solution for this is to save the email message in a file during the tests and make the tests read that file.</p>
<p>This is what you can see in this similified example.</p>
<h2 class="title is-4">Cargo.toml</h2>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/testing-email-sending/Cargo.toml">examples/testing-email-sending/Cargo.toml</a></strong></p>
<pre><code class="language-toml">[package]
name = &quot;mail-sender&quot;
version = &quot;0.1.0&quot;
edition = &quot;2024&quot;

[dependencies]
anyhow = &quot;1.0.102&quot;
clap = { version = &quot;4.5.60&quot;, features = [&quot;derive&quot;] }
lettre = { version = &quot;0.11.21&quot;, features = [&quot;file-transport&quot;, &quot;sendmail-transport&quot;] }
uuid = &quot;1.23.1&quot;

</code></pre>
<h2 class="title is-4">main.rs</h2>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/testing-email-sending/src/main.rs">examples/testing-email-sending/src/main.rs</a></strong></p>
<pre><code class="language-rust">use clap::Parser;
use lettre::{FileTransport, Message, SendmailTransport, Transport, message::header::ContentType};

#[derive(Parser)]
struct Cli {
    #[arg(long)]
    from: String,

    #[arg(long)]
    to: String,
}

fn main() {
    let args = Cli::parse();

    // We get this from the command line.
    // In a real application it would come from a config file.
    let from = &amp;args.from;

    // This is what the user entered when registering.
    let user_email = args.to.clone();

    register(from, &amp;user_email);
}

fn register(admin_email: &amp;str, user_email: &amp;str) -&gt; String {
    // This code is saved to the database and emailed to the user.
    let code = uuid::Uuid::new_v4().to_string();

    let subject = String::from(&quot;Email sent to confirm registration&quot;);
    let body = format!(&quot;Welcome! Use this code {code} to verify your email address.&quot;);

    let email = Message::builder()
        .from(admin_email.parse().unwrap())
        .to(user_email.parse().unwrap())
        .subject(subject)
        .header(ContentType::TEXT_PLAIN)
        .body(body)
        .unwrap();

    if cfg!(test) {
        let dirname = &quot;.&quot;;
        let sender = FileTransport::new(dirname);
        let filename = sender.send(&amp;email).unwrap();
        format!(&quot;{filename}.eml&quot;)
    } else {
        println!(&quot;Sending email to {}&quot;, user_email);
        let sender = SendmailTransport::new();
        sender.send(&amp;email).unwrap();
        String::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_register_creates_valid_email() {
        let filename = register(&quot;admin@example.com&quot;, &quot;user@example.com&quot;);
        let content = std::fs::read_to_string(filename).unwrap();

        assert!(content.contains(&quot;From: admin@example.com&quot;));
        assert!(content.contains(&quot;To: user@example.com&quot;));
        assert!(content.contains(&quot;Subject: Email sent to confirm registration&quot;));
        assert!(content.contains(&quot;Welcome! Use this code&quot;));

        let code_start =
            content.find(&quot;Welcome! Use this code &quot;).unwrap() + &quot;Welcome! Use this code &quot;.len();
        let code_end = content.find(&quot; to verify your&quot;).unwrap();
        let _code = &amp;content[code_start..code_end];

        // We can then use the code to verify the user in the test.
    }
}

</code></pre>
<h2 class="title is-4">Config test</h2>
<p>We can either use</p>
<pre><code class="language-rust">#[cfg(test)]
</code></pre>
<p>and</p>
<pre><code class="language-rust">#[cfg(not(test))]
</code></pre>
<p>or we can use</p>
<pre><code class="language-rust">if cfg!(test) {
    ...
} else {
    ...
}
</code></pre>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

  <entry>
    <title>Mail sender using the lettre crate</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2025-12-25T13:30:01Z</updated>
    <pubDate>2025-12-25T13:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/mail-sender" />
    <id>https://rust.code-maven.com/mail-sender</id>
    <content type="html"><![CDATA[<p><a href="https://crates.io/crates/lettre">lettre</a></p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/mail-sender/Cargo.toml">examples/mail-sender/Cargo.toml</a></strong></p>
<pre><code class="language-toml">[package]
name = &quot;mail-sender&quot;
version = &quot;0.1.0&quot;
edition = &quot;2024&quot;

[dependencies]
anyhow = &quot;1.0.102&quot;
clap = { version = &quot;4.5.60&quot;, features = [&quot;derive&quot;] }
lettre = { version = &quot;0.11.21&quot;, features = [&quot;file-transport&quot;, &quot;sendmail-transport&quot;] }

</code></pre>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/mail-sender/src/main.rs">examples/mail-sender/src/main.rs</a></strong></p>
<pre><code class="language-rust">use clap::Parser;
use lettre::{FileTransport, Message, SendmailTransport, Transport, message::header::ContentType};
use std::io::Read;

#[derive(Parser)]
struct Cli {
    #[arg(long)]
    from: String,

    #[arg(long)]
    to: String,

    #[arg(long)]
    subject: String,

    #[arg(long)]
    dir: Option&lt;String&gt;,
}

fn main() {
    let args = Cli::parse();
    let mut body = String::new();
    std::io::stdin().read_to_string(&amp;mut body).unwrap();

    let email = Message::builder()
        .from(args.from.parse().unwrap())
        .to(args.to.parse().unwrap())
        .subject(args.subject)
        .header(ContentType::TEXT_PLAIN)
        .body(body)
        .unwrap();

    match args.dir {
        Some(dirname) =&gt; {
            let sender = FileTransport::new(dirname);
            let filename = sender.send(&amp;email).unwrap();
            println!(&quot;{filename}.eml&quot;);
        }
        None =&gt; {
            let sender = SendmailTransport::new();
            sender.send(&amp;email).unwrap();
        }
    }
}

</code></pre>
]]></content>
    <author>
      <name>Gábor Szabó</name>
    </author>
  </entry>

</feed>

