Learning Library

← Back to Library

The Original Compiler Sin

Key Points

  • The Turing Award, often likened to the Nobel Prize of Computer Science, was highlighted by Ken Thompson’s 1984 acceptance speech, where he introduced the “Reflections on Trusting Trust” thought experiment exposing a meta‑backdoor in compilers.
  • Thompson’s concept of an “original compiler sin” describes how a maliciously altered compiler can silently embed backdoors into every program it later compiles, creating a self‑propagating security vulnerability that code audits cannot detect.
  • An anecdote about mispronouncing “contiguous” illustrates how errors or corruptions can be passed down through generations, mirroring how a compromised compiler’s flaw can persist across successive compiler versions.
  • Visualizing the family tree of programming languages and compilers reveals a daunting web of derivations, showing how a single compromised compiler could potentially affect countless languages and systems over decades.
  • Understanding this risk requires grasping that many compilers are self‑hosted—compiled by earlier versions of themselves—so a hidden flaw in an early compiler can cascade through the entire ecosystem.

Sections

Full Transcript

# The Original Compiler Sin **Source:** [https://www.youtube.com/watch?v=Fu3laL5VYdM](https://www.youtube.com/watch?v=Fu3laL5VYdM) **Duration:** 00:22:18 ## Summary - The Turing Award, often likened to the Nobel Prize of Computer Science, was highlighted by Ken Thompson’s 1984 acceptance speech, where he introduced the “Reflections on Trusting Trust” thought experiment exposing a meta‑backdoor in compilers. - Thompson’s concept of an “original compiler sin” describes how a maliciously altered compiler can silently embed backdoors into every program it later compiles, creating a self‑propagating security vulnerability that code audits cannot detect. - An anecdote about mispronouncing “contiguous” illustrates how errors or corruptions can be passed down through generations, mirroring how a compromised compiler’s flaw can persist across successive compiler versions. - Visualizing the family tree of programming languages and compilers reveals a daunting web of derivations, showing how a single compromised compiler could potentially affect countless languages and systems over decades. - Understanding this risk requires grasping that many compilers are self‑hosted—compiled by earlier versions of themselves—so a hidden flaw in an early compiler can cascade through the entire ecosystem. ## Sections - [00:00:00](https://www.youtube.com/watch?v=Fu3laL5VYdM&t=0s) **Ken Thompson's Trusting Trust Tale** - The passage outlines the prestige of the Turing Award, recounts Ken Thompson's 1984 acceptance speech that revealed the "Reflections on Trusting Trust" compiler backdoor concept, and ties it to a personal anecdote about mispronouncing “contiguous.” - [00:03:21](https://www.youtube.com/watch?v=Fu3laL5VYdM&t=201s) **Self-Hosting Compilers and Language Paradox** - The speaker explains the paradox of needing a language to define itself, illustrates it with the self‑hosted C compiler and its bootstrapping lineage from B compilers to early assemblers, and points out that the earliest computers relied on humans as the original “assemblers.” - [00:06:33](https://www.youtube.com/watch?v=Fu3laL5VYdM&t=393s) **Self‑Replicating Code Verification** - The speaker explains embedding ASCII codes for newline and quotation marks, compiles the program, diffs its output against the original source to confirm exact self‑generation, and notes a parallel implementation in Fortran. - [00:10:40](https://www.youtube.com/watch?v=Fu3laL5VYdM&t=640s) **Obfuscating Trojan Coin Code** - The speaker demonstrates how to conceal malicious functionality by encoding the program’s source as decimal ASCII values, creating a minimally obfuscated Trojan‑coin that’s harder to detect when compiled and run. - [00:14:23](https://www.youtube.com/watch?v=Fu3laL5VYdM&t=863s) **LLVM's Pervasive Role in Compilation** - The speaker explains how LLVM/Clang underlies many language compilers—including C, C++, Objective‑C, Swift, Rust, and Fortran—and demonstrates manually building an iOS Objective‑C app with a Makefile to illustrate LLVM’s widespread use. - [00:17:59](https://www.youtube.com/watch?v=Fu3laL5VYdM&t=1079s) **Ensuring Compiler Trustworthiness via Bootstrapping** - The speaker outlines a multi-step process of using a trusted second compiler to build GCC twice and verify identical outputs, suggests creating a self‑written minimal compiler to bootstrap larger ones, and cites the 2015 Xcode Ghost incident as a real‑world example of a compromised compiler. - [00:22:14](https://www.youtube.com/watch?v=Fu3laL5VYdM&t=1334s) **Lori's Video Sign-Off** - The speaker concludes the video by wishing viewers enjoyment and signing out with a friendly farewell. ## Full Transcript
0:00The Turing Award is widely considered to 0:02be the Nobel Prize of Computer Science. 0:04You may be surprised to know that this 0:07is not a real turning award, but it does 0:10look a lot like one. It is also in the 0:12shape of a bowl, but it also comes with 0:14a million-doll prize as well. When Ken 0:17Thompson, one of the original authors of 0:19the Unix operating system, accepted his 0:21touring award in 1984, his acceptance 0:24speech was a little bit different. It 0:26didn't talk about just like some 0:27generalized computing theory. He also 0:29didn't talk about the future of computer 0:31science. Instead, he released a very 0:34dark and terrifying thought experiment 0:36onto the world. What if every single 0:39compiler was already irreversibly 0:41compromised? 0:44An original sin passed to every 0:46generation of compiler with no cure. 0:52He called it reflections on trusting 0:54trust. It was the first example of a 0:56meta backdoor, a virus so perfect that 0:58even complete code auditing couldn't 1:00catch it. But let's think how an 1:02original compiler sin could permeate 1:04through multiple subsequent generations. 1:07Now, I have a story for you as an 1:09analogy. About a year ago, I made a 1:12video on virtual memory. It was a really 1:14good video. I encourage you to go watch 1:15it. In that video, I accidentally 1:18mispronounced the word contiguous as 1:20contiguous. And so inevitably when the 1:22comments made me realize my mistake, I 1:24ended up calling my mom because she 1:26watches all my videos. Hi mom. And I 1:29asked her, "Did you notice my mistake?" 1:32And she said, "What mistake?" And I 1:34said, "I mispronounced the word 1:35contiguous as contigious." And she just 1:38paused for a second and she said, "Is 1:40that wrong?" Now, I learned that word 1:42from my mom and she learned that word 1:44from her parents. So, it has to make you 1:46wonder how many generations far back do 1:48you have to go to find the original 1:50mistake? And that's exactly how the 1:53compiler original sin theory works. 1:55Basically, it's like self-replicating 1:57code where code reproduces code that 2:00also reproduces that same issue. Now, 2:03you might think this is kind of 2:04complicated, but let me make it much 2:06worse for you. If I look over here, this 2:09is actually the family tree for the 2:11fourth programming language. And this is 2:14kind of terrifying. And you will also be 2:16terrified to know that this is actually 2:18a very good representation of a lot of 2:21the other family trees for different 2:23programming languages and compilers 2:25themselves. This is just absolutely 2:28terrible to take a look at. We have all 2:31of these different derivations going 2:33from the year 1975 to 2010. I don't even 2:37want to know what happened after 2010. 2:39To understand how an original compiler 2:41sin would work, you first have to 2:43understand how compilers are compiled. 2:46And remember, compilers are just the 2:47programs that take in your source code 2:49and produce that compiled binary. A lot 2:52of different programming languages are 2:53something called self-hosted. And to 2:56understand what that means, let's take a 2:58step back for a second. I want you to 3:00think of a word, any word you want. I'm 3:02going to pick the word literal, and I'm 3:03going to come up with a definition for 3:05that word. My definition for a literal 3:07might be something like taking words at 3:10face value or taking something at their 3:11most basic definition. But pause for a 3:14second and how did I describe that 3:16definition of the English word literal? 3:19I used the English language to describe 3:21the definition of an English word. And 3:24you probably did the same if you were 3:25following along with that or or if you 3:27didn't let me know what you did cuz I 3:29need to like study you or something. But 3:31this kind of creates a paradox where you 3:34have to know the language in order to 3:36understand definitions of that language. 3:38And this is exactly how it works in the 3:40C programming language. Programming 3:42languages being self-hosted means that 3:45their compilers are written in the 3:47language that they compile for. Aka the 3:49C compiler is actually written in the C 3:52programming language. Now when I first 3:54started learning this, this kind of gave 3:56me an existential crisis. So allow me to 3:59also share my existential crisis with 4:01you. So if the C compiler is written in 4:04the C language itself, how was that 4:07compiler compiled? And the answer is 4:09another compiler. But how was that 4:12compiler compiled? Prior to the C 4:14compiler being fully self-hosted, it was 4:16actually derived from the B compiler. 4:19And I know naming conventions were 4:21absolutely genius back then. So if we go 4:23back generations of compilers compiling 4:26and deriving other compilers 4:28compiler baguette compiler sounds 4:31biblical goes along with this well we 4:33actually get the original self-hosted 4:35assemblers assembling assembly and I 4:38know what you're about to say but how 4:40are those assemblers assembled? I hope 4:42you're just as horrified as me to think 4:44that for the very earliest computers 4:47humans were the original assemblers. So 4:49what programmers had to do is they had 4:51to go handwrite their assembly programs 4:53and then at assemble time they had to go 4:56over to the instructions manual and 4:58handwrite those ones and zeros for the 5:01corresponding op codes of their program. 5:04So if you haven't thanked your compiler 5:05today, make sure to do so. We can 5:07demonstrate the idea of self-hosted and 5:09self-reroducing compilers with a 5:11programming exercise. Ken Thompson in 5:14his acceptance speech said that in 5:16college before video games they used to 5:18amuse themselves with different 5:20programming exercises. I don't think I 5:23was doing that in college. I think I was 5:24playing too much World of Warcraft. But 5:27the idea behind the exercise is to 5:29produce a program that when compiled and 5:31executed will output an exact copy of 5:34the original source code. And the name 5:36for these is actually quines after 5:38Willard Vin Orman Quin the philosopher. 5:40So, I'd like to try my hand at producing 5:42some self-producing code. And if you'd 5:45like to follow along, I've made all of 5:46the code for this available in my GitHub 5:48repository, which I will leave a link to 5:50in the description of this video. So, 5:52let's go over to our very first simple 5:55quin program, and this is going to be 5:56written in C. Now, remember, the goal 5:58behind this program is to produce 6:00exactly this source code as soon as it 6:03executes the program. And this is going 6:04to include all of these different 6:06comments as well as the actual code 6:08itself. So if you progressively just 6:10kept running and rerunning the output of 6:12this program, you would get kind of this 6:14recursive program that's always 6:16reproducing itself. So that's the whole 6:19complicated goal behind this. And I do a 6:22little bit of tricks with this with the 6:24format specifiers. For example, if I 6:26want to print a new line in this code, I 6:28can't just print a new line in the code. 6:31I have to use these format specifiers. 6:33So 10 corresponds to the asky value on 6:37the ASKI table for the new line 6:38character. And then if I want to print 6:41quotation marks inside of here, I can 6:43use the asky value 34 in order to 6:46produce those quotation marks inside of 6:48my string code that's going to be part 6:50of my output. Now that sounds 6:52complicated, but let's go and let's 6:54execute this program and make sure it 6:56produces all of the correct code. So 6:58I've already compiled my program and if 7:00I do /coin 7:02here you can see this exactly matches 7:05our original code and if I want to what 7:08I can do if I want to verify that the 7:10output is exactly the same I'm going to 7:13do this and I'm going to write the 7:15output of this to a temporary file I'll 7:18just call it temp. So now that contains 7:21the output of the program. And so if I 7:23want to diff this, I can do diff. I'm 7:26going to do the original quinine. C, 7:28which is the source code. And then I'm 7:30going to diff that with that temp 7:32output. And it should be exactly the 7:34same. Fingers crossed. Yes, it is 7:37exactly the same. So we have 7:38successfully made some self-producing 7:40code. Now Thompson did say that the best 7:42vehicle for producing this 7:44self-producing code was forran. So I 7:46decided to also write another version of 7:48this same code in the forran programming 7:50language. Now if we go over here, this 7:53looks very similar to the C program 7:55except so much uglier. But we have a 7:58kind of copy of the source code for this 8:01stored inside of this string here as 8:03well. So remember, we kind of have to 8:04self-reroduce the program inside of this 8:07string that's going to allow us to 8:08actually print this string one more 8:10time. And kind of a side note here, if 8:13you're ever coding in forran, note that 8:16a dow loop, you cannot increment the 8:18flag variable inside of it. So I had 8:20ended up having to change this to a dowh 8:22loop just to be able to increment my i 8:25variable. That's very interesting. And I 8:27believe this is the first time I've ever 8:29had the forran language as a language 8:32listed inside of my GitHub. So that's 8:34kind of a good achievement. To verify my 8:36forran quin is working properly, I'm 8:37going to compile this. So we'll do G for 8:41I'm going to do my fort quinine.f90 8:45output fort coin and we can run this 8:50fort coin and here you can see we do 8:52indeed have a another reproduction of 8:55this particular code. Now let's move on 8:57to the more interesting portion of this 8:59exercise. What if we slipped in some 9:01additional trojanized code inside of the 9:04self-producing program so that the 9:06second iteration would either have that 9:08trojanized code or have the code that 9:11was able to produce that code. So if I 9:13go over to Trojancoin.c, you can see the 9:16structure for this particular program is 9:18primarily the same as the previous ones, 9:20but I have this additional function 9:22inside of here. And so what this 9:24additional function is going to do is 9:26it's going to check for the string right 9:29found inside of the string that's about 9:30to be printed of the additional code 9:33that second iteration and it's going to 9:35replace the word right with the word 9:37wrong. So that means even inside of all 9:40these comments and stuff this is going 9:42to produce a trojanized version of the 9:44output. And you can see we also have to 9:47include this check function inside of 9:49the original string that's going to be 9:50our format specifier to specify the 9:53output of this. And if I go over and I 9:55want to execute this program slash 9:58judging coin, you can see if we go up 10:01here somewhere inside of this messy 10:03code, we have actually replaced the word 10:06right which was inside of this original 10:08comment with the word wrong which is 10:10making us look just a little bit crazy 10:12over here. If this idea for Trojanized 10:14code was instead part of a malicious 10:16compiler, it would basically have two 10:18different options. In the first option, 10:20if it recognized that it was compiling a 10:22regular program, it would slip in that 10:24malicious payload into the compiled 10:26binary. In the second case, if it 10:29realized that it was compiling code for 10:30a secondary compiler, aka it's 10:33recognizing its own source code, it 10:35would instead slip in the code that's 10:37used to generate the malicious payload. 10:39Now, you may be thinking that that 10:40Trojanized code was supremely obvious, 10:43and it kind of was, but I did that on 10:45purpose to demonstrate the point of how 10:47to slip in the original sin behavior 10:50into the coin itself. But there's just a 10:53multitude of offiscation techniques that 10:55you can add to code to make it more 10:57difficult to identify and detect inside 10:59of code. So, let's take a look at 11:01obfiscated Trojancoin. C to demonstrate 11:04how this is done. Now this is just 11:07honestly the bare minimum of obiscation 11:10I have added to this particular program. 11:12All I've simply done is taken the string 11:14that's used to generate the code for the 11:16program and translated that into the 11:19decimal version of the ASKI values. So 11:21if you take a look at the ASI table, all 11:24of those characters have corresponding 11:26decimal values. And so this is actually 11:29the original source code just encoded in 11:31its decimal value form. And you can see 11:34I still have my check function inside of 11:36here that's going to replace the word 11:38right with the word wrong. But instead 11:40I'm also using the asky representations 11:43in decimal form for this as well. And 11:46this function is also encoded inside of 11:48our giant number array here. I would say 11:52this is a lot more difficult to detect. 11:54So let's take a look at our offiscated 11:56code. I'm going to compile with GCC. 11:59Here's my offiscated Trojan coin. Ignore 12:02the warnings. Not normally, but in this 12:04particular case, you should. And we're 12:06going to execute this code. 12:10And you can see even though we had this 12:12confusing character array in decimal 12:14form in the original code, we actually 12:17have that original source code in the 12:20unobfiscated version. And this is really 12:22only the bare minimum of obfiscation 12:24that I'm adding here. As a professional 12:26reverse engineer, there is so much more 12:29that you can do with obfiscation. But 12:31back to our original sim compiler 12:33scenario, you can use this to obiscate 12:35the source code of the Trojanized 12:37compiler. But think about this, this 12:40might not even really be necessary 12:42because if you are using that compiler, 12:44you're compiling another compiler. And 12:47so other people are probably only using 12:50the compiled version of that. Meaning 12:52that if they really wanted to find that 12:54Trojanized code inside of it, they're 12:56probably working with a binary. So, 12:58they're going to have to actually 12:59reverse engineer that binary using tools 13:02like Gedra or IDA to even be able to 13:05detect that malicious code. I don't know 13:07about you, but I'm not really going 13:09around reverse engineering my compilers 13:11on a daily basis probably. Not only 13:14that, but if you're looking at the 13:16programs that are produced by this 13:18compiler, it would be very difficult to 13:20be able to detect this Trojanized 13:23behavior. you've effectively removed the 13:25Trojan version from the source code of 13:28that program. If you audit the source 13:30code, it's going to appear clean because 13:32the infection process only happens after 13:35the binary has been compiled. So, you 13:37would also have to reverse engineer that 13:39target binary. Now, you may be thinking 13:41that if you did this and infected the C 13:43compiler, you'd really only be infecting 13:46C programs. But that's actually not 13:48true. If you think about the complicated 13:50family tree of programming languages and 13:52compilers that I demonstrated earlier, a 13:55lot of programming languages will build 13:57off of other compilers to kind of avoid 14:00reinventing the wheel and focus on their 14:02new language that they're creating. A 14:04really good example of this is the LLVM 14:07project. Now, the LLVM project is a 14:09compiler infrastructure used by so many 14:13different languages. Basically, 14:14everything is LLVM. Everything is 14:17computer. 14:19So it's used directly to compile C, C++ 14:23or Objective C with its provided clang 14:25compiler or it's also used indirectly by 14:28a lot of different programming languages 14:30like uh Swift's compiler, Rust's 14:32compiler or even forrans compiler. To 14:35demonstrate just how pervasive this 14:36project actually is and how many 14:39compilers this applies to, think about 14:41developing an iOS application. Now, you 14:44normally would not consider an iOS 14:46application needing to involve the C 14:48programming language, but clang is used 14:51to compile Objective C, which used to be 14:53the language used for iOS apps. So, if 14:56we go over here, I have this make file. 14:58Instead of just doing this inside of 15:00Xcode, which normally does all of that 15:02on the back end, and you have no idea 15:04that LLVM is involved at all, I can do 15:07this manually. And I downloaded my own 15:09copy of the LLVM project, which is big 15:11ordeal. We'll get into that in a second. 15:14And I'm going to custom compile this 15:16directly. So I'm reading in all of the 15:19Objective C binaries and I'm going to be 15:22producing a target MacO binary for the 15:25iOS application. This is also very 15:27interesting because you can use this and 15:30add extra offiscation flags and 15:32customizations to LLVM to add automated 15:35offiscation to the binary. But that's 15:38kind of a topic for another video. So, 15:40let me go ahead real quick and 15:42demonstrate this. So, I'm just going to 15:44do make and it's reading in all of my 15:47Objective C binaries here. It's adding 15:49them in together. It's compiling them 15:51and it's going to produce the target 15:53binary. We're going to let this load cuz 15:55this is a really big application. 16:00And here we go. We have completed our 16:02test application which is comprised of 16:05originally Objective Code. Now, to show 16:07how large the LLVM project is, and to 16:11demonstrate that you're not going to be 16:13regularly auditing both your compiler 16:16and any inherited compilers that they 16:19rely on, let's take a look at the LLVM 16:21project. Now, this is available open 16:23source on GitHub, which is kind of cool. 16:26And this has this has so much stuff to 16:30it. And it did say it was an 16:31infrastructure. So that's just what the 16:33repository looks like. But let me show 16:35you something funny. So I'm going to 16:37clone this repository. 16:40I'm going to do get clone. That's my 16:43LLVM project, which I did tell you I 16:46downloaded and customized earlier. We 16:49are cloning this project. 16:52It's going to be a while. Everyone, 16:56how are you doing today? 16:58Hopefully good. 17:01What did the What did the brother cell 17:04say to the sister cell when she stepped 17:06on his toe? 17:09Mitosis. 17:13Okay, this is now cloning. You can see 17:15we're at 1% 2%. This is going to be very 17:19slow. So, you can see this repository is 17:21absolutely enormous. So, there is no way 17:23that you're going to be auditing this. I 17:25am going to kill this because I don't 17:27need that. I've talked a lot about how 17:29to implement a kind of proof of concept 17:31for this terrifying compiler thought 17:33experiment. But let's talk about some of 17:35the mitigations now and there are 17:37mitigations although they're pretty 17:39complex. David Wheeler as part of his 17:42PhD thesis created a technique for 17:44mitigating this known as diverse double 17:47compiling. So let's say if we wanted to 17:49try to prove that GCC hadn't been 17:52tampered with or trojanized. I have the 17:54steps right here for implementing DDC. 17:56One, pick a second independent compiler 17:59that you trust. Big job there. Two, use 18:03that second compiler to build a fresh 18:05GCC from source. We're going to call 18:07that source G1. And then three, use G1 18:11to build GCC again from source. We're 18:14going to call that result G2. And now 18:16the fourth step, compare G1 to G2. If 18:20they are bit forbit identical, then you 18:23know that successfully this compiler has 18:25not been tampered with. So you can use 18:27this and trust the programs created from 18:29it. Now this can get pretty complicated. 18:31So I will share a link to that paper in 18:33the description of this video. Now note 18:35to think about if you're trying to hand 18:37audit modern compilers these days like 18:40GCC or clang, they just have such a 18:43massive code base that it's going to be 18:45super challenging. So, another technique 18:47that you could try to use instead is 18:49kind of handwriting your own teeny 18:51compiler and then using that as a 18:53bootstrap to generate larger and larger 18:55compilers until you have a final 18:57compiler with a pure lineage that has 18:59been written entirely by yourself that 19:02you know you can trust. Now, you might 19:03think this all kind of sounds 19:05far-fetched, but this attack scenario 19:07has actually happened in real life. Back 19:10in 2015, there was this family of Mac 19:13malware called Xcode Ghost. And what it 19:16was was a Trojanized version elite Xcode 19:18compiler targeting iOS developers. So 19:22these developers would open up this 19:24Trojanized version of their IDE, write 19:26their iOS applications, and publish them 19:29to the App Store. But what the infected 19:32compiler would do is slip in additional 19:34malicious code from the infected IDE 19:38into the final applications. So that 19:40means hundreds of applications made it 19:42onto the app store looking like they 19:44were coming from legitimate developers 19:46with those developers being completely 19:48unaware that they were actually 19:50publishing Trojanized code. Now the 19:52scariest part about all of this is that 19:54Thompson gave a highly specific outline 19:56of how he would implement this kind of 19:58attack in his acceptance speech was a 20:01little too specific. In fact, if you 20:04scrape old Usenet archives, you can 20:06actually see the Oracle employees and 20:08the Bell Labs employees going back and 20:10forth theorizing about whether he 20:12actually did it. But the craziest part 20:14is if you look at the old archived 20:16messages, they're kind of corrupted. But 20:19Ken himself actually admits to slipping 20:21in the Trojanized login code into the 20:24Unix support group at Bell Labs for fun. 20:27They snuck it in by advertising it as 20:29some nonbackwards compatible feature so 20:31that the group would have to use their 20:33specialized compiler with the original 20:35sin code inside of it. But the original 20:37Trojan code inside was kind of smart. If 20:40you used the - S option to output the 20:43assembly of the program, it would 20:45actually not generate the Trojanized 20:47version of it. So it' kind of generate a 20:49clean version so that you wouldn't be 20:51able to detect it if you were trying to 20:52look at the assembly. And Ken claims 20:55that at some point someone ran it with 20:57the - S option and so the original SIN 21:01was removed from that compiler in the 21:03chain of compilers at Bell Labs. He also 21:05claimed that the compiler was never 21:07released outside of Bell Labs, but I'm 21:10not so sure about that. Bell Labs had 21:13their hands on just about everything in 21:15the 70s and 80s, so there's definitely a 21:17nonzero chance that that compiler 21:20actually escaped. Hopefully that doesn't 21:22keep you up at night. I particularly 21:24like one quote from Ken Thompson saying, 21:26"You can't trust code that you didn't 21:28totally write yourself, especially not 21:31code from companies that employ people 21:33like me." 21:35Like, Ken, if this is the story that you 21:37are sharing, what did you possibly do 21:40that you're not sharing with us? It's 21:42not really a feasible philosophy to 21:44follow though in this day and age. If 21:45you take a step back for a moment and 21:47think about all the proprietary software 21:49or applications that you've used even 21:51today, you're definitely not going to be 21:53able to go through and audit all of 21:55those applications, let alone write all 21:58of that code yourself. But personally, I 22:00think this is one of the spookiest 22:02thought experiments that I've read in a 22:03while. So, I'd be curious if anybody 22:05else has read any other spookier thought 22:08experiments lately. Let me know. Anyway, 22:10thank you so much for watching everyone. 22:12As always, I hope you enjoyed this 22:14video. Lori wired out.