Monday, February 24, 2020
Nibbles & Kiwi
Rascal was really thriving due to our training. He had grown much stronger from our first encounter in the fields beyond Pallet. His progress filled me with confidence. West of Viridian City in the foothills of the Indigo Plateau, we encountered an aggressive, little Nidoran. As absurd as it may seem, I think the Nidoran was weaker than Rascal when Professor Oak and I first caught him. He was puny and feeble, but he made up for it in sheer enthusiasm. I named that little fellow Nibbles and we began training as soon as he was rested. Nibbles was always eager to train and never shied from a challenge.
Now, I do recall the Pokédex made the distinction that Nibbles was male. I remember clearly because I pondered this several times throughout my journey in Kanto. Pokémon gender at the time was nothing more than hypothetical conjecture. There was no definitive study on the subject, and Professor Oak's Pokédex entry on the Nidoran species compiled by me and other contemporary Pallet Town trainers would spark a more conclusive investigation in the near future. I used the computer in the Viridian Pokémon Center to email Professor Oak several times about Nibble and the Pokédex entry. He requested I find a female variant of the species, but in all my searching of Kanto that year, I was never able to capture one. The closest I came to a female Nidoran was in trainer battles which collected a good amount of data, but unfortunately not as much as I'd be collecting on Pokémon directly in my care.
Training Nibbles was a lot of work. In those early days, he was pretty useless in a battle. We relied heavily on Rascal to teach him how to handle himself and get him ready for competitive battling in the future. Some days we were out in the south training against wild Rattata and Pidgey. On other days we made our way into the shadow of Indigo Plateau to the west and were fighting Rattata and other Nidoran. Eventually, Nibble's aggressive and enthusiastic nature paid off and he was able to protect me from all the wild Pokémon we encountered. He was ready, but unfortunately the gym was still closed. So we ventured to the north side of Viridian City for the first time to see what we could find, capture and study there.
On Route 2, Nibbles pinned down a Pidgey which I expertly captured. Kiwi was a welcome addition to the team. Kiwi was the strongest wild Pokémon we'd subdued so far, possibly stronger than both Rascal and Nibbles combined when I first met them. This made him a lot easier to train. He was able to steadily hold his own against wild Pokémon right away. The four of us continued to train around Viridian City until my two weeks worth of paid lodging expired. At that point, it was time to move on. There were no trainers to fight in Viridian City and I had given up on the gym reopening in time to rescue me from my financial crisis. I would have to take the team north through the forest to Pewter City and hope the competitive Pokémon scene was better.
I packed my meager supplies into my backpack and headed out the north gate. I would have been well on my way down Route 2 toward the Viridian Forest, except I had happened to overhear a conversation between two children. They noticed the Pokéballs holstered to my backpack and began excitedly chatting. They found it coincidental that I happened to be leaving just as a new trainer was arriving. I casually approached the children, trying to pretend I wasn't eavesdropping, but soon was crouched down beside them. With wide and eager eyes and perhaps a hint of desperation in my tone, I asked them where I could find this new trainer in town.
They began jumping up and down in excitement, asking if we were going to battle. Laughing, I told them it would be up to the other trainer, but I was hoping to challenge him. The next thing I remember, all three of us were rushing through the city streets toward Route 22. My heart was pumping at the thought of my first trainer battle. My finances were completely forgotten, too. My brain was a complete blur. The only thing I could think about was the challenge and the thrill. Despite building and training my team for two weeks, I really wasn't prepared for what we would find on the road to Indigo Plateau.
Current Team:
Attacks in Blue are recently learned.
Sunday, February 23, 2020
Day 2 Of Welcome Week For Our Games Design Freshers
This morning was a spontaneous session of marble madness!
Students built wooden block constructions and challenged each other to get their marble through the pathways they created.
Gaming morning to follow tomorrow :)
Thursday, February 20, 2020
Comparing All Four Versions Of A Star Is Born
This is a fine and memorable movie, worthy of being redone.
This is not worth watching, but the soundtrack is lovely. And then ...
Tech Book Face Off: How To Design Programs Vs. Structure And Interpretation Of Computer Programs
VS. |
How to Design Programs
While I have read many programming books as ebooks on my Kindle, this is the first book I've read as an online book. It's available in print version, but the online version looked nicely formatted and was heavily cross-linked, which was quite helpful. Also, since the book was right alongside my code editor, I could easily try out the problems and copy-paste code into the editor to run it.The programming language used in this book as the vehicle for learning was a variation on Scheme called BSL (Beginning Student Language) that had heavy restrictions on the language features available for use. For example, lists could not be constructed with (list <list of elements>) or '(<list of elements>), instead needing to be built up from (cons <element> <list>). These and other features were added with BSL+, ISL (Intermediate Student Language), and ISL+ as the reader progressed through the book.
I was not a big fan of this approach, since it was tedious to learn the wrong way first (or at least the way nobody actually writes code) and then learn the right way that also makes more sense. Starting with the reduced forms of the language didn't add anything to the explanations, and it mostly served as a point of frustration as the reader was forced through unnecessary tedium until the nicer language features were introduced. It was also not clear by the end that ISL+ was equivalent to the full Scheme programming language, so by the time the student reached the end of the book, they wouldn't even be sure that they had learned a real programming language.
The book was quite ambitious, since learning how to design programs starting from square one actually involves learning three almost distinct things at once: the syntax of a programming language, how to write code, and how to program. The first task is about learning what a programming language is, what keywords and punctuation are available, and what it all does when put together in the correct structure. This task alone can be overwhelming for the new student. Then, the second task, learning to write code, involves taking a small, well-defined problem statement, thinking up a solution to it, and translating that solution into code that can execute in the newly learned programming language. Normally, once some part of the language has been learned, the first two tasks can be done together, and they support each other as the student practices them both.
The third task, learning how to program, is a much deeper activity that takes a much longer time to become proficient. Learning how to program is not just about solving bigger problems that may not be self-contained or well-defined. It's about learning how to organize all of the required code to solve the problem in a way that makes that code easy to understand, is less likely to suffer from bugs, is testable (and tested), and hopefully is flexible and extensible. I'm not convinced that this book taught this much more advanced skill, or at least not thoroughly.
The book starts out with a little prologue chapter entitled "How to Program." It gives a short introduction and a few examples of how to write some simple programs in BSL, and here the authors try to get the reader excited about what they'll be learning in the rest of the book. I had some misgivings about it. They have a strange way of trying to connect with the reader by disparaging various subjects that the reader is likely taking in school, or at least has fresh memories about, like physics:
Physics?!? Well, perhaps you have already forgotten what you learned in that course. Or perhaps you have never taken a course on physics because you are way too young or gentle. No worries.I don't understand this kind of writing. It's not cool and it's not helpful to pretend to joke along with students about how much physics or mathematics or any subject sucks. It drives me nuts. Why can't we encourage students to take more of an interest in these subjects by showing how the knowledge can be useful, interesting, and dare I say, fun?! Thankfully, these comments don't continue in the rest of the book, but it's still irritating that they subtly perpetuate this anti-learning bias. It ended up coloring my opinion of the book in a negative way.
The rest of the book is split into six major sections with "intermezzos" between each section. I'm not quite sure why the intermezzos are there because they just seem to continue on with more topics that would fit in as additional chapters within the six sections, but that doesn't matter much. The first section introduces BSL features in more detail than the prologue, and it also lays out the recommended steps of a design process in chapter 3. These steps are touted as the steps for how to design a program, but they're really steps for how to design a function. The process is fine as far as it goes, but it doesn't really scale to large programs. This process is used and refined throughout the book.
The first section only introduced language features that allow for fixed-size data, so the next section introduces lists and recursion. It's a whole five chapters on lists, including basically a whole chapter of problems for the reader to solve. I don't remember lists being quite so hard to understand that it would require five chapters to adequately get the point across, especially with lists being a fundamental data structure of Scheme. Sorry, BSL+. Part of the problem is that the authors seem to explain things in as many words as possible. The text ends up plodding along with slow, tedious explanations, some of which don't even make much sense.
Another part of the problem of understanding in this book is the poor choice of variable names. When the authors are not using single-letter names (shudder), they're using names like alos. What is alos? Is it like, "Alos, poor Yorick! I new him, Horatio?" No, that's not right. That would be 'alas.' Instead, alos means "a list of strings." But why not just use list-of-strings, or even strings if you're into the whole brevity thing. The point is, these super abbreviated and truncated variable names make things more confusing than they need to be, because you have to keep the translation to the full name in your head along with the meaning of the variable and the rest of the code. Using full words for variable names makes the code so much more readable and understandable. It's not like we're working under any space constraints with the text of the code, except for the constraints of our own working memory.
The third section goes into detail on functions and how they enable abstractions that will make the programmer's life easier. Abstractions allow the programmer to solve low-level problems once and then think about harder problems from a higher level. It's a critical programming skill to learn. This section follows a similar format to the last one, with four chapters on functions done in excruciating detail, one of which is full of problems for the reader. We also advance to ISL for this section, and near the end we achieve the final level up to ISL+. Yipee! I remember hating when textbooks would introduce one way of doing things and then later contradict themselves and reveal the real way of doing it. This failing is worse with simplified languages, so I'm pretty tired of "student languages" by now.
The next section covers intertwined data, which is a convoluted title for a section that doesn't have a strong theme. The chapters in this section range from introducing trees to building a simple interpreter to processing multiple lists in parallel. The fifth section focuses on recursion for five chapters, and here they make the distinction between structural recursion, which is based on scanning lists, and generative recursion, which is more general and doesn't use lists as the looping mechanism. The final section discusses accumulators that are used with recursion to enable calculating properties of data that requires keeping track of additional state during the recursion. It's basically passing extra state variables in the recursive call in order to calculate aggregate or cumulative values on the data. All of these sections continued to have chapters near the end that were filled with extra problems for the reader.
This book was super long at nearly 750 pages—one of the longest programming books I've read in a while—and it did not seem like it covered enough ground to warrant that length. There were also 528 problems in total, so a huge amount of practice if the reader worked through all of the problems. Most of the problems were pretty decent, and they stayed relevant and reasonable for the material covered beforehand. But the book as a whole didn't hold up to its goal of teaching the beginner how to design programs. Learning how to program is a huge undertaking, and I don't believe it's possible to adequately cover that whole process in one book. On top of that, the level of discussion in much of the book was too complex for the beginner, and it would just as likely serve to confuse them as to teach them. Conversely, it doesn't seem to work well as a second programming book, either because it is so slow and tedious and long. By the end all we've learned is the basics of Scheme, lists, functions, and recursion. The Little Schemer taught much more in a more entertaining way in less than 200 pages. I can't recommend slogging through this book instead.
Structure and Interpretation of Computer Programs (SICP)
In testing primality of very large numbers chosen at random, the chance of stumbling upon a value that fools the Fermat test is less than the chance that cosmic radiation will cause the computer to make an error in carrying out a "correct" algorithm. Considering an algorithm to be inadequate for the first reason but not for the second illustrates the difference between mathematics and engineering.I mean, come on. That's not half bad for a computer science joke. The majority of the book was not about fun and games, though. It's a serious book on introducing the computer science student to how programming languages—particularly Scheme—work.
SICP is split into five fairly balanced chapters. Each chapter starts off easy with an introduction to the material covered in the chapter and more detailed explanations of the mechanics of Scheme or the interpreter or whatever is the topic for the chapter. As things develop, the difficulty ramps up until near the end you can feel your brain going numb and draining out of your ears. Then you get a breather at the beginning of the next chapter with another gentle introduction.
The first chapter starts off with the requisite intro-to-the-language stuff that every book for a new programming language needs. After covering Scheme's operators and primitives, we move on to functions and immediately jump into recursion. By the end of the chapter we're learning about how to pass functions around as arguments and return values, and I wonder how an entry-level student could really grok all of this in a semester course. This is just chapter 1!
Chapter 2 teaches us all about how to structure and process data in Scheme. Since the fundamental data structure in Scheme is the list, this means we're going to get very comfortable with list processing (which is how Lisp gets its name, see?). Between these first two chapters, we gain a thorough understanding of the foundations of Scheme and how to put together Scheme programs to do interesting things with data. Even after reading so many books on programming and practicing it in the field for a couple of decades, I was quite enjoying this "beginner" programming book.
Helpful exercises are interspersed with the text throughout the book, generally at the end of each subsection, and they are quite well thought-out exercises. With 356 exercises in all, they provide a ton of practice to ensure that the reader is understanding the material. At first they seem to be somewhat random but standard fare, asking the reader to solve programming problems with rational and complex numbers and other such mundane mathematical problems. Then, near the end of chapter 2, we learn how to implement generic arithmetic operations that can automatically promote and demote arguments from one class of number to another. It's pretty slick, if somewhat impractical. I can't think of a system where this behavior would be necessary, but it's cool to get it working nonetheless.
The next chapter kind of let the wind out of my sails a bit. The previous chapters had really exemplified the elegance of Scheme with beautiful functional programming, but now we had to learn about the mucky reality of objects and mutable state. This chapter introduces the set! operations that allow variables to be changed in place instead of creating and returning new variables that are set with the define primitive. The allowance for changing variable values enables the creation and maintenance of objects with state, and this complicates the analysis of program execution because now we have to deal with side effects. The authors did a nice job of explaining when objects are useful, because we don't want to use them for everything:
The object model approximates the world by dividing it into separate pieces. The functional model does not modularize along object boundaries. The object model is useful when the unshared state of the "objects" is much larger than the state that they share. An example of a place where the object viewpoint fails is quantum mechanics, where thinking of things as individual particles leads to paradoxes and confusions. Unifying the object view with the functional view may have little to do with programming, but rather with fundamental epistemological issues.The second half of the chapter continues on from objects with concurrency, which does not play nice with mutable state at all, and introduces streams in order to deal with that problem. Streams are a mechanism that enables lazy execution of functions on lists. Instead of performing all of the computations on a list at the time the processing function is called, the function will return another function that will do the computation on its corresponding list element at the time that element is needed to be read. It's wild and confusing at first, but working through the exercises helps clarify how it all works.
Chapter 4 tackles the task that all Lisp books seem to reach eventually, and that is to write an interpreter. How to Design Programs did it. The Little Schemer did it. SICP does it to, but it doesn't simply stop with one interpreter. No, after the basic interpreter, we go on to write a lazy interpreter that does delayed evaluation. Then, we write another interpreter that does ambiguous evaluation, meaning the programmer can specify a problem and an input range for that problem, and the interpreter will perform a search to find a solution (or every solution) that satisfies the constraints of the problem. Think that's enough? Not now that we're on a role! The final interpreter extends Scheme to be a logic language similar to Prolog. You would think the previous ambiguous interpreter would be a good basis for this extension, but the text uses the lazy interpreter as the base instead. Extending the ambiguous interpreter is left as an exercise.
Things are getting pretty mind-bending by now, so why don't we finish things off with something truly warped. The last chapter goes through implementing a register machine model in Scheme. What's a register machine? It's basically a model of a computer that uses fixed registers, a load-store memory model, and low-level operations to execute an assembly language. Then we need something to run on this register machine, so we modify the interpreter to run on top of this assembly language. Now let's step back and think about what we've done. We now have an interpreter that takes in Scheme code, spits out assembly code, and runs it on a model of a computer (the register machine); and this is all done inside another Scheme interpreter running on a real computer. Wat? Let's think again about what we've done:
From this perspective, our evaluator is seen to be a universal machine. It mimics other machines when these are described as Lisp programs. This is striking. Try to imagine an analogous evaluator for electrical circuits. This would be a circuit that takes as input a signal encoding the plans for some other circuit, such as a filter. Given this input, the circuit evaluator would then behave like a filter with the same description. Such a universal electrical circuit is almost unimaginably complex. It is remarkable that the program evaluator is a rather simple program.It's mind-blowing, really, but we're not done. The last part of the last chapter walks through building a compiler so that we can compile Scheme functions down to the assembly language of the register machine, and modify the register machine so that it can run the assembly code directly instead of it being fed from the interpreter. If that's not enough, the last two exercises are simply about writing a scheme interpreter in C and a compiler in C instead of what we just did in Scheme. Easy-peasy, right?
While these last two chapters were fun and fascinating, they were quite a stretch for one book. The first three chapters plus the basic Scheme interpreter would have been enough for the learning experience. I'm not sure how much practical knowledge readers would get out of the rest of the interpreters, the register machine, and the compiler. The explanations became very mechanical and it felt like a major effort just to fit in the code listings and brief descriptions while still keeping the book around 600 pages. Beyond the issue of cramming a bunch of complex stuff in the last chapter and a half of the book, there are much better books out there on compilers and interpreters, like the dragon book or Writing Compilers and Interpreters, that go into more detail and explain those details more thoroughly. Likewise for machine languages and computer architecture, if you really want to understand the underlying machine language and hardware, Computer Architecture: A Quantitative Approach is excellent. Although, for a lighter introduction, Computer Organization and Design might be a better place to start.
That criticism notwithstanding, SICP is an excellent book on both how to write programs in Scheme and how to write a Scheme interpreter. It's a solid textbook for a second course in programming, but not a first course. I can't imagine most entry-level students would grok everything this book tries to present, so it would be good to have some other programming language under your belt before tackling this beast. Given its age, it's still surprisingly relevant as a programming textbook, and quite enlightening.
SICP is far and away the better book in this face off. True, How to Design Programs is meant for a less technical audience, but I'm not convinced that it would be an appropriate book for non-programmers, either. Scheme is just not the right introductory language, and something like Python or Ruby would be a much better learning language. Taking that consideration out of the equation, SICP packs a ton more content into 150 less pages, and it goes in much more depth on both basic programming concepts like lists and functions, and advanced concepts like streams and interpreters. Did I mention it also uses way better variable names? The code is much easier to understand as a result, and it's only the complexity of the concepts later in the book that make that code difficult.
Definitely pass on How to Design Programs, but if you're in the mood to level-up your fundamental programming knowledge, give SICP a look. If you're so inclined to read it online, check out this version at Sara Bander's GitHub site. It's rendered in a beautiful Linux Libertine font that's an absolute joy to read on a screen, and the footnotes come up in text boxes when clicked. It's the best experience I've had reading an ebook.
People Of Frictional: Max Lidbeck
WHO AM I
I'm Max, and I do gameplay programming and design. I joined Frictional about a year and a half ago, and I've been working on one of our super secret projects since.
Yours truly. |
For the first nine months or so I, like everyone else, worked from home. Last summer we got an office set up in the heart of Malmö. Since then the amount of days I spend working from home has reduced greatly, though I still do it from time to time.
Setup at home and at work. |
These are my two workspaces, the first one in the office and the other one at home (which is rather bare bones right now, moved in just a couple of days ago!). They're quite similar; both the computers and the chairs are the same kind. I wanted to be even more consistent and get the same type of desk as the office one at home, a decision that was ultimately overruled by my better half (apparently it doesn't go with the rest of the decor).
BACKGROUND
Games have always been a big part of my life. Most of my time growing up was spent either playing games or talking about games. But, for quite a while, my family didn't have a PC. Which meant I was stuck playing all sorts of old, weird games on rapidly aging Apple computers. One of my earliest gaming memories consist of repeatedly failing at air-hockey, losing to a hideous pig-man in Shufflepuck Cafe on my dad's old Macintosh.
Eventually I scraped together enough money to put together my first PC, in front of which I would stay rooted for the following years. In addition to playing, I spent a lot of time creating custom content for games with my friends. It was always quite basic though, as I hadn't learned any programming yet.
For a year or so I studied film and media studies at the university, with a diffuse goal of wanting to work in games down the line. One night my girlfriend gave me a push, and I applied for a three-year game development program at Blekinge Institute of Technology (BTH).
My years at BTH were a mixed bag. On one hand, we had a lot of freedom and got to work on tons of small projects, which was very fun and super rewarding. On the other hand, some courses felt like they were only marginally related to game development. Working on side-projects during your spare time was crucial. I got through it all by finding a good group of like-minded students that I stuck to for the entirety of the education. Our final project was a side-scrolling adventure game called Far Away - you can watch the trailer for it on Youtube.
Perfectly in sync with graduating, I stumbled across a job opening at Frictional and sent in an application. Over the following weeks I answered some additional questions, did a work test and finally had an interview. A couple of days before I would hear from Frictional, I got a job offer from another company in software development. I clumsily explained to them I was waiting on another offer and asked for a few more days. Finally, I got an email from Fredrik and Thomas offering me the job. It was a no-brainer, and I happily accepted.
WHAT I DO
My first few weeks at the company consisted of completing a list of introductory tasks, to learn more about the tools and the engine. This was a lot of fun, and culminated in the creation of a silly mini-game where I got to put everything I had learned to the test.
After I had completed the introductory tasks I got to work on Safe Mode for SOMA, which was something I was really excited about -- contributing to a game I truly thought was great. From the get-go, we felt it was important to maintain the monsters' threatening presence in order for their new behaviours to gel with the overall tone of the game. We couldn't just disable their ability to harm you; doing this would end up breaking immersion (imagine repeatedly throwing a toolbox in Akers' face and him just standing there, taking it). Instead, we tried to focus on how to best tweak each monster's behaviour in a manner that suited that particular encounter. For instance, some might eerily walk up to you and size you up, and can even bluff charge you if you've strayed too close. To further enforce the behaviours fitting with the world, we decided that if you were to actively mess with monsters (like invading their personal space for too long, hurling trash at them and so on), they should still be able to hurt you, just not kill you. Overall it was a very worthwhile experience, and I'm quite happy with how it all turned out.
Now I'm working on one of our secret projects. As the gameplay programmer/designer workflow has already been described in previous posts I won't go into detail, but my days in general are spent designing and scripting events and scenes, as well as programming gameplay systems.
THE OFFICE
Additionally, I thought I'd talk a bit about the differences in working from home compared to working in the office. We're also gonna do a proper office tour later on, so stay tuned!
This is where the magic happens. |
This is our office! Currently, we're around seven people occupying this space, probably with more to come. It's quite seldom all of us are here at once though, but there are usually a few people around. And on the off chance that you're here by yourself one day, fear not; there's always the noisy, seemingly stiletto heel-wearing, tap-dancing travel agency crew upstairs to keep you company (seriously).
So, it really isn't all that crowded here. But, seeing as most of us don't work from the office, we often have meetings over Slack. It can easily get annoying for your desk-mates if you keep babbling on and on in various meetings throughout the day, which is why we've set up a separate meeting room. It also moonlights as a test room, complete with a TV, some dev kits and a monster webcam.
The fact that the company is split into people working from home and people working in the office could potentially lead to complications, such as communication issues. In order to prevent this we've made sure that all important decisions and discussions still happen over Slack, to keep everyone in the loop. So far this policy has worked well, and the transition has been quite smooth.
In the end, a typical day of work in the office is very similar to one at home. There is of course the added social aspect of working in the same physical space as you colleagues, which is great, but if you one morning feel like you'd rather stay at home and work, you can. Having this option every day really is quite luxurious.
Other than this, and the requirement to wear pants, the routines of working in the office and and working from home differ very little.
Wanna see who else works at Frictional? Check out the rest of the People of Frictional posts!
Wednesday, February 19, 2020
Of Bytes And Borders
Read more »
Thursday, February 13, 2020
Brave Browser the Best privacy-focused product of 2020
Out of all the privacy-focused products and apps available on the market, Brave has been voted the best. Other winners of Product Hunt's Golden Kitty awards showed that there was a huge interest in privacy-enhancing products and apps such as chats, maps, and other collaboration tools.
An extremely productive year for Brave
Last year has been a pivotal one for the crypto industry, but few companies managed to see the kind of success Brave did. Almost every day of the year has been packed witch action, as the company managed to officially launch its browser, get its Basic Attention Token out, and onboard hundreds of thousands of verified publishers on its rewards platform.
Luckily, the effort Brave has been putting into its product hasn't gone unnoticed.
The company's revolutionary browser has been voted the best privacy-focused product of 2019, for which it received a Golden Kitty award. The awards, hosted by Product Hunt, were given to the most popular products across 23 different product categories.
Ryan Hoover, the founder of Product Hunt said:
"Our annual Golden Kitty awards celebrate all the great products that makers have launched throughout the year"
Brave's win is important for the company—with this year seeing the most user votes ever, it's a clear indicator of the browser's rapidly rising popularity.
Privacy and blockchain are the strongest forces in tech right now
If reaching 10 million monthly active users in December was Brave's crown achievement, then the Product Hunt award was the cherry on top.
The recognition Brave got from Product Hunt users shows that a market for privacy-focused apps is thriving. All of the apps and products that got a Golden Kitty award from Product Hunt users focused heavily on data protection. Everything from automatic investment apps and remote collaboration tools to smart home products emphasized their privacy.
AI and machine learning rose as another note-worthy trend, but blockchain seemed to be the most dominating force in app development. Blockchain-based messaging apps and maps were hugely popular with Product Hunt users, who seem to value innovation and security.
For those users, Brave is a perfect platform. The company's research and development team has recently debuted its privacy-preserving distributed VPN, which could potentially bring even more security to the user than its already existing Tor extension.
Brave's effort to revolutionize the advertising industry has also been recognized by some of the biggest names in publishing—major publications such as The Washington Post, The Guardian, NDTV, NPR, and Qz have all joined the platform. Some of the highest-ranking websites in the world, including Wikipedia, WikiHow, Vimeo, Internet Archive, and DuckDuckGo, are also among Brave's 390,000 verified publishers.