# rss_item

guid: https://xkcd.com/2461/
title: 90's Kid Space Program
url: https://xkcd.com/2461/
feedurl: https://xkcd.com/rss.xml
content:
<img src="https://imgs.xkcd.com/comics/90s_kid_space_program.png" title="NASA may not want to admit it, but at this point they ARE the 90's Kid Space Program." alt="NASA may not want to admit it, but at this point they ARE the 90's Kid Space Program." />


guid: https://xkcd.com/2462/
title: NASA Award
url: https://xkcd.com/2462/
feedurl: https://xkcd.com/rss.xml
content:
<img src="https://imgs.xkcd.com/comics/nasa_award.png" title="The key to discovering life on Mars is to find someone who built a camera and landed it on Mars. Then you just look through the pictures for plants and dogs and stuff." alt="The key to discovering life on Mars is to find someone who built a camera and landed it on Mars. Then you just look through the pictures for plants and dogs and stuff." />


guid: https://xkcd.com/2463/
title: Astrophotography
url: https://xkcd.com/2463/
feedurl: https://xkcd.com/rss.xml
content:
<img src="https://imgs.xkcd.com/comics/astrophotography.png" title="[One hill over, a competing astrophotographer does a backflip over a commercial airliner while throwing a tray of plastic space stations into the air, through which a falcon swoops to 'grab' the real one.]" alt="[One hill over, a competing astrophotographer does a backflip over a commercial airliner while throwing a tray of plastic space stations into the air, through which a falcon swoops to 'grab' the real one.]" />


guid: https://xkcd.com/2464/
title: Muller's Ratchet
url: https://xkcd.com/2464/
feedurl: https://xkcd.com/rss.xml
content:
<img src="https://imgs.xkcd.com/comics/mullers_ratchet.png" title="Who knew you could learn so much about sexual reproduction from looking at pictures on the internet!" alt="Who knew you could learn so much about sexual reproduction from looking at pictures on the internet!" />


guid: yt:video:ckCNGJY6akM
title: Calculate Linux: Easy Gentoo
author: Switched to Linux
url: https://www.youtube.com/watch?v=ckCNGJY6akM
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCoryWpk4QVYKFCJul9KBdyw
content_mime_type: text/plain
content:
Calculate Linux is based on Gentoo. It comes with a variety of Desktops and has an easy installer. Here we look at the new version of Calculate and see what it has to offer.
https://wiki.calculate-linux.org/

#Calculate #Gentoo #Linux

-----------
Support Switched to Linux!
👕 Merch: https://shop.switchedtolinux.com
🛒 Amazon: http://tlm.li/amazon
💰 Support: https://switchedtolinux.com/support
🛒 Affiliates: https://switchedtolinux.com/affiliates
👥 Multichannel Support: https://thinklifemedia.com
💰 Patreon: /TomM
-----------
Social Media:
🐦 Twitter: @switchedtolinux
🐸 Gab: @switchedtolinux
💡 Minds: @switchedtolinux
Reddit: /r/switchedtolinux
Mastodon: https://fosstodon.org/@switchedtolinux
-----------

We are a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for us to earn fees by linking to Amazon.com and affiliated sites.


guid: yt:video:ABZONHh_Imo
title: The End of the Internet? | Weekly News Roundup
author: Switched to Linux
url: https://www.youtube.com/watch?v=ABZONHh_Imo
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCoryWpk4QVYKFCJul9KBdyw
content_mime_type: text/plain
content:
This week in Business News, Vivaldi blocks cookie popups, AlmaLinux now has commercial support, and Spotify is set to increase prices. Office looks to kill off Calibri, Apple sued over movie purchases, and Nestle issued a cease and desist over CA water bottling. Finally, EU issues new rules requiring certain content to be removed from the Internet in one hour. We also have some SillyVille articles.
#Nestle #EUParliament #Office

Affiliate: https://tlm.li/ev
https://subscribestar.com/switchedtolinux

00:00 Vivaldi Cookie Blocker
01:12 AlmaLinux Commercial
02:02 Spotify Price Increase
03:11 New Office Font
05:02 Apple Sued Over Movie Sales
08:07 Nestle Stealing CA Water
13:31 Uber Price Plunge
15:32 EU Internet Rules
18:18 Affiliate - ExpressVPN
19:13 Telegraming With Grandma
21:51 Beavers Kill Canada Internet
22:56 Felony VHS Embezzelment
25:17 Subscribestar

All Articles:
https://switchedtolinux.com/driver-monitoring-for-all/ ‎

-----------
Support Switched to Linux!
👕 Merch: https://shop.switchedtolinux.com
🛒 Amazon: http://tlm.li/amazon
💰 Support: https://switchedtolinux.com/support
🛒 Affiliates: https://switchedtolinux.com/affiliates
👥 Multichannel Support: https://thinklifemedia.com
💰 Patreon: /TomM
-----------
Social Media:
🐦 Twitter: @switchedtolinux
🐸 Gab: @switchedtolinux
💡 Minds: @switchedtolinux
Reddit: /r/switchedtolinux
Mastodon: https://fosstodon.org/@switchedtolinux
-----------

We are a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for us to earn fees by linking to Amazon.com and affiliated sites.


guid: yt:video:49rRhM71c5o
title: Elementary OS 6 Beta
author: Switched to Linux
url: https://www.youtube.com/watch?v=49rRhM71c5o
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCoryWpk4QVYKFCJul9KBdyw
content_mime_type: text/plain
content:
The new Elementary OS 6 has released a public beta and we will have a look. Elementary OS 6 will be moving to a Flatpak base including main system components. It also recieves some theming changes and a new installer.
#ElementaryOS #Flatpak #Linux

https://blog.elementary.io/elementary-os-6-odin-beta/

-----------
Support Switched to Linux!
👕 Merch: https://shop.switchedtolinux.com
🛒 Amazon: http://tlm.li/amazon
💰 Support: https://switchedtolinux.com/support
🛒 Affiliates: https://switchedtolinux.com/affiliates
👥 Multichannel Support: https://thinklifemedia.com
💰 Patreon: /TomM
-----------
Social Media:
🐦 Twitter: @switchedtolinux
🐸 Gab: @switchedtolinux
💡 Minds: @switchedtolinux
Reddit: /r/switchedtolinux
Mastodon: https://fosstodon.org/@switchedtolinux
-----------

We are a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for us to earn fees by linking to Amazon.com and affiliated sites.


guid: yt:video:qtsj6izqUf8
title: KDE Neon vs Fedora Plasma | DistroWars
author: Switched to Linux
url: https://www.youtube.com/watch?v=qtsj6izqUf8
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCoryWpk4QVYKFCJul9KBdyw
content_mime_type: text/plain
content:
Today we look at two different plasma builds: Neon, the plasma testing ground compared to Fedora Plasma. Which is best, and how has the Plasma desktop changed?
#Fedora #Neon #Plasma

https://neon.kde.org/download
https://spins.fedoraproject.org/en/kde/

00:00 Introduction
03:34 Neon
11:03 Fedora
17:48 Conclusions

-----------
Support Switched to Linux!
👕 Merch: https://shop.switchedtolinux.com
🛒 Amazon: http://tlm.li/amazon
💰 Support: https://switchedtolinux.com/support
🛒 Affiliates: https://switchedtolinux.com/affiliates
👥 Multichannel Support: https://thinklifemedia.com
💰 Patreon: /TomM
-----------
Social Media:
🐦 Twitter: @switchedtolinux
🐸 Gab: @switchedtolinux
💡 Minds: @switchedtolinux
Reddit: /r/switchedtolinux
Mastodon: https://fosstodon.org/@switchedtolinux
-----------

We are a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for us to earn fees by linking to Amazon.com and affiliated sites.


guid: yt:video:LZ0ruPG-_9I
title: Right to Repair
author: Switched to Linux
url: https://www.youtube.com/watch?v=LZ0ruPG-_9I
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCoryWpk4QVYKFCJul9KBdyw
content_mime_type: text/plain
content:
Today we will talk about the Right to Repair debate and what it means for our hardware and software.
#RightToRepair #Hardware #Linux

-----------
Support Switched to Linux!
👕 Merch: https://shop.switchedtolinux.com
🛒 Amazon: http://tlm.li/amazon
💰 Support: https://switchedtolinux.com/support
🛒 Affiliates: https://switchedtolinux.com/affiliates
👥 Multichannel Support: https://thinklifemedia.com
💰 Patreon: /TomM
-----------
Social Media:
🐦 Twitter: @switchedtolinux
🐸 Gab: @switchedtolinux
💡 Minds: @switchedtolinux
Reddit: /r/switchedtolinux
Mastodon: https://fosstodon.org/@switchedtolinux
-----------

We are a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for us to earn fees by linking to Amazon.com and affiliated sites.


guid: yt:video:d-Rm6nLUMpQ
title: Betrayed by Your Old Number | Weekly News Roundup
author: Switched to Linux
url: https://www.youtube.com/watch?v=d-Rm6nLUMpQ
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCoryWpk4QVYKFCJul9KBdyw
content_mime_type: text/plain
content:
This week in Privacy News, Google will follow Apple in privacy labels for apps, and Facebook says data collection keeps Facebook free. Also, Google is expanding assistant into a messenger, inside the voice profiling revolution, and hackers now take your old number to track you. We also include some tech news and security breaches.
#SMS #Google #Facebook

Affiliate: https://tlm.li/a2h
https://subscribestar.com/switchedtolinux

00:00 Google to add App Labels
01:28 Facebook Apple Privacy Notice
03:12 Google Assistant Messenger
04:37 Voice Profiling
09:41 Recycled Phone Number Hack
12:24 Affiliate - A2Hosting
13:27 Kroger Drone Deliveries
14:28 Space Pirates
16:47 Peloton Data Breach
18:31 Dell Escalation Flaw
19:18 Email Breach
20:41 Subscribestar

All Articles:
https://switchedtolinux.com/betrayed-by-your-old-number/ ‎

-----------
Support Switched to Linux!
👕 Merch: https://shop.switchedtolinux.com
🛒 Amazon: http://tlm.li/amazon
💰 Support: https://switchedtolinux.com/support
🛒 Affiliates: https://switchedtolinux.com/affiliates
👥 Multichannel Support: https://thinklifemedia.com
💰 Patreon: /TomM
-----------
Social Media:
🐦 Twitter: @switchedtolinux
🐸 Gab: @switchedtolinux
💡 Minds: @switchedtolinux
Reddit: /r/switchedtolinux
Mastodon: https://fosstodon.org/@switchedtolinux
-----------

We are a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for us to earn fees by linking to Amazon.com and affiliated sites.


guid: yt:video:GWUWodgsgcQ
title: Judge: Kodi Box is Not a Piracy Box | Weekly News Roundup
author: Switched to Linux
url: https://www.youtube.com/watch?v=GWUWodgsgcQ
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCoryWpk4QVYKFCJul9KBdyw
content_mime_type: text/plain
content:
This week in Business News, we get updates from Discord and "Shut Your Pai Hole." ISPs are out of control, a Netflix executive is guilty of accepting bribes, night shift does not help with sleep, and Amazon drivers are told to disable safety monitoring. Also a judge slaps Allarco while dismissing their piracy lawsuit. We conclude with SillyVille.
#Allarco #ISPs #AppStores

Affiliate: https://tlm.li/linode
https://patreon.com/tomm

00:00 PS and Discord
01:01 Pai's New Job
01:38 ISP Net Neutrality Comments
03:56 ISPs Sue New York
06:04 Netflix Executive Jailed
06:55 Night Shift
08:36 Amazon Unsafe Drivers
10:07 App Store Dominance
11:43 Allarco Lawsuit
16:24 Affiliate - Linode
17:12 Impossible Foods
18:48 Snap Lawsuit
20:20 Twitter Offensive Word Filter
21:46 PVC Racing
23:28 Patreon - Tomm

All Articles:
https://switchedtolinux.com/betrayed-by-your-old-number/ 

-----------
Support Switched to Linux!
👕 Merch: https://shop.switchedtolinux.com
🛒 Amazon: http://tlm.li/amazon
💰 Support: https://switchedtolinux.com/support
🛒 Affiliates: https://switchedtolinux.com/affiliates
👥 Multichannel Support: https://thinklifemedia.com
💰 Patreon: /TomM
-----------
Social Media:
🐦 Twitter: @switchedtolinux
🐸 Gab: @switchedtolinux
💡 Minds: @switchedtolinux
Reddit: /r/switchedtolinux
Mastodon: https://fosstodon.org/@switchedtolinux
-----------

We are a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for us to earn fees by linking to Amazon.com and affiliated sites.


guid: yt:video:delOa2Kvx8A
title: Warpinator and Hypnotics Linux Mint Updates
author: Switched to Linux
url: https://www.youtube.com/watch?v=delOa2Kvx8A
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCoryWpk4QVYKFCJul9KBdyw
content_mime_type: text/plain
content:
Today we will look at the latest updates from the Linux Mint blog. Here we see the progress that Linux Mint is taking toward doing what their users want.
Here we see updates to Warpinator, Hypnotics, the update manager, and the end of the life of Linux Mint 18.
#LinuxMint #Linux #Cinnamon

https://blog.linuxmint.com/?p=4054
https://github.com/slowscript/warpinator-android

-----------
Support Switched to Linux!
👕 Merch: https://shop.switchedtolinux.com
🛒 Amazon: http://tlm.li/amazon
💰 Support: https://switchedtolinux.com/support
🛒 Affiliates: https://switchedtolinux.com/affiliates
👥 Multichannel Support: https://thinklifemedia.com
💰 Patreon: /TomM
-----------
Social Media:
🐦 Twitter: @switchedtolinux
🐸 Gab: @switchedtolinux
💡 Minds: @switchedtolinux
Reddit: /r/switchedtolinux
Mastodon: https://fosstodon.org/@switchedtolinux
-----------

We are a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for us to earn fees by linking to Amazon.com and affiliated sites.


guid: yt:video:rN99FoWoo-g
title: How to Run a Linux Package on a Custom Theme
author: Switched to Linux
url: https://www.youtube.com/watch?v=rN99FoWoo-g
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCoryWpk4QVYKFCJul9KBdyw
content_mime_type: text/plain
content:
Today we will talk about how to run an application in a different theme than the one in your system default. This is excellent to fix an application that is hard to use in a dark theme, or one where you need something different from the rest of the system.
#Bluefish #Linux #Neon

-----------
Support Switched to Linux!
👕 Merch: https://shop.switchedtolinux.com
🛒 Amazon: http://tlm.li/amazon
💰 Support: https://switchedtolinux.com/support
🛒 Affiliates: https://switchedtolinux.com/affiliates
👥 Multichannel Support: https://thinklifemedia.com
💰 Patreon: /TomM
-----------
Social Media:
🐦 Twitter: @switchedtolinux
🐸 Gab: @switchedtolinux
💡 Minds: @switchedtolinux
Reddit: /r/switchedtolinux
Mastodon: https://fosstodon.org/@switchedtolinux
-----------

We are a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for us to earn fees by linking to Amazon.com and affiliated sites.


guid: yt:video:RsDvJxFvXL4
title: Desktop Environments: The Good, The Bad, and The Ugly
author: Switched to Linux
url: https://www.youtube.com/watch?v=RsDvJxFvXL4
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCoryWpk4QVYKFCJul9KBdyw
content_mime_type: text/plain
content:
Today we talk about the positives and negatives and various desktop environments. We will talk about what we like and don't like about our favorite desktops.
#DesktopEnvironments #Linux #SwitchedToLinux

-----------
Support Switched to Linux!
👕 Merch: https://shop.switchedtolinux.com
🛒 Amazon: http://tlm.li/amazon
💰 Support: https://switchedtolinux.com/support
🛒 Affiliates: https://switchedtolinux.com/affiliates
👥 Multichannel Support: https://thinklifemedia.com
💰 Patreon: /TomM
-----------
Social Media:
🐦 Twitter: @switchedtolinux
🐸 Gab: @switchedtolinux
💡 Minds: @switchedtolinux
Reddit: /r/switchedtolinux
Mastodon: https://fosstodon.org/@switchedtolinux
-----------

We are a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for us to earn fees by linking to Amazon.com and affiliated sites.


guid: yt:video:Hcf2XgUQJA0
title: Signal Trolling Facebook
author: Switched to Linux
url: https://www.youtube.com/watch?v=Hcf2XgUQJA0
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCoryWpk4QVYKFCJul9KBdyw
content_mime_type: text/plain
content:
This week in the Weekly News Roundup, we tackle the extreme data collection and use of our private data, the Colonial pipeline shutdown, and some insights into the many tech monopolies. We also have a look at some excellent silly news.
#WeeklyNewsRoundup #Instagram #Pipeline

All Articles:
https://switchedtolinux.com/signal-trolling-facebook/

-----------
Support Switched to Linux!
👕 Merch: https://shop.switchedtolinux.com
🛒 Amazon: http://tlm.li/amazon
💰 Support: https://switchedtolinux.com/support
🛒 Affiliates: https://switchedtolinux.com/affiliates
👥 Multichannel Support: https://thinklifemedia.com
💰 Patreon: /TomM
-----------
Social Media:
🐦 Twitter: @switchedtolinux
🐸 Gab: @switchedtolinux
💡 Minds: @switchedtolinux
Reddit: /r/switchedtolinux
Mastodon: https://fosstodon.org/@switchedtolinux
-----------

We are a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for us to earn fees by linking to Amazon.com and affiliated sites.


guid: yt:video:ss9IRmNlzIc
title: Signal Trolling Facebook | Weekly News Roundup
author: Switched to Linux
url: https://www.youtube.com/watch?v=ss9IRmNlzIc
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCoryWpk4QVYKFCJul9KBdyw
content_mime_type: text/plain
content:
This week in Privacy News, Vizio makes more selling your personal data than it does on televisions, most people opt out of ad tracking on iOS, and Facebook - Whatsapp connection questioned in Germany. Finally, Signal wants to show people just how much data Facebook collects on people, and Facebook wont be havin' it. We also look at some security news.
#Facebook #Hackers #Vizio

Affiliate: https://tlm.li/ev
Patreon: https://patreon.com/tomm

00:00 Smart Home Standard
02:43 Vizio Sells You
04:29 iOS privacy Opt-in stats
06:19 Whatsapp-Facebook Controvery
06:52 Germany Slaps Facebook
08:07 Signal Trolls Facebook
10:55 Affiliate - Express VPN
12:05 Airtag Jailbroken
13:16 Hackers Dox DC Police
15:06 Colonial Pipeline Breach
20:06 Patreon - Tomm
 
All Articles:
https://switchedtolinux.com/signal-trolling-facebook/

-----------
Support Switched to Linux!
👕 Merch: https://shop.switchedtolinux.com
🛒 Amazon: http://tlm.li/amazon
💰 Support: https://switchedtolinux.com/support
🛒 Affiliates: https://switchedtolinux.com/affiliates
👥 Multichannel Support: https://thinklifemedia.com
💰 Patreon: /TomM
-----------
Social Media:
🐦 Twitter: @switchedtolinux
🐸 Gab: @switchedtolinux
💡 Minds: @switchedtolinux
Reddit: /r/switchedtolinux
Mastodon: https://fosstodon.org/@switchedtolinux
-----------

We are a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for us to earn fees by linking to Amazon.com and affiliated sites.


guid: yt:video:BA8oaxuFd-E
title: Can a Raspberry Pi Replace Your Computer?
author: Switched to Linux
url: https://www.youtube.com/watch?v=BA8oaxuFd-E
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCoryWpk4QVYKFCJul9KBdyw
content_mime_type: text/plain
content:
Today I test if a Raspberry Pi can replace my web design work computer. I ran the computer in production for two weeks and this is the final analysis.
#RaspberryPi #Manjaro #ARM

-----------
Support Switched to Linux!
👕 Merch: https://shop.switchedtolinux.com
🛒 Amazon: http://tlm.li/amazon
💰 Support: https://switchedtolinux.com/support
🛒 Affiliates: https://switchedtolinux.com/affiliates
👥 Multichannel Support: https://thinklifemedia.com
💰 Patreon: /TomM
-----------
Social Media:
🐦 Twitter: @switchedtolinux
🐸 Gab: @switchedtolinux
💡 Minds: @switchedtolinux
Reddit: /r/switchedtolinux
Mastodon: https://fosstodon.org/@switchedtolinux
-----------

We are a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for us to earn fees by linking to Amazon.com and affiliated sites.


guid: yt:video:BaAzailaf2c
title: Big Tech Plays Monopoly | Weekly News Roundup
author: Switched to Linux
url: https://www.youtube.com/watch?v=BaAzailaf2c
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCoryWpk4QVYKFCJul9KBdyw
content_mime_type: text/plain
content:
This week in Business News, a Tesla owner is jailed for riding in his back seat, Impossible Foods wants to feed your children's school, and cryptocurrencies tank but it's Elon Musk's fault. Also, several big tech monopolies are being challenged in court. We also conclude with Sillyville news.
#Monopolies #Bitcoin #Tesla

Affiliate: https://tlm.li/a2h
http://subscribestar.com/switchedtolinux

00:00 Tesla Owner Jailed
02:53 Impossible Burgers for Kids
05:25 Tesla Tanks Crypto Market
05:58 Playstation Monopoly
07:20 Apple - Epic Update
10:18 Affiliate - A2Hosting
11:11 Streaming Password Theft Ring
11:57 Lawn Mower Thief
13:00 Only Criminals Use Encryption
15:18 Court Case Goes Bananas
18:26 Subscribestar

All Articles:
https://switchedtolinux.com/signal-trolling-facebook/

-----------
Support Switched to Linux!
👕 Merch: https://shop.switchedtolinux.com
🛒 Amazon: http://tlm.li/amazon
💰 Support: https://switchedtolinux.com/support
🛒 Affiliates: https://switchedtolinux.com/affiliates
👥 Multichannel Support: https://thinklifemedia.com
💰 Patreon: /TomM
-----------
Social Media:
🐦 Twitter: @switchedtolinux
🐸 Gab: @switchedtolinux
💡 Minds: @switchedtolinux
Reddit: /r/switchedtolinux
Mastodon: https://fosstodon.org/@switchedtolinux
-----------

We are a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for us to earn fees by linking to Amazon.com and affiliated sites.


guid: yt:video:EIf3lGrCKd0
title: Goodbye Audacity
author: Switched to Linux
url: https://www.youtube.com/watch?v=EIf3lGrCKd0
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCoryWpk4QVYKFCJul9KBdyw
content_mime_type: text/plain
content:
Audacity is adding analytics from Google and Yandex, and the FOSS community is NOT happy. Here we look at the release information and let you all know what they are doing so we can decide if we will stick with Audacity, fork it, or just look for something else.
#Audacity #Google #Analytics

-----------
Support Switched to Linux!
👕 Merch: https://shop.switchedtolinux.com
🛒 Amazon: http://tlm.li/amazon
💰 Support: https://switchedtolinux.com/support
🛒 Affiliates: https://switchedtolinux.com/affiliates
👥 Multichannel Support: https://thinklifemedia.com
💰 Patreon: /TomM
-----------
Social Media:
🐦 Twitter: @switchedtolinux
🐸 Gab: @switchedtolinux
💡 Minds: @switchedtolinux
Reddit: /r/switchedtolinux
Mastodon: https://fosstodon.org/@switchedtolinux
-----------

We are a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for us to earn fees by linking to Amazon.com and affiliated sites.


guid: yt:video:32W6Y8fVFzg
title: TryHackMe Blue - Walkthrough
author: HackerSploit
url: https://www.youtube.com/watch?v=32W6Y8fVFzg
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC0ZTPkdxlAKf-V33tqXwi3Q
content_mime_type: text/plain
content:
In this video, I will be showing you how to pwn Blue on TrryHackMe. We will cover the basics of Windows enumeration, post-exploitation, and password cracking.

Our videos are also available on the decentralized platform LBRY: https://lbry.tv/$/invite/@HackerSploit:26

SUPPORT US:
Patreon: https://www.patreon.com/hackersploit
Merchandise: https://teespring.com/en-GB/stores/hackersploitofficial

SOCIAL NETWORKS:
Twitter: https://twitter.com/HackerSploit
LinkedIn: https://www.linkedin.com/company/18713892

WHERE YOU CAN FIND US ONLINE:
HackerSploit - Cybersecurity Training Simplified: https://hackersploit.org/
HackerSploit Forum: https://forum.hackersploit.org
HackerSploit Academy: https://www.hackersploit.academy

LISTEN TO THE CYBERTALK PODCAST:
Spotify: https://open.spotify.com/show/6j0RhRiofxkt39AskIpwP7

We hope you enjoyed the video and found value in the content. We value your feedback. If you have any questions or suggestions feel free to post them in the comments section or contact us directly via our social platforms.

Thanks for watching!
Благодарю за просмотр!
Kiitos katsomisesta
Danke fürs Zuschauen!
感谢您观看
Merci d'avoir regardé
Obrigado por assistir
دیکھنے کے لیے شکریہ
देखने के लिए धन्यवाद
Grazie per la visione
Gracias por ver
شكرا للمشاهدة

#TryHackMe#Pentesting


guid: yt:video:Wc7NVl-wNXI
title: TryHackMe Ice - Walkthrough | Windows Privilege Escalation
author: HackerSploit
url: https://www.youtube.com/watch?v=Wc7NVl-wNXI
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC0ZTPkdxlAKf-V33tqXwi3Q
content_mime_type: text/plain
content:
In this video, I will be showing you how to pwn Ice on TryHackMe. We will cover the basics of Windows exploitation and post-exploitation.

Our videos are also available on the decentralized platform LBRY: https://lbry.tv/$/invite/@HackerSploit:26

SUPPORT US:
Patreon: https://www.patreon.com/hackersploit
Merchandise: https://teespring.com/en-GB/stores/hackersploitofficial

SOCIAL NETWORKS:
Twitter: https://twitter.com/HackerSploit
LinkedIn: https://www.linkedin.com/company/18713892

WHERE YOU CAN FIND US ONLINE:
HackerSploit Blog: https://hackersploit.org/
HackerSploit Forum: https://forum.hackersploit.org
HackerSploit Academy: https://www.hackersploit.academy

LISTEN TO THE CYBERTALK PODCAST:
Spotify: https://open.spotify.com/show/6j0RhRiofxkt39AskIpwP7

We hope you enjoyed the video and found value in the content. We value your feedback. If you have any questions or suggestions feel free to post them in the comments section or contact us directly via our social platforms.

Thanks for watching!
Благодарю за просмотр!
Kiitos katsomisesta
Danke fürs Zuschauen!
感谢您观看
Merci d'avoir regardé
Obrigado por assistir
دیکھنے کے لیے شکریہ
देखने के लिए धन्यवाद
Grazie per la visione
Gracias por ver
شكرا للمشاهدة

#TryHackMe#Pentesting


guid: yt:video:eIy69zUfbgI
title: TryHackMe Ice - Manual Exploitation Walkthrough
author: HackerSploit
url: https://www.youtube.com/watch?v=eIy69zUfbgI
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC0ZTPkdxlAKf-V33tqXwi3Q
content_mime_type: text/plain
content:
In this video, I will be showing you how to pwn Ice on TryHackMe. We will go through how to manually exploit Icecast on Windows 7 and how to escalate privileges once we have obtained a foothold.

Our videos are also available on the decentralized platform LBRY: https://lbry.tv/$/invite/@HackerSploit:26

SUPPORT US:
Patreon: https://www.patreon.com/hackersploit
Merchandise: https://teespring.com/en-GB/stores/hackersploitofficial

SOCIAL NETWORKS:
Twitter: https://twitter.com/HackerSploit
LinkedIn: https://www.linkedin.com/company/18713892

WHERE YOU CAN FIND US ONLINE:
HackerSploit Blog: https://hackersploit.org/
HackerSploit Forum: https://forum.hackersploit.org
HackerSploit Academy: https://www.hackersploit.academy

LISTEN TO THE CYBERTALK PODCAST:
Spotify: https://open.spotify.com/show/6j0RhRiofxkt39AskIpwP7

We hope you enjoyed the video and found value in the content. We value your feedback. If you have any questions or suggestions feel free to post them in the comments section or contact us directly via our social platforms.

Thanks for watching!
Благодарю за просмотр!
Kiitos katsomisesta
Danke fürs Zuschauen!
感谢您观看
Merci d'avoir regardé
Obrigado por assistir
دیکھنے کے لیے شکریہ
देखने के लिए धन्यवाद
Grazie per la visione
Gracias por ver
شكرا للمشاهدة

#TryHackMe#Pentesting


guid: yt:video:IO4caqGfa6Y
title: Cybertalk - EP9 - AI In Cyber Security, Bug Bounties & Reverse Engineering
author: HackerSploit
url: https://www.youtube.com/watch?v=IO4caqGfa6Y
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC0ZTPkdxlAKf-V33tqXwi3Q
content_mime_type: text/plain
content:
In this episode, we discuss the increasingly growing role of Artificial Intelligence(AI) in Cyber Security and its effect on Cyber Security jobs and roles going forward. We also discuss what bug bounty programs to begin with and how to learn malware analysis and reverse engineering.

-----------------------------------------------------------------------------------

SUBMIT YOUR QUESTIONS ►► https://bit.ly/2KL9lgw

-----------------------------------------------------------------------------------

BLOG  ►► https://bit.ly/3qjvSjK
FORUM  ►► https://bit.ly/39r2kcY
ACADEMY ►► https://bit.ly/39CuORr

-----------------------------------------------------------------------------------

TWITTER ►► https://bit.ly/3sNKXfq
INSTAGRAM ►► https://bit.ly/3sP1Syh
LINKEDIN ►► https://bit.ly/360qwlN
PATREON ►► https://bit.ly/365iDLK
MERCHANDISE ►► https://bit.ly/3c2jDEn

-----------------------------------------------------------------------------------

CYBERTALK PODCAST ►► https://open.spotify.com/show/6j0RhRiofxkt39AskIpwP7

-----------------------------------------------------------------------------------

We hope you enjoyed the video and found value in the content. We value your feedback, If you have any questions or suggestions feel free to post them in the comments section or contact us directly via our social platforms.

-----------------------------------------------------------------------------------
Thanks for watching!
Благодарю за просмотр!
Kiitos katsomisesta
Danke fürs Zuschauen!
感谢您观看
Merci d'avoir regardé
Obrigado por assistir
دیکھنے کے لیے شکریہ
देखने के लिए धन्यवाद
Grazie per la visione
Gracias por ver
شكرا للمشاهدة

-----------------------------------------------------------------------------------

#CyberTalk#BugBounty#AI#Malware


guid: yt:video:lJUuAILBFIg
title: The Role Of AI In Cyber Security
author: HackerSploit
url: https://www.youtube.com/watch?v=lJUuAILBFIg
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC0ZTPkdxlAKf-V33tqXwi3Q
content_mime_type: text/plain
content:
In this clip, we discuss the increasingly growing role of Artificial Intelligence(AI) in Cyber Security and its effect on Cyber Security jobs and roles going forward. 

-----------------------------------------------------------------------------------

SUBMIT YOUR QUESTIONS ►► https://bit.ly/2KL9lgw

-----------------------------------------------------------------------------------

BLOG  ►► https://bit.ly/3qjvSjK
FORUM  ►► https://bit.ly/39r2kcY
ACADEMY ►► https://bit.ly/39CuORr

-----------------------------------------------------------------------------------

TWITTER ►► https://bit.ly/3sNKXfq
INSTAGRAM ►► https://bit.ly/3sP1Syh
LINKEDIN ►► https://bit.ly/360qwlN
PATREON ►► https://bit.ly/365iDLK
MERCHANDISE ►► https://bit.ly/3c2jDEn

-----------------------------------------------------------------------------------

CYBERTALK PODCAST ►► https://open.spotify.com/show/6j0RhRiofxkt39AskIpwP7

-----------------------------------------------------------------------------------

We hope you enjoyed the video and found value in the content. We value your feedback, If you have any questions or suggestions feel free to post them in the comments section or contact us directly via our social platforms.

-----------------------------------------------------------------------------------
Thanks for watching!
Благодарю за просмотр!
Kiitos katsomisesta
Danke fürs Zuschauen!
感谢您观看
Merci d'avoir regardé
Obrigado por assistir
دیکھنے کے لیے شکریہ
देखने के लिए धन्यवाद
Grazie per la visione
Gracias por ver
شكرا للمشاهدة

-----------------------------------------------------------------------------------

#CyberTalk#AI#CyberSecurity


guid: yt:video:HtYlGdEo_9o
title: Getting Started With Malware Analysis & Reverse Engineering
author: HackerSploit
url: https://www.youtube.com/watch?v=HtYlGdEo_9o
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC0ZTPkdxlAKf-V33tqXwi3Q
content_mime_type: text/plain
content:
In this clip, we discuss how to get started with malware analysis and reverse engineering. 

-----------------------------------------------------------------------------------

SUBMIT YOUR QUESTIONS ►► https://bit.ly/2KL9lgw

-----------------------------------------------------------------------------------

BLOG  ►► https://bit.ly/3qjvSjK
FORUM  ►► https://bit.ly/39r2kcY
ACADEMY ►► https://bit.ly/39CuORr

-----------------------------------------------------------------------------------

TWITTER ►► https://bit.ly/3sNKXfq
INSTAGRAM ►► https://bit.ly/3sP1Syh
LINKEDIN ►► https://bit.ly/360qwlN
PATREON ►► https://bit.ly/365iDLK
MERCHANDISE ►► https://bit.ly/3c2jDEn

-----------------------------------------------------------------------------------

CYBERTALK PODCAST ►► https://open.spotify.com/show/6j0RhRiofxkt39AskIpwP7

-----------------------------------------------------------------------------------

We hope you enjoyed the video and found value in the content. We value your feedback, If you have any questions or suggestions feel free to post them in the comments section or contact us directly via our social platforms.

-----------------------------------------------------------------------------------
Thanks for watching!
Благодарю за просмотр!
Kiitos katsomisesta
Danke fürs Zuschauen!
感谢您观看
Merci d'avoir regardé
Obrigado por assistir
دیکھنے کے لیے شکریہ
देखने के लिए धन्यवाद
Grazie per la visione
Gracias por ver
شكرا للمشاهدة

-----------------------------------------------------------------------------------

#CyberTalk#Malware#ReverseEngineering


guid: yt:video:fiWcdtfpSQA
title: How To Secure phpMyAdmin
author: HackerSploit
url: https://www.youtube.com/watch?v=fiWcdtfpSQA
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC0ZTPkdxlAKf-V33tqXwi3Q
content_mime_type: text/plain
content:
In this video, we will take a look at how to comprehensively configure and secure phpMyAdmin. phpMyAdmin is a free, open-source, and cross-platform PHP based web application that offers a simple, powerful, and convenient browser-based GUI for interacting and working with MySQL databases

Video Documentation: https://www.linode.com/docs/guides/how-to-secure-phpmyadmin/

-----------------------------------------------------------------------------------

REGISTER FOR PART 2: https://bit.ly/3fsFPZV
GET $100 IN LINODE CREDIT: https://bit.ly/2PeFnDO

-----------------------------------------------------------------------------------

BLOG  ►► https://bit.ly/3qjvSjK
FORUM  ►► https://bit.ly/39r2kcY
ACADEMY ►► https://bit.ly/39CuORr

-----------------------------------------------------------------------------------

TWITTER ►► https://bit.ly/3sNKXfq
INSTAGRAM ►► https://bit.ly/3sP1Syh
LINKEDIN ►► https://bit.ly/360qwlN
PATREON ►► https://bit.ly/365iDLK
MERCHANDISE ►► https://bit.ly/3c2jDEn

-----------------------------------------------------------------------------------

CYBERTALK PODCAST ►► https://open.spotify.com/show/6j0RhRiofxkt39AskIpwP7

-----------------------------------------------------------------------------------

We hope you enjoyed the video and found value in the content. We value your feedback, If you have any questions or suggestions feel free to post them in the comments section or contact us directly via our social platforms.

-----------------------------------------------------------------------------------

Thanks for watching!
Благодарю за просмотр!
Kiitos katsomisesta
Danke fürs Zuschauen!
感谢您观看
Merci d'avoir regardé
Obrigado por assistir
دیکھنے کے لیے شکریہ
देखने के लिए धन्यवाद
Grazie per la visione
Gracias por ver
شكرا للمشاهدة

-----------------------------------------------------------------------------------
#Infosec#CyberSecurity#WebAppSec


guid: yt:video:MB7nQrlP5Yc
title: Apache2 ModSecurity Tutorial | Apache2 WAF
author: HackerSploit
url: https://www.youtube.com/watch?v=MB7nQrlP5Yc
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC0ZTPkdxlAKf-V33tqXwi3Q
content_mime_type: text/plain
content:
In this video, we will take a look at how to secure apache2 with ModSecurity. ModSecurity is a free and open-source web application firewall for apache, it started out as an apache module but has grown into a fully-fledged web application firewall.
It works by inspecting requests sent to the webserver in real-time against a predefined ruleset.
ModSecurity prevents typical web application attacks like XSS, SQL Injection. It does this by actively monitoring and logging requests being sent to the webserver.

Video Documentation: https://www.linode.com/docs/guides/securing-apache2-with-modsecurity/

-----------------------------------------------------------------------------------

REGISTER FOR PART 2: https://bit.ly/3fsFPZV
GET $100 IN LINODE CREDIT: https://bit.ly/2PeFnDO

-----------------------------------------------------------------------------------

BLOG  ►► https://bit.ly/3qjvSjK
FORUM  ►► https://bit.ly/39r2kcY
ACADEMY ►► https://bit.ly/39CuORr

-----------------------------------------------------------------------------------

TWITTER ►► https://bit.ly/3sNKXfq
INSTAGRAM ►► https://bit.ly/3sP1Syh
LINKEDIN ►► https://bit.ly/360qwlN
PATREON ►► https://bit.ly/365iDLK
MERCHANDISE ►► https://bit.ly/3c2jDEn

-----------------------------------------------------------------------------------

CYBERTALK PODCAST ►► https://open.spotify.com/show/6j0RhRiofxkt39AskIpwP7

-----------------------------------------------------------------------------------

We hope you enjoyed the video and found value in the content. We value your feedback, If you have any questions or suggestions feel free to post them in the comments section or contact us directly via our social platforms.

-----------------------------------------------------------------------------------

Thanks for watching!
Благодарю за просмотр!
Kiitos katsomisesta
Danke fürs Zuschauen!
感谢您观看
Merci d'avoir regardé
Obrigado por assistir
دیکھنے کے لیے شکریہ
देखने के लिए धन्यवाद
Grazie per la visione
Gracias por ver
شكرا للمشاهدة

-----------------------------------------------------------------------------------
#WebAppSec#Infosec


guid: yt:video:5eRxOYbaIEI
title: Nginx ModSecurity Tutorial | Nginx WAF
author: HackerSploit
url: https://www.youtube.com/watch?v=5eRxOYbaIEI
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC0ZTPkdxlAKf-V33tqXwi3Q
content_mime_type: text/plain
content:
In this video, we will take a look at how to secure Nginx with ModSecurity. ModSecurity is a free and open-source web application firewall for apache, it started out as an apache module but has grown into a fully-fledged web application firewall.
It works by inspecting requests sent to the webserver in real-time against a predefined ruleset.
ModSecurity prevents typical web application attacks like XSS, SQL Injection. It does this by actively monitoring and logging requests being sent to the webserver.

Video Documentation: https://www.linode.com/docs/guides/securing-nginx-with-modsecurity/

-----------------------------------------------------------------------------------

REGISTER FOR PART 2: https://bit.ly/3fsFPZV
GET $100 IN LINODE CREDIT: https://bit.ly/2PeFnDO

-----------------------------------------------------------------------------------

BLOG  ►► https://bit.ly/3qjvSjK
FORUM  ►► https://bit.ly/39r2kcY
ACADEMY ►► https://bit.ly/39CuORr

-----------------------------------------------------------------------------------

TWITTER ►► https://bit.ly/3sNKXfq
INSTAGRAM ►► https://bit.ly/3sP1Syh
LINKEDIN ►► https://bit.ly/360qwlN
PATREON ►► https://bit.ly/365iDLK
MERCHANDISE ►► https://bit.ly/3c2jDEn

-----------------------------------------------------------------------------------

CYBERTALK PODCAST ►► https://open.spotify.com/show/6j0RhRiofxkt39AskIpwP7

-----------------------------------------------------------------------------------

We hope you enjoyed the video and found value in the content. We value your feedback, If you have any questions or suggestions feel free to post them in the comments section or contact us directly via our social platforms.

-----------------------------------------------------------------------------------

Thanks for watching!
Благодарю за просмотр!
Kiitos katsomisesta
Danke fürs Zuschauen!
感谢您观看
Merci d'avoir regardé
Obrigado por assistir
دیکھنے کے لیے شکریہ
देखने के लिए धन्यवाद
Grazie per la visione
Gracias por ver
شكرا للمشاهدة

-----------------------------------------------------------------------------------
#WebAppSec#Infosec


guid: yt:video:KINjI1tlo2w
title: Docker Security Essentials | How To Secure Docker Containers
author: HackerSploit
url: https://www.youtube.com/watch?v=KINjI1tlo2w
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC0ZTPkdxlAKf-V33tqXwi3Q
content_mime_type: text/plain
content:
In this video, we will take a look at how to secure Docker containers and some of the security best practices to implement when running Docker containers. 
Docker is a set of platforms as service products that use OS-level virtualization to deliver software in packages called containers. Containers are isolated from one another and bundle their own software, libraries and configuration files; they can communicate with each other through well-defined channels.

Video Documentation: https://www.linode.com/docs/guides/docker-security-essentials/

-----------------------------------------------------------------------------------

REGISTER FOR PART 2: https://bit.ly/3fsFPZV
GET $100 IN LINODE CREDIT: https://bit.ly/2PeFnDO

-----------------------------------------------------------------------------------

BLOG  ►► https://bit.ly/3qjvSjK
FORUM  ►► https://bit.ly/39r2kcY
ACADEMY ►► https://bit.ly/39CuORr

-----------------------------------------------------------------------------------

TWITTER ►► https://bit.ly/3sNKXfq
INSTAGRAM ►► https://bit.ly/3sP1Syh
LINKEDIN ►► https://bit.ly/360qwlN
PATREON ►► https://bit.ly/365iDLK
MERCHANDISE ►► https://bit.ly/3c2jDEn

-----------------------------------------------------------------------------------

CYBERTALK PODCAST ►► https://open.spotify.com/show/6j0RhRiofxkt39AskIpwP7

-----------------------------------------------------------------------------------

We hope you enjoyed the video and found value in the content. We value your feedback, If you have any questions or suggestions feel free to post them in the comments section or contact us directly via our social platforms.

-----------------------------------------------------------------------------------

Thanks for watching!
Благодарю за просмотр!
Kiitos katsomisesta
Danke fürs Zuschauen!
感谢您观看
Merci d'avoir regardé
Obrigado por assistir
دیکھنے کے لیے شکریہ
देखने के लिए धन्यवाद
Grazie per la visione
Gracias por ver
شكرا للمشاهدة

-----------------------------------------------------------------------------------
#Infosec#Docker


guid: yt:video:ITSZ8743MUk
title: Dumping S3 Buckets | Exploiting S3 Bucket Misconfigurations
author: HackerSploit
url: https://www.youtube.com/watch?v=ITSZ8743MUk
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC0ZTPkdxlAKf-V33tqXwi3Q
content_mime_type: text/plain
content:
In this video, we will take a look at how to perform reconnaissance on AWS S3 buckets and how to exploit S3 bucket permission configurations to list and dump the contents of a poorly configured S3 bucket.

-----------------------------------------------------------------------------------

flaws.cloud: https://bit.ly/3thjB0k
S3Scanner: https://bit.ly/3vHG8oE
lazys3: https://bit.ly/3tleuvV

-----------------------------------------------------------------------------------

BLOG  ►► https://bit.ly/3qjvSjK
FORUM  ►► https://bit.ly/39r2kcY
ACADEMY ►► https://bit.ly/39CuORr

-----------------------------------------------------------------------------------

TWITTER ►► https://bit.ly/3sNKXfq
INSTAGRAM ►► https://bit.ly/3sP1Syh
LINKEDIN ►► https://bit.ly/360qwlN
PATREON ►► https://bit.ly/365iDLK
MERCHANDISE ►► https://bit.ly/3c2jDEn

-----------------------------------------------------------------------------------

CYBERTALK PODCAST ►► https://open.spotify.com/show/6j0RhRiofxkt39AskIpwP7

-----------------------------------------------------------------------------------

We hope you enjoyed the video and found value in the content. We value your feedback, If you have any questions or suggestions feel free to post them in the comments section or contact us directly via our social platforms.

-----------------------------------------------------------------------------------

Thanks for watching!
Благодарю за просмотр!
Kiitos katsomisesta
Danke fürs Zuschauen!
感谢您观看
Merci d'avoir regardé
Obrigado por assistir
دیکھنے کے لیے شکریہ
देखने के लिए धन्यवाद
Grazie per la visione
Gracias por ver
شكرا للمشاهدة

-----------------------------------------------------------------------------------
#BugBounty#Recon#AWS


guid: yt:video:Q85ku046Q_E
title: PwnLab VulnHub Walkthrough - Boot-To-Root
author: HackerSploit
url: https://www.youtube.com/watch?v=Q85ku046Q_E
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC0ZTPkdxlAKf-V33tqXwi3Q
content_mime_type: text/plain
content:
In this video, I will be showing you how to pwn PwnLab from VulnHub. 
VulnHub provides materials allowing anyone to gain practical hands-on experience with digital security, computer applications, and network administration tasks.

-----------------------------------------------------------------------------------

LINKS:
PwnLab: https://bit.ly/3f1gwMT

-----------------------------------------------------------------------------------

BLOG  ►► https://bit.ly/3qjvSjK
FORUM  ►► https://bit.ly/39r2kcY
ACADEMY ►► https://bit.ly/39CuORr

-----------------------------------------------------------------------------------

TWITTER ►► https://bit.ly/3sNKXfq
INSTAGRAM ►► https://bit.ly/3sP1Syh
LINKEDIN ►► https://bit.ly/360qwlN
PATREON ►► https://bit.ly/365iDLK
MERCHANDISE ►► https://bit.ly/3c2jDEn

-----------------------------------------------------------------------------------

CYBERTALK PODCAST ►► https://open.spotify.com/show/6j0RhRiofxkt39AskIpwP7

-----------------------------------------------------------------------------------

We hope you enjoyed the video and found value in the content. We value your feedback, If you have any questions or suggestions feel free to post them in the comments section or contact us directly via our social platforms.

-----------------------------------------------------------------------------------
Thanks for watching!
Благодарю за просмотр!
Kiitos katsomisesta
Danke fürs Zuschauen!
感谢您观看
Merci d'avoir regardé
Obrigado por assistir
دیکھنے کے لیے شکریہ
देखने के लिए धन्यवाद
Grazie per la visione
Gracias por ver
شكرا للمشاهدة
-----------------------------------------------------------------------------------
#CTF#VulnHub


guid: yt:video:NN9fQwiomAU
title: Anonymize Your Traffic With Proxychains & Tor
author: HackerSploit
url: https://www.youtube.com/watch?v=NN9fQwiomAU
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC0ZTPkdxlAKf-V33tqXwi3Q
content_mime_type: text/plain
content:
In this video, we will take a look at how to anonymize your traffic with Proxychains and the Tor service to stay anonymous while hacking.
proxychains - a tool that forces any TCP connection made by any given application. 

-----------------------------------------------------------------------------------

BLOG  ►► https://bit.ly/3qjvSjK
FORUM  ►► https://bit.ly/39r2kcY
ACADEMY ►► https://bit.ly/39CuORr

-----------------------------------------------------------------------------------

TWITTER ►► https://bit.ly/3sNKXfq
INSTAGRAM ►► https://bit.ly/3sP1Syh
LINKEDIN ►► https://bit.ly/360qwlN
PATREON ►► https://bit.ly/365iDLK
MERCHANDISE ►► https://bit.ly/3c2jDEn

-----------------------------------------------------------------------------------

CYBERTALK PODCAST ►► https://open.spotify.com/show/6j0RhRiofxkt39AskIpwP7

-----------------------------------------------------------------------------------

We hope you enjoyed the video and found value in the content. We value your feedback, If you have any questions or suggestions feel free to post them in the comments section or contact us directly via our social platforms.

-----------------------------------------------------------------------------------
Thanks for watching!
Благодарю за просмотр!
Kiitos katsomisesta
Danke fürs Zuschauen!
感谢您观看
Merci d'avoir regardé
Obrigado por assistir
دیکھنے کے لیے شکریہ
देखने के लिए धन्यवाद
Grazie per la visione
Gracias por ver
شكرا للمشاهدة
-----------------------------------------------------------------------------------
#Anonymity#Tor


guid: yt:video:i-dQwejj518
title: VulnOS V2 - VulnHub Walkthrough - Boot-To-Root
author: HackerSploit
url: https://www.youtube.com/watch?v=i-dQwejj518
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC0ZTPkdxlAKf-V33tqXwi3Q
content_mime_type: text/plain
content:
In this video, I will be showing you how to pwn VulnOS V2 from VulnHub. 
VulnHub provides materials allowing anyone to gain practical hands-on experience with digital security, computer applications, and network administration tasks.

-----------------------------------------------------------------------------------

LINKS:
VulnOS V2: https://bit.ly/3eEvl8W

-----------------------------------------------------------------------------------

BLOG  ►► https://bit.ly/3qjvSjK
FORUM  ►► https://bit.ly/39r2kcY
ACADEMY ►► https://bit.ly/39CuORr

-----------------------------------------------------------------------------------

TWITTER ►► https://bit.ly/3sNKXfq
INSTAGRAM ►► https://bit.ly/3sP1Syh
LINKEDIN ►► https://bit.ly/360qwlN
PATREON ►► https://bit.ly/365iDLK
MERCHANDISE ►► https://bit.ly/3c2jDEn

-----------------------------------------------------------------------------------

CYBERTALK PODCAST ►► https://open.spotify.com/show/6j0RhRiofxkt39AskIpwP7

-----------------------------------------------------------------------------------

We hope you enjoyed the video and found value in the content. We value your feedback, If you have any questions or suggestions feel free to post them in the comments section or contact us directly via our social platforms.

-----------------------------------------------------------------------------------
Thanks for watching!
Благодарю за просмотр!
Kiitos katsomisesta
Danke fürs Zuschauen!
感谢您观看
Merci d'avoir regardé
Obrigado por assistir
دیکھنے کے لیے شکریہ
देखने के लिए धन्यवाद
Grazie per la visione
Gracias por ver
شكرا للمشاهدة
-----------------------------------------------------------------------------------
#CTF#VulnHub


guid: yt:video:aD_KlzVK834
title: Windows Privilege Escalation Tutorial For Beginners
author: HackerSploit
url: https://www.youtube.com/watch?v=aD_KlzVK834
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC0ZTPkdxlAKf-V33tqXwi3Q
content_mime_type: text/plain
content:
In this video, I will be demonstrating how to perform privilege escalation on Windows through various tools and techniques. We will take a look at performing local enumeration, using the windows-exploit-suggester, performing token impersonation attacks, and dumping hashes. We will also be exploring the pass the hash attack and how to use NTLM hashes to obtain elevated privileges on the target Windows system.

-----------------------------------------------------------------------------------

BLOG  ►► https://bit.ly/3qjvSjK
FORUM  ►► https://bit.ly/39r2kcY
ACADEMY ►► https://bit.ly/39CuORr

-----------------------------------------------------------------------------------

TWITTER ►► https://bit.ly/3sNKXfq
INSTAGRAM ►► https://bit.ly/3sP1Syh
LINKEDIN ►► https://bit.ly/360qwlN
PATREON ►► https://bit.ly/365iDLK
MERCHANDISE ►► https://bit.ly/3c2jDEn

-----------------------------------------------------------------------------------

CYBERTALK PODCAST ►► https://open.spotify.com/show/6j0RhRiofxkt39AskIpwP7

-----------------------------------------------------------------------------------

We hope you enjoyed the video and found value in the content. We value your feedback, If you have any questions or suggestions feel free to post them in the comments section or contact us directly via our social platforms.

-----------------------------------------------------------------------------------
Thanks for watching!
Благодарю за просмотр!
Kiitos katsomisesta
Danke fürs Zuschauen!
感谢您观看
Merci d'avoir regardé
Obrigado por assistir
دیکھنے کے لیے شکریہ
देखने के लिए धन्यवाद
Grazie per la visione
Gracias por ver
شكرا للمشاهدة
-----------------------------------------------------------------------------------
#Pentesting#Windows


guid: yt:video:6KC1YrxJma8
title: A GUIDE TO ABSURDISM: The Philosophy For Living Fully
author: Sisyphus 55
url: https://www.youtube.com/watch?v=6KC1YrxJma8
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCDETFHKteb-C_EaXmRKvP4w
content_mime_type: text/plain
content:
Source: https://ralphammer.com/is-it-worth-the-trouble/

PATREON: [https://www.patreon.com/user?u=3261155](https://www.patreon.com/user?u=3261155)

MUSIC: [https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA](https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA)

TWITTER: [https://twitter.com/5isyphus55](https://twitter.com/5isyphus55)


guid: yt:video:KlSVoQiCijU
title: why you'll never be happy
author: Sisyphus 55
url: https://www.youtube.com/watch?v=KlSVoQiCijU
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCDETFHKteb-C_EaXmRKvP4w
content_mime_type: text/plain
content:
Podcast: https://www.youtube.com/watch?v=OzYOGsDKKzw&t=6s

PATREON: [https://www.patreon.com/user?u=3261155](https://www.patreon.com/user?u=3261155)

MUSIC: [https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA](https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA)

TWITTER: [https://twitter.com/5isyphus55](https://twitter.com/5isyphus55)


guid: yt:video:NPMLgCuNAK0
title: THE PROFESSOR WHO CHANGED THE WORLD : A GUIDE TO NOAM CHOMSKY
author: Sisyphus 55
url: https://www.youtube.com/watch?v=NPMLgCuNAK0
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCDETFHKteb-C_EaXmRKvP4w
content_mime_type: text/plain
content:
🎉 Get up to 65% OFF a Babbel subscription ➡️  limited time only 🕒 HERE: https://go.babbel.com/6m50-youtube-sisyphus55-feb-2021/default

NEW MERCH: https://teespring.com/stores/sisyphus-55

PATREON: [https://www.patreon.com/user?u=3261155](https://www.patreon.com/user?u=3261155)

MUSIC: HouseCat [https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA](https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA)

TWITTER: [https://twitter.com/5isyphus55](https://twitter.com/5isyphus55)


guid: yt:video:U9oFBV72jH0
title: How To Fall In Love
author: Sisyphus 55
url: https://www.youtube.com/watch?v=U9oFBV72jH0
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCDETFHKteb-C_EaXmRKvP4w
content_mime_type: text/plain
content:
PATREON: [https://www.patreon.com/user?u=3261155](https://www.patreon.com/user?u=3261155)

MUSIC: [https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA](https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA)

TWITTER: [https://twitter.com/5isyphus55](https://twitter.com/5isyphus55)


guid: yt:video:_WhhqNAlfnE
title: Episode 7: With Eamon Dolan | Editor of Mary Trump's "Too Much and Never Enough"
author: Sisyphus 55
url: https://www.youtube.com/watch?v=_WhhqNAlfnE
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCDETFHKteb-C_EaXmRKvP4w
content_mime_type: text/plain
content:
Today we sit down with VP of Simon & Schuster Eamon Dolan to discuss narcissism, Trump and the editing world in general. 

PATREON: [https://www.patreon.com/user?u=3261155]

MUSIC: [https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA]

TWITTER: [https://twitter.com/5isyphus55]


guid: yt:video:RlGZ0fDXAaY
title: orange man bad
author: Sisyphus 55
url: https://www.youtube.com/watch?v=RlGZ0fDXAaY
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCDETFHKteb-C_EaXmRKvP4w
content_mime_type: text/plain
content:
from the latest podcast with Eamon Dolan: https://www.youtube.com/watch?v=_WhhqNAlfnE&t=1s
PATREON: https://www.patreon.com/user?u=3261155

MUSIC: [https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA]

TWITTER: [https://twitter.com/5isyphus55]


guid: yt:video:42kixi7-Lsk
title: THE PHILOSOPHER WHO STARTED A CULT
author: Sisyphus 55
url: https://www.youtube.com/watch?v=42kixi7-Lsk
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCDETFHKteb-C_EaXmRKvP4w
content_mime_type: text/plain
content:
Get Surfshark VPN at https://surfshark.deals/sisyphus Enter promo code SISYPHUS for 83% off and 3 extra months for FREE!!

PATREON: [https://www.patreon.com/user?u=3261155](https://www.patreon.com/user?u=3261155)

MUSIC: [https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA](https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA)

TWITTER: [https://twitter.com/5isyphus55](https://twitter.com/5isyphus55)

Sources
10 Strange Facts about Pythagoras: https://listverse.com/2017/04/26/10-strange-facts-about-pythagoras-mathematician-and-cult-leader/#:~:text=10%20Pythagoras%20Led%20A%20Cult%20That%20Worshiped%20Numbers&text=Numbers%2C%20Pythagoras%20believed%2C%20were%20the,were%20sacred%E2%80%94almost%20like%20gods.
Stanford Philosophy: https://plato.stanford.edu/entries/pythagoras/

https://www.youtube.com/watch?v=JKLpTBIgoNU: samos footage


guid: yt:video:q9qtLY3SqqI
title: You Are Chasing The Wrong Goals
author: Sisyphus 55
url: https://www.youtube.com/watch?v=q9qtLY3SqqI
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCDETFHKteb-C_EaXmRKvP4w
content_mime_type: text/plain
content:
Go to http://www.curiositystream.com/Sisyphus & enter the promo code ‘sisyphus’ at checkout for $14.99 for the entire year!

Sources:
 https://www.njlifehacks.com/intrinsic-goals-vs-extrinsic-goals/
https://www.researchgate.net/publication/306055669_Examining_Intrinsic_versus_Extrinsic_Exercise_Goals_Cognitive_Affective_and_Behavioral_Outcomes

PATREON: [https://www.patreon.com/user?u=3261155](https://www.patreon.com/user?u=3261155)

MUSIC: [https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA](https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA)

TWITTER: [https://twitter.com/5isyphus55](https://twitter.com/5isyphus55)


guid: yt:video:Jk86MhvCceM
title: The Mindset That's Making You Miserable
author: Sisyphus 55
url: https://www.youtube.com/watch?v=Jk86MhvCceM
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCDETFHKteb-C_EaXmRKvP4w
content_mime_type: text/plain
content:
Go to http://www.curiositystream.com/Sisyphus & enter the promo code ‘sisyphus’ at checkout for $14.99 for the entire year!

Sources:

Main article on Brainpickings: [https://www.brainpickings.org/2014/01/29/carol-dweck-mindset/](https://www.brainpickings.org/2014/01/29/carol-dweck-mindset/)

Study 1: [https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5836039/](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5836039/)

Study 2: [https://www.ncbi.nlm.nih.gov/pmc/articles/PMC1838571/](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC1838571/)

Book by Carol Dweck: [https://www.amazon.ca/Mindset-Psychology-Carol-S-Dweck/dp/0345472322](https://www.amazon.ca/Mindset-Psychology-Carol-S-Dweck/dp/0345472322)

PATREON: 


MUSIC: 

[https://www.youtube.com/channel/UCKPZ...](https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA)

TWITTER: 



guid: yt:video:J8B50WK-B9I
title: THE FBI'S MOST WANTED PHILOSOPHER: A GUIDE TO ANGELA DAVIS
author: Sisyphus 55
url: https://www.youtube.com/watch?v=J8B50WK-B9I
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCDETFHKteb-C_EaXmRKvP4w
content_mime_type: text/plain
content:
Start building your ideal daily routine 💪 The first 100 people who click on the link will get a FREE week trial and 25% OFF 🎁 Fabulous Premium ➡️ LINK: https://thefab.co/sisyphus55

Sources:
https://www.wbur.org/hereandnow/2020/06/19/angela-davis-protests-anti-racism

https://www.thenation.com/article/archive/what-is-prison-abolition/

https://level.medium.com/why-arguments-against-abolition-inevitably-fail-991342b8d042

https://www.jstor.org/stable/44325619?seq=1#metadata_info_tab_contents

PATREON: [https://www.patreon.com/user?u=3261155](https://www.patreon.com/user?u=3261155)

MUSIC: [https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA](https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA)

TWITTER: [https://twitter.com/5isyphus55](https://twitter.com/5isyphus55)


guid: yt:video:6Y6ljxV2L1s
title: THE MAD SCIENTIST PHILOSOPHER
author: Sisyphus 55
url: https://www.youtube.com/watch?v=6Y6ljxV2L1s
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCDETFHKteb-C_EaXmRKvP4w
content_mime_type: text/plain
content:
BLINKIST 📚 Get Unlimited Access For 1 Week 😏 and 25% OFF a Full Membership ➡️  https://www.blinkist.com/sisyphus 

Sources: 
https://plato.stanford.edu/entries/utilitarianism-history/
https://iep.utm.edu/bentham/
https://www.theguardian.com/books/2014/jun/26/sexual-irregularities-morality-jeremy-bentham-review
https://ethics.org.au/big-thinker-jeremy-bentham/
https://www.ucl.ac.uk/bentham-project/who-was-jeremy-bentham/auto-icon

PATREON: [https://www.patreon.com/user?u=3261155](https://www.patreon.com/user?u=3261155)

MUSIC: [https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA](https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA)

TWITTER: [https://twitter.com/5isyphus55](https://twitter.com/5isyphus55)


guid: yt:video:EQH7whNRogg
title: How Michael Jordan Used Zen Mindfulness To Become The GOAT
author: Sisyphus 55
url: https://www.youtube.com/watch?v=EQH7whNRogg
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCDETFHKteb-C_EaXmRKvP4w
content_mime_type: text/plain
content:
Start speaking a language in 3 weeks with Babbel! 🎉 Get 6 months FREE when you sign up for 6 months! ➡️HERE : https://go.babbel.com/6m50-youtube-sisyphus55-2-april-2021/default

PATREON: [https://www.patreon.com/user?u=3261155](https://www.patreon.com/user?u=3261155)

MUSIC: [https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA](https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA)

The Cheesy by OB3ple


Creative Commons — Attribution-ShareAlike 3.0 Unported— CC BY-SA 3.0


Music provided by Music for Creators

[https://youtu.be/IYF-WT3sp_g](https://www.youtube.com/watch?v=IYF-WT3sp_g&t=0s)

TWITTER: [https://twitter.com/5isyphus55](https://twitter.com/5isyphus55)

SOURCES
https://crm.org/articles/zen-and-the-art-of-winning-phil-jacksons-team-leadership
https://www.vice.com/en/article/vvawmd/the-zen-masters-zen-master-how-phil-jacksons-mindfulness-guru-is-helping-the-new-york-knicks
https://medium.com/@SunilSharmaUK/phil-jackson-the-zen-master-who-conquered-basketball-e8257a76979d
https://www.spokesman.com/stories/1996/jun/15/sports-and-spirituality-chicago-bulls-coach-phil/
https://www.huffingtonpost.ca/entry/phil-jackson-zen_n_4995272?ri18n=true


guid: yt:video:ukORp-VwfdU
title: Epicurus's Three Steps To Happiness
author: Sisyphus 55
url: https://www.youtube.com/watch?v=ukORp-VwfdU
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCDETFHKteb-C_EaXmRKvP4w
content_mime_type: text/plain
content:
Download the free Ground News app and never have an awkward Christmas dinner again https://ground.news/sisyphus

PATREON: [https://www.patreon.com/user?u=3261155](https://www.patreon.com/user?u=3261155)

MUSIC: [https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA](https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA)

TWITTER: [https://twitter.com/5isyphus55](https://twitter.com/5isyphus55)

Sources: 

https://www.pursuit-of-happiness.org/history-of-happiness/epicurus/

https://medium.com/mind-cafe/5-tips-from-epicurus-to-help-you-live-a-happier-life-a81859cf60c4

Study: https://news.harvard.edu/gazette/story/2017/04/over-nearly-80-years-harvard-study-has-been-showing-how-to-live-a-healthy-and-happy-life/

https://iep.utm.edu/epicur/


guid: yt:video:xAUy0zCVuKc
title: The Mystical Philosopher
author: Sisyphus 55
url: https://www.youtube.com/watch?v=xAUy0zCVuKc
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCDETFHKteb-C_EaXmRKvP4w
content_mime_type: text/plain
content:
Written by Michael Berkowitz

PATREON: [https://www.patreon.com/user?u=3261155](https://www.patreon.com/user?u=3261155)

MUSIC: [https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA](https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA)

TWITTER: [https://twitter.com/5isyphus55](https://twitter.com/5isyphus55)


guid: yt:video:ATkjT79gNzM
title: The Philosophy of the Unabomber
author: Sisyphus 55
url: https://www.youtube.com/watch?v=ATkjT79gNzM
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCDETFHKteb-C_EaXmRKvP4w
content_mime_type: text/plain
content:
Get Surfshark VPN at https://surfshark.deals/sisyphus Enter promo code SISYPHUS for 83% off and 3 extra months for FREE!

PATREON: [https://www.patreon.com/user?u=3261155](https://www.patreon.com/user?u=3261155)

MUSIC: [https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA](https://www.youtube.com/channel/UCKPZHZzvSPYvqyk-nFS9kDA)

TWITTER: [https://twitter.com/5isyphus55](https://twitter.com/5isyphus55)


Sources: https://theanarchistlibrary.org/library/ole-martin-moen-the-unabomber-s-ethics
https://theanarchistlibrary.org/library/ole-martin-moen-the-unabomber-s-ethics#fn14)

https://thetyee.ca/Analysis/2018/10/12/Jacques-Ellul-Prophet/

https://www.washingtonpost.com/wp-srv/national/longterm/unabomber/manifesto.text.htm

https://www.theatlantic.com/magazine/archive/2000/06/harvard-and-the-making-of-the-unabomber/378239/


title: Choosing a new backup solution, Duplicity, rdiff-backup or Rsnapshot
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/tutorials/choosing-a-new-backup-solution-duplicity-rdiff-backup-or-rsnapshot.html2008-10-30

url:
https://unixsheikh.com/tutorials/choosing-a-new-backup-solution-duplicity-rdiff-backup-or-rsnapshot.html


title: Encrypting and decrypting files using GnuPG, OpenSSL or Mcrypt
url: https://unixsheikh.com/tutorials/encrypting-and-decrypting-files-using-gnupg-openssl-or-mcrypt.html
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/tutorials/encrypting-and-decrypting-files-using-gnupg-openssl-or-mcrypt.html2009-04-01


title: Mercurial branching, main and stable, a possible workflow
url: https://unixsheikh.com/tutorials/mercurial-branching-main-and-stable-a-possible-workflow.html
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/tutorials/mercurial-branching-main-and-stable-a-possible-workflow.html2009-10-14


title: Code Navigation, Design Patterns, and Too Many Functions
url: https://unixsheikh.com/articles/code-navigation-design-patterns-and-too-many-functions.html
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/articles/code-navigation-design-patterns-and-too-many-functions.html2010-10-12


title: Benchmark 1 - Dynamic pages vs. static pages vs. Memcached
url: https://unixsheikh.com/articles/benchmark-1-dynamic-pages-vs-static-pages-vs-memcached.html
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/articles/benchmark-1-dynamic-pages-vs-static-pages-vs-memcached.html2010-12-14


title: An alternative way to play YouTube videos without using Flash
url: https://unixsheikh.com/tutorials/an-alternative-way-to-play-youtube-videos-without-using-flash.html
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/tutorials/an-alternative-way-to-play-youtube-videos-without-using-flash.html2012-12-15


title: Procedural Programming vs Object Oriented Programming
url: https://unixsheikh.com/articles/procedural-programming-vs-object-oriented-programming.html
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/articles/procedural-programming-vs-object-oriented-programming.html2015-02-28


title: Real full disk encryption using GRUB on Arch Linux for BIOS and UEFI
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/tutorials/real-full-disk-encryption-using-grub-on-arch-linux-for-bios-and-uefi.html2017-05-30

url:
https://unixsheikh.com/tutorials/real-full-disk-encryption-using-grub-on-arch-linux-for-bios-and-uefi.html


title: Real full disk encryption using GRUB on Debian GNU/Linux for BIOS
url: https://unixsheikh.com/tutorials/real-full-disk-encryption-using-grub-on-debian-linux-for-bios.html
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/tutorials/real-full-disk-encryption-using-grub-on-debian-linux-for-bios.html2017-06-23


title: Make the current commit the initial commit in a Git repository
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/tutorials/make-the-current-commit-the-initial-commit-in-a-git-repository.html2017-12-10

url:
https://unixsheikh.com/tutorials/make-the-current-commit-the-initial-commit-in-a-git-repository.html


title: Arch Linux mail server tutorial - part 1 - What is email?
url: https://unixsheikh.com/tutorials/arch-linux-mail-server-tutorial-part-1-what-is-email.html
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/tutorials/arch-linux-mail-server-tutorial-part-1-what-is-email.html2017-12-27


title: Arch Linux mail server tutorial - part 2 - OpenSMTPD, Dovecot, DKIMproxy, and Let's Encrypt
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/tutorials/arch-linux-mail-server-tutorial-part-2-opensmtpd-dovecot-dkimproxy-and-lets-encrypt.html2017-12-28

url:
https://unixsheikh.com/tutorials/arch-linux-mail-server-tutorial-part-2-opensmtpd-dovecot-dkimproxy-and-lets-encrypt.html


title: Arch Linux mail server tutorial - part 3 - Get DNS right, it's important!
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/tutorials/arch-linux-mail-server-tutorial-part-3-get-dns-right-it-is-important.html2017-12-29

url:
https://unixsheikh.com/tutorials/arch-linux-mail-server-tutorial-part-3-get-dns-right-it-is-important.html


title: Real full disk encryption using GRUB on Void Linux for BIOS
url: https://unixsheikh.com/tutorials/real-full-disk-encryption-using-grub-on-void-linux-for-bios.html
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/tutorials/real-full-disk-encryption-using-grub-on-void-linux-for-bios.html2018-03-30


title: Remuxing ISO, DVD, or Bluray using cat and ffmpeg on Linux
url: https://unixsheikh.com/tutorials/remuxing-iso-dvd-or-bluray-using-cat-and-ffmpeg-on-linux.html
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/tutorials/remuxing-iso-dvd-or-bluray-using-cat-and-ffmpeg-on-linux.html2018-12-05


title: Battle testing data integrity verification with ZFS, Btrfs and mdadm+dm-integrity
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/articles/battle-testing-data-integrity-verification-with-zfs-btrfs-and-mdadm-dm-integrity.html2019-05-05

url:
https://unixsheikh.com/articles/battle-testing-data-integrity-verification-with-zfs-btrfs-and-mdadm-dm-integrity.html


title: When abstraction, design patterns, and principles leads to spaghetti code
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/articles/when-abstraction-design-patterns-and-principles-leads-to-spaghetti-code.html2019-05-26

url:
https://unixsheikh.com/articles/when-abstraction-design-patterns-and-principles-leads-to-spaghetti-code.html


title: Go (Golang) - understanding the object oriented features with structs, methods, and interfaces
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/articles/go-understanding-the-object-oriented-features-with-structs-methods-and-interfaces.html2019-11-02

url:
https://unixsheikh.com/articles/go-understanding-the-object-oriented-features-with-structs-methods-and-interfaces.html


title: Why you should migrate everything from Linux to BSD - part 2
url: https://unixsheikh.com/articles/why-you-should-migrate-everything-from-linux-to-bsd-part-2.html
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/articles/why-you-should-migrate-everything-from-linux-to-bsd-part-2.html2020-01-21


title: How to setup FreeBSD with a riced desktop - part 1 - Basic setup
url: https://unixsheikh.com/tutorials/how-to-setup-freebsd-with-a-riced-desktop-part-1-basic-setup.html
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/tutorials/how-to-setup-freebsd-with-a-riced-desktop-part-1-basic-setup.html2020-01-22


title: How to setup FreeBSD with a riced desktop - part 2 - Xfce
url: https://unixsheikh.com/tutorials/how-to-setup-freebsd-with-a-riced-desktop-part-2-xfce.html
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/tutorials/how-to-setup-freebsd-with-a-riced-desktop-part-2-xfce.html2020-01-23


title: Samba and NFS performance - ZFS on Linux vs ZFS on FreeBSD
url: https://unixsheikh.com/articles/samba-and-nfs-performance-zfs-on-linux-vs-zfs-on-freebsd.html
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/articles/samba-and-nfs-performance-zfs-on-linux-vs-zfs-on-freebsd.html2020-02-01


title: How you can manage the i3 window manager on multiple computers
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/tutorials/how-you-can-manage-the-i3-window-manager-on-multiple-computers.html2020-03-21

url:
https://unixsheikh.com/tutorials/how-you-can-manage-the-i3-window-manager-on-multiple-computers.html


title: Future prediction: The so-called modern web will die soon
url: https://unixsheikh.com/articles/future-prediction-the-so-called-modern-web-will-die-soon.html
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/articles/future-prediction-the-so-called-modern-web-will-die-soon.html2021-01-24


title: Real full disk encryption using GRUB on Artix Linux for BIOS and UEFI
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/tutorials/real-full-disk-encryption-using-grub-on-artix-linux-for-bios-and-uefi.html2021-02-10

url:
https://unixsheikh.com/tutorials/real-full-disk-encryption-using-grub-on-artix-linux-for-bios-and-uefi.html


title: Are you trusting open source blindly? Then you're in for a world of hurt!
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/articles/are-you-trusting-open-source-blindly-then-you-are-in-for-a-world-of-hurt.html2021-02-10

url:
https://unixsheikh.com/articles/are-you-trusting-open-source-blindly-then-you-are-in-for-a-world-of-hurt.html


title: This is how you keep your dignity and not sell your soul
url: https://unixsheikh.com/articles/this-is-how-you-keep-your-dignity-and-not-sell-your-soul.html
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/articles/this-is-how-you-keep-your-dignity-and-not-sell-your-soul.html2021-02-11


title: Code has to be simplified until it becomes absolutely correct
url: https://unixsheikh.com/articles/code-has-to-be-simplified-until-it-becomes-absolutely-correct.html
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/articles/code-has-to-be-simplified-until-it-becomes-absolutely-correct.html2021-02-16


title: How do I know if I really need object oriented programming?
url: https://unixsheikh.com/articles/how-do-i-know-if-i-really-need-object-oriented-programming.html
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/articles/how-do-i-know-if-i-really-need-object-oriented-programming.html2021-03-30


title: SQLite the only database you will ever need in most cases
url: https://unixsheikh.com/articles/sqlite-the-only-database-you-will-ever-need-in-most-cases.html
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/articles/sqlite-the-only-database-you-will-ever-need-in-most-cases.html2021-04-14


title: Stop submitting to social conformity and use your brain instead
feedurl: https://unixsheikh.com/feed.rss
guid:
https://unixsheikh.com/articles/stop-submitting-to-social-conformity-and-use-your-brain-instead.html2021-04-28

url:
https://unixsheikh.com/articles/stop-submitting-to-social-conformity-and-use-your-brain-instead.html


guid: yt:video:iS82_URhQ8s
title: Elon Musk DROPS Price Of Bitcoin By Tweeting About It, Maybe This Was His Plan All Along
author: Timcast IRL
url: https://www.youtube.com/watch?v=iS82_URhQ8s
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCLwNTXWEjVd2qIHLcXxQWxA
content_mime_type: text/plain
content:
Tim, Ian, and Lydia host congressional candidate and former movie producer Robby Starbuck to examine what Elon Musk was trying to do when he (perhaps unwittingly) dropped the price of Bitcoin with a single series of tweets. 

Guest: Robby Starbuck
@RobbyStarbuck (Twitter)
http://freedomforever.us

Merch - https://teespring.com/stores/timcast-2

Hosts: 
Tim @Timcast (everywhere) 
Ian @IanCrossland (everywhere)
Lydia @SourPatchLyds (Twitter, Minds), @RealSourPatchLyds (Gab, Instagram)

Podcast available on iTunes and Spotify, coming soon to all podcast platforms!


guid: yt:video:nYiI2_LO8q4
title: Timcast IRL - Democrat Starts Fight Over REFUSING To Remove Mask w/Janice Dean
author: Timcast IRL
url: https://www.youtube.com/watch?v=nYiI2_LO8q4
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCLwNTXWEjVd2qIHLcXxQWxA
content_mime_type: text/plain
content:
Merch - https://teespring.com/stores/timcast-2

Guest:  Janice Dean
@JaniceDean (Twitter)

Podcast available on iTunes and Spotify, coming soon to all podcast platforms!


guid: yt:video:MbcC3y-5rRs
title: Mask Argument Gets HEATED Between Eric Swalwell, MTG Staffer As Leftists REFUSE To Let Go Of Masks
author: Timcast IRL
url: https://www.youtube.com/watch?v=MbcC3y-5rRs
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCLwNTXWEjVd2qIHLcXxQWxA
content_mime_type: text/plain
content:
Tim, Ian, and Lydia join senior meteorologist at Fox News Janice Dean to discuss how unwilling to let go of the security blanket of masks leftists are proving to be.

Sign Up For Exclusive Episodes At https://timcast.com/

Guest: Janice Dean
@JaniceDean (Twitter)

Merch - https://teespring.com/stores/timcast-2

Hosts: 
Tim @Timcast (everywhere) 
Ian @IanCrossland (everywhere)
Lydia @SourPatchLyds (Twitter, Minds), @RealSourPatchLyds (Gab, Instagram)

Podcast available on iTunes and Spotify, coming soon to all podcast platforms!


guid: yt:video:jTbAnLkfbBo
title: Bill Maher Diagnosed With Covid AFTER Being Vaccinated, Forced To CANCEL 'Real Time' Airing
author: Timcast IRL
url: https://www.youtube.com/watch?v=jTbAnLkfbBo
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCLwNTXWEjVd2qIHLcXxQWxA
content_mime_type: text/plain
content:
Tim, Ian, and Lydia join senior meteorologist at Fox News Janice Dean to discuss Bill Maher's recent Covid diagnosis.

Sign Up For Exclusive Episodes At https://timcast.com/

Guest: Janice Dean
@JaniceDean (Twitter)

Merch - https://teespring.com/stores/timcast-2

Hosts: 
Tim @Timcast (everywhere) 
Ian @IanCrossland (everywhere)
Lydia @SourPatchLyds (Twitter, Minds), @RealSourPatchLyds (Gab, Instagram)

Podcast available on iTunes and Spotify, coming soon to all podcast platforms!


guid: yt:video:jx0r8BewBgU
author: Timcast IRL
url: https://www.youtube.com/watch?v=jx0r8BewBgU
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCLwNTXWEjVd2qIHLcXxQWxA
content_mime_type: text/plain
title:
Colbert REFUSES To Let Go Of Trump, NO ONE Is Funny Anymore And Trump Lives Rent-Free In Their Heads

content:
Tim, Ian, and Lydia join senior meteorologist at Fox News Janice Dean to analyze why, exactly Steven Colbert is falling in ratings - probably partly because he's still daydreaming about Donald Trump.

Sign Up For Exclusive Episodes At https://timcast.com/

Guest: Janice Dean
@JaniceDean (Twitter)
Merch - https://teespring.com/stores/timcast-2

Hosts: 
Tim @Timcast (everywhere) 
Ian @IanCrossland (everywhere)
Lydia @SourPatchLyds (Twitter, Minds), @RealSourPatchLyds (Gab, Instagram)

Podcast available on iTunes and Spotify, coming soon to all podcast platforms!


guid: yt:video:VcysHWejAEk
title: Brian Stelter DEMANDS Vaccine SELFIES From Fox Hosts, Leftists Media Is OBSESSED With Fox News
author: Timcast IRL
url: https://www.youtube.com/watch?v=VcysHWejAEk
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCLwNTXWEjVd2qIHLcXxQWxA
content_mime_type: text/plain
content:
Tim, Ian, and Lydia join senior meteorologist at Fox News Janice Dean to discuss Brian Stelter's approach to trying to 'hold Fox hosts accountable'.

Sign Up For Exclusive Episodes At https://timcast.com/

Guest: Janice Dean
@JaniceDean (Twitter)
Merch - https://teespring.com/stores/timcast-2

Hosts: 
Tim @Timcast (everywhere) 
Ian @IanCrossland (everywhere)
Lydia @SourPatchLyds (Twitter, Minds), @RealSourPatchLyds (Gab, Instagram)

Podcast available on iTunes and Spotify, coming soon to all podcast platforms!


guid: yt:video:qfoG_LnstdU
title: Dogecoin Could Save The WORLD, Probably Not, Actually, But It's Worth Discussing
author: Timcast IRL
url: https://www.youtube.com/watch?v=qfoG_LnstdU
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCLwNTXWEjVd2qIHLcXxQWxA
content_mime_type: text/plain
content:
Tim, Ian, and Lydia join Bitcoin experts and hosts of The Orange Pill Podcast Max Keiser and Stacy Abrams to argue over Dogecoin.

From Ep. #283, Monday, May 10, 2021. 

Sign Up For Exclusive Episodes At https://timcast.com/

Guests: Max Keiser & Stacy Herbert
@StacyHerbert (Twitter)
@OrangePillPod (Twitter)
@ORANGE PILL: A BITCOIN PODCAST (YouTube)

Merch - https://teespring.com/stores/timcast-2

Hosts: 
Tim @Timcast (everywhere) 
Ian @IanCrossland (everywhere)
Lydia @SourPatchLyds (Twitter, Minds), @RealSourPatchLyds (Gab, Instagram)

Podcast available on iTunes and Spotify, coming soon to all podcast platforms!


guid: yt:video:WQ2Dvh0lW8s
title: The US May Be Facing Its OWN Color Revolution, It's Happened In Other Countries JUST LIKE This
author: Timcast IRL
url: https://www.youtube.com/watch?v=WQ2Dvh0lW8s
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCLwNTXWEjVd2qIHLcXxQWxA
content_mime_type: text/plain
content:
Tim, Ian, and Lydia host congressional candidate and former movie producer Robby Starbuck to explain what a color revolution looks like, and why it seems the US is about to enter its own. 

From Ep. #286, Thursday, May 13, 2021.

Guest: Robby Starbuck
@RobbyStarbuck (Twitter)
http://freedomforever.us

Merch - https://teespring.com/stores/timcast-2

Hosts: 
Tim @Timcast (everywhere) 
Ian @IanCrossland (everywhere)
Lydia @SourPatchLyds (Twitter, Minds), @RealSourPatchLyds (Gab, Instagram)

Podcast available on iTunes and Spotify, coming soon to all podcast platforms!


guid: yt:video:fEjZceIzP50
title: US Navy Pilots See UFOs SO OFTEN They Worry They Are Foreign Spies, It's Becoming Commonplace
author: Timcast IRL
url: https://www.youtube.com/watch?v=fEjZceIzP50
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCLwNTXWEjVd2qIHLcXxQWxA
content_mime_type: text/plain
content:
Tim, Ian, and Lydia join senior meteorologist at Fox News Janice Dean to debate whether aliens exist.

From Ep. #287, Friday, May 14, 2021. 

Sign Up For Exclusive Episodes At https://timcast.com/

Guest: Janice Dean
@JaniceDean (Twitter)

Merch - https://teespring.com/stores/timcast-2

Hosts: 
Tim @Timcast (everywhere) 
Ian @IanCrossland (everywhere)
Lydia @SourPatchLyds (Twitter, Minds), @RealSourPatchLyds (Gab, Instagram)

Podcast available on iTunes and Spotify, coming soon to all podcast platforms!


guid: yt:video:FFpu2lHd5E0
title: Timcast IRL - Crowder Goes NUCLEAR On YouTube, SUES Over Censorship w/Forrest Of Recoil Magazine
author: Timcast IRL
url: https://www.youtube.com/watch?v=FFpu2lHd5E0
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCLwNTXWEjVd2qIHLcXxQWxA
content_mime_type: text/plain
content:
Sign Up For Exclusive Episodes At https://timcast.com/

Guest: Forrest Cooper, digital editor Recoil Magazine, OffGrid Magazine 
http://www.RecoilWeb.com
http://www.OffGridWeb.com

Merch - https://teespring.com/stores/timcast-2

Hosts: 
Tim @Timcast (everywhere) 
Ian @IanCrossland (everywhere)
Lydia @SourPatchLyds (Twitter, Minds), @RealSourPatchLyds (Gab, Instagram)

Podcast available on iTunes and Spotify, coming soon to all podcast platforms!


guid: yt:video:qLUVkjKDhYA
title: Steven Crowder SUES YouTube For Unfair Application Of Rules Resulting In CENSORSHIP
author: Timcast IRL
url: https://www.youtube.com/watch?v=qLUVkjKDhYA
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCLwNTXWEjVd2qIHLcXxQWxA
content_mime_type: text/plain
content:
Tim, Ian, and Lydia join Forrest Cooper, digital editor of Recoil Magazine and former Army Ranger to look at Steven Crowder's latest lawsuit, this time against YouTube. 

Sign Up For Exclusive Episodes At https://timcast.com/

Guest: Forrest Cooper
http://www.RecoilWeb.com
http://www.OffGridWeb.com
@RecoilMagazine (IG)
@RecoilOffGridMagazine (IG)

Merch - https://teespring.com/stores/timcast-2

Hosts: 
Tim @Timcast (everywhere) 
Ian @IanCrossland (everywhere)
Lydia @SourPatchLyds (Twitter, Minds), @RealSourPatchLyds (Gab, Instagram)

Podcast available on iTunes and Spotify, coming soon to all podcast platforms!


guid: yt:video:HgDi7Vrxjt0
title: Supreme Court UPHOLDS Fourth Amendment In Huge Victory, Police CANNOT Search Without Warrants
author: Timcast IRL
url: https://www.youtube.com/watch?v=HgDi7Vrxjt0
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCLwNTXWEjVd2qIHLcXxQWxA
content_mime_type: text/plain
content:
Tim, Ian, and Lydia join Forrest Cooper, digital editor of Recoil Magazine and former Army Ranger to 

Sign Up For Exclusive Episodes At https://timcast.com/

Guest: Forrest Cooper
http://www.RecoilWeb.com
http://www.OffGridWeb.com
@RecoilMagazine (IG)
@RecoilOffGridMagazine (IG)

Merch - https://teespring.com/stores/timcast-2

Hosts: 
Tim @Timcast (everywhere) 
Ian @IanCrossland (everywhere)
Lydia @SourPatchLyds (Twitter, Minds), @RealSourPatchLyds (Gab, Instagram)

Podcast available on iTunes and Spotify, coming soon to all podcast platforms!


guid: yt:video:rjuB0zl-2tg
title: BLM Scores Massive Win With Police Reform, Brooklyn Center Civilians Will Act As UNARMED 'Officers'
author: Timcast IRL
url: https://www.youtube.com/watch?v=rjuB0zl-2tg
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCLwNTXWEjVd2qIHLcXxQWxA
content_mime_type: text/plain
content:
Tim, Ian, and Lydia join Forrest Cooper, digital editor of Recoil Magazine and former Army Ranger to look at the recent police reform in Brooklyn Center, Minnesota in the wake of recent police-involved shootings. 

Sign Up For Exclusive Episodes At https://timcast.com/

Guest: Forrest Cooper
http://www.RecoilWeb.com
http://www.OffGridWeb.com
@RecoilMagazine (IG)
@RecoilOffGridMagazine (IG)

Merch - https://teespring.com/stores/timcast-2

Hosts: 
Tim @Timcast (everywhere) 
Ian @IanCrossland (everywhere)
Lydia @SourPatchLyds (Twitter, Minds), @RealSourPatchLyds (Gab, Instagram)

Podcast available on iTunes and Spotify, coming soon to all podcast platforms!


guid: yt:video:bTP7n1HjDE0
title: Gas Prices Are About To Hit A SEVEN-YEAR High After Cyberattack On Pipeline
author: Timcast IRL
url: https://www.youtube.com/watch?v=bTP7n1HjDE0
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCLwNTXWEjVd2qIHLcXxQWxA
content_mime_type: text/plain
content:
Tim, Ian, and Lydia join Forrest Cooper, digital editor of Recoil Magazine and former Army Ranger to analyze rising gas prices.

Sign Up For Exclusive Episodes At https://timcast.com/

Guest: Forrest Cooper
http://www.RecoilWeb.com
http://www.OffGridWeb.com
@RecoilMagazine (IG)
@RecoilOffGridMagazine (IG)

Merch - https://teespring.com/stores/timcast-2

Hosts: 
Tim @Timcast (everywhere) 
Ian @IanCrossland (everywhere)
Lydia @SourPatchLyds (Twitter, Minds), @RealSourPatchLyds (Gab, Instagram)

Podcast available on iTunes and Spotify, coming soon to all podcast platforms!


guid: yt:video:4PWxIilQEN0
title: Timcast IRL - NO CHARGES For Cops In New BLM Case, Protests Beginning w/Ryan Girdusky
author: Timcast IRL
url: https://www.youtube.com/watch?v=4PWxIilQEN0
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCLwNTXWEjVd2qIHLcXxQWxA
content_mime_type: text/plain
content:
Sign Up For Exclusive Episodes At https://timcast.com/

Guest: Ryan Girdusky
@RyanGidusky (Twitter)
Author, "They're Not Listening: How The Elite Created The National Populist Revolution"
http://www.NatPop.Substack.com

Merch - https://teespring.com/stores/timcast-2

Hosts: 
Tim @Timcast (everywhere) 
Ian @IanCrossland (everywhere)
Lydia @SourPatchLyds (Twitter, Minds), @RealSourPatchLyds (Gab, Instagram)

Podcast available on iTunes and Spotify, coming soon to all podcast platforms!


guid: yt:video:U65PdnYetaU
title: #GunReformNow? Not on Our Watch! | Louder with Crowder
author: StevenCrowder
url: https://www.youtube.com/watch?v=U65PdnYetaU
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCIveFvW-ARp_B_RckhweNJw
content_mime_type: text/plain
content:
The bodies in Colorado aren’t even cold, and the Left is pushing gun control. We’re not going to let them. Also, Joe Biden’s new “woke” military is making us a ripe target for China. Kamala Harris has a giggling problem. And did Kristi Noem flip-flop on protecting women’s sports?

GET TODAY'S SHOW NOTES with SOURCES: https://www.louderwithcrowder.com/

Join #MugClub to watch this show every day! http://louderwithcrowder.com/mugclub

Subscribe to my podcast on iTunes: https://podcasts.apple.com/us/podcast/louder-with-crowder/id929121341

FOLLOW ME:
Website: https://louderwithcrowder.com/
Twitter: https://twitter.com/scrowder
Facebook: https://www.facebook.com/stevencrowderofficial
Instagram: http://www.instagram.com/louderwithcrowder

Music by @Pogo


guid: yt:video:v6JW4OfLFbI
title: Crowder TAKES OVER Biden's 1st Press Conference! | Louder with Crowder
author: StevenCrowder
url: https://www.youtube.com/watch?v=v6JW4OfLFbI
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCIveFvW-ARp_B_RckhweNJw
content_mime_type: text/plain
content:
Steven Crowder will be LIVE and fact-checking Joe Biden’s first news conference so that you don't have to! Don’t worry, we’ll still be playing the infamous Crowder drinking game. You DON’T want to miss this. Though ... Biden might?

PROMO CODE: Dementia 
for $20 off MugClub annual expiring at midnight on 3/26.

10% off Spartan Armor go to https://www.spartanarmorsystems.com/ and enter promo code CROWDER

GET TODAY'S SHOW NOTES with SOURCES: https://www.louderwithcrowder.com/

Join #MugClub to watch this show every day! http://louderwithcrowder.com/mugclub

Subscribe to my podcast on iTunes: https://podcasts.apple.com/us/podcast/louder-with-crowder/id929121341

FOLLOW ME:
Website: https://louderwithcrowder.com/
Twitter: https://twitter.com/scrowder
Facebook: https://www.facebook.com/stevencrowderofficial
Instagram: http://www.instagram.com/louderwithcrowder

Music by @Pogo


guid: yt:video:ZRtPGEdpbZI
title: DEREK CHAUVIN TRIAL LIVESTREAM: Opening Arguments! | Louder with Crowder
author: StevenCrowder
url: https://www.youtube.com/watch?v=ZRtPGEdpbZI
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCIveFvW-ARp_B_RckhweNJw
content_mime_type: text/plain
content:
It’s day one of the Derek Chauvin trial, and the mainstream media can’t be trusted to give you the facts. We’ll tell you what they WON’T about George Floyd and give you the TRUTH about what Chauvin is being charged with.


GET TODAY'S SHOW NOTES with SOURCES: https://www.louderwithcrowder.com/derek-chauvin-trial-1

Join #MugClub to watch this show every day! http://louderwithcrowder.com/mugclub

Subscribe to my podcast on iTunes: https://podcasts.apple.com/us/podcast/louder-with-crowder/id929121341

FOLLOW ME:
Website: https://louderwithcrowder.com/
Twitter: https://twitter.com/scrowder
Facebook: https://www.facebook.com/stevencrowderofficial
Instagram: http://www.instagram.com/louderwithcrowder

Music by @Pogo


guid: yt:video:5qHLXbVDnkc
title: KNEE ON NECK: Crowder Tests The Theory LIVE! | Louder with Crowder
author: StevenCrowder
url: https://www.youtube.com/watch?v=5qHLXbVDnkc
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCIveFvW-ARp_B_RckhweNJw
content_mime_type: text/plain
content:
There was a MAJOR piece of new evidence uncovered during the Derek Chauvin trial, one that the mainstream media refuse to cover, because it BUSTS their narrative. Crowder also has a few choice words for the leftist hacks at “60 Minutes” over their DeSantis hit piece. We cover the latest on Biden’s immigration crisis. And Crowder has his producer kneel on his neck for nine minutes just to see what happens.

10% off Spartan Armor go to https://www.spartanarmorsystems.com/ and enter promo code CROWDER

NEW MERCH! https://crowdershop.com/

GET TODAY'S SHOW NOTES with SOURCES: https://www.louderwithcrowder.com/show-notes-chauvin-trial-media

Join #MugClub to watch this show every day! http://louderwithcrowder.com/mugclub

Subscribe to my podcast on iTunes: https://podcasts.apple.com/us/podcast/louder-with-crowder/id929121341

FOLLOW ME:
Website: https://louderwithcrowder.com/
Twitter: https://twitter.com/scrowder
Facebook: https://www.facebook.com/stevencrowderofficial
Instagram: http://www.instagram.com/louderwithcrowder

Music by @Pogo


guid: yt:video:HaMEndQeoc0
title: GUN CONTROL IS HERE! Biden’s Agenda Gets RADICAL | Louder with Crowder
author: StevenCrowder
url: https://www.youtube.com/watch?v=HaMEndQeoc0
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCIveFvW-ARp_B_RckhweNJw
content_mime_type: text/plain
content:
Joe Biden’s gun control agenda is WORSE than advertised. We take a thorough look at new executive orders. Also, Hunter Biden used to smoke cheese when he couldn’t find crack. Makes you wonder what DIDN’T he smoke? Bill Richmond joins us to explain Justice Thomas’ recent support for regulating Big Tech like we’re five. And you’ll be shocked to find out how many Hispanic people don’t know what a “Latinx” is.

NEW MERCH! https://crowdershop.com/ 

GET TODAY'S SHOW NOTES with SOURCES: https://www.louderwithcrowder.com/shhow-notes-biden-gun-control

Join #MugClub to watch this show every day! http://louderwithcrowder.com/mugclub

Subscribe to my podcast on iTunes: https://podcasts.apple.com/us/podcast/louder-with-crowder/id929121341

FOLLOW ME:
Website: https://louderwithcrowder.com/
Twitter: https://twitter.com/scrowder
Facebook: https://www.facebook.com/stevencrowderofficial
Instagram: http://www.instagram.com/louderwithcrowder

Music by @Pogo


guid: yt:video:IYKp9VMrGMw
title: MINNEAPOLIS BURNS: Daunte Wright Shooting Sparks Riots! | Louder with Crowder
author: StevenCrowder
url: https://www.youtube.com/watch?v=IYKp9VMrGMw
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCIveFvW-ARp_B_RckhweNJw
content_mime_type: text/plain
content:
They are rioting in Minneapolis again over a police-involved incident. We give you the FACTS as we know them, since you can’t trust the media. Joe Biden has also been busy lying about guns and looking to pack the Supreme Court. We take a sledgehammer to both of those as well. And why did YouTube delete a Ron DeSantis video?

NEW MERCH! https://crowdershop.com/ 

GET TODAY'S SHOW NOTES with SOURCES: https://www.louderwithcrowder.com/

Join MugClub to watch this show every day! http://louderwithcrowder.com/mugclub

Subscribe to my podcast on iTunes: https://podcasts.apple.com/us/podcast/louder-with-crowder/id929121341

FOLLOW ME:
Website: https://louderwithcrowder.com/
Twitter: https://twitter.com/scrowder
Facebook: https://www.facebook.com/stevencrowderofficial
Instagram: http://www.instagram.com/louderwithcrowder

Music by @Pogo


guid: yt:video:Y45-_HE91Us
title: Common Sense Gun Control is Nonsense | Change My Mind
author: StevenCrowder
url: https://www.youtube.com/watch?v=Y45-_HE91Us
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCIveFvW-ARp_B_RckhweNJw
content_mime_type: text/plain
content:
Steven Crowder goes to a college campus to have real conversations with real people. In this installment, Steven discusses the recent executive orders of former Vice President Joe Biden regarding gun control.

NEW MERCH! https://crowdershop.com/ 

GET TODAY'S SHOW NOTES with SOURCES: https://www.louderwithcrowder.com/

Join #MugClub to watch this show every day! http://louderwithcrowder.com/mugclub

Subscribe to my podcast on iTunes: https://podcasts.apple.com/us/podcast/louder-with-crowder/id929121341

FOLLOW ME:
Website: https://louderwithcrowder.com/
Twitter: https://twitter.com/scrowder
Facebook: https://www.facebook.com/stevencrowderofficial
Instagram: http://www.instagram.com/louderwithcrowder

Music by @Pogo


guid: yt:video:_Nz2kLbtvDc
title: Thanks, Trevor Noah! Erasing Women's Achievements One Puberty Blocker at a Time!
author: StevenCrowder
url: https://www.youtube.com/watch?v=_Nz2kLbtvDc
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCIveFvW-ARp_B_RckhweNJw
content_mime_type: text/plain
content:
Trevor Noah thinks men competing against women is awesome, and we think Trevor Noah is an idiot. Expect a THOROUGH debunking of his recent puberty blocker segment. We also expose the Left’s latest court-packing scheme. And as shocking as this sounds, Ben & Jerry's found a way to be more insufferable jackwagons. All this and special guest Jason Whitlock!

NEW MERCH! https://crowdershop.com/ 

GET TODAY'S SHOW NOTES with SOURCES: https://www.louderwithcrowder.com/show-notes-trevor-noah-rebuttal

Join MugClub to watch this show every day! http://louderwithcrowder.com/mugclub

Subscribe to my podcast on iTunes: https://podcasts.apple.com/us/podcast/louder-with-crowder/id929121341

FOLLOW ME:
Website: https://louderwithcrowder.com/
Twitter: https://twitter.com/scrowder
Facebook: https://www.facebook.com/stevencrowderofficial
Instagram: http://www.instagram.com/louderwithcrowder

Music by @Pogo


guid: yt:video:iinabQzrJFQ
title: LIVE FACT-CHECKING! Chauvin/Floyd Closing Arguments! | Ben Askren Guests! | Louder with Crowder
author: StevenCrowder
url: https://www.youtube.com/watch?v=iinabQzrJFQ
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCIveFvW-ARp_B_RckhweNJw
content_mime_type: text/plain
content:
It’s the closing arguments in the Derek Chauvin trial. We lay out the best arguments for the defense. Also, crazy Maxine Waters is on video encouraging violence among her supporters. Again. It’s kinda her thing that she does. We also recap the weekend in riots and protests, including one where it’s clear cops are NOT always our friends.

#DerekChauvinTrial #Floyd #Schleicher

NEW MERCH! https://crowdershop.com/ 

GET TODAY'S SHOW NOTES with SOURCES: https://www.louderwithcrowder.com/

Join MugClub to watch this show every day! http://louderwithcrowder.com/mugclub

Subscribe to my podcast on iTunes: https://podcasts.apple.com/us/podcast/louder-with-crowder/id929121341

FOLLOW ME:
Website: https://louderwithcrowder.com/
Twitter: https://twitter.com/scrowder
Facebook: https://www.facebook.com/stevencrowderofficial
Instagram: http://www.instagram.com/louderwithcrowder

Music by @Pogo


guid: yt:video:kRHnYUFeXbg
title: CAUGHT! Joy Behar Misgenders Caityln Jenner! CROWDER HAS THE SCOOP | Louder with Crowder
author: StevenCrowder
url: https://www.youtube.com/watch?v=kRHnYUFeXbg
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCIveFvW-ARp_B_RckhweNJw
content_mime_type: text/plain
content:
When is an insurrection not an insurrection? When the media can exploit it for political reasons. We expose how! Also, Joy Behar was busted misgendering Caitlyn Jenner. We pinpoint the exact moment she realizes she screwed up. And Happy Lesbian Day of Visibility to all who celebrate.

#JoyBehar #CaitlynJenner #LesbianVisibilityDay
NEW MERCH! https://crowdershop.com/ 

GET TODAY'S SHOW NOTES with SOURCES: https://www.louderwithcrowder.com/

Join MugClub to watch this show every day! http://louderwithcrowder.com/mugclub

Subscribe to my podcast on iTunes: https://podcasts.apple.com/us/podcast/louder-with-crowder/id929121341

FOLLOW ME:
Website: https://louderwithcrowder.com/
Twitter: https://twitter.com/scrowder
Facebook: https://www.facebook.com/stevencrowderofficial
Instagram: http://www.instagram.com/louderwithcrowder

Music by @Pogo


guid: yt:video:5YN8msXJIE8
title: Change My Mind: BONUS EDITION! Biden HATES The Middle Class | Louder with Crowder
author: StevenCrowder
url: https://www.youtube.com/watch?v=5YN8msXJIE8
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCIveFvW-ARp_B_RckhweNJw
content_mime_type: text/plain
content:
To watch my full conversation with George on gun control click here:
https://youtu.be/Y45-_HE91Us

PROMO CODE: FLAG
$20 off MugClub

Join MugClub to watch this show every day! http://louderwithcrowder.com/mugclub

Steven has an impromptu conversation on Libertarian Socialism, whether it can work and debunks the myth that the Left is the party of the "Little Guy" 

NEW MERCH! https://crowdershop.com/ 

10% off Spartan Armor go to https://www.spartanarmorsystems.com/ and enter promo code CROWDER

Use this link http://EXPRESSVPN.com/CROWDER today and get an extra three months FREE on a one year package!

Thompson Cigar is offering 15% off orders over $75 OR 20% off orders of $99 or more with the promo code:  CROWDER https://www.thompsoncigar.com/crowder
NEW MERCH! https://crowdershop.com/

Take a few minutes right now and stop overpaying on your car and home insurance!
Go to https://www.Gabi.com/CROWDER It’s totally free to check your rate and there’s no obligation.

GET TODAY'S SHOW NOTES with SOURCES: https://www.louderwithcrowder.com/

Subscribe to my podcast on iTunes: https://podcasts.apple.com/us/podcast/louder-with-crowder/id929121341

FOLLOW ME:
Website: https://louderwithcrowder.com/
Twitter: https://twitter.com/scrowder
Facebook: https://www.facebook.com/stevencrowderofficial
Instagram: http://www.instagram.com/louderwithcrowder

Music by @Pogo


guid: yt:video:ziljl1eYhkY
title: SKANKISM 101! Everything Billie Eilish Gets Wrong About 'Patriarchy' | Louder with Crowder
author: StevenCrowder
url: https://www.youtube.com/watch?v=ziljl1eYhkY
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCIveFvW-ARp_B_RckhweNJw
content_mime_type: text/plain
content:
Pop star Billie Eilish told Vogue she hates men. We’ll tell you how that ties to … Satanism? The beautiful and brave Elliot Page sat down with Oprah, and we have thoughts on that as well. Also, Trevor Noah dared to go against the CDC. And the CIA has lost its mind.


NEW MERCH! https://crowdershop.com/ 

GET TODAY'S SHOW NOTES with SOURCES: https://www.louderwithcrowder.com/

Join MugClub to watch this show every day! http://louderwithcrowder.com/mugclub

Subscribe to my podcast on iTunes: https://podcasts.apple.com/us/podcast/louder-with-crowder/id929121341

FOLLOW ME:
Website: https://louderwithcrowder.com/
Twitter: https://twitter.com/scrowder
Facebook: https://www.facebook.com/stevencrowderofficial
Instagram: http://www.instagram.com/louderwithcrowder

Music by @Pogo

#BillieEilish #TeacherAppreciationWeek #CIA


guid: yt:video:FOj6Kd4RQA8
title: America... A Nation of COWARDS! | Louder with Crowder
author: StevenCrowder
url: https://www.youtube.com/watch?v=FOj6Kd4RQA8
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCIveFvW-ARp_B_RckhweNJw
content_mime_type: text/plain
content:
Woke liberals want alternatives to policing, and yeah, one is worse than the other. We also expose BOTH critical race theory AND the communist pope. Biden has another Biden moment in a speech. And Bill and Melinda Gates are getting divorced. So sad!

NEW MERCH! https://crowdershop.com/ 

GET TODAY'S SHOW NOTES with SOURCES: https://www.louderwithcrowder.com/

Join MugClub to watch this show every day! http://louderwithcrowder.com/mugclub

Subscribe to my podcast on iTunes: https://podcasts.apple.com/us/podcast/louder-with-crowder/id929121341

FOLLOW ME:
Website: https://louderwithcrowder.com/
Twitter: https://twitter.com/scrowder
Facebook: https://www.facebook.com/stevencrowderofficial
Instagram: http://www.instagram.com/louderwithcrowder

Music by @Pogo

#CriticalRaceTheory #antiracism #billgates


guid: yt:video:Bk8euJWtANs
title: Liberal Lies About Racist Police Origins DEBUNKED! | Donald Trump Jr. Guests | Louder with Crowder
author: StevenCrowder
url: https://www.youtube.com/watch?v=Bk8euJWtANs
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCIveFvW-ARp_B_RckhweNJw
content_mime_type: text/plain
content:
The liberal claim that police descended from slave patrols? It’s a load of horse crap, and we explain why. There’s also a major legal update about Derek Chauvin. Can you say mistrial? We look at Caitlyn Jenner’s campaign ad. SJWs are angry at a Disney cartoon again. All this and special guest Donald Trump Jr.!

10% off Spartan Armor go to https://www.spartanarmorsystems.com/hercules-level-iv-special-intro
and enter promo code CROWDER

NEW MERCH! https://crowdershop.com/ 

GET TODAY'S SHOW NOTES with SOURCES: https://www.louderwithcrowder.com/

Join MugClub to watch this show every day! http://louderwithcrowder.com/mugclub

Subscribe to my podcast on iTunes: https://podcasts.apple.com/us/podcast/louder-with-crowder/id929121341

FOLLOW ME:
Website: https://louderwithcrowder.com/
Twitter: https://twitter.com/scrowder
Facebook: https://www.facebook.com/stevencrowderofficial
Instagram: http://www.instagram.com/louderwithcrowder

Music by @Pogo

#DonaldTrump #DeleteFacebook #CaitlynJenner


guid: yt:video:8R0h5Z3gLdw
title: GOVERNOR Caitlyn Jenner?! Well, Actually ... | Louder with Crowder
author: StevenCrowder
url: https://www.youtube.com/watch?v=8R0h5Z3gLdw
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCIveFvW-ARp_B_RckhweNJw
content_mime_type: text/plain
content:
Governor Caitlyn Jenner? Hey, stranger things have happened. We also take a deep dive into the D.C. statehood nonsense. Mask “guidelines” are doing more harm than good. And there is a rise in hate crimes against Asians, but not a lot of media attention. Why do you think that is? #CaitlynJenner #DCstatehood #StopAsianHate

NEW MERCH! https://crowdershop.com/ 

GET TODAY'S SHOW NOTES with SOURCES: https://www.louderwithcrowder.com/

Join MugClub to watch this show every day! http://louderwithcrowder.com/mugclub

Subscribe to my podcast on iTunes: https://podcasts.apple.com/us/podcast/louder-with-crowder/id929121341

FOLLOW ME:
Website: https://louderwithcrowder.com/
Twitter: https://twitter.com/scrowder
Facebook: https://www.facebook.com/stevencrowderofficial
Instagram: http://www.instagram.com/louderwithcrowder

Music by @Pogo


guid: yt:video:a-RFQXTQnw0
title: المُخبر الاقتصادي+ | لماذا سترتفع أسعار السيارات والهواتف والأجهزة المنزلية قريباً؟
author: AJ+ كبريت
url: https://www.youtube.com/watch?v=a-RFQXTQnw0
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC-4KnPMmZzwAzW7SbVATUZQ
content_mime_type: text/plain
content:
أزمة الرقائق الإلكترونية تشتعل وتخرج عن نطاق السيطرة! لماذا ستضطر كثير من الشركات العالمية لرفع أسعارها؟

مصادر المُخبر:
https://www.theguardian.com/business/2021/mar/21/global-shortage-in-computer-chips-reaches-crisis-point
https://www.bloomberg.com/news/articles/2021-02-05/chip-shortage-spirals-beyond-cars-to-phones-and-game-consoles
https://www.statista.com/statistics/867223/worldwide-semiconductor-foundries-by-market-share/
https://www.statista.com/statistics/208983/unit-sales-ps4-worldwide/
https://thediplomat.com/2021/03/taiwan-prays-for-rain-as-drought-threatens-chip-production/
https://www.reuters.com/article/us-xiaomi-chips-idUSKBN2BG222
https://www.statista.com/statistics/1005403/global-xbox-one-console-unit-sales/
https://www.ft.com/content/74038c71-f0a2-41e0-8cc3-5f61a6157931
https://www.bbc.com/news/technology-56114503
https://www.scmp.com/tech/tech-trends/article/3120936/phones-game-consoles-global-chip-shortage-spreads-beyond-cars
https://www.statista.com/statistics/667034/lcd-tv-shipments-worldwide-by-vendor/
https://pulsenews.co.kr/view.php?sc=30800028&year=2021&no=181781
https://www.statista.com/statistics/208983/unit-sales-ps4-worldwide/
https://fortune.com/2021/01/11/covid-computer-sales-lenovo-hp-dell-apple/
https://www.bloomberg.com/news/articles/2021-02-03/gm-to-temporarily-shut-trio-of-plants-as-chip-shortage-pinches
https://www.washingtonpost.com/technology/2021/03/01/semiconductor-shortage-halts-auto-factories/
https://www.bloomberg.com/news/articles/2021-02-18/biden-aide-deese-asks-taiwan-to-help-resolve-auto-chips-shortage
https://www.japantimes.co.jp/news/2021/03/24/business/renesas-chipmakers-carmakers-toyota-nissan/
https://www.bloomberg.com/news/articles/2021-03-17/samsung-warns-of-serious-imbalance-in-the-chips-industry
https://www.bloomberg.com/news/articles/2021-01-19/a-year-of-poor-planning-led-to-carmakers-massive-chip-shortage
https://www.bloomberg.com/news/articles/2021-01-11/missing-chips-snarl-car-production-at-factories-worldwide
https://www.bloomberg.com/news/articles/2021-02-17/the-world-is-short-of-computer-chips-here-s-why-quicktake
https://www.bloomberg.com/news/features/2021-01-25/the-world-is-dangerously-dependent-on-taiwan-for-semiconductors
https://www.reuters.com/article/us-taiwan-autos-chips-idUSKBN29W0O9

https://www.youtube.com/c/MokhbirEqtisadi
#المُخبر_الاقتصادي+

كن جزءاً من مجتمعنا
https://goo.gl/sCG87B
لمتابعتنا على
https://twitter.com/ajplusarabi
https://www.facebook.com/ajplusarabi
موقعنا: http://ajplus.net/arabi


guid: yt:video:zOahar99ozI
title: الجهبذ | خطة سرية مزعومة لاستبدال السكان الأوروببين بالمهاجرين، ماذا تعرفون عن الاستبدال الكبير؟
author: AJ+ كبريت
url: https://www.youtube.com/watch?v=zOahar99ozI
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC-4KnPMmZzwAzW7SbVATUZQ
content_mime_type: text/plain
content:
عزيزي الحالم بالهجرة، الجهبذ يقدم لك الدليل المرير في نظرية الاستبدال الكبير.
#الجهبذ

مصادر الجهبذ:
 https://link.springer.com/chapter/10.1007/978-3-030-14416-6_6
 https://link.springer.com/chapter/10.1007/978-3-319-90359-0_6
 https://onlinelibrary.wiley.com/doi/full/10.1111/1468-4446.12742
 https://www.tandfonline.com/doi/full/10.1080/17447143.2018.1511717?casa_token=-lWRUsQNaggAAAAA%3A6TIuU4jzHu7eJUDXv0vAMKL-Bo_miqfttIm-n6mErngc5R0svsG-tMsjBGAKQwo8S9y0iYrGU_jcNA 
 https://jean-jaures.org/nos-productions/le-mouvement-identitaire-ou-la-construction-d-un-mythe-des-origines-europeennes
https://www.oxfordhandbooks.com/view/10.1093/oxfordhb/9780190274559.001.0001/oxfordhb-9780190274559
 https://www.hup.harvard.edu/catalog.php?isbn=9780674971530

كن جزءاً من مجتمعنا
https://goo.gl/sCG87B
لمتابعتنا على
https://twitter.com/ajplusarabi
https://www.facebook.com/ajplusarabi
موقعنا: http://ajplus.net/arabi


guid: yt:video:2lwCuv36vH0
title: السليط الإخباري - حرب النجوم | الحلقة (12) موسم 2021
author: AJ+ كبريت
url: https://www.youtube.com/watch?v=2lwCuv36vH0
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC-4KnPMmZzwAzW7SbVATUZQ
content_mime_type: text/plain
content:
لمتابعة حلقات "السليط الإخباري"
https://goo.gl/sCG87B

السليط الإخباري - حرب النجوم | الحلقة (12) موسم 2021

في حلقة هذا الأسبوع.. غيرة ودموع، إحباط مشروع، شعب موجوع، والمرغوب ممنوع، وسكر عَ الموضوع.
#السليط_الإخباري

تفاصيل الحلقة:
00:00 مقدمة الحلقة
01:13 محاولة لزعزعة الأمن في الأردن
09:45 ما هي أمنية الرئيس اللبناني ميشال عون؟
11:56 أخبار دقيقة في دقيقة
14:15 رجل عراقي يوجه رسالة مهمة
17:00 خطاب الرئيس السوري بشار الأسد الأخير
20:30 فيديو الأسبوع

جميع حلقات "السليط الإخباري" 
https://goo.gl/jg5VNX

كن جزءاً من مجتمعنا 
https://goo.gl/sCG87B

لمتابعتنا على 
https://twitter.com/ajplusarabi
https://www.facebook.com/ajplusarabi
موقعنا: http://ajplus.net/arabi


guid: yt:video:VVFeOMRJ9VE
title: المُخبر الاقتصادي+ | كيف تخطط الصين وإيران سراً لتحدي هيمنة أمريكا؟
author: AJ+ كبريت
url: https://www.youtube.com/watch?v=VVFeOMRJ9VE
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC-4KnPMmZzwAzW7SbVATUZQ
content_mime_type: text/plain
content:
مطارات وموانئ وتعاون عسكري و400 مليار دولار.. تعرف على أبرز بنود الاتفاق الصيني الإيراني الذي سيستمر 25 عاماً.

مصادر المُخبر: 
https://www.wsj.com/articles/iran-china-sign-economic-security-agreement-challenging-u-s-pressure-11616866936
https://www.ft.com/content/21eb2d88-3bae-4db3-944c-ba92f3924300
https://www.nytimes.com/2020/07/11/world/asia/china-iran-trade-military-deal.html
https://www.nytimes.com/2019/07/02/world/middleeast/china-oil-iran-sanctions.html
https://www.wsj.com/articles/iran-and-china-angle-for-broad-partnership-to-offset-u-s-pressure-11594582885?mod=article_inline
https://www.economist.com/middle-east-and-africa/2020/10/08/iran-wants-a-strategic-partnership-with-china
https://www.bloomberg.com/opinion/articles/2021-03-29/china-iran-deal-there-s-less-to-it-than-meets-the-eye
https://thediplomat.com/2021/03/china-is-buying-record-amounts-of-iranian-oil/
https://www.reuters.com/article/china-economy-trade-oil-int/saudi-arabia-pips-russia-to-be-chinas-biggest-oil-supplier-in-2020-idUSKBN29P0ZG
https://www.reuters.com/article/us-usa-china-blinken-idUSKBN2AV28C
https://www.nytimes.com/2021/03/27/world/middleeast/china-iran-deal.html
https://www.bloomberg.com/news/articles/2021-03-27/china-signs-25-year-deal-with-iran-in-challenge-to-the-u-s?sref=am1wYMj6
https://thediplomat.com/2021/03/whats-in-the-china-iran-strategic-cooperation-agreement/
https://www.csis.org/analysis/china-and-iran-major-chinese-gain-white-area-warfare-gulf

https://www.youtube.com/c/MokhbirEqtisadi
#المُخبر_الاقتصادي+

كن جزءاً من مجتمعنا
https://goo.gl/sCG87B
لمتابعتنا على
https://twitter.com/ajplusarabi
https://www.facebook.com/ajplusarabi
موقعنا: http://ajplus.net/arabi


guid: yt:video:F8ifD2uOORc
title: الجهبذ | مرض أرعب البشرية، و كان أشبه بسلاح جرثومي. كيف ساهم الجدري في تطوير اللقاحات التي نعرفها؟
author: AJ+ كبريت
url: https://www.youtube.com/watch?v=F8ifD2uOORc
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC-4KnPMmZzwAzW7SbVATUZQ
content_mime_type: text/plain
content:
الجهبذ | اللقاحات من بيوت الجدّات إلى المختبرات
الأصل المنسي للقاحات، وما دور الأمهات في تطور اللقاحات من السودان إلى إسطنبول وبريطانيا؟
#الجهبذ

مصادر الجهبذ:
https://www.palgrave.com/gp/book/9780230274716
https://press.uchicago.edu/ucp/books/book/chicago/G/bo3647267.html
https://www.cambridge.org/fr/academic/subjects/life-sciences/microbiology-and-immunology/life-and-death-smallpox?format=HB&isbn=9780521845427
https://www.editions-vendemiaire.com/catalogue/collection-chroniques/antivax-francoise-salvadori-et-laurent-henri-vignaud/
https://royalsocietypublishing.org/doi/abs/10.1098/rstl.1768.0020
https://www.caxtonpress.com/rottingfacesmallpoxandtheamericanindian.aspx
https://www.rand.org/pubs/research_reports/RRA769-1.html#:~:text=Vaccine%20nationalism%20could%20lead%20to,a%20year%20in%20GDP%20terms
https://www.sciencedirect.com/science/article/pii/S235239641630398X

كن جزءاً من مجتمعنا
https://goo.gl/sCG87B
لمتابعتنا على
https://twitter.com/ajplusarabi
https://www.facebook.com/ajplusarabi
موقعنا: http://ajplus.net/arabi


guid: yt:video:TlJSUhxQTYA
title: المُخبر الاقتصادي+ | كيف امتلكت تايوان الفقيرة أهم وأقوى شركة في العالم؟
author: AJ+ كبريت
url: https://www.youtube.com/watch?v=TlJSUhxQTYA
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC-4KnPMmZzwAzW7SbVATUZQ
content_mime_type: text/plain
content:
عملاق الرقائق الإلكترونية التايواني "TSMC".. ما السر وراء الشركة التي تفوقت على "إنتل" الأمريكية و"إن إي سي" اليابانية وسيطرت على الصناعة؟

مصادر المُخبر:
https://foreignpolicy.com/2021/02/16/semiconductors-us-china-taiwan-technology-innovation-competition/
https://www.nytimes.com/2019/10/25/technology/pentagon-taiwan-tsmc-chipmaker.html
https://www.ft.com/content/05206915-fd73-4a3a-92a5-6760ce965bd9
https://www.economist.com/christmas-specials/2019/12/18/a-look-inside-the-factory-around-which-the-modern-world-turns
https://www.nytimes.com/2020/12/14/opinion/taiwan-computer-chips.html
https://fortune.com/2020/08/10/us-china-trade-war-semiconductors-chips-tsmc-chipmakers/
https://www.pcmag.com/news/intels-7nm-pc-chip-will-arrive-in-2023-using-tsmcs-tech
https://www.tsmc.com/english/aboutTSMC/TSMC_Fabs
https://www.bloomberg.com/news/articles/2021-04-01/tsmc-to-invest-100-billion-over-three-years-to-grow-capacity
https://asia.nikkei.com/Business/Technology/Exclusive-Washington-pressures-TSMC-to-make-chips-in-US
https://www.bloomberg.com/opinion/articles/2021-01-22/tsmc-can-breathe-easy-intel-will-keep-making-chips
https://csr.tsmc.com/download/csr/2009_tsmc_csr_e/e_2_2.pdf
https://spectrum.ieee.org/at-work/tech-careers/morris-chang-foundry-father

https://www.youtube.com/c/MokhbirEqtisadi
#المُخبر_الاقتصادي+

كن جزءاً من مجتمعنا
https://goo.gl/sCG87B
لمتابعتنا على
https://twitter.com/ajplusarabi
https://www.facebook.com/ajplusarabi
موقعنا: http://ajplus.net/arabi


guid: yt:video:jGbC1PET-NQ
title: الجهبذ | تحدي البقاء أو الموت: كيف أصبحت حياتنا صراعاً يشبه ألعاب الفيديو؟
author: AJ+ كبريت
url: https://www.youtube.com/watch?v=jGbC1PET-NQ
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC-4KnPMmZzwAzW7SbVATUZQ
content_mime_type: text/plain
content:
هل تستطيع النجاة؟ تحدي البقاء بين ألعاب الفيديو ورغيف الخبز 
#الجهبذ


مصادر الجهبذ: 
https://journals.sfu.ca/loading/index.php/loading/article/view/202
https://dl.acm.org/doi/abs/10.5555/2207096.2207097
https://www.ign.com/articles/2013/07/05/virtual-selection-the-rise-of-the-survival-game
https://journals.sagepub.com/doi/full/10.1177/1555412016655678
https://www.tandfonline.com/doi/full/10.1080/01425692.2019.1640596?casa_token=qQhCzERlplAAAAAA%3A6hfL3Qnglf2DF9tBhZprbrrfsyT_t1snexVY2JmIOK9gE-k8mGaa5rKrw3MF_l93T0Reo6eTMTmCLg
https://www.jstor.org/stable/26241316#metadata_info_tab_contents
https://www.lcdpu.fr/livre/?GCOI=27000100975010
https://www.droz.org/monde/product/9782600002172

كن جزءاً من مجتمعنا
https://goo.gl/sCG87B
لمتابعتنا على
https://twitter.com/ajplusarabi
https://www.facebook.com/ajplusarabi
موقعنا: http://ajplus.net/arabi


guid: yt:video:1d33nVIfqLw
title: المُخبر الاقتصادي+ | ماذا لو قطع العرب البترول عن أمريكا؟
author: AJ+ كبريت
url: https://www.youtube.com/watch?v=1d33nVIfqLw
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC-4KnPMmZzwAzW7SbVATUZQ
content_mime_type: text/plain
content:
حظر تصدير النفط إلى الولايات المتحدة! هل تستطيع أمريكا الاستغناء عن البترول العربي؟

مصادر المُخبر:
https://link.springer.com/chapter/10.1007/978-1-349-17797-4_2
https://www.jstor.org/stable/10.7591/j.ctt207g7cv.4?seq=1#metadata_info_tab_contents
https://www.cfr.org/timeline/oil-dependence-and-us-foreign-policy
https://www.bloomberg.com/opinion/articles/2021-02-28/what-energy-dependence-the-u-s-still-needs-russian-oil-and-middle-east-peace
https://edition.cnn.com/2020/01/08/business/oil-middle-east-trump-iran/index.html
https://www.economist.com/united-states/2020/04/23/the-limits-of-energy-independence
https://www.bloomberg.com/opinion/articles/2020-01-12/trump-is-wrong-the-u-s-does-need-middle-east-oil
https://link.springer.com/content/pdf/10.1007%2F978-1-4020-9453-8_13.pdf
https://www.bloomberg.com/news/articles/2021-01-06/saudi-oil-exports-to-u-s-at-zero-for-first-time-in-35-years
https://www.eia.gov/dnav/pet/hist/LeafHandler.ashx?n=pet&s=mcrfpus2&f=a
https://www2.deloitte.com/content/dam/insights/us/articles/energy-independence/Energy-Indpendence-and-Security_A-reality-check.pdf
https://www.foreignaffairs.com/articles/middle-east/1973-04-01/oil-crisis
https://www.nytimes.com/1973/11/11/archives/things-will-get-worse-before-they-get-worse-shortages-of-oil-the.html
https://www.cvce.eu/content/publication/2003/7/3/1158015d-8cf9-4fae-8128-0f1ee8a8d292/publishable_en.pdf
https://static.history.state.gov/frus/frus1969-76v25/pdf/frus1969-76v25.pdf
https://www.cia.gov/readingroom/docs/1973-10-19E.pdf
https://ycharts.com/indicators/us_oil_consumption
https://www.bloomberg.com/news/articles/2020-12-02/u-s-imports-of-saudi-crude-oil-fall-to-lowest-in-three-decades
https://www.eia.gov/dnav/pet/hist/LeafHandler.ashx?n=pet&s=mcrimuspg2&f=a
https://www.eia.gov/todayinenergy/detail.php?id=37053
https://money.cnn.com/2018/09/12/investing/us-oil-production-russia-saudi-arabia/index.html
https://www.eia.gov/dnav/pet/hist/LeafHandler.ashx?n=PET&s=MTTIMXX1&f=M
https://www.statista.com/statistics/244423/estimated-petroleum-consumption-in-the-united-states/

https://www.youtube.com/c/MokhbirEqtisadi
#المُخبر_الاقتصادي+

كن جزءاً من مجتمعنا
https://goo.gl/sCG87B
لمتابعتنا على
https://twitter.com/ajplusarabi
https://www.facebook.com/ajplusarabi
موقعنا: http://ajplus.net/arabi


guid: yt:video:lLii4nsCPNc
title: الجهبذ | هل فعلاً لم تكن لحضارة مصر والعراق إسهامات في تاريخ العلوم؟
author: AJ+ كبريت
url: https://www.youtube.com/watch?v=lLii4nsCPNc
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC-4KnPMmZzwAzW7SbVATUZQ
content_mime_type: text/plain
content:
هل نحن من يحمل المومياوات ويدور بها في الموكب.. أم هي التي تحملنا وتدعم وجودنا؟ 
#الجهبذ

مصادر الجهبذ:
https://press.princeton.edu/books/hardcover/9780691117133/mathematics-in-ancient-egypt
https://press.princeton.edu/books/paperback/9780691135267/the-crest-of-the-peacock
https://press.princeton.edu/books/hardcover/9780691091822/mathematics-in-ancient-iraq
https://books.google.com/books/about/Under_One_Sky.html?id=UHxuQgAACAAJ&redir_esc=y
https://www.worldscientific.com/worldscibooks/10.1142/6338
https://www.worldscientific.com/worldscibooks/10.1142/5824 
https://ixtheo.de/Record/1589327551

كن جزءاً من مجتمعنا
https://goo.gl/sCG87B
لمتابعتنا على
https://twitter.com/ajplusarabi
https://www.facebook.com/ajplusarabi
موقعنا: http://ajplus.net/arabi


guid: yt:video:gLViDiXktso
title: المُخبر الاقتصادي+ | لماذا استحق أكبر محتال في التاريخ السجن 150عاماً؟
author: AJ+ كبريت
url: https://www.youtube.com/watch?v=gLViDiXktso
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC-4KnPMmZzwAzW7SbVATUZQ
content_mime_type: text/plain
content:
بعد أن مات في سجنه وحيداً.. ما الذي فعله برنارد مادوف ليستحق هذا المصير وليستحق قبل ذلك لقب أكبر محتال في التاريخ؟

مصادر المُخبر:
https://www.amazon.com/Wizard-Lies-Bernie-Madoff-Death/dp/1452633290
https://www.nytimes.com/2009/01/02/business/02madoff.html
https://www.sec.gov/files/oig-509-exec-summary.pdf
https://www.wsj.com/articles/SB123033797182136463\
https://fortune.com/longform/how-bernie-did-it/?utm_source=email&utm_medium=newsletter&utm_campaign=bull-sheet&utm_content=2021041516pm
https://www.nytimes.com/2010/12/12/business/12madoff.html
https://www.washingtonpost.com/national/andrew-h-madoff-son-of-convicted-financier-dies-at-48/2014/09/03/49c10da4-0e81-11e4-b8e5-d0de80767fc2_story.html
https://apnews.com/article/bernie-madoff-dead-9d9bd8065708384e0bf0c840bd1ae711
https://www.nytimes.com/2005/09/14/obituaries/business/norman-f-levy-93-broker-who-led-new-york-realty-firm.html

https://www.youtube.com/c/MokhbirEqtisadi
#المُخبر_الاقتصادي+

كن جزءاً من مجتمعنا
https://goo.gl/sCG87B
لمتابعتنا على
https://twitter.com/ajplusarabi
https://www.facebook.com/ajplusarabi
موقعنا: http://ajplus.net/arabi


guid: yt:video:H68E-lUAqRA
title: الجهبذ | صلاح الدين الأيوبي.. كيف أعجب به الغرب واختلف عليه العرب؟
author: AJ+ كبريت
url: https://www.youtube.com/watch?v=H68E-lUAqRA
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC-4KnPMmZzwAzW7SbVATUZQ
content_mime_type: text/plain
content:
الجهبذ | من منكم صلاح الدين؟
صلاح الدين الأيوبي.. كيف أعجب به الغرب واختلف عليه العرب؟
#الجهبذ

مصادر الجهبذ:
https://books.google.fr/books?hl=fr&lr=&id=YF9kDwAAQBAJ&oi=fnd&pg=PT7&ots=0q_4bh15Yv&sig=7NfYhtjp65sXcC36D5AsonUYqlg&redir_esc=y#v=onepage&q&f=false
https://iupress.org/9780253008947/visual-culture-in-the-modern-middle-east/
https://www.routledge.com/Arab-Nationalism-The-Politics-of-History-and-Culture-in-the-Modern-Middle/Wien/p/book/9780415499385
https://onlinelibrary.wiley.com/doi/abs/10.1111/jpcu.12503
https://editions.flammarion.com/saladin/9782080205254
https://link.springer.com/chapter/10.1057/9780230603561_4
https://link.springer.com/chapter/10.1057/9780230603561_2
https://d1wqtxts1xzle7.cloudfront.net/31685479/Abouali_Saladin_Crusades.pdf?1375839737=&response-content-disposition=inline%3B+filename%3DSaladins_Legacy_in_the_Middle_East_befo.pdf&Expires=1619957280&Signature=F2fH-WImjBPh6Y7TyudJNMQ9aTZ2qn37-Rd6Ig9g0Iryj8PpMqR8zeJ1SUo8A2jcrxmzY3OK5ESyCNq~hPd-lNJXIBZ71mwEhaHLUF7VDOYuZvtzPlWq31N0Gl1dwP6~PJY3ZxhxUtexPOshCcIuH2-Z8BkNUzVR2Hq6Xh3zs~u83HBhF50wxYLTdOpDSq9SNyL9sMiGQ8Ehrk36TOoPs~ik6xXqysGSH6eavvRBRd-0kQ9rFDzssHGGw7SaL194RpuAOCn89LAGDPtk97MLvir~eVI2JL49pT2FyOQ63mPoFPz2fZ84ZFftKxAcpw0OhaFrT2Bwlx7fW-oxNX68XQ__&Key-Pair-Id=APKAJLOHF5GGSLRBV4ZA
https://www.cambridge.org/fr/academic/subjects/history/regional-history-1500/saladin-politics-holy-war?format=PB&isbn=9780521317399
https://jhupbooks.press.jhu.edu/title/saladin
https://brill.com/view/title/6547
https://books.google.de/books?id=G9jnL131V3UC
https://www.youtube.com/watch?v=TC7e0Vg3lKg
https://www.youtube.com/watch?v=88Qqa3hkE0E
https://arabic.cnn.com/middleeast/2015/03/19/egypt-school-revisited
https://press.uchicago.edu/ucp/books/book/chicago/A/bo22776830.html

كن جزءاً من مجتمعنا
https://goo.gl/sCG87B
لمتابعتنا على
https://twitter.com/ajplusarabi
https://www.facebook.com/ajplusarabi
موقعنا: http://ajplus.net/arabi


guid: yt:video:IlKjcrm2vjM
title: المُخبر الاقتصادي+ | ما السر الذي جعل سنغافورة واحدة من أغنى دول العالم؟
author: AJ+ كبريت
url: https://www.youtube.com/watch?v=IlKjcrm2vjM
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC-4KnPMmZzwAzW7SbVATUZQ
content_mime_type: text/plain
content:
التعليم أولاً وقبل كل شيء! كيف انتقلت سنغافورة من العالم الثالث إلى الأول في غفلة من الزمن؟

مصادر المُخبر:
https://www.amazon.com/Third-World-First-Singapore-1965-2000/dp/0060197765
https://digital-commons.usnwc.edu/ciwag-case-studies/6/
https://openknowledge.worldbank.org/handle/10986/34206
https://www.statista.com/statistics/1189920/singapor-share-of-government-spending-by-ministries/
https://edition.cnn.com/travel/article/henley-index-world-best-passport-2021/index.html
https://www.emerald.com/insight/content/doi/10.1108/PAP-06-2018-002/full/html
https://www.researchgate.net/publication/298329899_Investment_in_Human_Capital_and_Economic_Growth_in_Singapore
https://www.project-syndicate.org/commentary/lee-kuan-lew-singapore-education-legacy-by-stavros-n--yiannouka-2015-04?barrier=accesspaylog
https://www.straitstimes.com/singapore/singapore-students-top-maths-science-rankings-for-second-consecutive-edition-of
https://www.economist.com/leaders/2018/08/30/what-other-countries-can-learn-from-singapores-schools
https://www.economist.com/the-economist-explains/2015/03/22/how-singapore-gained-its-independence
https://www.straitstimes.com/singapore/education/the-education-system-over-the-years
https://www.economist.com/asia/2017/07/06/why-80-of-singaporeans-live-in-government-built-flats
https://www.statista.com/statistics/785044/singapore-number-of-millionaires/
https://www.reuters.com/article/gic-idUSL3E7IP3TG20110725
https://www.temasek.com.sg/en/what-we-do/our-portfolio
https://www.statista.com/statistics/379466/singapore-budget-balance-in-relation-to-gdp/

https://www.youtube.com/c/MokhbirEqtisadi
#المُخبر_الاقتصادي+

كن جزءاً من مجتمعنا
https://goo.gl/sCG87B
لمتابعتنا على
https://twitter.com/ajplusarabi
https://www.facebook.com/ajplusarabi
موقعنا: http://ajplus.net/arabi


guid: yt:video:Sre2Oa1CoQQ
title: الجهبذ | مجتمع عنصري، ذكوري، ديكتاتوري.. ماذا تعرف عن الوجه المظلم للسنافر؟
author: AJ+ كبريت
url: https://www.youtube.com/watch?v=Sre2Oa1CoQQ
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC-4KnPMmZzwAzW7SbVATUZQ
content_mime_type: text/plain
content:
مجتمع عنصري، ذكوري، ديكتاتوري..
ماذا تعرف عن الوجه المظلم للسنافر؟
#الجهبذ

مصادر الجهبذ:
https://books.google.fr/books/about/Contribution_%C3%A0_une_sociologie_des_oeuvr.html?id=DlsHOQAACAAJ&redir_esc=y
https://books.google.fr/books?hl=fr&lr=&id=o1aQF3k_9WYC&oi=fnd&pg=PT6&dq=Le+petit+livre+bleu+-+analyse+critique+et+politique+de+la+societ%C3%A9+des+...&ots=vr_WHNXwz_&sig=p7vt22agheuOe531CgWXIiUiwCI#v=onepage&q=Le%20petit%20livre%20bleu%20-%20analyse%20critique%20et%20politique%20de%20la%20societ%C3%A9%20des%20...&f=false
https://www.google.fr/books/edition/Peyo_l_enchanteur/QqCtvAEACAAJ?hl=fr
https://global.oup.com/academic/product/utopianism-a-very-short-introduction-9780199573400?cc=fr&lang=en&

كن جزءاً من مجتمعنا
https://goo.gl/sCG87B
لمتابعتنا على
https://twitter.com/ajplusarabi
https://www.facebook.com/ajplusarabi
موقعنا: http://ajplus.net/arabi


guid: yt:video:MP2zGbuhqmk
title: المُخبر الاقتصادي+ | ماذا لو سحب الناس أموالهم من البنوك في نفس الوقت؟
author: AJ+ كبريت
url: https://www.youtube.com/watch?v=MP2zGbuhqmk
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC-4KnPMmZzwAzW7SbVATUZQ
content_mime_type: text/plain
content:
أموال المودعين في البنوك.. أين تذهب بها، ولماذا لا تستطيع ردها لأصحابها إذا ما طلبوها في نفس الوقت؟
مصادر المُخبر:
https://www.researchgate.net/publication/319983393_Preventing_bank_runs
https://www.semanticscholar.org/paper/The-causes-of-bank-runs-on-banking-institutions-and-Mofor/bdf5544f622e1b61328a64296f272e7c977120a6
https://www.bloomberg.com/news/articles/2019-11-01/bank-run-in-rural-china-tests-faith-in-thousands-of-lenders
https://www.ft.com/content/199f8681-d540-32a6-ae45-5ee19b3cdb70
https://www.ft.com/content/aa9f01a0-b48e-11e3-a09a-00144feabdc0
https://www.wsj.com/articles/citigroup-fights-to-recover-from-stress-test-failure-1403291332
https://www.wired.com/2015/06/greece-atms/
https://www.washingtonpost.com/world/europe/greece-reportedly-decides-to-close-banks-monday/2015/06/28/071f4ef4-1dab-11e5-a135-935065bc30d0_story.html
https://www.nytimes.com/2015/06/29/business/greek-debt-crisis-european-central-bank.html
https://www.nytimes.com/2014/07/01/business/international/feud-between-oligarchs-seen-as-cause-of-bank-run-in-bulgaria.html
https://www.bbc.com/news/business-41229513
https://www.theguardian.com/business/2001/dec/04/argentina.internationalnews
https://www.nytimes.com/2001/12/24/world/argentine-leader-declares-default-on-billions-in-debt.html
https://www.nytimes.com/2001/12/03/world/argentina-limits-withdrawals-as-banks-near-collapse.html

https://www.youtube.com/c/MokhbirEqtisadi
#المُخبر_الاقتصادي+

كن جزءاً من مجتمعنا
https://goo.gl/sCG87B
لمتابعتنا على
https://twitter.com/ajplusarabi
https://www.facebook.com/ajplusarabi
موقعنا: http://ajplus.net/arabi


guid: yt:video:Z4XrI_8SJbI
title: الجهبذ | بطالة، ووظائف دون عمل..كيف حوّل الفساد الاقتصاد لخدمة المقربين والأحباب؟
author: AJ+ كبريت
url: https://www.youtube.com/watch?v=Z4XrI_8SJbI
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UC-4KnPMmZzwAzW7SbVATUZQ
content_mime_type: text/plain
content:
بطالة، ووظائف دون عمل.. 
كيف حوّل الفساد الاقتصاد لخدمة المقربين والأحباب؟
#الجهبذ


مصادر الجهبذ:
https://oxford.universitypressscholarship.com/view/10.1093/oso/9780198799870.001.0001/oso-9780198799870-chapter-1
https://oxford.universitypressscholarship.com/view/10.1093/oso/9780198799870.001.0001/oso-9780198799870-chapter-2
https://papers.ssrn.com/sol3/papers.cfm?abstract_id=305099https://oxford.universitypressscholarship.com/view/10.1093/oso/9780198799870.001.0001/oso-9780198799870-chapter-3
https://oxford.universitypressscholarship.com/view/10.1093/oso/9780198799870.001.0001/oso-9780198799870-chapter-7
http://www.ferdinandeibl.com/uploads/2/2/9/8/22989858/cronyntm_complete.pdf
https://scholar.harvard.edu/files/haidar/files/diwanhaidar-jobcreation-06302016.pdf
https://www.hoover.org/research/crony-capitalism-and-economic-growth-latin-america-theory-and-evidence
https://www.sup.org/books/title/?id=18447

كن جزءاً من مجتمعنا
https://goo.gl/sCG87B
لمتابعتنا على
https://twitter.com/ajplusarabi
https://www.facebook.com/ajplusarabi
موقعنا: http://ajplus.net/arabi


guid: yt:video:SAI1HXS9NwQ
title: Imitation as a Gateway to Development | Russell Brand & Mikhaila & Jordan Peterson
author: Jordan B Peterson
url: https://www.youtube.com/watch?v=SAI1HXS9NwQ
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCL_f53ZEJxp8TtlOkHwMV9Q
content_mime_type: text/plain
content:
To watch the full episode: https://youtu.be/ISHmPXOS_Og @Mikhaila Peterson 

If you want to improve yourself, you might look to someone you admire and imitate them. You'll pull yourself towards them by the process of imitation.

You might think comparing yourself to someone is different than imitating, but imitating and comparing are the same thing. When you compare yourself to someone, you start pulling yourself towards them. You have to be careful you don't get envious or resentful. In some sense, by continually imitating somebody at a higher level, you're always unfulfilled. In another sense, that means you're always growing. 

Jung believed the book of Revelations had been tacked onto the New Testament because the Christ in the gospels was portrayed too much as a figure of mercy. Whereas, in Revelations, Christ is portrayed primarily as a judge. Jung’s explanation was that every ideal is a judge. The ultimate ideal is the ultimate judge. The ultimate ideal judges your soul. The higher the ideal, the more severe the judge. That should make you quake. When your conscience assaults you in the middle of the night for things you’ve done wrong, it’s because you’re quaking in your boots, morally, because you’ve failed to live up to this ideal.

Please do not forget to subscribe to the channel in order to enjoy weekly videos. We thank you for your continued support.

To order Dr. Peterson's new book, Beyond Order: 12 More Rules For Life: https://jordanbpeterson.com/beyond-order

Other ways to connect with Dr. Peterson:

New - TikTok: https://vm.tiktok.com/ZMejKSC6d/

Website: https://jordanbpeterson.com/​
Donations: https://www.jordanbpeterson.com/donate​
Podcast: https://jordanbpeterson.com/podcast/​
Twitter: https://twitter.com/jordanbpeterson​
Instagram: https://www.instagram.com/jordan.b.peterson
Facebook: https://www.facebook.com/drjordanpeterson


guid: yt:video:Su1FQUkMojU
title: The Development of the Individual Requires Sacrifice | Russell Brand & Mikhaila & Jordan Peterson
author: Jordan B Peterson
url: https://www.youtube.com/watch?v=Su1FQUkMojU
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCL_f53ZEJxp8TtlOkHwMV9Q
content_mime_type: text/plain
content:
To watch the full episode: https://youtu.be/ISHmPXOS_Og @Mikhaila Peterson 

As a special treat for our fans, Russell added the option for a free of month of his subscription platform Luminary. Visit luminary.link/mp to start your trial.

The process of maturation requires multiple levels of sacrifice, including what some would call the ultimate sacrifice, putting another's needs in front of your own. This is the role of the parent to the child, the mentor to the protege, and in Christian terms - Christ to the Believer. 

Often, people think of the act of sacrifice in terms of loss, but it is just as valid to think of sacrifice as a necessary vehicle to future gain. Without sacrifice, it would seem that the individual is incentivized to search for nothing more than impulsive pleasures with short-term gain and long-term consequence as a result.

What have you sacrificed for the people you love? Having seen the result of your sacrifice, would you trade that sacrifice for short-term pleasure-seeking behavior?

Please do not forget to subscribe to the channel in order to enjoy weekly videos. We thank you for your continued support.

To order Dr. Peterson's new book, Beyond Order: 12 More Rules For Life: https://jordanbpeterson.com/beyond-order

Other ways to connect with Dr. Peterson:

New - TikTok: https://vm.tiktok.com/ZMejKSC6d/

Website: https://jordanbpeterson.com/​
Donations: https://www.jordanbpeterson.com/donate​
Podcast: https://jordanbpeterson.com/podcast/​
Twitter: https://twitter.com/jordanbpeterson​
Instagram: https://www.instagram.com/jordan.b.peterson
Facebook: https://www.facebook.com/drjordanpeterson


guid: yt:video:HA4Bkybx1ps
title: Literacy and Strength | Jocko Willink - Jordan B Peterson Podcast S4 E13
author: Jordan B Peterson
url: https://www.youtube.com/watch?v=HA4Bkybx1ps
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCL_f53ZEJxp8TtlOkHwMV9Q
content_mime_type: text/plain
content:
I had the pleasure of inviting Jocko Willink @Jocko Podcast onto my podcast for the first time. 

I've been on Jocko’s podcast several times in the past and now get the opportunity to reverse the interviewing role to learn more about his life and endeavors. We discuss his experience in the military and war; exploring time in the Navy Seals, Afghanistan, and Iraq. 

Jocko recounts what it looks like to be on the ground in combat scenarios and the requirement of strong leadership in the Seal teams. I ask him about his formative years growing up with a warrior personality. We cover other engaging points of interest in his kid books, time as an English major, restarting a clothing line in a dying factory town, and much more.

Jocko Willink is an American author, podcaster, and retired naval officer who served in the Navy SEALs. His books include New York Times bestseller Extreme Ownership,  Discipline Equals Freedom a field manual, and his children’s book The Way of the Warrior Kid. Jocko also has one of the most successful podcasts out there so check out the Jocko Podcast.

Find more of Jocko Willink on his podcast website, check out his clothing line www.originmaine.com

Please do not forget to subscribe to the channel in order to enjoy weekly videos. We thank you for your continued support.

To order Dr. Peterson's new book, Beyond Order: 12 More Rules For Life: https://jordanbpeterson.com/beyond-order

Other ways to connect with Dr. Peterson:

Website: https://jordanbpeterson.com/​
Podcast: https://jordanbpeterson.com/podcast/​
Twitter: https://twitter.com/jordanbpeterson​
Instagram: https://www.instagram.com/jordan.b.peterson
Facebook: https://www.facebook.com/drjordanpeterson
Donations: https://www.jordanbpeterson.com/donate​


guid: yt:video:y5Pl6DQ54X4
title: Government as Force | Senator Mike Lee - Jordan B Peterson Podcast S4 E14
author: Jordan B Peterson
url: https://www.youtube.com/watch?v=y5Pl6DQ54X4
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCL_f53ZEJxp8TtlOkHwMV9Q
content_mime_type: text/plain
content:
I had the pleasure of speaking with Senator Mike Lee on February 18, 2021. We discuss his experiences as a United States Senator for the state of Utah. Senator Lee and I talked at length about the structure and original formation of the US government. We also cover his hypothesis of what’s happening politically today, why it’s a problem, as well as possible solutions.

Mike Lee has been a conservative Republican for the state of Utah since January 3, 2011. He is also a New York Times bestseller with his book “Written Out of History: The Forgotten Founders Who Fought Big Government.” 

Find more of Senator Mike Lee on Twitter @SenMikeLee and in his books.

Please do not forget to subscribe to the channel in order to enjoy weekly videos. We thank you for your continued support.

To order Dr. Peterson's new book, Beyond Order: 12 More Rules For Life: https://jordanbpeterson.com/beyond-order

Other ways to connect with Dr. Peterson:

Website: https://jordanbpeterson.com/​
Podcast: https://jordanbpeterson.com/podcast/​
Twitter: https://twitter.com/jordanbpeterson​
Instagram: https://www.instagram.com/jordan.b.peterson
Facebook: https://www.facebook.com/drjordanpeterson
Donations: https://www.jordanbpeterson.com/donate​

--- PRODUCTS ---

Personality Course:  https://jordanbpeterson.com/personality
Self Authoring Suite: https://selfauthoring.com/
Understand Myself personality test: https://understandmyself.com/
Merchandise: https://teespring.com/stores/jordanbpeterson


guid: yt:video:j_MXSE3wUT4
title: Jordan Peterson's Critique of the Communist Manifesto
author: Jordan B Peterson
url: https://www.youtube.com/watch?v=j_MXSE3wUT4
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCL_f53ZEJxp8TtlOkHwMV9Q
content_mime_type: text/plain
content:
On February, April 19, 2019, I debated Marxist philosopher Slavoj Zizek in Toronto, April 19 at the Sony Centre. I started with a critique of The Communist Manifesto, which is the central revolutionary document of the Marxist movement. 

Dr. Zizek is a Slovenian philosopher and professor at the Institute for Sociology and Philosophy at the University of Ljubljana, whose works on cultural studies, psychoanalysis, and, above all, for the purposes of our debate, Marxism, are world-renowned. The topic? Happiness: Marxism vs Capitalism.

A good article, I think, on Zizek: https://www.iep.utm.edu/zizek/#H2

Full debate: https://www.youtube.com/watch?v=lsWndfzuOc4

--- SUPPORT THIS CHANNEL ---

Donations: https://www.jordanbpeterson.com/donate
Merchandise: https://teespring.com/stores/jordanbpeterson

--- BOOKS ---
Beyond Order: 12 More Rules for Life: https://jordanbpeterson.com/Beyond-Order
12 Rules for Life: An Antidote to Chaos: https://jordanbpeterson.com/12-rules-for-life/
Maps of Meaning: The Architecture of Belief: https://jordanbpeterson.com/maps-of-meaning/

--- LINKS ---

Website: https://jordanbpeterson.com/
12 Rules for Life Tour: https://jordanbpeterson.com/events/
Blog: https://jordanbpeterson.com/blog/
Podcast: https://jordanbpeterson.com/podcast/
Reading List: https://jordanbpeterson.com/great-books/
Twitter: https://twitter.com/jordanbpeterson
Instagram: https://www.instagram.com/jordan.b.peterson/
Facebook: https://www.facebook.com/drjordanpeterson

--- PRODUCTS ---

Personality Course:  https://jordanbpeterson.com/personality
Self Authoring Suite: https://selfauthoring.com/
Understand Myself personality test: https://understandmyself.com/
Merchandise: https://teespring.com/stores/jordanbpeterson


guid: yt:video:BVrLqpt0APo
title: Christianity and the Modern World | Bishop Barron - Jordan B Peterson Podcast S4 E15
author: Jordan B Peterson
url: https://www.youtube.com/watch?v=BVrLqpt0APo
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCL_f53ZEJxp8TtlOkHwMV9Q
content_mime_type: text/plain
content:
Beyond Order: 12 More Rules for Life: https://jordanbpeterson.com/Beyond-Order

@Bishop Robert Barron and I sat down on March 5th, 2021 to discuss a variety of topics in the realm of the importance of the bible, the bridge between religion and biology, the nature of good, how the limits of the bible can be useful, why young people are leaving the catholic church, the hunger for serious deep conversation on religious topics done intellectually, and more. 

Bishop Barron is the founder of Word on Fire catholic ministries and auxiliary bishop of the archdiocese of Los Angeles. He is also a number one Amazon best-selling author and has published a number of books on theology and spiritual life. He has been invited to speak about religion at the headquarters of Facebook, Google, and Amazon and is one of the most followed Catholics of the world on social media.

Find more of Bishop Barron on YouTube @Bishop Robert Barron and on https://www.wordonfire.org/

--- SUPPORT THIS CHANNEL ---

Donations: https://www.jordanbpeterson.com/donate
Merchandise: https://teespring.com/stores/jordanbpeterson

--- BOOKS ---

Beyond Order: 12 More Rules for Life: https://jordanbpeterson.com/Beyond-Order
12 Rules for Life: An Antidote to Chaos: https://jordanbpeterson.com/12-rules-for-life/
Maps of Meaning: The Architecture of Belief: https://jordanbpeterson.com/maps-of-meaning/

--- LINKS ---

Website: https://jordanbpeterson.com/
12 Rules for Life Tour: https://jordanbpeterson.com/events/
Blog: https://jordanbpeterson.com/blog/
Podcast: https://jordanbpeterson.com/podcast/
Reading List: https://jordanbpeterson.com/great-books/
Twitter: https://twitter.com/jordanbpeterson
Instagram: https://www.instagram.com/jordan.b.peterson/
Facebook: https://www.facebook.com/drjordanpeterson

--- PRODUCTS ---

Personality Course:  https://jordanbpeterson.com/personality
Self Authoring Suite: https://selfauthoring.com/
Understand Myself personality test: https://understandmyself.com/
Merchandise: https://teespring.com/stores/jordanbpeterson


guid: yt:video:vDNSnMTem98
title: Is Everything Better Than We Think? | Bjorn Lomborg - Jordan B Peterson Podcast S4 E16
author: Jordan B Peterson
url: https://www.youtube.com/watch?v=vDNSnMTem98
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCL_f53ZEJxp8TtlOkHwMV9Q
content_mime_type: text/plain
content:
Bjorn Lomborg's newest book "False Alarm" available here: https://www.amazon.com/False-Alarm-Climate-Change-Trillions/dp/1541647467

This episode was recorded on January 21, 2021.

Dr. Bjorn Lomborg and I discuss a variety of topics in the realm of climate change and worldwide problems. We examine the claims made in his latest book False Alarm. Throughout the episode we touch on sustainable development goals, prioritizing problems for the world, achieving the highest return on investment, the apocalypse lens we apply to many global issues, making the poor richer, innovation, adaptation, selling and marketing solutions, and much more.

Dr. Bjorn Lomborg is a Danish author and President of the think tank, Copenhagen Consensus Center. Bjorn champions a path to solving world problems through the use of economic research to determine where to spend our resources based on the return on investment and severity of the impending issue. Dr. Lomborg’s more notable books include False Alarm and How to Spend $75 Billion to Make the World a Better Place.

--- SUPPORT THIS CHANNEL ---

Donations: https://www.jordanbpeterson.com/donate
Merchandise: https://teespring.com/stores/jordanbpeterson

--- BOOKS ---
Beyond Order: 12 More Rules for Life: https://jordanbpeterson.com/Beyond-Order
12 Rules for Life: An Antidote to Chaos: https://jordanbpeterson.com/12-rules-for-life/
Maps of Meaning: The Architecture of Belief: https://jordanbpeterson.com/maps-of-meaning/

--- LINKS ---

Website: https://jordanbpeterson.com/
12 Rules for Life Tour: https://jordanbpeterson.com/events/
Blog: https://jordanbpeterson.com/blog/
Podcast: https://jordanbpeterson.com/podcast/
Reading List: https://jordanbpeterson.com/great-books/
Twitter: https://twitter.com/jordanbpeterson
Instagram: https://www.instagram.com/jordan.b.peterson/
Facebook: https://www.facebook.com/drjordanpeterson

--- PRODUCTS ---

Personality Course:  https://jordanbpeterson.com/personality
Self Authoring Suite: https://selfauthoring.com/
Understand Myself personality test: https://understandmyself.com/
Merchandise: https://teespring.com/stores/jordanbpeterson


guid: yt:video:ysQBegyQP8A
title: Grace Church High School: Teaching and the Voice of Conscience | Paul Rossi - JBP Podcast S4 E17
author: Jordan B Peterson
url: https://www.youtube.com/watch?v=ysQBegyQP8A
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCL_f53ZEJxp8TtlOkHwMV9Q
content_mime_type: text/plain
content:
Important Context and Timeline:  https://www.fairforall.org/grace-church-whistleblower/

This episode was recorded on April 22nd, 2021

Paul Rossi and I discuss the controversy surrounding a recent article Paul wrote. It has become apparent that an anti-racism curriculum is being instituted in schools across the United States and that doesn’t initially sound like anything but a positive change. I had Paul on to share his concerns after working in one of these schools that are implementing new ways of thinking about how our western society is structured. We spoke about many of the flaws that we see with the current direction of teaching.

Paul Rossi is a high school mathematics teacher and writer. His April 21st, 2021 essay titled “I Refuse to Stand by While my Students are Indoctrinated” was published on Bari Weiss’ Substack “Common Sense with Bari Weiss”. Viewers can also contact Paul at: teachingfortruth@gmail.com

Link to essay, "I Refuse to Stand By While My Students Are Indoctrinated":
https://bariweiss.substack.com/p/i-refuse-to-stand-by-while-my-students

--- SUPPORT THIS CHANNEL ---

Donations: https://www.jordanbpeterson.com/donate
Merchandise: https://teespring.com/stores/jordanbpeterson

--- BOOKS ---
Beyond Order: 12 More Rules for Life: https://jordanbpeterson.com/Beyond-Order
12 Rules for Life: An Antidote to Chaos: https://jordanbpeterson.com/12-rules-for-life/
Maps of Meaning: The Architecture of Belief: https://jordanbpeterson.com/maps-of-meaning/

--- LINKS ---

Website: https://jordanbpeterson.com/
12 Rules for Life Tour: https://jordanbpeterson.com/events/
Blog: https://jordanbpeterson.com/blog/
Podcast: https://jordanbpeterson.com/podcast/
Reading List: https://jordanbpeterson.com/great-books/
Twitter: https://twitter.com/jordanbpeterson
Instagram: https://www.instagram.com/jordan.b.peterson/
Facebook: https://www.facebook.com/drjordanpeterson

--- PRODUCTS ---

Personality Course:  https://jordanbpeterson.com/personality
Self Authoring Suite: https://selfauthoring.com/
Understand Myself personality test: https://understandmyself.com/
Merchandise: https://teespring.com/stores/jordanbpeterson


guid: yt:video:Q-geMoCsNAw
title: Q&A 05-01-2021 | Jordan B. Peterson
author: Jordan B Peterson
url: https://www.youtube.com/watch?v=Q-geMoCsNAw
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCL_f53ZEJxp8TtlOkHwMV9Q
content_mime_type: text/plain
content:
I recently answered questions that were submitted on the social media platform - https://www.thinkspot.com. thinkspot is still in beta, and would greatly appreciate your participation. These answers were also released early on thinkspot, so if you want an earlier view of these Q&A's you can see them on thinkspot a few days early.

Some of these questions have been edited for concision and grouped together in order to answer the broader topic.

--- SUPPORT THIS CHANNEL ---

Donations: https://www.jordanbpeterson.com/donate
Merchandise: https://teespring.com/stores/jordanbpeterson

--- BOOKS ---
Beyond Order: 12 More Rules for Life: https://jordanbpeterson.com/Beyond-Order
12 Rules for Life: An Antidote to Chaos: https://jordanbpeterson.com/12-rules-for-life/
Maps of Meaning: The Architecture of Belief: https://jordanbpeterson.com/maps-of-meaning/

--- LINKS ---

Website: https://jordanbpeterson.com/
12 Rules for Life Tour: https://jordanbpeterson.com/events/
Blog: https://jordanbpeterson.com/blog/
Podcast: https://jordanbpeterson.com/podcast/
Reading List: https://jordanbpeterson.com/great-books/
Twitter: https://twitter.com/jordanbpeterson
Instagram: https://www.instagram.com/jordan.b.peterson/
Facebook: https://www.facebook.com/drjordanpeterson

--- PRODUCTS ---

Personality Course:  https://jordanbpeterson.com/personality
Self Authoring Suite: https://selfauthoring.com/
Understand Myself personality test: https://understandmyself.com/
Merchandise: https://teespring.com/stores/jordanbpeterson


guid: yt:video:VIANLddo-ec
title: Ten Global Trends Every Smart Person Should Know | Marian Tupy - Jordan B Peterson Podcast S4 E18
author: Jordan B Peterson
url: https://www.youtube.com/watch?v=VIANLddo-ec
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCL_f53ZEJxp8TtlOkHwMV9Q
content_mime_type: text/plain
content:
This episode was recorded on  03/24/2021

For decades, we have been inundated with information purporting to demonstrate that the apocalypse is if not upon us then certainly threatening to appear in the next few decades. In the 1960s, dire predictions of overpopulation and certain mass starvation by the year 2000 were commonplace. In the 1970s, it was the oil shock and the energy crisis. In the 1980s it was acid rain -- and then came global warming, which morphed into climate change. This was all played out over a background of genuine thermonuclear threat. It's no wonder we believed that ultimate catastrophe was looming. 

Surprising as it may seem, however, there is no shortage of reasons for holding the opposite viewpoint. The lives of most people, planet-wide, have dramatically improved in recent decades, extending a trend that began with the industrial revolution. In many important ways, things are looking better than they every have before. 

Dr. Marian Tupy and I discuss the macro-state of the world as outlined in his book Ten Global Trends. The ten trends identified and highlighted by Dr. Tupy are all associated with a large and important improvement in living standards for most of humanity, in rich and poor nations alike. 
Could we dare to be cautiously and attentively optimistic about the future? 

Dr. Marian Tupy is senior policy analyst at the Cato Institute’s Center for Global Liberty and Prosperity and co-author of Ten Global Trends Every Smart Person Should Know: and Many Others You Will Find Interesting. Find out more about Dr. Tupy at his website - https://www.HumanProgress.org. His book is available at https://www.amazon.com/Global-Trends-Every-Smart-Person/dp/1948647737/ref=tmm_hrd_swatch_0?_encoding=UTF8&qid=&sr=

If you found this video useful and informative, you might consider watching or listening to Is Everything Better than we Think? -- my April 26 2021 discussion with environmentalist and economist Bjorn Lomborg

https://www.youtube.com/watch?v=vDNSnMTem98

and Rational Optimism, my February 08 2021 discussion with British journalist and businessman Matt Ridley:

https://www.youtube.com/watch?v=kjqEMqOyUr8&t=1s

--- SUPPORT THIS CHANNEL ---

Donations: https://www.jordanbpeterson.com/donate
Merchandise: https://teespring.com/stores/jordanbpeterson

--- BOOKS ---
Beyond Order: 12 More Rules for Life: https://jordanbpeterson.com/Beyond-Order
12 Rules for Life: An Antidote to Chaos: https://jordanbpeterson.com/12-rules-for-life/
Maps of Meaning: The Architecture of Belief: https://jordanbpeterson.com/maps-of-meaning/

--- LINKS ---

Website: https://jordanbpeterson.com/
12 Rules for Life Tour: https://jordanbpeterson.com/events/
Blog: https://jordanbpeterson.com/blog/
Podcast: https://jordanbpeterson.com/podcast/
Reading List: https://jordanbpeterson.com/great-books/
Twitter: https://twitter.com/jordanbpeterson
Instagram: https://www.instagram.com/jordan.b.peterson/
Facebook: https://www.facebook.com/drjordanpeterson

--- PRODUCTS ---

Personality Course:  https://jordanbpeterson.com/personality
Self Authoring Suite: https://selfauthoring.com/
Understand Myself personality test: https://understandmyself.com/
Merchandise: https://teespring.com/stores/jordanbpeterson


guid: yt:video:PSkQlc-6vpY
title: Writer of Braveheart | Randall Wallace - Jordan B Peterson Podcast S4 E19
author: Jordan B Peterson
url: https://www.youtube.com/watch?v=PSkQlc-6vpY
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCL_f53ZEJxp8TtlOkHwMV9Q
content_mime_type: text/plain
content:
Randall Wallace, graduate of Duke University, is an American NYT bestselling author of seven novels, as well as a screenwriter (TV and film), director, producer, songwriter, holder of a black belt in karate, and founder of Hollywood for Habitat for Humanity. He is perhaps best known for writing the historical drama Braveheart (1995), which earned him a Writers Guild of America Award for Best Original Screenplay and an Academy Award nomination in the same category, but has since directed The Man in the Iron Mask (1998), We Were Soldiers (2002), Secretariat (2010) and Heaven Is for Real (2014). Mr. Wallace also penned the lyrics to the acclaimed hymn Mansions of the Lord (music by Nick Glennie-Smith), featured in the soundtrack of When We Were Soldiers, and performed as the recessional for President Ronald Reagan's funeral. 

Mr. Wallace and I discussed the power of art, music, and story, his unlikely stint writing songs for an animal band, the profound influence of Biblical stories on his work and thought, the experience of depression, the necessity and significance of sacrifice, the general development of his career as a successful Hollywood writer and director, and his upcoming action movie about the Pope. 

This episode was recorded on March 9th, 2021.

--- SUPPORT THIS CHANNEL ---

Donations: https://www.jordanbpeterson.com/donate
Merchandise: https://teespring.com/stores/jordanbpeterson

--- BOOKS ---
Beyond Order: 12 More Rules for Life: https://jordanbpeterson.com/Beyond-Order
12 Rules for Life: An Antidote to Chaos: https://jordanbpeterson.com/12-rules-for-life/
Maps of Meaning: The Architecture of Belief: https://jordanbpeterson.com/maps-of-meaning/

--- LINKS ---

Website: https://jordanbpeterson.com/
12 Rules for Life Tour: https://jordanbpeterson.com/events/
Blog: https://jordanbpeterson.com/blog/
Podcast: https://jordanbpeterson.com/podcast/
Reading List: https://jordanbpeterson.com/great-books/
Twitter: https://twitter.com/jordanbpeterson
Instagram: https://www.instagram.com/jordan.b.peterson/
Facebook: https://www.facebook.com/drjordanpeterson

--- PRODUCTS ---

Personality Course:  https://jordanbpeterson.com/personality
Self Authoring Suite: https://selfauthoring.com/
Understand Myself personality test: https://understandmyself.com/
Merchandise: https://teespring.com/stores/jordanbpeterson


guid: yt:video:NGIP-3Q-p_s
title: The Psychology of the Psychedelics | Roland Griffiths - Jordan B Peterson Podcast - S4 E20
author: Jordan B Peterson
url: https://www.youtube.com/watch?v=NGIP-3Q-p_s
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCL_f53ZEJxp8TtlOkHwMV9Q
content_mime_type: text/plain
content:
Dr. Roland Griffiths, Ph.D., is a professor of neuroscience, psychiatry, and behavioral science and director of the Psychedelic and Consciousness Research at Johns Hopkins University School of Medicine.  He is the author of over 400 scientific research publications and has trained more than 50 postdoctoral research fellows. He has been a consultant to the National Institutes of Health and numerous pharmaceutical companies in the development of new psychotropic drugs.

Dr. Roland Griffiths and I discuss the research with John Hopkins University. We spoke about how he got into psychedelics and convinced ethic committees to approve such research, why he chose the scientific path, specifics about his studies with psilocybin, transformations of cancer patients with family members, the impact of psilocybin in existing institutions, the ongoing studies he is performing with long-time meditators and religious leaders, how the integration of psilocybin into society may look and more.

Find more information about the center for psychedelic and consciousness research at https://hopkinspsychedelic.org, and read Roland’s publications at https://hopkinspsychedelic.org/publications

This episode was recorded on March 2nd, 2021

FOR MORE INFORMATION ABOUT THE CENTER FOR PSYCHEDELIC AND CONSCIOUSNESS RESEARCH:
http://hopkinspsychedelic.org

ONGOING STUDIES:
Depression Study Website
https://hopkinspsychedelic.org/depressionstudy

Cigarette Smoking-Psilocybin Study Website
https://www.quitsmokingbaltimore.org/

Alzheimer’s Disease-Psilocybin Study Website
https://hopkinspsychedelic.org/alzheimers

Anorexia Nervosa-Psilocybin Study Website
https://hopkinspsychedelic.org/anorexia

Co-occurring Depression and Alcohol Use Disorder
https://hopkinspsychedelic.org/depression-alcohol

Psychedelic Survey Studies
https://hopkinspsychedelic.org/index/#research

PUBLISHED STUDIES:
All Johns Hopkins Psychedelic Science Publications
https://hopkinspsychedelic.org/publications


--- SUPPORT THIS CHANNEL ---

Donations: https://www.jordanbpeterson.com/donate
Merchandise: https://teespring.com/stores/jordanbpeterson

--- BOOKS ---
Beyond Order: 12 More Rules for Life: https://jordanbpeterson.com/Beyond-Order
12 Rules for Life: An Antidote to Chaos: https://jordanbpeterson.com/12-rules-for-life/
Maps of Meaning: The Architecture of Belief: https://jordanbpeterson.com/maps-of-meaning/

--- LINKS ---

Website: https://jordanbpeterson.com/
12 Rules for Life Tour: https://jordanbpeterson.com/events/
Blog: https://jordanbpeterson.com/blog/
Podcast: https://jordanbpeterson.com/podcast/
Reading List: https://jordanbpeterson.com/great-books/
Twitter: https://twitter.com/jordanbpeterson
Instagram: https://www.instagram.com/jordan.b.peterson/
Facebook: https://www.facebook.com/drjordanpeterson

--- PRODUCTS ---

Personality Course:  https://jordanbpeterson.com/personality
Self Authoring Suite: https://selfauthoring.com/
Understand Myself personality test: https://understandmyself.com/
Merchandise: https://teespring.com/stores/jordanbpeterson


guid: yt:video:qGgEF-SlSEU
title: Provocations: Nicole Arbour interviews Jordan Peterson
author: Jordan B Peterson
url: https://www.youtube.com/watch?v=qGgEF-SlSEU
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCL_f53ZEJxp8TtlOkHwMV9Q
content_mime_type: text/plain
content:
Sometimes we post interviews in full when they are conducted by other people due to misrepresentation. In this case, @Nicole Arbour posted clips, and we posted the whole interview, aiming to offer both our audiences something entertaining and, hopefully, compelling. Nicole and I discuss role models, casual contempt, sales and marketing, social media, Harry Potter books and films, gender dysphoria, dating advice for women with high IQ’s, and more.

Nicole Arbour is a Canadian (now American) comedian, choreographer, singer, and YouTuber. She is known for her work in acting on television and film and more recently as a comedian and entertainer through the most popular social media channels.

Find more of Nicole Arbour on Twitter @NicoleArbour, Instagram @ibnicolearbour, and on YouTube.

 This interview was recorded on 03/29/2021

--- SUPPORT THIS CHANNEL ---

Donations: https://www.jordanbpeterson.com/donate
Merchandise: https://teespring.com/stores/jordanbpeterson

--- BOOKS ---
Beyond Order: 12 More Rules for Life: https://jordanbpeterson.com/Beyond-Order
12 Rules for Life: An Antidote to Chaos: https://jordanbpeterson.com/12-rules-for-life/
Maps of Meaning: The Architecture of Belief: https://jordanbpeterson.com/maps-of-meaning/

--- LINKS ---

Website: https://jordanbpeterson.com/
12 Rules for Life Tour: https://jordanbpeterson.com/events/
Blog: https://jordanbpeterson.com/blog/
Podcast: https://jordanbpeterson.com/podcast/
Reading List: https://jordanbpeterson.com/great-books/
Twitter: https://twitter.com/jordanbpeterson
Instagram: https://www.instagram.com/jordan.b.peterson/
Facebook: https://www.facebook.com/drjordanpeterson

--- PRODUCTS ---

Personality Course:  https://jordanbpeterson.com/personality
Self Authoring Suite: https://selfauthoring.com/
Understand Myself personality test: https://understandmyself.com/
Merchandise: https://teespring.com/stores/jordanbpeterson


guid: yt:video:0Zld-MX11lA
title: A Brain Divided | Iain McGilchrist - Jordan B Peterson Podcast - S4 E21
author: Jordan B Peterson
url: https://www.youtube.com/watch?v=0Zld-MX11lA
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCL_f53ZEJxp8TtlOkHwMV9Q
content_mime_type: text/plain
content:
Iain McGilchrist is a psychiatrist, author, thinker, and lecturer. He is maybe best known for his book The Master and His Emissary: The Divided Brain and the Making of the Western World

Dr. Iain McGilchrist and I discussed a variety of topics relating to the bifurcated brain, how we process reality as human beings, and the downfalls of the views that have shaped western culture according to McGilchrist. 

For The Divided Brain film go to https://thedividedbrain.com/buy-the-film/

Find more about Iain McGilchrist on his new website https://channelmcgilchrist.com, and check out his book “The Master and his Emissary”, and look for Iain's new book The Matter with Things coming in the near future.

This episode was recorded on February 15th, 2021.


--- SUPPORT THIS CHANNEL ---

Donations: https://www.jordanbpeterson.com/donate
Merchandise: https://teespring.com/stores/jordanbpeterson

--- BOOKS ---
Beyond Order: 12 More Rules for Life: https://jordanbpeterson.com/Beyond-Order
12 Rules for Life: An Antidote to Chaos: https://jordanbpeterson.com/12-rules-for-life/
Maps of Meaning: The Architecture of Belief: https://jordanbpeterson.com/maps-of-meaning/

--- LINKS ---

Website: https://jordanbpeterson.com/
12 Rules for Life Tour: https://jordanbpeterson.com/events/
Blog: https://jordanbpeterson.com/blog/
Podcast: https://jordanbpeterson.com/podcast/
Reading List: https://jordanbpeterson.com/great-books/
Twitter: https://twitter.com/jordanbpeterson
Instagram: https://www.instagram.com/jordan.b.peterson/
Facebook: https://www.facebook.com/drjordanpeterson

--- PRODUCTS ---

Personality Course:  https://jordanbpeterson.com/personality
Self Authoring Suite: https://selfauthoring.com/
Understand Myself personality test: https://understandmyself.com/
Merchandise: https://teespring.com/stores/jordanbpeterson


guid: yt:video:fFFSKedy9f4
title: An Atheist in the Realm of Myth | Stephen Fry - Jordan B Peterson Podcast - S4 E22
author: Jordan B Peterson
url: https://www.youtube.com/watch?v=fFFSKedy9f4
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCL_f53ZEJxp8TtlOkHwMV9Q
content_mime_type: text/plain
content:
On this episode of the Jordan B Peterson Podcast, I am joined by Stephen Fry. Stephen Fry is a noted British actor, writer, comedian, political figure, journalist, poet, intellectual and much more. You may have seen him in the films Chariots of Fire, A Fish Called Wanda, The Life and Death of Peter Sellers, V for Vendetta, Sherlock Holmes: A Game of Shadows, and The Hobbit film series. He’s also served as the president of a mental health charity. Stephen’s list of accomplishments is far too long to list here.

Stephen and I discussed a variety of topics in the realm of drama, literature, and politics. We also discuss among other topics, atheism, religion, rationalism, empiricism, myth/story, bartering with reality, Greek mythology, Egyptian mythology, resentment, cruelty in the world, constitutional monarchy versus a democratic republic, and much more.

Find more of Stephen Fry on Twitter @stephenfry, his website stephenfry.com, check IMDB for his many movie and television appearances, and his many books.

This episode was recorded on March 28th, 2021.

--- SUPPORT THIS CHANNEL ---

Donations: https://www.jordanbpeterson.com/donate
Merchandise: https://teespring.com/stores/jordanbpeterson

--- BOOKS ---
Beyond Order: 12 More Rules for Life: https://jordanbpeterson.com/Beyond-Order
12 Rules for Life: An Antidote to Chaos: https://jordanbpeterson.com/12-rules-for-life/
Maps of Meaning: The Architecture of Belief: https://jordanbpeterson.com/maps-of-meaning/

--- LINKS ---

Website: https://jordanbpeterson.com/
12 Rules for Life Tour: https://jordanbpeterson.com/events/
Blog: https://jordanbpeterson.com/blog/
Podcast: https://jordanbpeterson.com/podcast/
Reading List: https://jordanbpeterson.com/great-books/
Twitter: https://twitter.com/jordanbpeterson
Instagram: https://www.instagram.com/jordan.b.peterson/
Facebook: https://www.facebook.com/drjordanpeterson

--- PRODUCTS ---

Personality Course:  https://jordanbpeterson.com/personality
Self Authoring Suite: https://selfauthoring.com/
Understand Myself personality test: https://understandmyself.com/
Merchandise: https://teespring.com/stores/jordanbpeterson


guid: https://based.cooking/yibin-burning-noodles.html
title: Yibin Burning Noodles
url: https://based.cooking/yibin-burning-noodles.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Yibin Burning Noodles</h1>

<p>This is a dry noodle dish from the town of Yibin in Sichuan, China.</p>

<h2>Ingredients</h2>

<h3>Yibin Chili Oil</h3>

<ul>
<li>Sichuan ground chilies, 1/3 cup</li>
<li>Roasted rapeseed oil (caizi you) or Chinese peanut oil, 2/3 cup</li>
<li>Peeled and smashed ginger, 2 inches</li>
<li>Cassia bark (or cinnamon stick), 2 inches</li>
<li>Star anise, 2</li>
<li>Chinese black cardamom (optional), 1</li>
<li>Sichuan peppercorn, 1 tsp</li>
<li>Roughly chopped walnut pieces, 2 tbsp</li>
<li>High-quality melted pork lard, 1/3 cup</li>
</ul>


<h3>Noodles</h3>

<ul>
<li>Fresh alkaline noodles, 150g</li>
<li><strong>Yibin Chili Oil</strong>, 2 tbsp</li>
<li>Light soy sauce, 1 tbsp</li>
<li>White sesame oil, 1 tbsp</li>
<li>Toasted yacai, 2 tbsp</li>
<li>Mixed toasted crushed peanuts/sesame, 2 tbsp</li>
<li>Sliced scallion greens, 2 tbsp</li>
<li>MSG, &frac14; tbsp</li>
</ul>


<h2>Directions</h2>

<h3>Yibin Chili Oil</h3>

<ol>
<li>Add ground chilies to a heat-proof jar or bowl.</li>
<li>Heat rapeseed oil (or Chinese peanut oil) over medium heat until lightly smoking at approximately 230°C for 2 minutes.</li>
<li>Turn off heat and let oil cool down to about 150°C.</li>
<li>Turn flame back to medium and add ginger, cassia bark, star anise, black cardamom, Sichuan peppercorn and chopped walnut pieces.</li>
<li>Simmer for 10 minutes.</li>
<li>Ensure the oil is approximately 150°C</li>
<li>Pour oil through a strainer onto the ground chilies.</li>
<li>Stir thoroughly.</li>
<li>Add the melted pork lard.</li>
<li>Stir thoroughly.</li>
</ol>


<h3>Noodles</h3>

<ol>
<li>Boil the noodles for approximately 1 minute (slightly past al dente).</li>
<li>Strain the noodles thoroughly.</li>
<li>Add all the sauces and oils from the &ldquo;Noodles&rdquo; ingredients list.</li>
<li>Top with the remaining ingredients.</li>
</ol>


<h2>Contribution</h2>

<ul>
<li>ThePademelon</li>
</ul>


<p>;tags: noodles asian chinese spicy</p>


guid: https://based.cooking/oatmeal-pancakes.html
title: Oatmeal Pancakes
url: https://based.cooking/oatmeal-pancakes.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Oatmeal Pancakes</h1>

<p><img src="pix/oatmeal-pancakes.webp" alt="oatmeal-pancakes" /></p>

<ul>
<li>⏲️ Prep time: 10 min</li>
<li>🍳 Cook time: 15 min</li>
<li>🍽️ Servings: 8</li>
</ul>


<h2>Ingredients</h2>

<ul>
<li>2 eggs</li>
<li>40g sugar (3 tbsp)</li>
<li>20g honey (1 tbsp)</li>
<li>60ml milk (4 tbsp) (you can use water instead)</li>
<li>120g oat flour (1 cup)</li>
<li>1 tsp baking powder (or baking soda + some acid to activate it)</li>
<li>Raspberry jam (optional)</li>
</ul>


<h2>Directions</h2>

<ol>
<li>Mix eggs, sugar, honey and milk.</li>
<li>In another bowl mix oat flour and baking powder.</li>
<li>Combine two mixtures and let the batter rest for about 15 minutes.</li>
<li>Preheat the pan for 5 minutes over low (~33%) heat, cook for about 1 - 1.5 minutes then flip when you see bubbles come out and cook for another 45s - 1 minute.</li>
<li>Eat them with raspberry (or any other) jam.</li>
</ol>


<h2>Contribution</h2>

<ul>
<li>wpnwbn</li>
</ul>


<p>;tags: breakfast sweet dessert pancake</p>


guid: https://based.cooking/diannes-southwest-salad.html
title: Dianne's Southwestern Cornbread Salad
url: https://based.cooking/diannes-southwest-salad.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Dianne&rsquo;s Southwestern Cornbread Salad</h1>

<p><img src="pix/diannes-cornbread-salad.webp" alt="Dianne's Southwestern Cornbread Salad" /></p>

<p>Dianne&rsquo;s Southwestern Cornbread Salad is as colorful as it is delicious.</p>

<ul>
<li>⏲️ Prep time: 30 min</li>
<li>🍳 Cook time: 15 min</li>
<li>🍽️ Servings: 10-12</li>
<li>🥶 Chill: 2 hrs</li>
</ul>


<h2>Ingredients</h2>

<ul>
<li>1 (6-ounce) package Mexican cornbread mix</li>
<li>1 (1-ounce) envelope buttermilk Ranch salad dressing mix</li>
<li>1 small head romaine lettuce, shredded</li>
<li>2 large tomatoes, chopped</li>
<li>1 (15-ounce) can black beans, rinsed and drained</li>
<li>1 (8-ounce) package shredded Mexican four-cheese blend</li>
<li>6 bacon slices, cooked and crumbled</li>
<li>5 green onions, chopped</li>
</ul>


<h2>Directions</h2>

<ol>
<li><strong>Prepare</strong> cornbread according to package directions, cool, and crumble. Then set aside.</li>
<li><strong>Prepare</strong> salad dressing according to package directions.</li>
<li><strong>Layer</strong> a large bowl with half each of cornbread, lettuce, and the next 6 ingredients: spoon half of dressing evenly over top. Repeat layers with remaining ingredients and dressing. Cover and chill at least 2 hours.</li>
</ol>


<p>;tags: salad mexican southwest</p>


guid: https://based.cooking/tanzania-tea-with-milk.html
title: Tanzanian Tea w/ Milk
url: https://based.cooking/tanzania-tea-with-milk.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Tanzanian Tea w/ Milk</h1>

<p><img src="pix/tanzania-tea-with-milk-01.webp" alt="tea-n-milk" /></p>

<p>This is a very traditional simple beverage from Tanzania, a country in East Africa. While I stayed there in Mwanza and Dar es Salaam, they
would always have this option for breakfast (or in general).</p>

<ul>
<li>⏲️ Prep time: 5-10 min</li>
<li>🍳 Cook time: 3-8 min</li>
<li>🍽️ Servings: 1</li>
</ul>


<h2>Ingredients</h2>

<ul>
<li>Black Ceylon Tea (Preferably, you want a dark, herbal flavor from your tea. I have some from Dar es Salaam,
but when I tried researching, I couldn&rsquo;t find out what kind of tea it is. No, they didn&rsquo;t list the ingredients on
the box lol)</li>
<li>Milk/Sweet Cream</li>
<li>Sweetener (Sugar, Syrup, Monk Fruit extract, etc.) (optional, but recommended)</li>
</ul>


<h2>Directions</h2>

<p><img src="pix/tanzania-tea-with-milk-02.webp" alt="tea" /></p>

<ol>
<li>Bring some hot water to boil and seep the tea. Depending on how strong you like it, you can do this for up to 10 min at most.
Be warned; typically black teas are very strong.</li>
<li>When done seeping, add in the milk (or cream).</li>
<li>Sweeten to taste. Remember you can always add more if there isn&rsquo;t enough.</li>
</ol>


<h2>Contribution</h2>

<ul>
<li>extramundane (Ex) - <a href="https://extramundane.xyz">website</a>, <a href="https://extramundane.xyz/donate.html">donate</a></li>
</ul>


<p>;tags: drink milk quick</p>


guid: https://based.cooking/yorkshire-puddings.html
title: Yorkshire Puddings
url: https://based.cooking/yorkshire-puddings.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Yorkshire Puddings</h1>

<p><img src="pix/yorkshire-puddings.webp" alt="Yorkshire Puddings" /></p>

<p>Basically the northern England equivalent of the french pancake ( a means to make use of extra flour when you didn&rsquo;t have enough for bread ). They go well with Sunday Roasts.
Puddings may be preserved in freezer for up to a month.</p>

<ul>
<li>⏲️ Prep time: 5 min</li>
<li>🍳 Cook time: 20 min</li>
<li>🍽️ Servings: 2</li>
</ul>


<h2>Ingredients</h2>

<ul>
<li>140g flour</li>
<li>4 eggs</li>
<li>200ml milk</li>
<li>sunflower oil</li>
</ul>


<h2>Directions</h2>

<ol>
<li>Preheat oven to 230°C / gas mark 8.</li>
<li>Drizzle oil into 24 &lsquo;cupcake tin&rsquo; slots. (The pans you make cupcakes in). Heat in oven.</li>
<li>Pour flour into bowl.</li>
<li>Whisk eggs, add to bowl.</li>
<li>Add milk to bowl in small amounts, beating/whisking after each addition. Until there are no lumps in the batter. You may season with salt &amp; pepper.</li>
<li>Tip batter into a jug so that you may pour into the cupcake pan slots evenly and carefully.</li>
<li>Bake undisturbed ( opening oven will impede the rising ), until the puddings have puffed up and browned.</li>
</ol>


<p>Originally published at https://www.bbcgoodfood.com/recipes/best-yorkshire-puddings</p>

<h2>Contribution</h2>

<ul>
<li>siggines - <a href="http://jacobsiggins.co.uk">website</a></li>
</ul>


<p>;tags: english side</p>


guid: https://based.cooking/australian-snags.html
title: Australian snags (sausage sizzle)
url: https://based.cooking/australian-snags.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Australian snags (sausage sizzle)</h1>

<p>An australian BBQ classic tradition that is simple and very easy to make. Great for parties and outdoor events
especially national events. Sometimes served at hardware chains.</p>

<ul>
<li>⏲️ Prep time: 2 min</li>
<li>🍳 Cook time: 20 min</li>
<li>🍽️ Servings: Depends</li>
</ul>


<h2>Ingredients</h2>

<ul>
<li>Sausages (thin)</li>
<li>Onions (4g per sausage)</li>
<li>Tomato sauce</li>
<li>Mustard (optional)</li>
<li>Bread</li>
<li>Butter</li>
<li>Oil</li>
<li>Wood chips (optional, fuel for smokey flavour)</li>
</ul>


<h2>Directions</h2>

<ol>
<li>Chop up the onions into rings</li>
<li>Bring the sausages to the grill, turning once every 5 mins</li>
<li>Add oil of your choice to the hotplate then add the onions</li>
<li>Use your tongs to toss the onions until they are golden brown</li>
<li>When the onions are golden brown turn off the hotplate</li>
<li>When the sausages are cooked, butter the bread then add a sausage (optionally split)</li>
<li>Add onions then tomato sauce on top</li>
</ol>


<p>;tags: basic snack australian pork</p>


guid: https://based.cooking/honey-garlic-chicken.html
title: Honey Garlic Chicken with Broccoli and Brown Rice
url: https://based.cooking/honey-garlic-chicken.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Honey Garlic Chicken with Broccoli and Brown Rice</h1>

<p>Very easy, high protein.</p>

<ul>
<li>Servings: 2</li>
</ul>


<h2>Ingredients</h2>

<ul>
<li>&frac12; cup ( 100g ) brown rice</li>
<li>&frac12; cup ( 70g ) frozen peas</li>
<li>1 head broccoli (you can use really any amount of broccoli)</li>
<li>2 chicken breasts</li>
<li>1 tbsp honey</li>
<li>1 tbsp low-sodium soy sauce</li>
<li>1 tbsp minced garlic</li>
</ul>


<h2>Directions</h2>

<ol>
<li>Cook rice in a pot. Instructions are on the bag it comes in.</li>
<li>While rice is cooking, cut chicken breasts into cube. Season with olive oil, black pepper, and
paprika. Cut broccoli into pieces and place into steamer basket over pot &frac12; filled with water, do
not start it yet.</li>
<li>Put chicken cubes into a hot pan and cook for ~3 minutes. After 3 minutes add honey, soy sauce,
and garlic. Cook for another 5 minutes. Begin boiling broccoli water.</li>
<li>Add frozen peas to rice and stir, they will heat up quickly.</li>
<li>Add rice and peas to chicken and stir.</li>
</ol>


<h2>Contribution</h2>

<ul>
<li>Connor McLean</li>
</ul>


<p>;tags: chicken broccoli rice quick</p>


guid: https://based.cooking/chicken-tenders-airfried.html
title: Chicken Tenders Airfried
url: https://based.cooking/chicken-tenders-airfried.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Chicken Tenders Airfried</h1>

<ul>
<li>⏲️ Prep time: 5 min</li>
<li>🍳 Cook time: 20 min</li>
</ul>


<h2>Ingredients</h2>

<ul>
<li>Raw chicken strips</li>
<li>Flour</li>
<li>Egg wash</li>
<li>Bread crumbs</li>
<li>Vegetable oil</li>
<li>Seasoning:salt and pepper with cayenne or paprika (optional)</li>
</ul>


<h2>Directions</h2>

<ol>
<li>In a plate, mix a little over a table spoon of spices into your flour.</li>
<li>Dip the chicken into the flour one strip at a time coating the entire surface.</li>
<li>Dip the floured chicken into the eggwash.</li>
<li>Press the chicken into the breadcrumbs trying to pick up as much as possible.</li>
<li>Repeat until all strips have been floured egged and breaded.</li>
<li>Coat both sides of the tenders with a light amount of vegetable oil.</li>
<li>Place the tenders into your airfryer, do not layer them on top of each other.</li>
<li>Set your airfryer to chicken mode and cook for 20 minutes at 360 degrees fahrenheit.</li>
<li>Serve with honey mustard for maximum effect.</li>
</ol>


<h2>Contribution</h2>

<p>Original recipe by Mental Outlaw on Youtube and Odysee.
Translated from video to text by Yoshiguy35.
Any changes I made were to abide by rule #4.
<a href="https://www.youtube.com/watch?v=PymSsu_LufA">original video</a></p>

<ul>
<li>Mental Outlaw - <a href="https://www.youtube.com/user/MentalOutlawStudios">youtube</a>, xmr: <code>45F2bNHVcRzXVBsvZ5giyvKGAgm6LFhMsjUUVPTEtdgJJ5SNyxzSNUmFSBR5qCCWLpjiUjYMkmZoX9b3cChNjvxR7kvh436</code></li>
<li>Yoshiguy35 - <a href="https://www.youtube.com/channel/UCWX13rdnpFNeMh7gOhexnlg">youtube</a>, <a href="https://www.yoshiguy35.com/">website</a></li>
</ul>


<p>;tags: chicken fry</p>


guid: https://based.cooking/chorizo-and-chickpea-soup.html
title: Chorizo & Chickpea Soup
url: https://based.cooking/chorizo-and-chickpea-soup.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Chorizo &amp; Chickpea Soup</h1>

<p>Recommend serving with corn bread.</p>

<ul>
<li>🍳 Cook time: 10-15 min</li>
</ul>


<h2>Ingredients</h2>

<ul>
<li>Chorizo Sausage(s)</li>
<li>2 Garlic cloves</li>
<li>Ginger</li>
<li>Paprika, 2 Tsp</li>
<li>Cumin, Parsley</li>
<li>Juice from whole Lemon</li>
<li>Chickpeas, 400g ( drained )</li>
<li>Butter and sunflower oil, for frying</li>
</ul>


<h2>Directions</h2>

<ol>
<li>Fry the sliced Chorizo in butter, along-with diced Ginger and Garlic. Add oil after a couple mins.</li>
<li>Pour in Lemon-juice, Chickpeas, and Cumin &amp; Paprika. Then 100ml of water.</li>
<li>Allow to boil for 5 or so min. Add Parsley and then salt to taste.</li>
</ol>


<h2>Contribution</h2>

<p>Recipe modified from original published at: ( https://www.bbcgoodfood.com/recipes/chorizo-chickpea-stew )</p>

<ul>
<li>Siggines - <a href="http://jacobsiggins.co.uk">website</a></li>
</ul>


<p>;tags: pork soup spanish quick</p>


guid: https://based.cooking/curry-sauce.html
title: Curry sauce
url: https://based.cooking/curry-sauce.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Curry sauce</h1>

<p>I like to make double this amount and freeze the rest.</p>

<ul>
<li>⏲️ Prep time: 20 min</li>
<li>🍳 Cook time: 60 min</li>
<li>🍽️ Servings: 4</li>
</ul>


<h2>Ingredients</h2>

<ul>
<li>25g butter</li>
<li>1 onion, sliced</li>
<li>2 garlic cloves, sliced</li>
<li>Thumb of ginger, sliced</li>
<li>2 tbsp curry powder</li>
<li>&frac12; tsp turmeric</li>
<li>1 tbsp malt vinegar</li>
<li>1 star anise</li>
<li>250ml chicken stock</li>
<li>1 tbsp cornflour</li>
<li>2 tbsp water</li>
<li>Lemon juice (optional)</li>
</ul>


<h2>Directions</h2>

<ol>
<li>Melt the butter in a large saucepan over medium heat.</li>
<li>Add in the sliced onion, sliced garlic, and ginger.</li>
<li>Fry for 15 min, until the onion soft.</li>
<li>Add the curry powder, turmeric, vinegar, and star anise.</li>
<li>Fry for 1 minute.</li>
<li>Pour in the stock.</li>
<li>Simmer for 30 minutes while stirring.</li>
<li>Remove the star anise.</li>
<li>Add the cornflour and water.</li>
<li>Simmer for 5 minutes while stirring.</li>
<li>Blend the sauce. Add in some lemon juice if you want.</li>
</ol>


<h2>Contribution</h2>

<p>Fiddelate</p>

<p>;tags: sauce indian curry</p>


guid: https://based.cooking/coleslaw.html
title: Coleslaw
url: https://based.cooking/coleslaw.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Coleslaw</h1>

<p>This is a coleslaw recipe that I got from a chili restaurant in my neighborhood that closed down a few years ago. This recipe makes more dressing than needed for the coleslaw, so you can save it or use it as a vegetable dip.</p>

<ul>
<li>⏲️ Prep time: 25 min</li>
<li>🥶 Fridge time: 1 hr</li>
<li>🍽️ Servings: 8 - 10</li>
</ul>


<h2>Ingredients</h2>

<ul>
<li>&frac34; cup mayonnaise</li>
<li>&frac12; cup buttermilk</li>
<li>3 tbsp lemon juice</li>
<li>3 tbsp apple cider vinegar</li>
<li>4 tbsp distilled vinegar</li>
<li>1/3 cup canola oil</li>
<li>&frac14; cup granulated sugar</li>
<li>1 &frac12; tsp kosher salt</li>
<li>1 tsp ground black pepper</li>
<li>1 tsp celery seeds</li>
<li>&frac12; tsp onion powder</li>
<li>&frac14; tsp granulated garlic</li>
<li>&frac14; tsp mustard powder</li>
<li>One large head of green cabbage</li>
<li>One large carrot</li>
</ul>


<h2>Directions</h2>

<ol>
<li>Finely shred, rinse, and drain the carrot</li>
<li>Finely shred the cabbage (use a food processor if possible)</li>
<li>Whisk together the mayonnaise, buttermilk, lemon juice, cider vinegar, distilled vinegar, canola oil, and sugar</li>
<li>Add the salt, pepper, celery seeds, onion powder, and granulated garlic, and combine well</li>
<li>Combine the shredded cabbage and carrot in a separate bowl</li>
<li>Slowly add the dressing until it lightly coats the vegetables, and toss well. Add more dressing until it tastes good</li>
<li>Refrigerate for at least an hour before serving</li>
</ol>


<h2>Contribution</h2>

<ul>
<li>Declan Cash - <a href="https://declancash.com">website</a></li>
</ul>


<p>;tags: side cabbage southern salad</p>


guid: https://based.cooking/mushroom-stragonov.html
title: Mushroom Stroganov
url: https://based.cooking/mushroom-stragonov.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Mushroom Stroganov</h1>

<p>Prep time: 10 Minutes
Cook time: 20 Minutes
Servings: 2</p>

<h2>Ingredients</h2>

<ul>
<li>8 oz uncooked pasta (spaghetti or any other long noodle will work. Stroganov can also be served over rice.)</li>
<li>12 oz mushrooms (I reccommend shitake, but white, portabello, or maitake will also work.)</li>
<li>2 cloves of garlic, minced</li>
<li>1 small yellow onion, minced</li>
<li>2 Tbsp butter</li>
<li>1 Tbsp general purpose flour</li>
<li>1 Cup vegetable broth</li>
<li>1 Tsp dijon mustard</li>
<li>1 Tsp Smoked paprika</li>
<li>4 Tbsp creme fraiche (can be made by mixing equal parts heavy and sour cream)</li>
<li>2 Tbsp parsely</li>
</ul>


<h2>Directions</h2>

<ol>
<li>Bring a large pot of salted water to a boil and cook pasta al dente</li>
<li>In a cup, combine flour, mustard, smoked paprika, salt and pepper. Add broth and whisk until no lumps remain.</li>
<li>While pasta is cooking, melt butter in a medium skillet and over medium heat.</li>
<li>When the butter is melted, add onions and cook until softened.</li>
<li>Add mushrooms and cook until all water evaporates and mushrooms are slightly browned, about 7 minutes.</li>
<li>Add garlic and cook for another 30 seconds.</li>
<li>Pour the flour and broth mixture into the mushrooms and cook until thickens, about 2 minutes.</li>
<li>Stir in Creme Fraiche.</li>
<li>Add the strained pasta to the mushroom sauce and stir to coat the pasta completely.</li>
<li>Serve immediately.</li>
</ol>


<h2>Contribution</h2>

<ul>
<li>Aayla Semyonova - <a href="https://aayla.dev">website</a></li>
</ul>


<p>;tags: russian pasta mushrooms</p>


guid: https://based.cooking/ravioli.html
title: Ravioli
url: https://based.cooking/ravioli.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Ravioli</h1>

<p><img src="pix/ravioli-01.webp" alt="Ravioli" /></p>

<ul>
<li>⏲️ Prep time: 30 min</li>
<li>🍳Cook time: 2 min</li>
<li>🍽️ Servings: 4</li>
</ul>


<h2>Ingredients</h2>

<h3>Dough</h3>

<ul>
<li>4 eggs</li>
<li>400 g 00 flour</li>
<li>Drizzle of olive oil</li>
</ul>


<h3>Cheese Filling</h3>

<ul>
<li>1 lemon</li>
<li>50 g grated Pecorino Romano cheese</li>
<li>250 g ricotta</li>
<li>1 egg</li>
</ul>


<h3>Seafood Fillings</h3>

<ul>
<li>Chopped leftover lobster legs, lobster tail, or minced crab (optional)</li>
</ul>


<h2>Directions</h2>

<ol>
<li>The basic rule of thumb I use for pasta is 100g, 1 egg per person</li>
<li>For this recipe you can go two ways, the old school &ldquo;well&rdquo; method or a kitchen aid mixer (skip to step 7)</li>
<li>For the well method, pile the flour onto the counter and with your hand carve a hole or a well in the center</li>
<li>Crack the eggs into the center of the well, and drizzle a bit of olive oil into the center</li>
<li>With a fork, begin slowly breaking up, mixing, and incorporating the egg into the flour until there is no longer any loose egg that can escape the outer well border</li>
<li>At this point use your hands to bring the sandy mixture together and knead the dough for about 5-10 minutes or until the dough is smooth</li>
<li>For the stand mixer method just throw all the ingredients into the mixer with a dough hook and set it to level 4 for about 3-5 minutes and it will be done</li>
<li>You might need to scrape the sides down and maybe hand knead the dough a bit longer after it&rsquo;s done to make it into a nice smooth ball</li>
<li>Cover the dough with plastic wrap and let it rest in the fridge a bit so it&rsquo;s easier to roll out (15-30 mins)</li>
<li>While the dough is resting, make the filling by first mixing the  ricotta and egg into a bowl</li>
<li>Zest and juice a lemon peel into the bowl</li>
<li>Optionally add seafood ingredients at this point</li>
<li>Grate the Pecorino into the bowl, add salt and pepper to taste, and mix to distribute the ingredients evenly</li>
<li>Take out the dough and cut it into 4 pieces, keeping the ones not currently being worked on covered so they don&rsquo;t dry out</li>
<li>Roll the dough out with a pasta machine down to the point where you can just barely see your hand through it (setting 2-3 out of 7) or roll it out with a rolling pin into a long sheet, maybe like 16 x 8 inches or so</li>
<li>At this point you can either cut the sheet in half and make two sheets, a top and bottom, or one sheet, where you will fold the dough over and use the folded seam as one side of the ravioli
<img src="pix/ravioli-02.webp" alt="Lobster Ravioli" /></li>
<li>Using a teaspoon, evenly space out the ricotta filling onto the sheets, leaving a few inches on each side for the seams</li>
<li>As stated in step 16, either take the 2nd sheet and place it over top or fold over the dough and press down firmly, forcing out any air and making sure the two pieces of dough stick</li>
<li>You may need to brush some water onto the dough if it is too heavily floured and not sticking</li>
<li>Using a fancy pasta cutter, a knife, or even a pizza cutter, cut evenly between the seams of the raviolis to separate them</li>
<li>If you used a pasta cutter, you are now done, store the raviolis on a floured wax paper sheet or freeze them for later
<img src="pix/ravioli-03.webp" alt="Finished Ravioli" /></li>
<li>If you don&rsquo;t have a pasta cutter, use a fork to press down the dough around the edges of the cut raviolis to ensure they are firmly closed and no leaks or air bubbles are visible, or else they will explode when cooked</li>
<li>To cook, throw them in salted boiling water and they will let you know when they&rsquo;re done when they float to the top (1-2 minutes)</li>
<li>Serve the seafood version with a simple fresh red sauce and basil, or spice it up a bit and go with a base of red sauce with some added heavy cream, and a pinch of red pepper flakes to make a pink sauce for the seafood version
<img src="pix/ravioli-04.webp" alt="Served Ravioli" /></li>
</ol>


<h2>Contribution</h2>

<ul>
<li>mfed3 - xmr: <code>48eEMdYtCQaV5wY7wvmxK6jCxKkia9dgpNTMNT1do7RLWXCwWDgSKjN3kiZ6yHbAuAXWgDGN6imnGT9NPeHWD7zX9hSyHu2</code></li>
</ul>


<p>;tags: pasta italian</p>


guid: https://based.cooking/ragu-napoletano.html
title: Ragu Napoletano
url: https://based.cooking/ragu-napoletano.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Ragu Napoletano</h1>

<p>This recipe is known by Italian-Americans as &ldquo;Sunday Gravy&rdquo;, which originated from the Southern Italian dish Ragu Napoletano. This is my variation of my family&rsquo;s version which was passed down 3 generations to me.</p>

<p><img src="pix/ragu-napoletano-1.webp" alt="Ragu Napoletano" /></p>

<ul>
<li>⏲️ Prep time: 30-60 min</li>
<li>🍳Cook time: 4-5 hrs</li>
<li>🍽️ Servings: 10-12</li>
</ul>


<h2>Ingredients</h2>

<h3>Tomato Sauce</h3>

<ul>
<li>6-10 lbs San Marzano plum tomatoes (fresh or canned peeled)</li>
<li>Tomato paste (optional)</li>
</ul>


<h3>Aromatics and Herbs</h3>

<ul>
<li>8 cloves garlic</li>
<li>1.5 white onions</li>
<li>6-8 oz red wine</li>
<li>8 fresh basil leaves</li>
<li>Dry oregano</li>
<li>Red pepper</li>
</ul>


<h3>Meat</h3>

<ul>
<li>1-2 lb pork tenderloin</li>
<li>1-2 lb sweet and or spicy Italian sausage</li>
<li>1 lb cubed stewing beef (chuck, short rib, or oxtail)</li>
</ul>


<h3>Meatballs</h3>

<ul>
<li>1-2 lb total of ground beef chuck, veal, and pork</li>
<li>1 &frac12; cups grated Pecorino Romano cheese</li>
<li>1 &frac12; cups breadcrumbs (baked stale bread, oregano, salt and pepper pulsed in a food processor)</li>
<li>2-3 eggs</li>
<li>Splash of milk</li>
<li>Handfull of fresh parsley chopped</li>
<li>Sprig of fresh basil chopped</li>
<li>&frac12; onion minced</li>
<li>4-8 cloves garlic minced</li>
</ul>


<h2>Directions</h2>

<ol>
<li>If you already have tomato sauce skip to step 5</li>
<li>For fresh tomatoes, wash and cut out off the green stems of the tomatoes and cut them into a few chunks and lightly salt them over a collander or strainer so they release water and break down quicker</li>
<li>For canned tomatoes, use your hands to crush the peeled tomatoes (don&rsquo;t use a food processor)</li>
<li>In a large stock pot cook down the tomatoes for approximately 30 mins then use a food mill or strainer to remove the skins and seeds to yield tomato sauce (this can be done beforehand and frozen / canned for months)
<img src="pix/ragu-napoletano-2.webp" alt="Sauce" /></li>
<li>Mix all the ingredients in the Meatballs section by hand and form equal sized meatballs</li>
<li>Either bake the meatballs at 400°F until brown or fry them with the the other meats in step 7</li>
<li>Coat the bottom of a dutch oven or large stock pot with olive oil and  sear each meat one by one, removing from the pot once browned on the outside (do not cook the meat all the way through)</li>
<li>Sweat the onion and garlic, then deglaze the pan with the red wine</li>
<li>Fill the pot with the seared meat, tomato sauce, add the fresh basil, then season with dried oregano, red pepper, salt, pepper, and a pinch of sugar to taste
<img src="pix/ragu-napoletano-1.webp" alt="Meats" /></li>
<li>Cook on very low flame uncovered for 4-5 hours stirring making sure it doesn&rsquo;t burn</li>
<li>Serve over cooked dry pasta such as ziti, penne, rigatoni</li>
<li>Portion the sauce and meats and freeze in containers for up to 4-6 months</li>
</ol>


<h2>Contribution</h2>

<ul>
<li>mfed3 - xmr: <code>48eEMdYtCQaV5wY7wvmxK6jCxKkia9dgpNTMNT1do7RLWXCwWDgSKjN3kiZ6yHbAuAXWgDGN6imnGT9NPeHWD7zX9hSyHu2</code></li>
</ul>


<p>;tags: tomato sauce italian pork veal</p>


guid: https://based.cooking/mapo-tofu.html
title: Mapo Tofu (麻婆豆腐)
url: https://based.cooking/mapo-tofu.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Mapo Tofu (麻婆豆腐)</h1>

<p><img src="pix/mapo-tofu-01.webp" alt="Mapo Tofu Over Rice" /></p>

<ul>
<li>⏲️ Prep time: 10 min</li>
<li>🍳Cook time: 15 min</li>
<li>🍽️ Servings: 4</li>
</ul>


<h2>Ingredients</h2>

<h3>Marinated Pork</h3>

<ul>
<li>450 g (1 lb) ground pork</li>
<li>1 tbsp soy sauce</li>
<li>1 tbsp Shaoxing cooking wine</li>
<li>1 tsp cornstarch</li>
<li>1 tsp white pepper powder</li>
</ul>


<h3>Braise</h3>

<ul>
<li>2 tbsp spicy doubanjiang (la doubanjiang)</li>
<li>1 tsp dou-chi</li>
<li>2-3 chopped scallions white and green separated)</li>
<li>2-4 minced garlic cloves</li>
<li>2 inch minced ginger (similar amount as garlic)</li>
<li>400 ml chicken broth or water</li>
<li>340 g (1 package) soft tofu cut into 1.5cm (&frac12; inch cubes)</li>
<li>1 tbsp Sichuan peppercorns crushed</li>
</ul>


<h2>Directions</h2>

<p><img src="pix/mapo-tofu-02.webp" alt="Mapo Tofu Simmering" />
1. Marinade the pork in shaoxing cooking wine, a splash of cooking oil, the soy sauce,
2. Add cooking oil to a wok and sear the ground pork until browned, chopping it up as it cooks
3. Add the doubanjiang and let it simmer for about a minute
4. Add the minced aromatics (ginger, garlic) scallion whites, and dou-chi and cook until fragrant
5. Add the stock and a splash of soy sauce, turn up the gas and bring to a boil
6. Add the tofu, lower the gas, and braise for around 15 mins
7. You&rsquo;ll know it&rsquo;s done when the tofu shows their trademark &ldquo;pockmarks&rdquo; and the seasoning sticks to them
8. Mix in the crushed sichuan peppercorns and green parts of the scallions right before serving
9. Serve over steamed rice</p>

<h2>Contribution</h2>

<ul>
<li>mfed3 - xmr: <code>48eEMdYtCQaV5wY7wvmxK6jCxKkia9dgpNTMNT1do7RLWXCwWDgSKjN3kiZ6yHbAuAXWgDGN6imnGT9NPeHWD7zX9hSyHu2</code></li>
</ul>


<p>;tags: chinese pork tofu</p>


guid: https://based.cooking/limoncello.html
title: Limoncello
url: https://based.cooking/limoncello.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Limoncello</h1>

<p><img src="pix/limoncello.webp" alt="Limoncello" /></p>

<ul>
<li>⏲️ Prep time: 10 min</li>
<li>🍳Wait time: 20 days</li>
<li>🍽️ Servings: 22</li>
</ul>


<h2>Ingredients</h2>

<ul>
<li>5-7 organic lemons (regular lemons are covered in wax)</li>
<li>300ml 95% ABV grain alcohol</li>
<li>700ml water</li>
<li>500ml sugar</li>
</ul>


<h2>Directions</h2>

<ol>
<li>Pour the alcohol into a 1 liter mason jar</li>
<li>Peel the lemons avoiding the white pith (it will make your limoncello bitter) and submerse them in the alcohol</li>
<li>Cover the jar and let the lemons infuse the alcohol for 20 days</li>
<li>After the infusion is completed, create a simple syrup by boiling the water and dissolving the sugar in the water</li>
<li>Allow the water to cool completely, then strain the alcohol into the sugar water and stir</li>
<li>Bottle or put it back into the mason jar</li>
<li>Feel free to scale the recipe up or down, and adjust the sugar to the sweetness you like, but the ABV should remain somewhere around 28-30%</li>
</ol>


<h2>Contribution</h2>

<ul>
<li>mfed3 - xmr: <code>48eEMdYtCQaV5wY7wvmxK6jCxKkia9dgpNTMNT1do7RLWXCwWDgSKjN3kiZ6yHbAuAXWgDGN6imnGT9NPeHWD7zX9hSyHu2</code></li>
</ul>


<p>;tags: alcohol lemons digestivo liquor</p>


guid: https://based.cooking/italian-mulled-wine.html
title: Italian Mulled Wine
url: https://based.cooking/italian-mulled-wine.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Italian Mulled Wine</h1>

<p><img src="pix/italian-mulled-wine.webp" alt="Italian Mulled Wine" /></p>

<ul>
<li>⏲️ Prep time: 5 min</li>
<li>🍳Cook time: 15 min</li>
<li>🍽️ Servings: 4</li>
</ul>


<h2>Ingredients</h2>

<h3>Crushed Ingredients</h3>

<ul>
<li>1 star anise</li>
<li>1 bay leaf</li>
<li>1 pinch rosemary</li>
<li>1 pinch peppercorn</li>
<li>1 pinch thyme</li>
<li>1 pinch red pepper</li>
<li>1 pinch fennel seeds</li>
<li>1 pinch cloves</li>
<li>1 pinch nutmeg</li>
</ul>


<h3>Non-Crushed Ingredients</h3>

<ul>
<li>1 bottle Italian red wine</li>
<li>1 orange</li>
<li>1 lemon</li>
<li>1 tbsp honey</li>
<li>1 tsp vanilla</li>
<li>1 stick cinnamon</li>
<li>4 figs (optional)</li>
<li>100 ml limoncello (optional)</li>
<li>50 ml sweet vermouth (optional)</li>
<li>50 ml bourbon, brandy, or cognac (optional)</li>
</ul>


<h2>Directions</h2>

<ol>
<li>Pour the wine into a stock pot and turn the gas on medium high</li>
<li>Crush all the &ldquo;Crushed Ingredients&rdquo; in a mortar and pestle</li>
<li>Peel and juice the orange and lemon (toss the peels and juice into the wine but not the white pith)</li>
<li>When the wine is up to a simmer, immediately bring the gas down to low and pour in all the rest of the ingredients</li>
<li>Cook on low for at least 15 minutes to infuse the flavors</li>
<li>Keep the flame on low so the wine stays warm and continues to infuse, but doesn&rsquo;t bubble / burn off the alcohol</li>
<li>Feel free to double the recipe or scale any of these ingredients up or down to suite your taste</li>
</ol>


<h2>Contribution</h2>

<ul>
<li>mfed3 - xmr: <code>48eEMdYtCQaV5wY7wvmxK6jCxKkia9dgpNTMNT1do7RLWXCwWDgSKjN3kiZ6yHbAuAXWgDGN6imnGT9NPeHWD7zX9hSyHu2</code></li>
</ul>


<p>;tags: alcohol wine liquor drink</p>


guid: https://based.cooking/chocolate-chip-cookies.html
title: Chocolate Chip Cookies
url: https://based.cooking/chocolate-chip-cookies.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Chocolate Chip Cookies</h1>

<p><img src="pix/chocolate-chip-cookies.webp" alt="Chocolate Chip Cookies" /></p>

<ul>
<li>⏲️ Prep time: 10 min</li>
<li>🍳Cook time: 10 min</li>
<li>🍽️ Servings: 4</li>
</ul>


<h2>Ingredients</h2>

<ul>
<li>230 g melted butter (2 sticks)</li>
<li>330 g bread flour</li>
<li>5 g salt</li>
<li>5 g baking soda</li>
<li>100-200 g white sugar</li>
<li>100-200 g brown sugar</li>
<li>1 egg</li>
<li>15 g milk</li>
<li>5 g vanilla</li>
<li>225 g 50-70% dark chocolate chips or semi-sweet milk chocolate chips</li>
</ul>


<h2>Directions</h2>

<ol>
<li>Preheat oven to 375°F</li>
<li>Mix the flour, baking soda, and salt in a bowl</li>
<li>Using a mixer or whisk, beat the butter, sugar, eggs, and vanilla in a separate bowl for a few mins</li>
<li>Combine and stir in the dry ingredients, then the chocolate chips</li>
<li>Use an ice cream scooper or spoon to make uniform balls of cookie dough to the size you like and evenly space them out on a parchment paper lined baking sheet (you may need more than one sheet depending on the size of the cookies)</li>
<li>Bake in the oven one baking sheet at a time for around 8-10 minutes, taking them out when they start to brown</li>
<li>Cool for a few minutes then put them on a cooling rack</li>
</ol>


<h2>Contribution</h2>

<ul>
<li>mfed3 - xmr: <code>48eEMdYtCQaV5wY7wvmxK6jCxKkia9dgpNTMNT1do7RLWXCwWDgSKjN3kiZ6yHbAuAXWgDGN6imnGT9NPeHWD7zX9hSyHu2</code></li>
</ul>


<p>;tags: dessert cookies sweet chocolate</p>


guid: https://based.cooking/apple-pie.html
title: Apple Pie
url: https://based.cooking/apple-pie.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Apple Pie</h1>

<p><img src="pix/apple-pie.webp" alt="Apple Pie" /></p>

<ul>
<li>⏲️ Prep time: 30 min</li>
<li>🍳Cook time: 45 min</li>
<li>🍽️ Servings: 8</li>
</ul>


<h2>Ingredients</h2>

<h3>Filling</h3>

<ul>
<li>900 g (4-5) golden delicious apples</li>
<li>15 g (1 tbsp) lemon juice</li>
<li>50 g white sugar</li>
<li>65 g brown sugar</li>
<li>5 g (1 tsp) cinnamon</li>
<li>1-2 g nutmeg</li>
<li>15 g cornstarch</li>
<li>15 g ice water</li>
<li>226 g (2 sticks) cold butter, cut into slices</li>
</ul>


<h3>Crust</h3>

<ul>
<li>350 g flour</li>
<li>5 g salt</li>
<li>30 g white sugar</li>
<li>225 g butter</li>
<li>50-100 ml ice water</li>
</ul>


<h3>Egg Wash</h3>

<ul>
<li>1 egg (optional)</li>
<li>15 g water (optional)</li>
</ul>


<h2>Directions</h2>

<ol>
<li>Peel and cut the apples into 1-2 inch strips</li>
<li>Put the apples in a bowl and mix in the lemon juice, sugar, cinnamon, nutmeg, and cornstarch and let it sit for 15 mins to release water</li>
<li>Transfer the filling mixture to a sauce pan and reduce the liquid over medium to low heat for around 15 mins, stirring regularly, then turn off the gas</li>
<li>While the filling is sitting / reducing, start the crust by putting the flour, salt, sugar, and pieces of butter in a food processor</li>
<li>Run the food processor until it resembles a coarse sand (5-10 seconds) then start dripping in the ice water until the mixture starts to chunk together</li>
<li>You&rsquo;ll know when it&rsquo;s done if you can pinch the dough with your hand and it sticks together</li>
<li>Preheat oven to 350°F then start making the pie crust</li>
<li>Cut the dough in half and roll both halves out with a rolling pin until they are big enough to cover your pie pan (around 9 inch diameter)</li>
<li>Put the bottom half dough into the pie pan and cut off the excess dough with a knife</li>
<li>Dump the sauce pan full of the filling into the pie pan and even it out</li>
<li>Cover the pie filling with the top dough and fold over and tuck in the excess crust</li>
<li>Use a fork or your fingers to pinch down the top crust to the bottom crust so you don&rsquo;t have air gaps</li>
<li>Optionally you can now brush on the egg wash to make the crust get a shiny golden brown color when it cooks</li>
<li>Cut a few slits in the top crust with a knife to give it a nice design and allow for air to release</li>
<li>Bake 45 minutes at 350°F or until the crust is brown to your liking and the apples are bubbling inside</li>
</ol>


<h2>Contribution</h2>

<ul>
<li>mfed3 - xmr: <code>48eEMdYtCQaV5wY7wvmxK6jCxKkia9dgpNTMNT1do7RLWXCwWDgSKjN3kiZ6yHbAuAXWgDGN6imnGT9NPeHWD7zX9hSyHu2</code></li>
</ul>


<p>;tags: dessert pie sweet apples</p>


guid: https://based.cooking/soleier.html
title: Soleier (pickled eggs)
url: https://based.cooking/soleier.html
feedurl: https://based.cooking/rss.xml
content:
<h1>Soleier (pickled eggs)</h1>

<p><img src="pix/soleier.webp" alt="Soleier" /></p>

<p>Soleier are a german pub dish. They are typically enjoyed between two beers.</p>

<ul>
<li>⏲️ Preparation time: 10min</li>
<li>🍳 Cook time: 10min</li>
<li>🍽️ Servings: 10</li>
</ul>


<h2>Ingredients</h2>

<ul>
<li>peels of five onions</li>
<li>10 eggs</li>
<li>2 loorber leaves</li>
<li>3 cloves</li>
<li>4 allspice</li>
<li>1Tbsp peppercorns</li>
<li>1Tbsp caraway seeds</li>
<li>1Tbsp mustard seeds</li>
<li>1tsp of Szechuan pepper (optional)</li>
<li>1tsp lovage (optional)</li>
<li>1tsp nutmeg (optional)</li>
<li>100mL vinegar</li>
<li>3 cloves of garlic</li>
</ul>


<h2>Directions</h2>

<ol>
<li>Put 750mL of water and the peels of five onions in a pot and let them cook for five minutes. Remove the peels about twenty minutes later.</li>
<li>Put the eggs, one teaspoon of sugar, two tablespoons of salt and all spices (but vinegar and garlic) in the pot, bring it to a boil and cook them for seven minutes.</li>
<li>Use a spoon to remove the eggs from the pot and crack them all around. Do not remove the eggshell!</li>
<li>Place the eggs and the garlic in a jar, fill it with the spiced water and add the vinegar. Add water, if needed, so that the eggs are covered.</li>
<li>Let them rest for at least three days and at most two weeks at room temperature or slightly below.</li>
</ol>


<h2>Consumption Recommendation</h2>

<ol>
<li>Peel the egg and cut it in half.</li>
<li>Remove the yolk and fill the egg with mustard, oil, salt and pepper.</li>
<li>Place the yolk on top.</li>
</ol>


<h2>Contribution</h2>

<ul>
<li>SvenT<a href="https://github.com/s8svtang">github</a></li>
</ul>


<p>;tags: snack german eggs pub</p>


guid: yt:video:Smm8lPLP4aM
title: David Holthouse on Confronting Childhood Abuser, After Once Plotting to Murder Him
author: PowerfulJRE
url: https://www.youtube.com/watch?v=Smm8lPLP4aM
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCzQUP1qoWDoEbmsQxvdjxgQ
content_mime_type: text/plain
content:
Taken from JRE #1646 w/David Holthouse:
https://open.spotify.com/episode/4UxbpaduzjFsb5hVx2LQqk?si=g7G7aQ-6Sqil7SdBhpuCVQ


guid: yt:video:IWpfgpIIkgg
title: A Batman Moment - JRE Toons
author: PowerfulJRE
url: https://www.youtube.com/watch?v=IWpfgpIIkgg
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCzQUP1qoWDoEbmsQxvdjxgQ
content_mime_type: text/plain
content:
Another hilarious moment animated by PaulyToon from the Joe Rogan Experience - Fight Breakdown - Mayweather vs. McGregor  - Now Available exclusively on Spotify - https://open.spotify.com/episode/4WpZvJWrWL5yH9yVPxk2wf?si=4Enuaed4RYCzefB4QVA1qQ


guid: yt:video:GbJgNNgt3Vw
title: Dave Chappelle on Getting the Rights to "Chappelle's Show"
author: PowerfulJRE
url: https://www.youtube.com/watch?v=GbJgNNgt3Vw
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCzQUP1qoWDoEbmsQxvdjxgQ
content_mime_type: text/plain
content:
Taken from JRE #1647 w/Dave Chappelle:
https://open.spotify.com/episode/6uCmb5wbprKYnpGwtktjgd?si=Gy_s7WmVT_mdkxm3lVc06A


guid: yt:video:T5x7lyWPnX8
title: Reggie Watts Explains NFT's to Joe
author: PowerfulJRE
url: https://www.youtube.com/watch?v=T5x7lyWPnX8
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCzQUP1qoWDoEbmsQxvdjxgQ
content_mime_type: text/plain
content:
Taken from JRE #1648 w/Reggie Watts:
https://open.spotify.com/episode/4Ct5bhOwlhgMSP77rBupIH?si=gUOqyo8MSkyiLvNqyhJN5Q


guid: yt:video:wh-LTVrdOPQ
title: Michael Easter on The Comfort Crisis
author: PowerfulJRE
url: https://www.youtube.com/watch?v=wh-LTVrdOPQ
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCzQUP1qoWDoEbmsQxvdjxgQ
content_mime_type: text/plain
content:
Taken from JRE #1649 w/Michael Easter:
https://open.spotify.com/episode/0OZrk81nGEPTk9KfeJbtaC?si=rGQyK0o0Sauk0qow9lF7sg


guid: yt:video:tK8YLq2LC4o
title: Joe on Canelo Alvarez vs. Billy Joe Saunders w/Russell Peters
author: PowerfulJRE
url: https://www.youtube.com/watch?v=tK8YLq2LC4o
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCzQUP1qoWDoEbmsQxvdjxgQ
content_mime_type: text/plain
content:
Taken from JRE #1650 w/Russell Peters:
https://open.spotify.com/episode/1GC9qr0mhi6wfJrKbzeL8W?si=RxASyJEbQMiouiTSKQ-S6Q


guid: yt:video:Z1eZxsPZZcE
title: Joe List's Scary Altercation in Downtown Austin
author: PowerfulJRE
url: https://www.youtube.com/watch?v=Z1eZxsPZZcE
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCzQUP1qoWDoEbmsQxvdjxgQ
content_mime_type: text/plain
content:
Taken from JRE #1651 w/Joe List:
https://open.spotify.com/episode/4byEJXRnOlFt8lxcBNz5vv?si=V6XW7OXsTzyhJAAY1tzX5w


guid: yt:video:gb3l1onK5LY
title: Anthony Cumia Reflects on the Impact of Opie & Anthony
author: PowerfulJRE
url: https://www.youtube.com/watch?v=gb3l1onK5LY
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCzQUP1qoWDoEbmsQxvdjxgQ
content_mime_type: text/plain
content:
Taken from JRE #1652 w/Anthony Cumia:
https://open.spotify.com/episode/6vjQnd6YhImZrJlse8V7wF?si=idbKbXmOSR2Q5eqTfPNhrg


guid: yt:video:kh3BLm2KYwg
title: Andy Norman on the Mental Immune System
author: PowerfulJRE
url: https://www.youtube.com/watch?v=kh3BLm2KYwg
feedurl: https://www.youtube.com/feeds/videos.xml?channel_id=UCzQUP1qoWDoEbmsQxvdjxgQ
content_mime_type: text/plain
content:
Taken from JRE #1653 w/Andy Norman:
https://open.spotify.com/episode/4o2EcXVdTAz9QuDNEjmp4O?si=OeFunk7dRXi3JPN2Ac0S5Q


guid: https://drewdevault.com/2013/08/19/You-dont-need-jQuery.html
title: You don't need jQuery
url: https://drewdevault.com/2013/08/19/You-dont-need-jQuery.html
feedurl: https://drewdevault.com/blog/index.xml
content:
<p>It&rsquo;s true. You really don&rsquo;t need jQuery. Modern web browsers can do most of what you want from jQuery,
without jQuery.</p>
<p>For example, take <a href="https://mediacru.sh">MediaCrush</a>. It&rsquo;s a website I spent some time working on with a friend.
It&rsquo;s actually quite sophisticated - drag-and-drop uploading, uploading via a hidden form, events wired up to
links and dynamically generated content, and ajax requests/file uploads, the whole she-bang. It does all of
that without jQuery. It&rsquo;s <a href="https://github.com/MediaCrush/MediaCrush">open source</a>, if you&rsquo;re looking for a good
example of how all of this can be used in the wild.</p>
<p>Let&rsquo;s walk through some of the things you like jQuery for, and I&rsquo;ll show you how to do it without.</p>
<h2 id="document-querying-with-css-selectors">Document Querying with CSS Selectors</h2>
<p>You like jQuery for selecting content. I don&rsquo;t blame you - it&rsquo;s really cool. Here&rsquo;s some code using jQuery:</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="nx">$</span><span class="p">(</span><span class="s1">&#39;div.article p&#39;</span><span class="p">).</span><span class="nx">addClass</span><span class="p">(</span><span class="s1">&#39;test&#39;</span><span class="p">);</span>
</code></pre></div><p>Now, here&rsquo;s how you can do it on vanilla JS:</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kd">var</span> <span class="nx">items</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelectorAll</span><span class="p">(</span><span class="s1">&#39;div.article p&#39;</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">items</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span>
    <span class="nx">items</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">classList</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="s1">&#39;test&#39;</span><span class="p">);</span>
</code></pre></div><p>Documentation: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document.querySelectorAll">querySelectorAll</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/API/element.classList">classList</a></p>
<p>This is, of course, a little more verbose. However, it&rsquo;s probably a lot simpler than you expected. Works in
IE 8 and newer - except for classList, which works in IE 10 and newer. You can instead use className, which is
a little less flexible, but still pretty easy to work with.</p>
<h2 id="ajax">Ajax</h2>
<p>You want to make requests in JavaScript. This is how you POST with jQuery:</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="nx">$</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s1">&#39;/path/to/endpoint&#39;</span><span class="p">,</span> <span class="p">{</span>
    <span class="nx">parameter</span><span class="o">:</span> <span class="nx">value</span>
    <span class="nx">otherParameter</span><span class="o">:</span> <span class="nx">otherValue</span>
<span class="p">},</span>
<span class="nx">success</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">alert</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
<span class="p">});</span>
</code></pre></div><p>Here&rsquo;s the same code, without jQuery:</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kd">var</span> <span class="nx">xhr</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">XMLHttpRequest</span><span class="p">();</span> <span class="c1">// A little deceptively named
</span><span class="c1"></span><span class="nx">xhr</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span><span class="s1">&#39;POST&#39;</span><span class="p">,</span> <span class="s1">&#39;/path/to/endpoint&#39;</span><span class="p">);</span>
<span class="nx">xhr</span><span class="p">.</span><span class="nx">onload</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="nx">alert</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">responseText</span><span class="p">);</span>
<span class="p">};</span>
<span class="kd">var</span> <span class="nx">formData</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">FormData</span><span class="p">();</span>
<span class="nx">formData</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="s1">&#39;parameter&#39;</span><span class="p">,</span> <span class="nx">value</span><span class="p">);</span>
<span class="nx">formData</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="s1">&#39;otherParameter&#39;</span><span class="p">,</span> <span class="nx">value</span><span class="p">);</span>
<span class="nx">xhr</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">formData</span><span class="p">);</span>
</code></pre></div><p>Documentation: <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a></p>
<p>Also a bit more verbose than jQuery, but much simpler than you might&rsquo;ve expected. Now here&rsquo;s the real kicker:
It works in IE 7, and IE 5 with a little effort. IE actually pioneered XHR.</p>
<h2 id="animations">Animations</h2>
<p>This is where it starts to get more subjective and breaks backwards compatability. Here&rsquo;s my opinion on the
matter of transitions: dropping legacy browser support for fancy animations is acceptable. I don&rsquo;t think it&rsquo;s
a problem if your website isn&rsquo;t pretty and animated on older browsers. Keep that in mind as we move on.</p>
<p>I want to animate the opacity of a <code>.foobar</code> when you hover over it. With jQuery:</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="nx">$</span><span class="p">(</span><span class="s1">&#39;.foobar&#39;</span><span class="p">).</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;mouseenter&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">animate</span><span class="p">({</span>
        <span class="nx">opacity</span><span class="o">:</span> <span class="mf">0.5</span>
    <span class="p">},</span> <span class="mi">2000</span><span class="p">);</span>
<span class="p">}).</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;mouseleave&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">animate</span><span class="p">({</span>
        <span class="nx">opacity</span><span class="o">:</span> <span class="mi">1</span>
    <span class="p">},</span> <span class="mi">2000</span><span class="p">);</span>
<span class="p">});</span>
</code></pre></div><p>Without jQuery, I wouldn&rsquo;t do this in Javascript. I&rsquo;d use the magic of CSS animations:</p>
<div class="highlight"><pre class="chroma"><code class="language-css" data-lang="css"><span class="p">.</span><span class="nc">foobar</span> <span class="p">{</span>
    <span class="k">transition</span><span class="p">:</span> <span class="k">opacity</span> <span class="mi">2</span><span class="kt">s</span> <span class="kc">linear</span><span class="p">;</span>
<span class="p">}</span>

<span class="p">.</span><span class="nc">foobar</span><span class="p">:</span><span class="nd">hover</span> <span class="p">{</span>
    <span class="k">opacity</span><span class="p">:</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><p class="foobar">Hover over this text</p>
<style>.foobar{transition:opacity 2s linear;font-weight:bold;}.foobar:hover{opacity:0.5;}</style>
<p>Documentation: <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Using_CSS_animations">CSS animations</a></p>
<p>Much better, eh? Works in IE 10+. You can do much more complicated animations with CSS, but I can&rsquo;t think of
a good demo, so that&rsquo;s an exercise left to the reader.</p>
<h2 id="tree-traversal">Tree traversal</h2>
<p>jQuery lets you navigate a tree pretty easily. Let&rsquo;s say you want to find the container of a button and remove
all .foobar elements underneath it, upon clicking the button.</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="nx">$</span><span class="p">(</span><span class="s1">&#39;#mybutton&#39;</span><span class="p">).</span><span class="nx">click</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">parent</span><span class="p">().</span><span class="nx">children</span><span class="p">(</span><span class="s1">&#39;.foobar&#39;</span><span class="p">).</span><span class="nx">remove</span><span class="p">();</span>
<span class="p">});</span>
</code></pre></div><p>Nice and succinct. I&rsquo;m sure you can tell the theme so far - the main advantage of jQuery is a less verbose
syntax. Here&rsquo;s how it&rsquo;s done without jQuery:</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">&#39;mybutton&#39;</span><span class="p">).</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;click&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="nx">foobars</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">parentElement</span><span class="p">.</span><span class="nx">querySelectorAll</span><span class="p">(</span><span class="s1">&#39;.foobar&#39;</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">foobars</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">parentElement</span><span class="p">.</span><span class="nx">removeChild</span><span class="p">(</span><span class="nx">foobars</span><span class="p">[</span><span class="nx">i</span><span class="p">]);</span>
<span class="p">},</span> <span class="kc">false</span><span class="p">);</span>
</code></pre></div><p>A little wordier, but not so bad. Works in IE 9+ (8+ if you don&rsquo;t use addEventListener).</p>
<h2 id="in-conclusion">In conclusion</h2>
<p>jQuery is, of course, based on JavaScript, and as a result, anything jQuery can do can be done without jQuery.
Feel free to <a href="mailto:sir@cmpwn.com">ask me</a> if you&rsquo;re curious about how I&rsquo;d do something else without jQuery.</p>
<p>I feel like adding jQuery is one of the first things a web developer does to their shiny new website. It just
isn&rsquo;t really necessary in this day and age. That extra request, 91kb, and load time are probably negligible,
but it&rsquo;s still a little less clean than it could be. There&rsquo;s no need to go back and rid all of your projects of
jQuery, but I&rsquo;d suggest that for your next one, you try to do without. Keep MDN open in the next tab over and
I&rsquo;m sure you&rsquo;ll get through it fine.</p>


guid: https://drewdevault.com/2013/08/24/Music-syncing-on-Android.html
title: Custom Music Syncing on Android
url: https://drewdevault.com/2013/08/24/Music-syncing-on-Android.html
feedurl: https://drewdevault.com/blog/index.xml
content:
<p>I have an HTC One, with CyanogenMod installed. I usually use Spotify, but I&rsquo;ve been wanting to move away from it for a while.
The biggest thing keeping me there was the ease of syncing up with my phone - I added music on my PC and it just showed up
on my phone.</p>
<p>So, I finally decided to make it work on my phone without Spotify. You might have success if you aren&rsquo;t using CyanogenMod,
but you definitely need to be rooted and you need to access a root shell on your phone. I was using <code>adb shell</code> to start with,
but it has poor terminal emulation. Instead, I ended up installing an SSH daemon on the phone and just using that. Easier to
use vim in such an enviornment.</p>
<p>The end result is that a cronjob kicks off each hour on my phone and runs a script that uses rsync to sync up my phone&rsquo;s music
with my desktop&rsquo;s music. That&rsquo;s another thing - a prerequisite of this working is that you have to expose your music to the
outside world on an SSH server somewhere.</p>
<p>I&rsquo;ll tell you how I got it working, then you can see if it works for you. It might take some effort on your part to tweak
these instructions to fit your requirements.</p>
<h2 id="sanity-checks">Sanity checks</h2>
<p>Get into your phone&rsquo;s shell and make sure you have basic things installed. You&rsquo;ll need to make sure you have:</p>
<ul>
<li>bash</li>
<li>cron</li>
<li>ssh</li>
<li>rsync</li>
</ul>
<p>If you don&rsquo;t have them, you can probably get them by installing busybox.</p>
<h2 id="setting-up-ssh">Setting up SSH</h2>
<p>We need to generate a key. I tried using ssh-keygen before, but it had problems with rsync on Android. Instead, we use
dropbearkey. Generate your key with <code>dropbearkey -t rsa -f /data/.ssh/id_rsa</code>. You&rsquo;ll see the public key echoed to stdout.
It&rsquo;s not saved anywhere for you, so grab it out of your shell and put it somewhere - namely, in the authorized_keys file
on the SSH server you plan to pull music from.</p>
<p>At this point, you can probably SSH into the server you want to pull from. Run <code>ssh -i /data/.ssh/id_rsa &lt;your server here&gt;</code>
to double check. Note that this isn&rsquo;t just for fun - you need to do this to get your server into known_hosts, so we can
non-interactively access it.</p>
<h2 id="making-android-more-sane">Making Android more sane</h2>
<p>Now that this is working, we need to clean up a little before cron will run right. Android is only a &ldquo;Linux&rdquo; system in the
sense that <code>uname</code> outputs &ldquo;Linux&rdquo;. It grossly ignores the FHS and you need to fix it a little. Figure out how to do a
nice init.d script on your phone. For my CyanogenMod install, I can add scripts to <code>/data/local/userlocal.d/</code> and they&rsquo;ll
be run at boot. Here&rsquo;s my little script for making Android a little more sane:</p>
<div class="highlight"><pre class="chroma"><code class="language-bash" data-lang="bash"><span class="cp">#!/system/bin/sh
</span><span class="cp"></span><span class="c1"># Making /system rw isn&#39;t strictly needed</span>
mount -o remount,rw /system
mount -o remount,rw /
ln -s /data/var /var
ln -s /system/bin /bin
ln -s /data/.ssh /.ssh
crond
</code></pre></div><h2 id="update-script-and-initial-import">Update script and initial import</h2>
<p>The following is the script we&rsquo;ll use to update your phone&rsquo;s music library.</p>
<div class="highlight"><pre class="chroma"><code class="language-bash" data-lang="bash"><span class="cp">#!/system/xbin/bash
</span><span class="cp"></span><span class="c1"># Syncs music between a remote computer and this phone</span>
<span class="nv">RHOST</span><span class="o">=</span>&lt;remote hostname&gt;
<span class="nv">EHOST</span><span class="o">=</span>&lt;fallback, I use this <span class="k">for</span> connecting from outside my LAN&gt;
<span class="nv">RPORT</span><span class="o">=</span><span class="m">22</span>
<span class="nv">RUSER</span><span class="o">=</span>&lt;username&gt;
<span class="nv">ID</span><span class="o">=</span>/data/.ssh/id_rsa
<span class="nv">RPATH</span><span class="o">=</span>/path/to/your/remote/music
<span class="c1"># Omit the final directory. On my setup, this goes to /sdcard/Music, and my remote is /home/sircmpwn/Music</span>
<span class="nv">LPATH</span><span class="o">=</span>/sdcard

<span class="nb">echo</span> <span class="k">$(</span>date<span class="k">)</span> &gt;&gt; /var/log/update-music.log

rsync -ruvL --delete --rsh<span class="o">=</span><span class="s2">&#34;ssh -p </span><span class="nv">$RPORT</span><span class="s2"> -i </span><span class="nv">$ID</span><span class="s2">&#34;</span> <span class="nv">$RUSER</span>@<span class="nv">$RHOST</span>:<span class="nv">$RPATH</span> <span class="nv">$LPATH</span> &gt;&gt; /var/log/update-music-rsync-so.log 2&gt;<span class="p">&amp;</span><span class="m">1</span>
<span class="k">if</span> <span class="o">[[</span> <span class="nv">$?</span> !<span class="o">=</span> <span class="m">0</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
    rsync -ruvL --delete --rsh<span class="o">=</span><span class="s2">&#34;ssh -p </span><span class="nv">$RPORT</span><span class="s2"> -i </span><span class="nv">$ID</span><span class="s2">&#34;</span> <span class="nv">$RUSER</span>@<span class="nv">$EHOST</span>:<span class="nv">$RPATH</span> <span class="nv">$LPATH</span> &gt;&gt; /var/log/update-music-rsync-so.log 2&gt;<span class="p">&amp;</span><span class="m">1</span>
<span class="k">fi</span>
</code></pre></div><p>Save this script to <code>/data/updateMusic</code>, make it executable with <code>chmod +x /data/updateMusic</code>, then run the initial import
with <code>/data/updateMusic</code>. After a while, you&rsquo;ll have all your computer&rsquo;s music on your phone. Now, we just need to make it
update automatically.</p>
<p>Note: I set up a couple of logs for you. <code>/var/log/update-music.log</code> has the timestamp of every time it did an update. Also,
<code>/var/log/update-music-rsync-so.log</code> has the output of rsync from each run.</p>
<h2 id="cron">Cron</h2>
<p>Finally, we need to set up a cronjob. If you followed the instructions so far (and if you&rsquo;re lucky), you should have everything
ready for cron. The biggest pain in my ass was getting cron to coorperate, but the init script earlier should take care of
that. Run <code>crontab -e</code> and write your crontab:</p>
<pre><code>0 * * * * /data/updateMusic
</code></pre>
<p>Nice and simple. Your phone will now sync up your music every hour, on the hour, with your home computer. Here are some
possible points for improvement:</p>
<ul>
<li>Check wlan0 and only sync if it&rsquo;s up</li>
<li>Log cron somewhere</li>
<li>Alter the update script to do a little bit better about the &ldquo;fallback&rdquo;</li>
<li>Sync more than just music</li>
</ul>
<p>After all of this, I now have a nice setup that syncs music to my phone so I can listen to it with Apollo. I might switch
away from Apollo, though, it&rsquo;s pretty buggy. <a href="mailto:sir@cmpwn.com">Let me know</a> if you can suggest an alternative music
player, or if you get stuck working through this procedure yourself.</p>


guid: https://drewdevault.com/2014/02/02/The-worst-bugs.html
title: The bug that hides from breakpoints
url: https://drewdevault.com/2014/02/02/The-worst-bugs.html
feedurl: https://drewdevault.com/blog/index.xml
content:
<p>This is the story of the most difficult bug I ever had to solve. See if you can
figure it out before the conclusion.</p>
<h3 id="background">Background</h3>
<p>For some years now, I&rsquo;ve worked on a kernel for Texas
Instruments calculators called <a href="https://github.com/KnightOS/kernel">KnightOS</a>.
This kernel is written entirely in assembly, and targets the old-school z80
processor from back in 1976. This classic processor was built without any
concept of protection rings. It&rsquo;s an 8-bit processor, with 150-some instructions
and (in this application) 32K of RAM and 32K of Flash. This stuff is so old, I
ended up writing most of the KnightOS toolchain from scratch rather than try to
get archaic assemblers and compilers running on modern systems.</p>
<p>When you&rsquo;re working in an enviornment like this, there&rsquo;s no seperation between
kernel and userland. All &ldquo;userspace&rdquo; programs run as root, and crashing the entire
system is a simple task. All the memory my kernel sets aside for the
process table, or memory ownership, file handles, stacks, any other executing
process - any program can modify this freely. Of course, we have to rely on the
userland to play nice, and it usually does. But when there are bugs, they can be a
real pain in the ass to hunt down.</p>
<h3 id="the-elusive-bug">The elusive bug</h3>
<p>The original bug report: <strong>When running the counting demo and switching between
applications, the thread list graphics become corrupted.</strong></p>
<p>I can reproduce this problem, so I settle into my development enviornment and I
set a breakpoint near the thread list&rsquo;s graphical code. I fire up the emulator and
repeat the steps&hellip; but it doesn&rsquo;t happen. This happened consistently: <strong>the bug
was not reproduceable when a breakpoint was set</strong>. Keep in mind, I&rsquo;m running this
in a z80 emulator, so the enviornment is supposedly no different. There&rsquo;s no
debugger attached here.</p>
<p>Though this is quite strange, I don&rsquo;t immediately despair. I try instead setting a
&ldquo;breakpoint&rdquo; by dropping an infinite loop in the code, instead of a formal
breakpoint. I figure that I can halt the program flow manually and open the
debugger to inspect the problem. However, the bug wouldn&rsquo;t be tamed quite so
easily. The bug was unreproducable when I had this psuedo-breakpoint in place,
too.</p>
<p>At this point, I started to get a little frustrated. How do I debug a problem that
disappears when you debug it? I decided to try and find out what caused it after
it had taken place, by setting the breakpoint to be hit only after the graphical
corruption happened. Here, I gained some ground. I was able to reproduce it, and
<em>then</em> halt the machine, and I could examine memory and such after the bug was
given a chance to have its way over the system.</p>
<p>I discovered the reason the graphics were being corrupted. The kernel kept the
length of the process table at a fixed address. The thread list, in order to draw
the list of active threads, looks to this value to determine how many threads it
should draw. Well, when the bug occured, the value was too high! The thread list
was drawing threads that did not exist, and the text rendering puked non-ASCII
characters all over the display. But why was that value being corrupted?</p>
<p>It was an oddly specific address to change. None of the surrounding memory was
touched. Making it even more odd was the very specific conditions this happened
under - only when the counting demo was running. I asked myself, &ldquo;what makes the
counting demo unique?&rdquo; It hit me after a moment of thought. The counting demo
existed to demonstrate non-supsendable threads. The kernel would stop executing
threads (or &ldquo;suspend&rdquo; them) when they lost focus, in an attempt to keep the
system&rsquo;s very limited resources available. The counting demo was marked as
non-suspendable, a feature that had been implemented a few months prior. It
showed a number on the screen that counted up forever, and the idea was that you
could go give some other application focus, come back, and the number would have
been counting up while you were away. A background task, if you will.</p>
<p>A more accurate description of the bug emerged: &ldquo;the length of the kernel process
table gets corrupted when launching the thread list when a non-suspendable thread
is running&rdquo;. What followed was hours and hours of crawling through the hundreds of
lines of assembly between summoning the thread list, and actually seeing it. I&rsquo;ll
spare you the details, because they are very boring. We&rsquo;ll pick the story back up
at the point where I had isolated the area in which it occured: applib.</p>
<p>The KnightOS userland offered &ldquo;applib&rdquo;, a library of common functions applications
would need to get the general UX of the system. Among these was the function
<code>applibGetKey</code>, which was a wrapper around the kernel&rsquo;s <code>getKey</code> function. The
idea was that it would work the same way (return the last key pressed), but for
special keys, it would do the appropriate action for you. For example, if you
pressed the F5 key, it would suspend the current thread and launch the thread
list. This is the mechanism with which most applications transfer control out of
their own thread and into the thread list.</p>
<p>Eager that I had found the source of the issue, I placed a breakpoint nearby. That
same issue from before struck again - the bug vanished when the breakpoint was
set. I tried a more creative approach: instead of using a proper breakpoint, I
asked the emulator to halt whenever that address was written to. Even still - the
bug hid itself whenever this happened.</p>
<p>I decided to dive into the kernel&rsquo;s getKey function. Here&rsquo;s the start of the
function, as it appeared at the time:</p>
<pre><code>getKey:
    call hasKeypadLock
    jr _
    xor a
    ret
_:  push bc
; ...
</code></pre><p>I started going through this code line-by-line, trying to see if there was
anything here that could concievably touch the thread table. I noticed a minor
error here, and corrected it without thinking:</p>
<pre><code>getKey:
    call hasKeypadLock
    jr z, _
    xor a
    ret
_:  push bc
; ...
</code></pre><p>The simple error I had corrected: getKey was pressing forward, even when the
current thread didn&rsquo;t have control of the keyboard hardware. This was a silly
error - only two characters were omitted.</p>
<p>A moment after I fixed that issue, the answer set in - this was the source of the
entire problem. Confirming it, I booted up the emulator with this change applied
and the bug was indeed resolved.</p>
<p>Can you guess what happened here? Here&rsquo;s the other piece of the puzzle to help you
out, translated more or less into C for readability:</p>
<div class="highlight"><pre class="chroma"><code class="language-c" data-lang="c"><span class="kt">int</span> <span class="nf">applibGetKey</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">key</span> <span class="o">=</span> <span class="n">getKey</span><span class="p">();</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">key</span> <span class="o">==</span> <span class="n">KEY_F5</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">launch_threadlist</span><span class="p">();</span>
        <span class="n">suspend_thread</span><span class="p">();</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">key</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><p>Two more details you might not have picked up on:</p>
<ul>
<li>applibGetKey is non-blocking</li>
<li>suspend_thread suspends the current thread immediately, so it doesn&rsquo;t return until the
thread resumes.</li>
</ul>
<h3 id="the-bug-uncovered">The bug, uncovered</h3>
<p>Here&rsquo;s what actually happened. For most threads (the suspendable kind), that
thread stops processing when <code>suspend_thread()</code> is called. The usually
non-blocking applibGetKey function blocks until the thread is resumed in this
scenario. However, the counting demo was <em>non-suspendable</em>. The suspend_thread
function has no effect, by design. So, suspend_thread did not block, and the
keypress was returned straight away. By this point, the thread list had launched
properly and it was given control of the keyboard.</p>
<p>However, the counting demo went back into its main loop, and started calling
applibGetKey again. Since the average user&rsquo;s finger remained pressed against the
button for a few moments more, applibGetKey <em>continued to launch the thread list,
over and over</em>. The thread list itself is a special thread, and it doesn&rsquo;t
actually have a user-friendly name. It was designed to ignore itself when it drew
the active threads. However, it was <em>not</em> designed to ignore other instances of
itself, the reason being that there would never be two of them running at once.
When attempting to draw these other instances, the thread list started rendering
text that wasn&rsquo;t there, causing the corruption.</p>
<p>This bug vanished whenever I set a breakpoint because it would halt the system&rsquo;s
keyboard processing logic. I lifted my finger from the key before allowing it to
move on.</p>
<p>The solution was to make the kernel&rsquo;s getKey function respect hardware locks by
fixing that simple, two-character typo. That way, the counting demo, which had no
right to know what keys were being pressed, would not know that they key was still
being pressed.</p>
<p>The debugging described by this blog post took approximately three weeks.</p>
<p><a href="https://news.ycombinator.com/item?id=7688700">Discussion on Hacker News</a></p>


guid: https://drewdevault.com/2014/02/25/Hacking-on-your-TI-calculator.html
title: Hacking on your TI calculator
url: https://drewdevault.com/2014/02/25/Hacking-on-your-TI-calculator.html
feedurl: https://drewdevault.com/blog/index.xml
content:
<p>I&rsquo;ve built the <a href="https://github.com/KnightOS/kernel">KnightOS kernel</a>, an open-source OS that runs on
several TI calculator models, including the popular TI-83+ family, and recently the new TI-84+ Color
Silver Edition. I have published some information on how to build your own operating sytsems for these
devices, but I&rsquo;ve learned a lot since then and I&rsquo;m writing this blog post to include the lessons I&rsquo;ve
learned from other attempts.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>Coming into this, you should be comforable with z80 assembly. It&rsquo;s possible to write an OS for these
devices in C (and perhaps other high-level languages), but proficiency in z80 assembly is still
required. Additionally, I don&rsquo;t consider C a viable choice for osdev on these devices when you
consider that the available compliers do not optimize the result very well, and these devices have
very limited resources.</p>
<p>You will also have to be comfortable (though not neccessarily expert-level) with these tools:</p>
<ul>
<li>make</li>
<li>The assembler of your choice</li>
<li>The toolchain of your choice</li>
</ul>
<p>I&rsquo;m going to gear this post from the perspective of a Linux user, but Windows users should be able to
do fine with cygwin. If you&rsquo;re looking for a good assembler, I suggest
<a href="https://github.com/KnightOS/sass">sass</a>, the assembler KnightOS uses. I built it myself to address
the needs of the kernel, and it includes several nice features that make it easier to maintain such a
large and complex codebase. Other good choices include
<a href="https://wabbit.codeplex.com/releases/view/45088">spasm</a> and
<a href="https://code.google.com/p/brass-assembler/">brass</a>.</p>
<p>For your toolchain, there are a few options, but I&rsquo;ve built custom tools that work well for KnightOS
and should fit into your project as well. You need to accomplish a couple of tasks:</p>
<ul>
<li><a href="https://github.com/KnightOS/MakeROM">Create ROM files from assembler output</a></li>
<li><a href="https://github.com/KnightOS/CreateUpgrade">Create OS upgrades from ROM files</a></li>
</ul>
<p>You also need the <a href="http://brandonw.net/calculators/keys/">cryptographic signing keys</a> for any of the
calculators you intend to support. There are ways to get around using these (which you&rsquo;ll need to
research for the TI-84+ CSE, for example) that you may want to look into. These keys will allow you
to add a cryptographic signature on your OS upgrades that will make your calculator think it&rsquo;s an
official Texas Instruments operating system, and you will be able to send it to the device. The
CreateUpgrade tool linked above produces signed upgrade files for you, but if you choose to use other
tools you may need to find a seperate signing tool.</p>
<p>Additonally, if you target devices with a newer boot code, you&rsquo;ll have to reflash your boot code or
use a tool like <a href="http://brandonw.net/calcstuff/uosrecv.zip">UOSRECV</a> to send your OS to an actual
device.</p>
<h2 id="what-youre-getting-into">What you&rsquo;re getting into</h2>
<p>You will be replacing everything on the calculator with your own system (though if you want to retain
compatability with TIOS like <a href="http://brandonw.net/calculators/OS2/">OS2</a> tried to, feel free). You&rsquo;ll
need to do <em>everything</em>, including common things like providing your own multiplication functions, or
drawing functions, or anything else. You&rsquo;ll also be responsible for initializing the calculator and
all of the hardware you want to use (such as the LCD or keypad).</p>
<p>That being said, you can take some code from projects like the KnightOS kernel to help you out. The
KnightOS kernel is open sourced under the MIT license, which means you&rsquo;re free to take any code from
it and use it in your own project. I also strongly suggest using it as a reference for when you get
stuck.</p>
<p>The advantage to taking on this task is that you can leverage the full potential of these devices.
What you&rsquo;re building for is a 6/15 MHz z80 with 32K or more of RAM, plus plenty of Flash and all
sorts of fun hardware. You can also build something that frees your device of proprietary code, if
that is what you are interested in (though the proprietary boot code would remain - but that&rsquo;s a
story for another day).</p>
<p>If you plan on making a full blown operating systems that can run arbituary programs and handle all
sorts of fun things, you&rsquo;ll want to make sure you have a strong understanding of programming in
general, as well as solid algorithmic knowledge and low-level knowledge. If you don&rsquo;t know how to
use pointers or bit math, or don&rsquo;t fully understand the details of the device, you may want to try
again when you do. That being said, I didn&rsquo;t know a lot when I started KnightOS (as the community was
happy to point out), and now I feel much more secure in my skills.</p>
<h2 id="building-the-basic-os">Building the basic OS</h2>
<p>We&rsquo;ll build a simple OS here to get you started, including booting the thing up and showing a
simple sprite on the screen. First, we&rsquo;ll create a simple Makefile. This OS will run on the
TI-73, TI-83+, TI-83+ SE, TI-84+, TI-84+ SE, and TI-84+ CSE, as well as the French variations
on these devices.</p>
<p><a href="https://drewdevault.com/demo_os.tar.gz">Grab this tarball</a> with the basic OS to get started. It looks like this:</p>
<pre><code>.
├── build
│   ├── CreateUpgrade.exe
│   ├── MakeROM.exe
│   └── sass.exe
├── inc
│   └── platforms.inc
├── Makefile
└── src
    ├── 00
    │   ├── base.asm
    │   ├── boot.asm
    │   ├── display.asm
    │   └── header.asm
    └── boot
        └── base.asm
</code></pre>
<p>If you grab this, run <code>make all</code> and you&rsquo;ll get a bunch of ROM files in the <code>bin</code> directory.
I&rsquo;ll explain a little bit about how it works. The important file here is <code>boot.asm</code>, but I
encourage you to read whatever else you feel like - especially the Makefile.</p>
<h3 id="miscellaneous-files">Miscellaneous Files</h3>
<p>Here is the purpose of each file, save for boot.asm (which gets its own section later):</p>
<ul>
<li>The makefile is like a script for building the OS. You should probably learn how these work
if you don&rsquo;t already.</li>
<li>Everything in build/ is part of the suggested toolchain.</li>
<li>The inc folder can be #included to, and includes <code>platforms.inc</code>, which defines a bunch of
useful constants for you.</li>
<li><code>base.asm</code> is just a bunch of #include statements, for linking without a linker</li>
<li><code>display.asm</code> has some useful display code I pulled out of KnightOS</li>
<li><code>header.asm</code> contains the OS header and RST list</li>
</ul>
<h3 id="bootasm">boot.asm</h3>
<p>The real juciy stuff is boot.asm. This file initializes everything and draws a smiley face
in the middle of the screen. Here&rsquo;s what it does (in order):</p>
<ol>
<li>Disable interrupts</li>
<li>Set up memory mappings</li>
<li>Create a stack and set SP accordingly</li>
<li>Initialize the LCD (B&amp;W or color)</li>
<li>Draw a smiley face</li>
</ol>
<p>I&rsquo;m sure your OS will probably want to do more interesting things. The KnightOS kernel, for
example, adds on top of this a bunch of kernel state initialization, filesystem initialization,
and loads up a boot program.</p>
<p><code>boot.asm</code> is well-commented and I encourage you to read through it to get an idea of what
needs to be done. The most complicated and annoying bit is the color LCD initialization, which is
mostly in <code>display.asm</code>.</p>
<p>I encourage you to spend some time playing with this. Bring in more things and try to build
something simple. Remember, you have no bcalls here. You need to build everything yourself.</p>
<h2 id="resources">Resources</h2>
<p>There are several things you might want to check out. The first and most obvious is
<a href="http://wikiti.brandonw.net/index.php?title=Calculator_Documentation">WikiTI</a>. I don&rsquo;t use much
here except for the documentation on I/O ports, and you&rsquo;ll find it useful, too.</p>
<p>The rest of the resources here are links to code in the KnightOS kernel.</p>
<p>The <a href="https://github.com/KnightOS/kernel/blob/master/src/00/interrupt.asm#L19">interrupt handler</a>
is a good reference for anyone wanting to work with interrupts to do things like handle the ON
button, link activity, or timers. One good use case here (and what KnightOS uses it for) is
preemptive multitasking. Note that you might want to use <code>exx</code> and <code>ex af, af'</code> instead of
pushing all the registers like KnightOS does. Take special note of how we handle USB activity.</p>
<p>You might want to consider offering some sort of color LCD compatabilty mode like KnightOS does.
This allows you to treat it like a black &amp; white screen. The relevant code is
<a href="https://github.com/KnightOS/kernel/blob/master/src/00/display-color.asm">here</a>.</p>
<p>If you want to interact with the keyboard, you&rsquo;ll probably want to reference the KnightOS
keyboard code <a href="https://github.com/KnightOS/kernel/blob/master/src/00/keyboard.asm">here</a>. You
might also consider working out an interrupt-based keyboard driver.</p>
<p>If you&rsquo;d like to manipulate Flash, you need to run most of it from RAM. You will probably want
to reference the <a href="https://github.com/KnightOS/kernel/blob/master/src/00/flash.asm">KnightOS Flash driver</a>.</p>
<h2 id="skipping-to-the-good-part">Skipping to the good part</h2>
<p>It&rsquo;s entirely possible to avoid writing an entire system by yourself. If you want to dive right
in and start immediately making something cool, you might consider grabbing the KnightOS kernel.
Right off the bat, you&rsquo;ll get:</p>
<ul>
<li>A tree-based filesystem</li>
<li>Multitasking and IPC</li>
<li>Memory management</li>
<li>A standard library (math, sorting, etc)</li>
<li>Library support</li>
<li>Hardware drivers for the keyboard, displays, etc</li>
<li>Color and monochrome graphics (and a compatability layer)</li>
<li>A font and text rendering</li>
<li><a href="http://www.knightos.org/documentation.html">Great documentation</a></li>
<li>Full support for 9 calculator models</li>
</ul>
<p>The kernel is standalone and open-source, and it runs great without the KnightOS userspace.
If you&rsquo;re interested in that, you can get started <a href="https://github.com/KnightOS/kernel">on GitHub</a>.
We&rsquo;d also love some contributors, if you want to help make the kernel even better.</p>
<h2 id="closing-thoughts">Closing thoughts</h2>
<p>I hope to see a few cool OSes come into being in the TI world. It&rsquo;s unfortunately sparse in that
regard. If you run into any problems, feel free to drop by #knightos on irc.freenode.net, where
I&rsquo;m sure myself or someone else can help answer your questions. Good luck!</p>


guid: https://drewdevault.com/2014/06/07/Why-Go-error-handling-doesnt-sit-right-with-me.html
title: Go's error handling doesn't sit right with me
url: https://drewdevault.com/2014/06/07/Why-Go-error-handling-doesnt-sit-right-with-me.html
feedurl: https://drewdevault.com/blog/index.xml
content:
<p>I&rsquo;ll open up by saying that I am not a language designer, and I do like a lot of
things about Go. I just recently figured out how to describe why Go&rsquo;s error
handling mechanics don&rsquo;t sit right with me.</p>
<p>If you aren&rsquo;t familiar with Go, here&rsquo;s an example of how Go programmers might do
error handling:</p>
<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="nx">result</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nf">SomethingThatMightGoWrong</span><span class="p">()</span>
<span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
    <span class="c1">// Handle error
</span><span class="c1"></span><span class="p">}</span>
<span class="c1">// Proceed
</span></code></pre></div><p>Let&rsquo;s extrapolate this:</p>
<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">MightFail</span><span class="p">()</span> <span class="p">{</span>
    <span class="nx">result</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nf">doStuffA</span><span class="p">()</span>
    <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
        <span class="c1">// Error handling omitted
</span><span class="c1"></span>    <span class="p">}</span>
    <span class="nx">result</span><span class="p">,</span> <span class="nx">err</span> <span class="p">=</span> <span class="nf">doStuffB</span><span class="p">()</span>
    <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
        <span class="c1">// Error handling omitted
</span><span class="c1"></span>    <span class="p">}</span>
    <span class="nx">result</span><span class="p">,</span> <span class="nx">err</span> <span class="p">=</span> <span class="nf">doStuffC</span><span class="p">()</span>
    <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
        <span class="c1">// Error handling omitted
</span><span class="c1"></span>    <span class="p">}</span>
    <span class="nx">result</span><span class="p">,</span> <span class="nx">err</span> <span class="p">=</span> <span class="nf">doStuffD</span><span class="p">()</span>
    <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
        <span class="c1">// Error handling omitted
</span><span class="c1"></span>    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div><p>Go has good intentions by removing exceptions. They add a lot of overhead and
returning errors isn&rsquo;t a bad thing in general. However, I spend a lot of my time
writing assembly. Assembly can use similar mechanics, but I&rsquo;m spoiled by it (I
know, spoiled by assembly?) and I can see how Go could have done better. In
assembly, <code>goto</code> (or instructions like it) are the only means you have of
branching. It&rsquo;s not like other languages where it&rsquo;s taboo - you pretty much <em>have</em>
to use it. Most assembly also makes it fancy and conditional. For example:</p>
<pre><code>goto condition, label
</code></pre>
<p>This would jump to <code>label</code> given that <code>condition</code> is met. Like Go, assembly
generally doesn&rsquo;t have exceptions or anything similar. In my own personal flavor
of assembly, I have my functions return error codes as well.  Here&rsquo;s how it&rsquo;s
different, though. Let&rsquo;s look at some code:</p>
<pre><code>call somethingThatMightFail
jp nz, errorHandler
call somethingThatMightFailB
jp nz, errorHandler
call somethingThatMightFailC
jp nz, errorHandler
call somethingThatMightFailD
jp nz, errorHandler
</code></pre><p>The difference here is that all functions return errors in the same way - by
resetting the Z flag. If that flag is set, we do a quick branch (the <code>jp</code>
instruction is short for <code>jump</code>) to the error handler. It&rsquo;s not clear from looking
at this snippet, but the error code is stored in the A register, which the
<code>errorHandler</code> recognizes as an error code and shows an appropriate message for.
We can have one error handler for an entire procedure, and it feels natural.</p>
<p>In Go, you have to put an if statement here. Each error caught costs you three
lines of code in the middle of your important logic flow. With languages that
throw exceptions, you have all the logic in a readable procedure, and some error
handling at the end of it all. With Go, you have to throw a bunch of
3-line-minimum error handlers all over the middle of your procedure.</p>
<p>In my examples, you can still return errors like this, but you can do so with a
lot less visual clutter. One line of error handling is better than 3 lines, if you
ask me. Also, no one gives a damn how you format assembly code, so if you wanted
to do something like this you&rsquo;d be fine:</p>
<pre><code>call somethingThatMightFail
  jp nz, errorHandler
call somethingThatMightFailB
  jp nz, errorHandler
call somethingThatMightFailC
  jp nz, errorHandler
call somethingThatMightFailD
  jp nz, errorHandler
</code></pre><p>Or something like this:</p>
<pre><code>call somethingThatMightFail  \ jp nz, errorHandler
call somethingThatMightFailB \ jp nz, errorHandler
call somethingThatMightFailC \ jp nz, errorHandler
call somethingThatMightFailD \ jp nz, errorHandler
</code></pre><p>The point is, I think Go&rsquo;s error handling stuff make your code harder to read and
more tedious to write. The basic idea - return errors instead of throwing them -
has good intentions. It&rsquo;s just that how they&rsquo;ve done it isn&rsquo;t so great.</p>


guid: https://drewdevault.com/2014/06/28/Python-datetime-sucks.html
title: Python's datetime sucks
url: https://drewdevault.com/2014/06/28/Python-datetime-sucks.html
feedurl: https://drewdevault.com/blog/index.xml
content:
<p>I&rsquo;ve been playing with Python for about a year now, and I like pretty much
everything about it. There&rsquo;s one thing that&rsquo;s really rather bad and really should
not be that bad, however - date &amp; time support. It&rsquo;s ridiculous how bad it is in
Python. This is what you get with the standard datetime module:</p>
<ul>
<li>The current time and strftime, with a reasonable set of properties</li>
<li>Time deltas with days, seconds, and microseconds and nothing else</li>
<li>Acceptable support for parsing dates and times</li>
</ul>
<p>What you don&rsquo;t get is:</p>
<ul>
<li>Meaningful time deltas</li>
<li>Useful arithmetic</li>
</ul>
<p>Date and time support is a rather tricky thing to do and it&rsquo;s something that the
standard library should support well enough to put it in the back of your mind
instead of making you do all the work.</p>
<p>We&rsquo;ll be comparing it to C# and .NET.</p>
<p>Let&rsquo;s say I want to get the total hours between two <code>datetime</code>s.</p>
<div class="highlight"><pre class="chroma"><code class="language-cs" data-lang="cs"><span class="c1">// C#
</span><span class="c1"></span><span class="n">DateTime</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">;</span>
<span class="kt">double</span> <span class="n">hours</span> <span class="p">=</span> <span class="p">(</span><span class="n">b</span> <span class="p">-</span> <span class="n">a</span><span class="p">).</span><span class="n">TotalHours</span><span class="p">;</span>
</code></pre></div><div class="highlight"><pre class="chroma"><code class="language-python" data-lang="python"><span class="c1"># Python</span>
<span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="o">...</span>
<span class="n">hours</span> <span class="o">=</span> <span class="p">(</span><span class="n">b</span> <span class="o">-</span> <span class="n">a</span><span class="p">)</span><span class="o">.</span><span class="n">seconds</span> <span class="o">/</span> <span class="mi">60</span> <span class="o">/</span> <span class="mi">60</span>
</code></pre></div><p>That&rsquo;s not so bad. How about getting the time exactly one month in the future:</p>
<div class="highlight"><pre class="chroma"><code class="language-cs" data-lang="cs"><span class="kt">var</span> <span class="n">a</span> <span class="p">=</span> <span class="n">DateTime</span><span class="p">.</span><span class="n">Now</span><span class="p">.</span><span class="n">AddMonths</span><span class="p">(</span><span class="m">1</span><span class="p">);</span>
</code></pre></div><div class="highlight"><pre class="chroma"><code class="language-python" data-lang="python"><span class="n">a</span> <span class="o">=</span> <span class="n">date</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">+</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">days</span><span class="o">=</span><span class="mi">30</span><span class="p">)</span>
</code></pre></div><p>Well, that&rsquo;s not ideal. In C#, if you add one month to Janurary 30th, you get
Feburary 28th (or leap day if appropriate). In Python, you could write a janky
function to do this for you, or you could use the crappy alternative I wrote
above.</p>
<p>How about if I want to take a delta between dates and show it somewhere, like a
countdown? Say an event is happening at some point in the future and I want to
print &ldquo;3 days, 5 hours, 12 minutes, 10 seconds left&rdquo;. This is distinct from the
first example, which could give you &ldquo;50 hours&rdquo;, whereas this example would give
you &ldquo;2 days, 2 hours&rdquo;.</p>
<div class="highlight"><pre class="chroma"><code class="language-cs" data-lang="cs"><span class="n">DateTime</span> <span class="n">future</span> <span class="p">=</span> <span class="p">...;</span>
<span class="kt">var</span> <span class="n">delta</span> <span class="p">=</span> <span class="n">future</span> <span class="p">-</span> <span class="n">DateTime</span><span class="p">.</span><span class="n">Now</span><span class="p">;</span>
<span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="s">&#34;{0} days, {1} hours, {2} minutes, {3} seconds left&#34;</span><span class="p">,</span>
    <span class="n">delta</span><span class="p">.</span><span class="n">Days</span><span class="p">,</span>
    <span class="n">delta</span><span class="p">.</span><span class="n">Hours</span><span class="p">,</span>
    <span class="n">delta</span><span class="p">.</span><span class="n">Minutes</span><span class="p">,</span>
    <span class="n">delta</span><span class="p">.</span><span class="n">Seconds</span><span class="p">);</span>
</code></pre></div><div class="highlight"><pre class="chroma"><code class="language-python" data-lang="python"><span class="c1"># ...mess of math you have to implement yourself omitted...</span>
</code></pre></div><p>Maybe I have a website where users can set their locale?</p>
<div class="highlight"><pre class="chroma"><code class="language-cs" data-lang="cs"><span class="n">DateTime</span> <span class="n">a</span> <span class="p">=</span> <span class="p">...;</span>
<span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">a</span><span class="p">.</span><span class="n">ToString</span><span class="p">(</span><span class="s">&#34;some format string&#34;</span><span class="p">,</span> <span class="n">user</span><span class="p">.</span><span class="n">Locale</span><span class="p">));</span>
</code></pre></div><div class="highlight"><pre class="chroma"><code class="language-python" data-lang="python"><span class="n">locale</span><span class="o">.</span><span class="n">setlocale</span><span class="p">(</span><span class="n">locale</span><span class="o">.</span><span class="n">LC_TIME</span><span class="p">,</span> <span class="s2">&#34;sv_SE&#34;</span><span class="p">)</span> <span class="c1"># Global!</span>
<span class="k">print</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">&#34;some format string&#34;</span><span class="p">))</span>
</code></pre></div><p>By the way, that Python one doesn&rsquo;t work on Windows. It uses system locales names
which are different on Windows than on Linux or OS X. Mono (cross-platform .NET)
handles this for you on any system.</p>
<p>And a few other cases that are easy in .NET and not in Python:</p>
<ul>
<li>Days since the start of this year</li>
<li>Constants like the days in every month</li>
<li>Is it currently DST in this timezone?</li>
<li>Is this a leap year?</li>
</ul>
<p>In short, Python&rsquo;s datetime module could really use a lot of fleshing out. This
is common stuff and easy for a naive programmer to do wrong.</p>


guid: https://drewdevault.com/2014/09/02/Process-scheduling-in-KnightOS.html
title: Process scheduling and multitasking in KnightOS
url: https://drewdevault.com/2014/09/02/Process-scheduling-in-KnightOS.html
feedurl: https://drewdevault.com/blog/index.xml
content:
<p>I&rsquo;m going to do some blogging about technical decisions made with
<a href="http://knightos.org">KnightOS</a>. It&rsquo;s an open-source project I&rsquo;ve been working
on for the past four years to build an open-source Unix-like kernel for TI
calculators (in assembly). It&rsquo;s been a cool platform on top of which I can
research low level systems concepts and I thought I&rsquo;d share some of my findings
with the world.</p>
<p>So, first of all, what is scheduling? For those who are completely out of the
loop, I&rsquo;ll explain what exactly it is and why it&rsquo;s neccessary. Computers run on
a CPU, which executes a series of instructions in order. Each core is not
capable of running several instructions concurrently. However, you can run
hundreds of processes at once on your computer (and you probably are doing so
as you read this article). There are a number of ways of accomplishing, but the
one that suits the most situations is <em>preemtive multitasking</em>. This is what
KnightOS uses. You see, a CPU can only execute one instruction after another,
but you can &ldquo;raise an interrupt&rdquo;. This will halt execution and move to some
other bit of code for a moment. This can be used to handle various events (for
example, the GameBoy raises an interrupt when a button is pressed). One of
these events is often a timer, which raises an interrupt at a fixed interval.
This is the mechanism by which preemptive multitasking is accomplished.</p>
<p>Let&rsquo;s say for a moment that you have two programs loaded into memory and
running, at addresses 0x1000 and 0x2000. Your kernel has an interrupt handler
at 0x100. So if program A is running and an interrupt fires, the following
happens:</p>
<ol>
<li>0x1000 is pushed to the stack as the return address</li>
<li>The program counter is set to 0x100 and the interrupt runs</li>
<li>The interrupt concludes and returns, which pops 0x1000 from the stack and
into the program counter.</li>
</ol>
<p>Once the interrput handler runs, however, the kernel has a chance to be sneaky:</p>
<ol>
<li>0x1000 is pushed to the stack as the return address</li>
<li>The program counter is set to 0x100 and the interrupt runs</li>
<li>The interrupt removes 0x1000 from the stack and puts 0x2000 there instead</li>
<li>The interrupt concludes and returns, which pops 0x2000 from the stack and
into the program counter.</li>
</ol>
<p>Now the interrupt has switched the CPU from program A to program B. And the
next time an interrupt occurs, the kernel can switch from program B to program
A. This event is called a &ldquo;context switch&rdquo;.  This is the basis of preemptive
multitasking. On top of this, however, there are lots of ideas around which
processes should get CPU time and when. Some systems have more complex
schedulers, but KnightOS runs on limited hardware and I wanted the context
switch to be short and sweet so that the running processes get as much of the
CPU as possible. I&rsquo;ll explain the simple KnightOS scheduling algorithm here.
First, its goals:</p>
<ul>
<li>Short and simple context switches</li>
<li>Ability to suspend processes when not in foreground</li>
<li>Ability to run background processes</li>
</ul>
<p>What KnightOS uses is a simple round robin with the ability to suspend threads.
That is, we have a list of processes and then some flags, among which is
whether or not the processes is currently suspended. So say we have this list
of processes in memory:</p>
<ul>
<li>1: PC=0x2000, not suspended</li>
<li>2: PC=0x2000, not suspended</li>
<li>3: PC=0x2000, suspended</li>
<li>4: PC=0x2000, not suspended</li>
</ul>
<p>As process 1 is running and an interrupt fires, the kernel looks at this table
and picks the next non-suspended process to run - process 2. On the next
interrupt, it does it again, skipping process 3 and giving time to process 4.</p>
<p>To actually implement this, we have to think about the stack. KnightOS runs on
z80 processors, which have a single stack and a shared memory space. The CPU
uses the PC register to keep track of which address the current instruction is
at. That is, say you compile this code:</p>
<pre><code>ld a, 10
inc a
ld (hl), a
</code></pre><p>This compiles to the machine code 3E 0A 3C 77. Say we load this program at
0x8000 - then 0x8000 will point to <code>ld a, 10</code>. When the CPU finishes executing
this instruction, it advances PC to 0x8002 (since <code>ld a, 10</code> is a two-byte
instruction). The next instruction it executes will be <code>inc a</code>, and then PC
advances to 0x8003.</p>
<p>The stack is used for a lot of things. It can be used to save values, and it is
used to call subroutines. It is also used for interrupts. It&rsquo;s like the same
stacks you use in higher level applications, but it&rsquo;s at a very low level. When
an interrupt fires, the current value of PC is pushed to the stack. Then PC is
set to the interrupt routine, and then when that&rsquo;s done the top of the stack is
removed and placed into PC (effectively returning control to the original
location). However, since the stack is used for much more than that, we have
additional things to consider.</p>
<p>In KnightOS, when a new process starts, it&rsquo;s allocated a stack in memory and
the CPU&rsquo;s stack pointer (SP) is set to its address. When an interrupt happens,
we need to change the stack to point at some other process so it has time to
run (since that&rsquo;s where its PC is). However, we need to make sure that the
first processes stack is left intact. Since we allocate a new stack for the
next process, we can simply change SP to that processes stack. This will leave
behind the value of PC that was pushed during the interrupt for the previous
process, and lo and behlod a similar value of PC is waiting on top of the other
processes stack.</p>
<p>So that&rsquo;s it! We do a simple round robin, skipping suspended processes and
following the procedure outlined above to switch between them. This is how
KnightOS shares one CPU with several &ldquo;concurrent&rdquo; processes. Operating systems
like Linux use more complicated schedulers with more interesting theory if
you&rsquo;d like some additional reading. And of course, since KnightOS is open
source, you may enjoy reading all of our code for handling this stuff (in
assembly):</p>
<p><a href="https://github.com/KnightOS/kernel/blob/master/src/00/interrupt.asm">Context switching</a></p>
<p><a href="https://github.com/KnightOS/kernel/blob/master/src/00/thread.asm#L72">Stack allocation during process creation</a></p>
<p>We&rsquo;re hanging out on #knightos on Freenode if you want to chat about cool
low-level stuff like scheduling and memory management.</p>


guid: https://drewdevault.com/2014/10/10/The-profitability-of-online-services.html
title: On the profitability of image hosting websites
url: https://drewdevault.com/2014/10/10/The-profitability-of-online-services.html
feedurl: https://drewdevault.com/blog/index.xml
content:
<p>I&rsquo;ve been doing a lot of thought about whether or not it&rsquo;s even possible to both
run a simple website <em>and</em> turn a profit from it <em>and</em> maintain a high quality
of service. In particular, I&rsquo;m thinking about image hosts, considering that I
run one (a rather unprofitable one, too), but I would
think that my thoughts on this matter apply to more kinds of websites. That
being said, I&rsquo;ll just talk about media hosting because that&rsquo;s where I have
tangible expertise.</p>
<p>I think that all image hosts suffer from the same sad pattern of eventual
failure. That pattern is:</p>
<ol>
<li>Create a great image hosting website (you should stop here)</li>
<li>Decide to monetize it</li>
<li>Add advertising</li>
<li>Stop allowing hotlinking</li>
<li>Add more advertising</li>
<li>Add social tools like comments, voting - attempt build a community to look at
your ads</li>
</ol>
<p>Monetization is a poison. You start realizing that you wrote a shitty website in
PHP on shared hosting and it can&rsquo;t handle the traffic. You spend more money on
it and realize you don&rsquo;t like spending your money on it, so you decide to
monetize, and now the poison has got you. There&rsquo;s an extremely fine line to walk
with monetization. You start wanting to make enough money to support your
servers, but then you think to yourself &ldquo;well, I worked hard for this, maybe I
should make a living from it!&rdquo; This introduces several problems.</p>
<p>First of all, you made an image hosting website. It&rsquo;s already perfect. Almost
anything you can think of adding will only make it worse. If you suddenly decide
that you need to spend more time on it to justify taking money from it, then you
have a lot of time to get things wrong. You eventually run out of the good
features and start implementing the bad ones.</p>
<p>More importantly, though, you realize that you should be making <em>more</em> money.
Maybe you can turn this into a nice job working on your own website! And that
means you should start a business and assign yourself a salary and start making
a profit and hire new people. The money has to come from somewhere. So you make
even more compromises. Eventually, people stop using your service. People start
to <em>detest</em> your service. It can get so bad that people will refuse to click on
any link that leads to your website. Your users will be harassed for continuing
to use your site. <strong>You fail, and everyone hates you.</strong></p>
<p>This trend is observable with PhotoBucket, ImageShack, TinyPic, the list goes
on. The conclusion I&rsquo;ve drawn from this is that <strong>it is impossible to run a
profitable image hosting service without sacrificing what makes your service
worthwhile</strong>. We have arrived at a troubling place with the case of Imgur,
however.  MrGrim (the creator of Imgur) also identified this trend and decided
to put a stop to it by building a simple image hosting service for Reddit. It
had great intentions, check out the old archive.org mirror of it<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.  With
these great intentions and a great service, Imgur rose to become the 46th most
popular website globally<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>, and 18th in the United States alone, on the
shoulders of Reddit, which now ranks 47th. I&rsquo;m going to expand upon this here,
particularly with respect to Reddit, but I included the ranks here to dissuade
anyone who says &ldquo;there&rsquo;s more than Reddit out there&rdquo; in response to this post.
Reddit is a <em>huge</em> deal.</p>
<p>Other image hosts died down when people recognized their problems. Imgur has
reached a critical mass where that will not happen. 20% of all new Reddit posts
are Imgur, and most users just don&rsquo;t know better than to use anything else. That
being said, Imgur shows the signs of the image hosting poison. They stopped
being an image hosting website and became their own community. They added
advertising, which is fine on its own, but then they started redirecting direct
links<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> to pages with ads. And still, their userbase is just as strong,
despite better alternatives appearing.</p>
<p>I&rsquo;m not sure what to do about Imgur. I don&rsquo;t like that they&rsquo;ve won the mindshare
with a staggering margin. I do know that I&rsquo;ve tried to make my own service
immune to the image hosting poison. We run it incredibly lean - we handle over
10 million HTTP requests per day on a single server that also does transcoding
and storage for $200 per month. We get about $20-$30 in monthly revenue from our
Project Wonderful<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> ads, and a handful of donations that usually amount to
less than $20. Fortunately, $150ish isn&rsquo;t a hard number to pay out of our own
pockets every month, and we&rsquo;ve made a damn good website that&rsquo;s extremely
scalable to keep our costs low. We haven&rsquo;t taken seed money, and we&rsquo;re not
really the sort to fix problems by throwing more money at it. We also won&rsquo;t be
hiring any paid staff any time soon, so our costs are pretty much constant. On
top of that, if we do fall victim to the image hosting poison, 100% of our code
is open source, so the next service can skip R&amp;D and start being awesome
immediately. Even with all of that, though, all I can think of doing is sticking
around until people realize that Imgur really does suck.</p>
<p><em>2017-03-07 update</em></p>
<ul>
<li>mediacru.sh shut down (out of money)</li>
<li>pomf.se shut down (out of money)</li>
<li>minus.com shut down after going down the decline described in this post</li>
</ul>
<p>I have started a private service called <a href="https://sr.ht">sr.ht</a>, which I aim to
use to fix the problem by only letting my friends and I use it. It has
controlled growth and won&rsquo;t get too big and too expensive. It&rsquo;s on Github if you
want to <a href="https://github.com/SirCmpwn/sr.ht">use it</a>.</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p><a href="https://web.archive.org/web/20090225014924/http://imgur.com/">Original Imgur home page</a> <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p><a href="http://www.alexa.com/siteinfo/imgur.com">Imgur on Alexa</a> <a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p><a href="https://dillpickle.github.io/imgur-please-dont-be-the-next-tinypic-or-imageshack.html">Imgur redirects &ldquo;direct&rdquo; links based on referrals</a> <a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4" role="doc-endnote">
<p><a href="https://www.projectwonderful.com/">Project Wonderful, an advertising service that doesn&rsquo;t suck</a> <a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>


guid: https://drewdevault.com/2014/11/30/Porting-an-entire-toolchain-to-the-browser-with-emscripten.html
title: Porting an assembler, debugger, and more to WebAssembly
url: https://drewdevault.com/2014/11/30/Porting-an-entire-toolchain-to-the-browser-with-emscripten.html
feedurl: https://drewdevault.com/blog/index.xml
content:
<p>WebAssembly is pretty cool! It lets you write portable C and cross-compile it to
JavaScript so it&rsquo;ll run in a web browser. As the maintainer of
<a href="http://www.knightos.org">KnightOS</a>, I looked to WASM as a potential means
of reducing the cost of entry for new developers hoping to target the OS.</p>
<noscript>
Note: this article uses JavaScript to run all of this stuff in your web browser.
I don't use any third-party scripts, tracking, or anything else icky.
</noscript>
<h2 id="rationale-for-wasm">Rationale for WASM</h2>
<p>There are several pieces of software in the toolchain that are required to write
and test software for KnightOS:</p>
<ul>
<li><a href="https://github.com/KnightOS/scas">scas</a> - a z80 assembler</li>
<li><a href="https://github.com/KnightOS/genkfs">genkfs</a> - generates KFS filesystem images</li>
<li><a href="https://github.com/KnightOS/kpack">kpack</a> - packaging tool, like makepkg on Arch Linux</li>
<li><a href="https://github.com/KnightOS/z80e">z80e</a> - a z80 calculator emulator</li>
</ul>
<p>You also need a copy of the latest kernel and any of your dependencies from
<a href="https://packages.knightos.org">packages.knightos.org</a>. Getting all of this is
not straightforward. On Linux and Mac, there are no official packages for any of
these tools. On Windows, there are still no official packages, and you have to
use Cygwin on top of that. The first step to writing KnightOS programs is to
manually compile and install several tools, which is a lot to ask of someone who
just wants to experiment.</p>
<p>All of the tools in our toolchain are written in C. We saw WASM as an
opportunity to reduce all of this effort into simply firing up your web browser.
It works, too! Here&rsquo;s what was involved.</p>
<blockquote>
<p><strong>Note</strong>: Click the screen on the emulator to the left to give it your
keyboard. Click away to take it back. You can use your arrow keys, F1-F5,
enter, and escape (as MODE).</p>
</blockquote>
<h2 id="the-final-product">The final product</h2>
<p>Let&rsquo;s start by showing you what we&rsquo;ve accomplished. It&rsquo;s now possible for
curious developers to try out KnightOS programming in their web browser. Of
course, they still have to do it in assembly, but we&rsquo;re <a href="https://github.com/KnightOS/kcc">working on
that</a> 😉. Here&rsquo;s a &ldquo;hello world&rdquo; you can run in
your web browser:</p>
<div class="demo">
    <div class="editor"
        data-source="/sources/helloworld.asm"
        data-file="main.asm"></div>
    <div class="calculator-wrapper">
        <div class="calculator">
            <canvas width="385" height="256" class="emulator-screen"></canvas>
        </div>
    </div>
</div>
<p>We can also install new dependencies on the fly and use them in our programs.
Here&rsquo;s another program that draws the &ldquo;hello world&rdquo; message in a window. You
should install <code>core/corelib</code> first:</p>
<p><input type="text" id="package-name" value="core/corelib" />
<input type="button" id="install-package" value="Install" /></p>
<div class="demo">
    <div class="editor" data-source="/sources/corelib-hello.asm" data-file="main.asm"></div>
    <div class="calculator-wrapper">
        <div class="calculator">
            <canvas width="385" height="256" class="emulator-screen"></canvas>
        </div>
    </div>
</div>
<p>You can find more packages to try out on
<a href="https://packages.knightos.org">packages.knightos.org</a>. Here&rsquo;s another example,
this one launches the file manager. You&rsquo;ll have to install a few packages for it
to work:</p>
<p>Install:
<input type="button" class="install-package-button" data-package="extra/fileman" value="extra/fileman" />
<input type="button" class="install-package-button" data-package="core/configlib" value="core/configlib" />
<input type="button" class="install-package-button" data-package="core/corelib" value="core/corelib" /></p>
<div class="demo">
    <div class="editor" data-source="/sources/fileman.asm" data-file="main.asm"></div>
    <div class="calculator-wrapper">
        <div class="calculator">
            <canvas width="385" height="256" class="emulator-screen"></canvas>
        </div>
    </div>
</div>
<p>Feel free to edit any of these examples! You can run them again with the Run
button. These resources might be useful if you want to play with this some more:</p>
<p><a href="http://www.z80.info/z80-op.txt">z80 instruction set</a> - <a href="http://tutorials.eeems.ca/ASMin28Days/lesson/toc.html">z80 assembly tutorial</a> - <a href="http://www.knightos.org/documentation/reference">KnightOS reference documentation</a></p>
<p>Note: our toolchain has some memory leaks, so eventually WASM is going to
run out of memory and then you&rsquo;ll have to refresh. Sorry!</p>
<h2 id="how-all-of-the-pieces-fit-together">How all of the pieces fit together</h2>
<p>When you
loaded this page, a bunch of things happened. First, the <a href="https://github.com/KnightOS/kernel/releases">latest
release</a> of the <a href="https://github.com/KnightOS/kernel">KnightOS
kernel</a> was downloaded. Then all of the
WASM ports of the toolchain were downloaded and loaded. Some virtual filesystems
were set up, and two KnightOS packages were downloaded and installed:
<a href="https://packages.knightos.org/core/init"><code>core/init</code></a>, and
<a href="https://packages.knightos.org/core/kernel-headers"><code>core/kernel-headers</code></a>,
respectively necessary for booting the system and compiling code against the
kernel API.  Extracting those packages involves copying them into kpack&rsquo;s
virtual filesystem and running <code>kpack -e path/to/package root/</code>.</p>
<p>When you click &ldquo;Run&rdquo; on one of these text boxes, the contents of the text box is
written to <code>/main.asm</code> in the assembler&rsquo;s virtual filesystem. The package
installation process extracts headers to <code>/include/</code>, and scas itself is run
with <code>/main.asm -I/include -o /executable</code>, which assembles the program and
writes the output to <code>/executable</code>.</p>
<p>Then we copy the executable into the genkfs filesystem (this is the tool that
generates filesystem images). We also copy the empty kernel into this
filesystem, as well as any of the packages we&rsquo;ve installed. We then run <code>genkfs /kernel.rom /root</code>, which creates a filesystem image from <code>/root</code> and bakes it
into <code>kernel.rom</code>. This produces a ready-to-emulate ROM image that we can load
into the z80e emulator on the left.</p>
<h2 id="the-wasm-details">The WASM details</h2>
<p>Porting all this stuff to WASM wasn&rsquo;t straightforward. The easiest part
was cross-compiling all of them to JavaScript:</p>
<pre><code>cd build
emconfigure cmake ..
emmake make
</code></pre>
<p>The process was basically that simple for each piece of software. There were
<a href="https://github.com/KnightOS/genkfs/commit/c4eefa87a3b5bdbafcc6d971654608c594f779a1">a</a>
<a href="https://github.com/KnightOS/scas/commit/d2044e7d7586a946422ce6493cc6dff01127d1c2">few</a>
<a href="https://github.com/KnightOS/scas/commit/8bc31af28e8419a9fa6c421147ea522935bd0df4">changes</a>
made to some of the tools to fix a few problems. The hard part
came when I wanted to run all of them on the same page. WASM compiled code
assumes that it will be the only WASM module on the page at any given
time, so this was a bit challenging and involved editing the generated JS.</p>
<p>The first thing I did was wrap all of the modules in isolated AMD loaders<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.
You can see how some of this ended up looking by visiting the actual scripts
(warning, big files):</p>
<ul>
<li><a href="https://drewdevault.com/tools/scas.js">scas.js</a></li>
<li><a href="https://drewdevault.com/tools/kpack.js">kpack.js</a></li>
<li><a href="https://drewdevault.com/tools/genkfs.js">genkfs.js</a></li>
</ul>
<p>That was enough to make it so that they could all run. These are part of a
toolchain, though, so somehow they needed to share files. Emscripten&rsquo;s <a href="http://kripken.github.io/emscripten-site/docs/api_reference/Filesystem-API.html">FS
object</a>
cannot be shared between modules, so the solution was to write a little JS:</p>
<div class="highlight"><pre class="chroma"><code class="language-coffeescript" data-lang="coffeescript"><span class="nv">copy_between_systems = </span><span class="nf">(fs1, fs2, from, to, encoding) -&gt;</span>
  <span class="k">for</span> <span class="nx">f</span> <span class="k">in</span> <span class="nx">fs1</span><span class="p">.</span><span class="nx">readdir</span><span class="p">(</span><span class="nx">from</span><span class="p">)</span>
    <span class="k">continue</span> <span class="k">if</span> <span class="nx">f</span> <span class="k">in</span> <span class="p">[</span><span class="s">&#39;.&#39;</span><span class="p">,</span> <span class="s">&#39;..&#39;</span><span class="p">]</span>
    <span class="nv">fs1p = </span><span class="nx">from</span> <span class="o">+</span> <span class="s">&#39;/&#39;</span> <span class="o">+</span> <span class="nx">f</span>
    <span class="nv">fs2p = </span><span class="nx">to</span> <span class="o">+</span> <span class="s">&#39;/&#39;</span> <span class="o">+</span> <span class="nx">f</span>
    <span class="nv">s = </span><span class="nx">fs1</span><span class="p">.</span><span class="nx">stat</span><span class="p">(</span><span class="nx">fs1p</span><span class="p">)</span>
    <span class="nx">log</span><span class="p">(</span><span class="s">&#34;Writing </span><span class="si">#{</span><span class="nx">fs1p</span><span class="si">}</span><span class="s"> to </span><span class="si">#{</span><span class="nx">fs2p</span><span class="si">}</span><span class="s">&#34;</span><span class="p">)</span>
    <span class="k">if</span> <span class="nx">fs1</span><span class="p">.</span><span class="nx">isDir</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nx">mode</span><span class="p">)</span>
      <span class="k">try</span>
        <span class="nx">fs2</span><span class="p">.</span><span class="nx">mkdir</span><span class="p">(</span><span class="nx">fs2p</span><span class="p">)</span>
      <span class="k">catch</span>
        <span class="c1"># pass
</span><span class="c1"></span>      <span class="nx">copy_between_systems</span><span class="p">(</span><span class="nx">fs1</span><span class="p">,</span> <span class="nx">fs2</span><span class="p">,</span> <span class="nx">fs1p</span><span class="p">,</span> <span class="nx">fs2p</span><span class="p">,</span> <span class="nx">encoding</span><span class="p">)</span>
    <span class="k">else</span>
      <span class="nx">fs2</span><span class="p">.</span><span class="nx">writeFile</span><span class="p">(</span><span class="nx">fs2p</span><span class="p">,</span> <span class="nx">fs1</span><span class="p">.</span><span class="nx">readFile</span><span class="p">(</span><span class="nx">fs1p</span><span class="p">,</span> <span class="p">{</span> <span class="nv">encoding: </span><span class="nx">encoding</span> <span class="p">}),</span> <span class="p">{</span> <span class="nv">encoding: </span><span class="nx">encoding</span> <span class="p">})</span>
</code></pre></div><p>With this, we can extract packages in the kpack filesystem and copy them to the
genkfs filesystem:</p>
<div class="highlight"><pre class="chroma"><code class="language-coffeescript" data-lang="coffeescript"><span class="nv">install_package = </span><span class="nf">(repo, name, callback) -&gt;</span>
  <span class="nv">full_name = </span><span class="nx">repo</span> <span class="o">+</span> <span class="s">&#39;/&#39;</span> <span class="o">+</span> <span class="nx">name</span>
  <span class="nx">log</span><span class="p">(</span><span class="s">&#34;Downloading &#34;</span> <span class="o">+</span> <span class="nx">full_name</span><span class="p">)</span>
  <span class="nv">xhr = </span><span class="k">new</span> <span class="nx">XMLHttpRequest</span><span class="p">()</span>
  <span class="nx">xhr</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span><span class="s">&#39;GET&#39;</span><span class="p">,</span> <span class="s">&#34;https://packages.knightos.org/&#34;</span> <span class="o">+</span> <span class="nx">full_name</span> <span class="o">+</span> <span class="s">&#34;/download&#34;</span><span class="p">)</span>
  <span class="nv">xhr.responseType = </span><span class="s">&#39;arraybuffer&#39;</span>
  <span class="nv">xhr.onload = </span><span class="nf">() -&gt;</span>
    <span class="nx">log</span><span class="p">(</span><span class="s">&#34;Installing &#34;</span> <span class="o">+</span> <span class="nx">full_name</span><span class="p">)</span>
    <span class="nv">file_name = </span><span class="s">&#39;/packages/&#39;</span> <span class="o">+</span> <span class="nx">repo</span> <span class="o">+</span> <span class="s">&#39;-&#39;</span> <span class="o">+</span> <span class="nx">name</span> <span class="o">+</span> <span class="s">&#39;.pkg&#39;</span>
    <span class="nv">data = </span><span class="k">new</span> <span class="nx">Uint8Array</span><span class="p">(</span><span class="nx">xhr</span><span class="p">.</span><span class="nx">response</span><span class="p">)</span>
    <span class="nx">toolchain</span><span class="p">.</span><span class="nx">kpack</span><span class="p">.</span><span class="nx">FS</span><span class="p">.</span><span class="nx">writeFile</span><span class="p">(</span><span class="nx">file_name</span><span class="p">,</span> <span class="nx">data</span><span class="p">,</span> <span class="p">{</span> <span class="nv">encoding: </span><span class="s">&#39;binary&#39;</span> <span class="p">})</span>
    <span class="nx">toolchain</span><span class="p">.</span><span class="nx">kpack</span><span class="p">.</span><span class="nx">Module</span><span class="p">.</span><span class="nx">callMain</span><span class="p">([</span><span class="s">&#39;-e&#39;</span><span class="p">,</span> <span class="nx">file_name</span><span class="p">,</span> <span class="s">&#39;/pkgroot&#39;</span><span class="p">])</span>
    <span class="nx">copy_between_systems</span><span class="p">(</span><span class="nx">toolchain</span><span class="p">.</span><span class="nx">kpack</span><span class="p">.</span><span class="nx">FS</span><span class="p">,</span> <span class="nx">toolchain</span><span class="p">.</span><span class="nx">scas</span><span class="p">.</span><span class="nx">FS</span><span class="p">,</span> <span class="s">&#34;/pkgroot/include&#34;</span><span class="p">,</span> <span class="s">&#34;/include&#34;</span><span class="p">,</span> <span class="s">&#34;utf8&#34;</span><span class="p">)</span>
    <span class="nx">copy_between_systems</span><span class="p">(</span><span class="nx">toolchain</span><span class="p">.</span><span class="nx">kpack</span><span class="p">.</span><span class="nx">FS</span><span class="p">,</span> <span class="nx">toolchain</span><span class="p">.</span><span class="nx">genkfs</span><span class="p">.</span><span class="nx">FS</span><span class="p">,</span> <span class="s">&#34;/pkgroot&#34;</span><span class="p">,</span> <span class="s">&#34;/root&#34;</span><span class="p">,</span> <span class="s">&#34;binary&#34;</span><span class="p">)</span>
    <span class="nx">log</span><span class="p">(</span><span class="s">&#34;Package installed.&#34;</span><span class="p">)</span>
    <span class="nx">callback</span><span class="p">()</span> <span class="k">if</span> <span class="nx">callback</span><span class="o">?</span>
  <span class="nx">xhr</span><span class="p">.</span><span class="nx">send</span><span class="p">()</span>
</code></pre></div><p>And this puts all the pieces in place for us to actually pass an assembly file
through our toolchain:</p>
<div class="highlight"><pre class="chroma"><code class="language-coffeescript" data-lang="coffeescript"><span class="nv">run_project = </span><span class="nf">(main) -&gt;</span>
  <span class="c1"># Assemble
</span><span class="c1"></span>  <span class="nb">window</span><span class="p">.</span><span class="nx">toolchain</span><span class="p">.</span><span class="nx">scas</span><span class="p">.</span><span class="nx">FS</span><span class="p">.</span><span class="nx">writeFile</span><span class="p">(</span><span class="s">&#39;/main.asm&#39;</span><span class="p">,</span> <span class="nx">main</span><span class="p">)</span>
  <span class="nx">log</span><span class="p">(</span><span class="s">&#34;Calling assembler...&#34;</span><span class="p">)</span>
  <span class="nv">ret = </span><span class="nb">window</span><span class="p">.</span><span class="nx">toolchain</span><span class="p">.</span><span class="nx">scas</span><span class="p">.</span><span class="nx">Module</span><span class="p">.</span><span class="nx">callMain</span><span class="p">([</span><span class="s">&#39;/main.asm&#39;</span><span class="p">,</span> <span class="s">&#39;-I/include/&#39;</span><span class="p">,</span> <span class="s">&#39;-o&#39;</span><span class="p">,</span> <span class="s">&#39;executable&#39;</span><span class="p">])</span>
  <span class="k">return</span> <span class="nx">ret</span> <span class="k">if</span> <span class="nx">ret</span> <span class="o">!=</span> <span class="mi">0</span>
  <span class="nx">log</span><span class="p">(</span><span class="s">&#34;Assembly done!&#34;</span><span class="p">)</span>
  <span class="c1"># Build filesystem
</span><span class="c1"></span>  <span class="nv">executable = </span><span class="nb">window</span><span class="p">.</span><span class="nx">toolchain</span><span class="p">.</span><span class="nx">scas</span><span class="p">.</span><span class="nx">FS</span><span class="p">.</span><span class="nx">readFile</span><span class="p">(</span><span class="s">&#34;/executable&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nv">encoding: </span><span class="s">&#39;binary&#39;</span> <span class="p">})</span>
  <span class="nb">window</span><span class="p">.</span><span class="nx">toolchain</span><span class="p">.</span><span class="nx">genkfs</span><span class="p">.</span><span class="nx">FS</span><span class="p">.</span><span class="nx">writeFile</span><span class="p">(</span><span class="s">&#34;/root/bin/executable&#34;</span><span class="p">,</span> <span class="nx">executable</span><span class="p">,</span> <span class="p">{</span> <span class="nv">encoding: </span><span class="s">&#39;binary&#39;</span> <span class="p">})</span>
  <span class="nb">window</span><span class="p">.</span><span class="nx">toolchain</span><span class="p">.</span><span class="nx">genkfs</span><span class="p">.</span><span class="nx">FS</span><span class="p">.</span><span class="nx">writeFile</span><span class="p">(</span><span class="s">&#34;/root/etc/inittab&#34;</span><span class="p">,</span> <span class="s">&#34;/bin/executable&#34;</span><span class="p">)</span>
  <span class="nb">window</span><span class="p">.</span><span class="nx">toolchain</span><span class="p">.</span><span class="nx">genkfs</span><span class="p">.</span><span class="nx">FS</span><span class="p">.</span><span class="nx">writeFile</span><span class="p">(</span><span class="s">&#34;/kernel.rom&#34;</span><span class="p">,</span> <span class="k">new</span> <span class="nx">Uint8Array</span><span class="p">(</span><span class="nx">toolchain</span><span class="p">.</span><span class="nx">kernel_rom</span><span class="p">),</span> <span class="p">{</span> <span class="nv">encoding: </span><span class="s">&#39;binary&#39;</span> <span class="p">})</span>
  <span class="nb">window</span><span class="p">.</span><span class="nx">toolchain</span><span class="p">.</span><span class="nx">genkfs</span><span class="p">.</span><span class="nx">Module</span><span class="p">.</span><span class="nx">callMain</span><span class="p">([</span><span class="s">&#34;/kernel.rom&#34;</span><span class="p">,</span> <span class="s">&#34;/root&#34;</span><span class="p">])</span>
  <span class="nv">rom = </span><span class="nb">window</span><span class="p">.</span><span class="nx">toolchain</span><span class="p">.</span><span class="nx">genkfs</span><span class="p">.</span><span class="nx">FS</span><span class="p">.</span><span class="nx">readFile</span><span class="p">(</span><span class="s">&#34;/kernel.rom&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nv">encoding: </span><span class="s">&#39;binary&#39;</span> <span class="p">})</span>

  <span class="nx">log</span><span class="p">(</span><span class="s">&#34;Loading your program into the emulator!&#34;</span><span class="p">)</span>
  <span class="k">if</span> <span class="nx">current_emulator</span> <span class="o">!=</span> <span class="kc">null</span>
    <span class="nx">current_emulator</span><span class="p">.</span><span class="nx">cleanup</span><span class="p">()</span>
  <span class="nv">current_emulator = </span><span class="k">new</span> <span class="nx">toolchain</span><span class="p">.</span><span class="nx">ide_emu</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s">&#39;screen&#39;</span><span class="p">))</span>
  <span class="nx">current_emulator</span><span class="p">.</span><span class="nx">load_rom</span><span class="p">(</span><span class="nx">rom</span><span class="p">.</span><span class="nx">buffer</span><span class="p">)</span>
  <span class="k">return</span> <span class="mi">0</span>
</code></pre></div><p>This was fairly easy to put together once we got all the tools to cooperate.
After all, these are all command-line tools. Invoking them is as simple as
calling <code>main</code> and then fiddling with the files that come out. Porting z80e, on
the other hand, was not nearly as simple.</p>
<h2 id="porting-z80e-to-the-browser">Porting z80e to the browser</h2>
<p><a href="https://github.com/KnightOS/z80e">z80e</a> is our calculator emulator. It&rsquo;s also
written in C, but needs to interact much more closely with the user. We need to
be able to render the display to a canvas, and to receive input from the user.
This isn&rsquo;t nearly as simple as just calling <code>main</code> and playing with some files.</p>
<p>To accomplish this, we&rsquo;ve put together
<a href="https://github.com/KnightOS/OpenTI">OpenTI</a>, a set of JavaScript bindings to
z80e. This is mostly the work of my friend puckipedia, but I can explain a bit
of what is involved. The short of it is that we needed to map native structs to
JavaScript objects and pass JavaScript code as function pointers to z80e&rsquo;s
hooks. So far as I know, the KnightOS team is the only group to have attempted
something with this deep of integration between WASM and JavaScript - because we
had to do a ton of the work ourselves.</p>
<p>OpenTI contains a
<a href="https://github.com/KnightOS/OpenTI/blob/master/webui/js/OpenTI/wrap.js">wrap</a>
module that is capable of wrapping structs and pointers in JavaScript objects.
This is a tedious procedure, because we have to know the offset and size of each
field in native code. An example of a wrapped object is given here:</p>
<div class="highlight"><pre class="chroma"><code class="language-javascript" data-lang="javascript"><span class="nx">define</span><span class="p">([</span><span class="s2">&#34;../wrap&#34;</span><span class="p">],</span> <span class="kd">function</span><span class="p">(</span><span class="nx">Wrap</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">var</span> <span class="nx">Registers</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">pointer</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">pointer</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">throw</span> <span class="s2">&#34;This object can only be instantiated with a memory region predefined!&#34;</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">this</span><span class="p">.</span><span class="nx">pointer</span> <span class="o">=</span> <span class="nx">pointer</span><span class="p">;</span>

    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt16</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;AF&#34;</span><span class="p">,</span> <span class="nx">pointer</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;F&#34;</span><span class="p">,</span> <span class="nx">pointer</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;A&#34;</span><span class="p">,</span> <span class="nx">pointer</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>

    <span class="k">this</span><span class="p">.</span><span class="nx">flags</span> <span class="o">=</span> <span class="p">{};</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">flags</span><span class="p">,</span> <span class="s2">&#34;C&#34;</span><span class="p">,</span>  <span class="nx">pointer</span><span class="p">,</span> <span class="mi">128</span><span class="p">,</span> <span class="mi">7</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">flags</span><span class="p">,</span> <span class="s2">&#34;N&#34;</span><span class="p">,</span>  <span class="nx">pointer</span><span class="p">,</span>  <span class="mi">64</span><span class="p">,</span> <span class="mi">6</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">flags</span><span class="p">,</span> <span class="s2">&#34;PV&#34;</span><span class="p">,</span> <span class="nx">pointer</span><span class="p">,</span>  <span class="mi">32</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">flags</span><span class="p">,</span> <span class="s2">&#34;3&#34;</span><span class="p">,</span>  <span class="nx">pointer</span><span class="p">,</span>  <span class="mi">16</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">flags</span><span class="p">,</span> <span class="s2">&#34;H&#34;</span><span class="p">,</span>  <span class="nx">pointer</span><span class="p">,</span>   <span class="mi">8</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">flags</span><span class="p">,</span> <span class="s2">&#34;5&#34;</span><span class="p">,</span>  <span class="nx">pointer</span><span class="p">,</span>   <span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">flags</span><span class="p">,</span> <span class="s2">&#34;Z&#34;</span><span class="p">,</span>  <span class="nx">pointer</span><span class="p">,</span>   <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">flags</span><span class="p">,</span> <span class="s2">&#34;S&#34;</span><span class="p">,</span>  <span class="nx">pointer</span><span class="p">,</span>   <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="nx">pointer</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">;</span>

    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt16</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;BC&#34;</span><span class="p">,</span> <span class="nx">pointer</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;C&#34;</span><span class="p">,</span> <span class="nx">pointer</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;B&#34;</span><span class="p">,</span> <span class="nx">pointer</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
    <span class="nx">pointer</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">;</span>

    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt16</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;DE&#34;</span><span class="p">,</span> <span class="nx">pointer</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;E&#34;</span><span class="p">,</span> <span class="nx">pointer</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;D&#34;</span><span class="p">,</span> <span class="nx">pointer</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
    <span class="nx">pointer</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">;</span>

    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt16</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;HL&#34;</span><span class="p">,</span> <span class="nx">pointer</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;L&#34;</span><span class="p">,</span> <span class="nx">pointer</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;H&#34;</span><span class="p">,</span> <span class="nx">pointer</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
    <span class="nx">pointer</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">;</span>

    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt16</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;_AF&#34;</span><span class="p">,</span> <span class="nx">pointer</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt16</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;_BC&#34;</span><span class="p">,</span> <span class="nx">pointer</span> <span class="o">+</span> <span class="mi">2</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt16</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;_DE&#34;</span><span class="p">,</span> <span class="nx">pointer</span> <span class="o">+</span> <span class="mi">4</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt16</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;_HL&#34;</span><span class="p">,</span> <span class="nx">pointer</span> <span class="o">+</span> <span class="mi">6</span><span class="p">);</span>
    <span class="nx">pointer</span> <span class="o">+=</span> <span class="mi">8</span><span class="p">;</span>

    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt16</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;PC&#34;</span><span class="p">,</span> <span class="nx">pointer</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt16</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;SP&#34;</span><span class="p">,</span> <span class="nx">pointer</span> <span class="o">+</span> <span class="mi">2</span><span class="p">);</span>
    <span class="nx">pointer</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>

    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt16</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;IX&#34;</span><span class="p">,</span> <span class="nx">pointer</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;IXL&#34;</span><span class="p">,</span> <span class="nx">pointer</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;IXH&#34;</span><span class="p">,</span> <span class="nx">pointer</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
    <span class="nx">pointer</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">;</span>

    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt16</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;IY&#34;</span><span class="p">,</span> <span class="nx">pointer</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;IYL&#34;</span><span class="p">,</span> <span class="nx">pointer</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;IYH&#34;</span><span class="p">,</span> <span class="nx">pointer</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
    <span class="nx">pointer</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">;</span>

    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;I&#34;</span><span class="p">,</span> <span class="nx">pointer</span><span class="o">++</span><span class="p">);</span>
    <span class="nx">Wrap</span><span class="p">.</span><span class="nx">UInt8</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s2">&#34;R&#34;</span><span class="p">,</span> <span class="nx">pointer</span><span class="o">++</span><span class="p">);</span>

    <span class="c1">// 2 dummy bytes needed for 4-byte alignment
</span><span class="c1"></span>  <span class="p">}</span>

  <span class="nx">Registers</span><span class="p">.</span><span class="nx">sizeOf</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">return</span> <span class="mi">26</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="k">return</span> <span class="nx">Registers</span><span class="p">;</span>
<span class="p">});</span>
</code></pre></div><p>The result of that effort is that you can find out what the current value of a
register is from some nice clean JavaScript: <code>asic.cpu.registers.PC</code> (it&rsquo;s <code
id="register-pc"></code>, by the way). Pop open your JavaScript console and play
around with the <code>current_asic</code> global!</p>
<h2 id="conclusions">Conclusions</h2>
<p>I&rsquo;ve put all of this together on <a href="http://try.knightos.org">try.knightos.org</a>.
The source is available on
<a href="https://github.com/KnightOS/try.knightos.org">GitHub</a>. It&rsquo;s entirely
client-side, so it can be hosted on GitHub Pages. I&rsquo;m hopeful that this will
make it easier for people to get interested in KnightOS development, but it&rsquo;ll
be a lot better once I can get more documentation and tutorials written. It&rsquo;d be
pretty cool if we could have interactive tutorials like this!</p>
<p>If you, reader, are interested in working on some pretty cool shit, there&rsquo;s a
place for you! We have things to do in Assembly, C, JavaScript, Python, and a
handful of other things. Maybe you have a knack for design and want to help
improve it. Whatever the case may be, if you have interest in this stuff, come
hang out with us on IRC: <a href="http://webchat.freenode.net/?channels=knightos&amp;uio=d4">#knightos on
irc.freenode.net</a>.</p>
<hr>
<p><img src="https://sr.ht/zhRB.jpg" alt=""></p>
<p><strong>2018-08-31</strong>: This article was updated to fix some long-broken scripts and
adjust everything to fit into the since-updated blog theme. The title was also
changed from &ldquo;Porting an entire desktop toolchain to the browser with
Emscripten&rdquo; and some minor editorial corrections were made. References to
Emscripten were replaced with WebAssembly - WASM is the standard API that
browsers have implemented to replace asm.js, and the Emscripten toolchain and
JavaScript API remained compatible throughout the process.</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>AMD was an early means of using modules with JavaScript, which was popular at the time this article was written (2014). Today, a different form of modules has become part of the JavaScript language standard. <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>


guid: https://drewdevault.com/2015/04/19/Hooks.html
title: Hooks - running stuff on Github hooks
url: https://drewdevault.com/2015/04/19/Hooks.html
feedurl: https://drewdevault.com/blog/index.xml
content:
<p>I found myself in need of a simple tool for deploying a project on every git
commit, but I didn&rsquo;t have a build server set up. This led to Hooks - a very
simple tool that allows you to run arbitrary commands when Github&rsquo;s hooks
execute.</p>
<p>The configuration is very simple. In <code>/etc/hooks.conf</code>, write:</p>
<pre><code>[truecraft]
repository=SirCmpwn/TrueCraft
branch=master
command=systemctl restart hooks
valid_ips=204.232.175.64/27,192.30.252.0/22,127.0.0.1
</code></pre>
<p>You may include any number of hooks. The <code>valid_ips</code> entry in that example
allows you to accept hooks from Github and from localhost. Then you run Hooks
itself, it will execute your command when you push a commit to your repository.</p>
<p>This allows you to do continuous deployment on the cheap and easy. I hope you
find it useful. <a href="https://github.com/SirCmpwn/hooks">Hooks</a>.</p>


guid: https://drewdevault.com/2015/06/14/osuweb.html
title: osu!web - WebGL & Web Audio
url: https://drewdevault.com/2015/06/14/osuweb.html
feedurl: https://drewdevault.com/blog/index.xml
content:
<script src="https://drewdevault.com/js/underscore-min.js"></script>
<p>I&rsquo;ve taken a liking to a video game called <a href="https://osu.ppy.sh">osu!</a> over the
past few months. It&rsquo;s a rhythm game where you use move your mouse to circles
that appear with the beat, and click (or press a key) at the right time. It
looks something like this:</p>
<iframe src="https://www.youtube.com/embed/qdaZnQQAPqQ" frameborder="0" allowfullscreen></iframe>
<p>The key of this game is that the &ldquo;beatmaps&rdquo; (a song plus notes to hit) are
user-submitted. There are thousands of them, and the difficulty curve is very
long - I&rsquo;ve been playing for 10 months and I&rsquo;m only maybe 70% of the way up the
difficulty curve. It&rsquo;s also a competitive game, which leads to a lot more fun,
where each user tries to complete maps a little bit better than everyone else
can. You can see on the left in that video - this is a very good player who
earned the #1 rank during this play.</p>
<p>In my tendency to start writing code related to every game I play, I&rsquo;ve been
working on a cool project called <a href="http://www.drewdevault.com/osuweb">osu!web</a>.
This is a Javascript project that can:</p>
<ul>
<li>Decompress osu beatmap archives</li>
<li>Decode the music with Web Audio</li>
<li>Decode the osu! beatmap format</li>
<li>Play the map!</li>
</ul>
<p>In case you don&rsquo;t have any osz files hanging around, try out <a href="https://sr.ht/f30.osz">this
one</a>, which is the one from the video above.</p>
<p><img src="https://sr.ht/044.png" alt=""></p>
<h2 id="osuweb-and-the-future">osu!web and the future</h2>
<p>This part of the blog post is for non-technical readers, mostly osu players.
osu!web is pretty cool, and I want to make it even better. My current plans are
just to make it a beatmap viewer, and I&rsquo;m working now on achieving that goal. I
have to finish sliders and add spinners, and eventually work on things like
storyboards. Playing background videos is not in the cards because of
limitations with HTML5 video.</p>
<p>Eventually, I&rsquo;d like to make it possible to link to a certain time in a certain
map, or in a certain replay. Oh yeah, I want to make it support replays, too.
If I get replays working, though, then I don&rsquo;t see any reason not to let players
try the maps out in their web browsers, too. Keep an eye out!</p>
<h2 id="technical-details">Technical Details</h2>
<p>This project is only possible thanks to a whole bunch of new web technologies
that have been stabilizing in the past year or so. The source code is <a href="https://github.com/SirCmpwn/osuweb">on
Github</a> if you want to check it out.</p>
<h3 id="loading-beatmaps">Loading beatmaps</h3>
<p>When the user <a href="https://github.com/SirCmpwn/osuweb/blob/gh-pages/scripts/scenes/need-files.js#L8-L41">drags and
drops</a>
an osz file, we use <a href="https://github.com/gildas-lormeau/zip.js">zip.js</a> and
create a virtual filesystem of sorts to browse through the archive. In this
archive we have several things:</p>
<ul>
<li>A number of &ldquo;tracks&rdquo; - osu files that define notes and such for various
difficulties</li>
<li>The song (mp3) and optionally a video background (avi)</li>
<li>Assets - a background image and optionally a skin (like a Minecraft texture
pack)</li>
</ul>
<p><img src="https://sr.ht/ce6.png" alt=""></p>
<p>We then load the *.osu files and decode them. They look similar to ini files or
Unix config files. Here&rsquo;s a snippet:</p>
<pre><code>[General]
AudioFilename: MuryokuP - Sweet Sweet Cendrillon Drug.mp3
AudioLeadIn: 1000
PreviewTime: 69853

# snip

[Metadata]
Title:Sweet Sweet Cendrillon Drug
TitleUnicode:Sweet Sweet Cendrillon Drug
Artist:MuryokuP
ArtistUnicode:MuryokuP
Creator:Smoothie
Version:Cendrillon

# snip

[HitObjects]
104,308,1246,5,0,0:0:0:0:
68,240,1553,1,0,0:0:0:0:
68,164,1861,1,0,0:0:0:0:
104,96,2169,1,0,0:0:0:0:
172,60,2476,2,0,P|256:48|340:60,1,170,0|0,0:0|0:0,0:0:0:0:
404,104,3399,5,0,0:0:0:0:

# snip
</code></pre>
<p>This is decoded by
<a href="https://github.com/SirCmpwn/osuweb/blob/gh-pages/scripts/osu.js">osu.js</a>. For
some sections (like <code>[Metadata]</code>), it just puts each entry into a dict that you
can pull from later. It does more for things like hit objects, and understands
which of these lines is a slider versus a hit circle versus a spinner and so on.</p>
<p>I sneakily loaded a beatmap in the background in your browser as you were
reading. If you want to check it out, open up your console and play with the
<code>track</code> object. Ignore all the disqus errors, they&rsquo;re irrelevant.</p>
<p><img src="https://sr.ht/a81.png" alt=""></p>
<h2 id="enter-stage-web-audio">Enter stage: Web Audio</h2>
<p>Web Audio had a bit of a rocky development cycle, what with Chrome thinking it&rsquo;s
special and implementing a completely different standard from everyone else.
Things have <a href="http://caniuse.com/#feat=audio-api">settled</a> by now, and I can
start playing with it 😁 Bonus: Mozilla finally added mp3 support to all
platforms, including Linux (which my dev machine runs).</p>
<p>The osz file includes an mp3, which we
<a href="https://github.com/SirCmpwn/osuweb/blob/gh-pages/scripts/osu.js#L209-L224">extract</a>
into an ArrayBuffer, and
<a href="https://github.com/SirCmpwn/osuweb/blob/gh-pages/scripts/osu-audio.js">load</a>
into a Web Audio context. This is super cool and totally would not have been
possible even a few months ago - kudos to the teams implementing all this
exciting stuff in the browsers.</p>
<p>That&rsquo;s about all we&rsquo;re doing with Web Audio right now. I do add a gain node so
that you can control the volume with your mouse wheel. In the future, we can get
more creative by:</p>
<ul>
<li>Adding support for HT/DT mods</li>
<li>Adding support for NC</li>
</ul>
<h2 id="enter-stage-pixi">Enter stage: PIXI</h2>
<p>Once we&rsquo;ve decoded the beatmap and loaded the audio, we can play it. After
briefly showing the user a difficulty selection, we jump into rendering the map.
For this, I&rsquo;ve decided to use <a href="http://pixijs.com/">PIXI.js</a>, which gives us a
really nice API to use on top of WebGL with a canvas fallback for when WebGL is
not available. I was originally just using canvas, but it wasn&rsquo;t very
performant, so I went looking for a 2D WebGL framework and found PIXI. It&rsquo;s
pretty cool.</p>
<p>First, we iterate over all of the hit objects on the beatmap and generate
sprites for them:</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="k">this</span><span class="p">.</span><span class="nx">populateHit</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">hit</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// Creates PIXI objects for a given hit
</span><span class="c1"></span>    <span class="nx">hit</span><span class="p">.</span><span class="nx">objects</span> <span class="o">=</span> <span class="p">[];</span>
    <span class="nx">hit</span><span class="p">.</span><span class="nx">score</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
    <span class="k">switch</span> <span class="p">(</span><span class="nx">hit</span><span class="p">.</span><span class="nx">type</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">case</span> <span class="s2">&#34;circle&#34;</span><span class="o">:</span>
            <span class="nx">self</span><span class="p">.</span><span class="nx">createHitCircle</span><span class="p">(</span><span class="nx">hit</span><span class="p">);</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="s2">&#34;slider&#34;</span><span class="o">:</span>
            <span class="nx">self</span><span class="p">.</span><span class="nx">createSlider</span><span class="p">(</span><span class="nx">hit</span><span class="p">);</span>
            <span class="k">break</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="k">this</span><span class="p">.</span><span class="nx">hits</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">this</span><span class="p">.</span><span class="nx">populateHit</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">hits</span><span class="p">[</span><span class="nx">i</span><span class="p">]);</span> <span class="c1">// Prepare sprites and such
</span><span class="c1"></span><span class="p">}</span>
</code></pre></div><p>This is all done before we start playing. We consider the timestamp in the music
that the hit is scheduled for, and then we place <em>all</em> of the hit objects into
an array and start the song. See code for
<a href="https://github.com/SirCmpwn/osuweb/blob/gh-pages/scripts/scenes/playback.js#L88-L143">createHitCircle</a>,
which puts together a bunch of sprites for each hit cirlce and sets their alpha
to zero. See also
<a href="https://github.com/SirCmpwn/osuweb/blob/gh-pages/scripts/scenes/playback.js#L145-L228">createSlider</a>,
which is more complicated (I&rsquo;ll go into detail later).</p>
<p>Each frame, we get the current time from the Web Audio layer, and we run a
function that updates a list of upcoming hit objects:</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="k">this</span><span class="p">.</span><span class="nx">updateUpcoming</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">timestamp</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// Cache the next ten seconds worth of hit objects
</span><span class="c1"></span>    <span class="k">while</span> <span class="p">(</span><span class="nx">current</span> <span class="o">&lt;</span> <span class="nx">self</span><span class="p">.</span><span class="nx">hits</span><span class="p">.</span><span class="nx">length</span>
        <span class="o">&amp;&amp;</span> <span class="nx">futuremost</span> <span class="o">&lt;</span> <span class="nx">timestamp</span> <span class="o">+</span> <span class="p">(</span><span class="mi">10</span> <span class="o">*</span> <span class="nx">TIME_CONSTANT</span><span class="p">))</span> <span class="p">{</span>
        <span class="kd">var</span> <span class="nx">hit</span> <span class="o">=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">hits</span><span class="p">[</span><span class="nx">current</span><span class="o">++</span><span class="p">];</span>
        <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">objects</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span><span class="o">--</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">self</span><span class="p">.</span><span class="nx">game</span><span class="p">.</span><span class="nx">stage</span><span class="p">.</span><span class="nx">addChildAt</span><span class="p">(</span><span class="nx">hit</span><span class="p">.</span><span class="nx">objects</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span> <span class="mi">2</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="nx">self</span><span class="p">.</span><span class="nx">upcomingHits</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">hit</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">hit</span><span class="p">.</span><span class="nx">time</span> <span class="o">&gt;</span> <span class="nx">futuremost</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">futuremost</span> <span class="o">=</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">time</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">self</span><span class="p">.</span><span class="nx">upcomingHits</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">var</span> <span class="nx">hit</span> <span class="o">=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">upcomingHits</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
        <span class="kd">var</span> <span class="nx">diff</span> <span class="o">=</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">time</span> <span class="o">-</span> <span class="nx">timestamp</span><span class="p">;</span>
        <span class="kd">var</span> <span class="nx">despawn</span> <span class="o">=</span> <span class="nx">NOTE_DESPAWN</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">hit</span><span class="p">.</span><span class="nx">type</span> <span class="o">===</span> <span class="s2">&#34;slider&#34;</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">despawn</span> <span class="o">-=</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">sliderTimeTotal</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">diff</span> <span class="o">&lt;</span> <span class="nx">despawn</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">self</span><span class="p">.</span><span class="nx">upcomingHits</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
            <span class="nx">i</span><span class="o">--</span><span class="p">;</span>
            <span class="nx">_</span><span class="p">.</span><span class="nx">each</span><span class="p">(</span><span class="nx">hit</span><span class="p">.</span><span class="nx">objects</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="p">{</span>
                <span class="nx">self</span><span class="p">.</span><span class="nx">game</span><span class="p">.</span><span class="nx">stage</span><span class="p">.</span><span class="nx">removeChild</span><span class="p">(</span><span class="nx">o</span><span class="p">);</span>
                <span class="nx">o</span><span class="p">.</span><span class="nx">destroy</span><span class="p">();</span>
            <span class="p">});</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div><p>I adopted this pattern early on for performance reasons. During each frame&rsquo;s
rendering step, we only have the sprites and such loaded for hit objects in the
near future. This saves a lot of time. PIXI has all of these sprites loaded and
draws them for us each frame. During each frame, all we have to do is update
them:</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="k">this</span><span class="p">.</span><span class="nx">updateHitObjects</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">time</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">self</span><span class="p">.</span><span class="nx">updateUpcoming</span><span class="p">(</span><span class="nx">time</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">upcomingHits</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span><span class="o">--</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">var</span> <span class="nx">hit</span> <span class="o">=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">upcomingHits</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
        <span class="k">switch</span> <span class="p">(</span><span class="nx">hit</span><span class="p">.</span><span class="nx">type</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">case</span> <span class="s2">&#34;circle&#34;</span><span class="o">:</span>
                <span class="nx">self</span><span class="p">.</span><span class="nx">updateHitCircle</span><span class="p">(</span><span class="nx">hit</span><span class="p">,</span> <span class="nx">time</span><span class="p">);</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="k">case</span> <span class="s2">&#34;slider&#34;</span><span class="o">:</span>
                <span class="nx">self</span><span class="p">.</span><span class="nx">updateSlider</span><span class="p">(</span><span class="nx">hit</span><span class="p">,</span> <span class="nx">time</span><span class="p">);</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="k">case</span> <span class="s2">&#34;spinner&#34;</span><span class="o">:</span>
                <span class="c1">//self.updateSpinner(hit, time); // TODO
</span><span class="c1"></span>                <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div><p>This is passed in the current timestamp in the song, and based on this we are
able to do some simple math to calculate how much alpha each note should have,
as well as the scale of the approach circle (which tells you when to click the
note):</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="k">this</span><span class="p">.</span><span class="nx">updateHitCircle</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">hit</span><span class="p">,</span> <span class="nx">time</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="nx">diff</span> <span class="o">=</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">time</span> <span class="o">-</span> <span class="nx">time</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">alpha</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="nx">diff</span> <span class="o">&lt;=</span> <span class="nx">NOTE_APPEAR</span> <span class="o">&amp;&amp;</span> <span class="nx">diff</span> <span class="o">&gt;</span> <span class="nx">NOTE_FULL_APPEAR</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">alpha</span> <span class="o">=</span> <span class="nx">diff</span> <span class="o">/</span> <span class="nx">NOTE_APPEAR</span><span class="p">;</span>
        <span class="nx">alpha</span> <span class="o">-=</span> <span class="mf">0.5</span><span class="p">;</span> <span class="nx">alpha</span> <span class="o">=</span> <span class="o">-</span><span class="nx">alpha</span><span class="p">;</span> <span class="nx">alpha</span> <span class="o">+=</span> <span class="mf">0.5</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">diff</span> <span class="o">&lt;=</span> <span class="nx">NOTE_FULL_APPEAR</span> <span class="o">&amp;&amp;</span> <span class="nx">diff</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">alpha</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">diff</span> <span class="o">&gt;</span> <span class="nx">NOTE_DISAPPEAR</span> <span class="o">&amp;&amp;</span> <span class="nx">diff</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">alpha</span> <span class="o">=</span> <span class="nx">diff</span> <span class="o">/</span> <span class="nx">NOTE_DISAPPEAR</span><span class="p">;</span>
        <span class="nx">alpha</span> <span class="o">-=</span> <span class="mf">0.5</span><span class="p">;</span> <span class="nx">alpha</span> <span class="o">=</span> <span class="o">-</span><span class="nx">alpha</span><span class="p">;</span> <span class="nx">alpha</span> <span class="o">+=</span> <span class="mf">0.5</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">if</span> <span class="p">(</span><span class="nx">diff</span> <span class="o">&lt;=</span> <span class="nx">NOTE_APPEAR</span> <span class="o">&amp;&amp;</span> <span class="nx">diff</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">hit</span><span class="p">.</span><span class="nx">approach</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="p">((</span><span class="nx">diff</span> <span class="o">/</span> <span class="nx">NOTE_APPEAR</span> <span class="o">*</span> <span class="mi">2</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mf">0.9</span><span class="p">;</span>
        <span class="nx">hit</span><span class="p">.</span><span class="nx">approach</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="p">((</span><span class="nx">diff</span> <span class="o">/</span> <span class="nx">NOTE_APPEAR</span> <span class="o">*</span> <span class="mi">2</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mf">0.9</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="nx">hit</span><span class="p">.</span><span class="nx">approach</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">objects</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="nx">scale</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="nx">_</span><span class="p">.</span><span class="nx">each</span><span class="p">(</span><span class="nx">hit</span><span class="p">.</span><span class="nx">objects</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="p">{</span> <span class="nx">o</span><span class="p">.</span><span class="nx">alpha</span> <span class="o">=</span> <span class="nx">alpha</span><span class="p">;</span> <span class="p">});</span>
<span class="p">}</span>
</code></pre></div><p>I&rsquo;ve left out sliders, which again are pretty complicated. We&rsquo;ll get to them
after you look at this screenshot again:</p>
<p><img src="https://sr.ht/044.png" alt=""></p>
<p>All of these hit objects are having their alpha and approach circle scale
adjusted each frame by the above method. Since we&rsquo;re basing this on the
timestamp of the map, a convenient side effect is that we can pass in any time
to see what the map should look like at that time.</p>
<h2 id="curves">Curves</h2>
<p>The hardest thing so far has been rendering sliders, which are hit objects that
you&rsquo;re meant to click and hold as you move across the &ldquo;slider&rdquo;. They look like
this:</p>
<p><img src="https://sr.ht/c97.png" alt=""></p>
<p>The golden circle is the area you need to keep your mouse in if you want to pass
this slider. Sliders are defined as a series of curves. There are a few kinds:</p>
<ul>
<li>Linear sliders (not curves)</li>
<li>Catmull sliders</li>
<li>Bezier sliders</li>
</ul>
<p>For now I&rsquo;ve only done bezier sliders. I give many thanks to
<a href="https://github.com/itdelatrisu/opsu">opsu</a>, which I learned a lot of useful
stuff about sliders from. Each slider is currently generated using the
now-deprecated &ldquo;peppysliders&rdquo; method, where the sprite is repeated along the
curve several times. If you look carefully as a slider fades out, you can notice
that this is the case.</p>
<p><img src="https://sr.ht/787.png" alt=""></p>
<p>The newer style of sliders involves rendering them with a custom shader. This
should be possible with PIXI, but I haven&rsquo;t done any research on them yet.
Again, I expect to be able to draw a lot of knowledge from reading the opsu
source code.</p>
<p>I left out the initializer for sliders earlier, because it&rsquo;s long and
complicated. I&rsquo;ll include it here so you can see how this goes:</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="k">this</span><span class="p">.</span><span class="nx">createSlider</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">hit</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="nx">lastFrame</span> <span class="o">=</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">keyframes</span><span class="p">[</span><span class="nx">hit</span><span class="p">.</span><span class="nx">keyframes</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">];</span>
    <span class="kd">var</span> <span class="nx">timing</span> <span class="o">=</span> <span class="nx">track</span><span class="p">.</span><span class="nx">timingPoints</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">track</span><span class="p">.</span><span class="nx">timingPoints</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">var</span> <span class="nx">t</span> <span class="o">=</span> <span class="nx">track</span><span class="p">.</span><span class="nx">timingPoints</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">t</span><span class="p">.</span><span class="nx">offset</span> <span class="o">&lt;</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">time</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="nx">timing</span> <span class="o">=</span> <span class="nx">t</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="nx">hit</span><span class="p">.</span><span class="nx">sliderTime</span> <span class="o">=</span> <span class="nx">timing</span><span class="p">.</span><span class="nx">millisecondsPerBeat</span> <span class="o">*</span>
        <span class="p">(</span><span class="nx">hit</span><span class="p">.</span><span class="nx">pixelLength</span> <span class="o">/</span> <span class="nx">track</span><span class="p">.</span><span class="nx">difficulty</span><span class="p">.</span><span class="nx">SliderMultiplier</span><span class="p">)</span> <span class="o">/</span> <span class="mi">100</span><span class="p">;</span>
    <span class="nx">hit</span><span class="p">.</span><span class="nx">sliderTimeTotal</span> <span class="o">=</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">sliderTime</span> <span class="o">*</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">repeat</span><span class="p">;</span>
    <span class="c1">// TODO: Other sorts of curves besides LINEAR and BEZIER
</span><span class="c1"></span>    <span class="c1">// TODO: Something other than shit peppysliders
</span><span class="c1"></span>    <span class="nx">hit</span><span class="p">.</span><span class="nx">curve</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">LinearBezier</span><span class="p">(</span><span class="nx">hit</span><span class="p">,</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">type</span> <span class="o">===</span> <span class="nx">SLIDER_LINEAR</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">curve</span><span class="p">.</span><span class="nx">curve</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">var</span> <span class="nx">c</span> <span class="o">=</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">curve</span><span class="p">.</span><span class="nx">curve</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
        <span class="kd">var</span> <span class="nx">base</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PIXI</span><span class="p">.</span><span class="nx">Sprite</span><span class="p">(</span><span class="nx">Resources</span><span class="p">[</span><span class="s2">&#34;hitcircle.png&#34;</span><span class="p">]);</span>
        <span class="nx">base</span><span class="p">.</span><span class="nx">anchor</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">base</span><span class="p">.</span><span class="nx">anchor</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="mf">0.5</span><span class="p">;</span>
        <span class="nx">base</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">xoffset</span> <span class="o">+</span> <span class="nx">c</span><span class="p">.</span><span class="nx">x</span> <span class="o">*</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">width</span><span class="p">;</span>
        <span class="nx">base</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">yoffset</span> <span class="o">+</span> <span class="nx">c</span><span class="p">.</span><span class="nx">y</span> <span class="o">*</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">height</span><span class="p">;</span>
        <span class="nx">base</span><span class="p">.</span><span class="nx">alpha</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="nx">base</span><span class="p">.</span><span class="nx">tint</span> <span class="o">=</span> <span class="nx">combos</span><span class="p">[</span><span class="nx">hit</span><span class="p">.</span><span class="nx">combo</span> <span class="o">%</span> <span class="nx">combos</span><span class="p">.</span><span class="nx">length</span><span class="p">];</span>
        <span class="nx">hit</span><span class="p">.</span><span class="nx">objects</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">base</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="nx">self</span><span class="p">.</span><span class="nx">createHitCircle</span><span class="p">({</span> <span class="c1">// Far end
</span><span class="c1"></span>        <span class="nx">time</span><span class="o">:</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">time</span><span class="p">,</span>
        <span class="nx">combo</span><span class="o">:</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">combo</span><span class="p">,</span>
        <span class="nx">index</span><span class="o">:</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span>
        <span class="nx">x</span><span class="o">:</span> <span class="nx">lastFrame</span><span class="p">.</span><span class="nx">x</span><span class="p">,</span>
        <span class="nx">y</span><span class="o">:</span> <span class="nx">lastFrame</span><span class="p">.</span><span class="nx">y</span><span class="p">,</span>
        <span class="nx">objects</span><span class="o">:</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">objects</span>
    <span class="p">});</span>
    <span class="nx">self</span><span class="p">.</span><span class="nx">createHitCircle</span><span class="p">(</span><span class="nx">hit</span><span class="p">);</span> <span class="c1">// Near end
</span><span class="c1"></span>    <span class="c1">// Add follow circle
</span><span class="c1"></span>    <span class="kd">var</span> <span class="nx">follow</span> <span class="o">=</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">follow</span> <span class="o">=</span>
        <span class="k">new</span> <span class="nx">PIXI</span><span class="p">.</span><span class="nx">Sprite</span><span class="p">(</span><span class="nx">Resources</span><span class="p">[</span><span class="s2">&#34;sliderfollowcircle.png&#34;</span><span class="p">]);</span>
    <span class="nx">follow</span><span class="p">.</span><span class="nx">visible</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
    <span class="nx">follow</span><span class="p">.</span><span class="nx">alpha</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="nx">follow</span><span class="p">.</span><span class="nx">anchor</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">follow</span><span class="p">.</span><span class="nx">anchor</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="mf">0.5</span><span class="p">;</span>
    <span class="nx">follow</span><span class="p">.</span><span class="nx">manualAlpha</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
    <span class="nx">hit</span><span class="p">.</span><span class="nx">objects</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">follow</span><span class="p">);</span>
    <span class="c1">// Add follow ball
</span><span class="c1"></span>    <span class="kd">var</span> <span class="nx">ball</span> <span class="o">=</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">ball</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PIXI</span><span class="p">.</span><span class="nx">Sprite</span><span class="p">(</span><span class="nx">Resources</span><span class="p">[</span><span class="s2">&#34;sliderb0.png&#34;</span><span class="p">]);</span>
    <span class="nx">ball</span><span class="p">.</span><span class="nx">visible</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
    <span class="nx">ball</span><span class="p">.</span><span class="nx">alpha</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="nx">ball</span><span class="p">.</span><span class="nx">anchor</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">ball</span><span class="p">.</span><span class="nx">anchor</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="mf">0.5</span><span class="p">;</span>
    <span class="nx">ball</span><span class="p">.</span><span class="nx">tint</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="nx">ball</span><span class="p">.</span><span class="nx">manualAlpha</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
    <span class="nx">hit</span><span class="p">.</span><span class="nx">objects</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">ball</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="nx">hit</span><span class="p">.</span><span class="nx">repeat</span> <span class="o">!==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// Add reverse symbol
</span><span class="c1"></span>        <span class="kd">var</span> <span class="nx">reverse</span> <span class="o">=</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">reverse</span> <span class="o">=</span>
            <span class="k">new</span> <span class="nx">PIXI</span><span class="p">.</span><span class="nx">Sprite</span><span class="p">(</span><span class="nx">Resources</span><span class="p">[</span><span class="s2">&#34;reversearrow.png&#34;</span><span class="p">]);</span>
        <span class="nx">reverse</span><span class="p">.</span><span class="nx">alpha</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="nx">reverse</span><span class="p">.</span><span class="nx">anchor</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">reverse</span><span class="p">.</span><span class="nx">anchor</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="mf">0.5</span><span class="p">;</span>
        <span class="nx">reverse</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">xoffset</span> <span class="o">+</span> <span class="nx">lastFrame</span><span class="p">.</span><span class="nx">x</span> <span class="o">*</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">width</span><span class="p">;</span>
        <span class="nx">reverse</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">yoffset</span> <span class="o">+</span> <span class="nx">lastFrame</span><span class="p">.</span><span class="nx">y</span> <span class="o">*</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">height</span><span class="p">;</span>
        <span class="nx">reverse</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">reverse</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="mf">0.8</span><span class="p">;</span>
        <span class="nx">reverse</span><span class="p">.</span><span class="nx">tint</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="c1">// This makes the arrow point back towards the start of the slider
</span><span class="c1"></span>        <span class="c1">// TODO: Make it point at the previous keyframe instead
</span><span class="c1"></span>        <span class="kd">var</span> <span class="nx">deltaX</span> <span class="o">=</span> <span class="nx">lastFrame</span><span class="p">.</span><span class="nx">x</span> <span class="o">-</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">x</span><span class="p">;</span>
        <span class="kd">var</span> <span class="nx">deltaY</span> <span class="o">=</span> <span class="nx">lastFrame</span><span class="p">.</span><span class="nx">y</span> <span class="o">-</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">y</span><span class="p">;</span>
        <span class="nx">reverse</span><span class="p">.</span><span class="nx">rotation</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">atan2</span><span class="p">(</span><span class="nx">deltaY</span><span class="p">,</span> <span class="nx">deltaX</span><span class="p">)</span> <span class="o">+</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">PI</span><span class="p">;</span>

        <span class="nx">hit</span><span class="p">.</span><span class="nx">objects</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">reverse</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">if</span> <span class="p">(</span><span class="nx">hit</span><span class="p">.</span><span class="nx">repeat</span> <span class="o">&gt;</span> <span class="mi">2</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// Add another reverse symbol
</span><span class="c1"></span>        <span class="kd">var</span> <span class="nx">reverse</span> <span class="o">=</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">reverse_b</span>
            <span class="o">=</span> <span class="k">new</span> <span class="nx">PIXI</span><span class="p">.</span><span class="nx">Sprite</span><span class="p">(</span><span class="nx">Resources</span><span class="p">[</span><span class="s2">&#34;reversearrow.png&#34;</span><span class="p">]);</span>
        <span class="nx">reverse</span><span class="p">.</span><span class="nx">alpha</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="nx">reverse</span><span class="p">.</span><span class="nx">anchor</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">reverse</span><span class="p">.</span><span class="nx">anchor</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="mf">0.5</span><span class="p">;</span>
        <span class="nx">reverse</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">xoffset</span> <span class="o">+</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">x</span> <span class="o">*</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">width</span><span class="p">;</span>
        <span class="nx">reverse</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">yoffset</span> <span class="o">+</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">y</span> <span class="o">*</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">height</span><span class="p">;</span>
        <span class="nx">reverse</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">reverse</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="mf">0.8</span><span class="p">;</span>
        <span class="nx">reverse</span><span class="p">.</span><span class="nx">tint</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="kd">var</span> <span class="nx">deltaX</span> <span class="o">=</span> <span class="nx">lastFrame</span><span class="p">.</span><span class="nx">x</span> <span class="o">-</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">x</span><span class="p">;</span>
        <span class="kd">var</span> <span class="nx">deltaY</span> <span class="o">=</span> <span class="nx">lastFrame</span><span class="p">.</span><span class="nx">y</span> <span class="o">-</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">y</span><span class="p">;</span>
        <span class="nx">reverse</span><span class="p">.</span><span class="nx">rotation</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">atan2</span><span class="p">(</span><span class="nx">deltaY</span><span class="p">,</span> <span class="nx">deltaX</span><span class="p">);</span>
        <span class="c1">// Only visible when it&#39;s the next end to hit:
</span><span class="c1"></span>        <span class="nx">reverse</span><span class="p">.</span><span class="nx">visible</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>

        <span class="nx">hit</span><span class="p">.</span><span class="nx">objects</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">reverse</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div><p>As you can see, there are many more moving pieces here. The important part is
the curve:</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="nx">hit</span><span class="p">.</span><span class="nx">curve</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">LinearBezier</span><span class="p">(</span><span class="nx">hit</span><span class="p">,</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">type</span> <span class="o">===</span> <span class="nx">SLIDER_LINEAR</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">curve</span><span class="p">.</span><span class="nx">curve</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="nx">c</span> <span class="o">=</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">curve</span><span class="p">.</span><span class="nx">curve</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
    <span class="kd">var</span> <span class="nx">base</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PIXI</span><span class="p">.</span><span class="nx">Sprite</span><span class="p">(</span><span class="nx">Resources</span><span class="p">[</span><span class="s2">&#34;hitcircle.png&#34;</span><span class="p">]);</span>
    <span class="nx">base</span><span class="p">.</span><span class="nx">anchor</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">base</span><span class="p">.</span><span class="nx">anchor</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="mf">0.5</span><span class="p">;</span>
    <span class="nx">base</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">xoffset</span> <span class="o">+</span> <span class="nx">c</span><span class="p">.</span><span class="nx">x</span> <span class="o">*</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">width</span><span class="p">;</span>
    <span class="nx">base</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">yoffset</span> <span class="o">+</span> <span class="nx">c</span><span class="p">.</span><span class="nx">y</span> <span class="o">*</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">height</span><span class="p">;</span>
    <span class="nx">base</span><span class="p">.</span><span class="nx">alpha</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="nx">base</span><span class="p">.</span><span class="nx">tint</span> <span class="o">=</span> <span class="nx">combos</span><span class="p">[</span><span class="nx">hit</span><span class="p">.</span><span class="nx">combo</span> <span class="o">%</span> <span class="nx">combos</span><span class="p">.</span><span class="nx">length</span><span class="p">];</span>
    <span class="nx">hit</span><span class="p">.</span><span class="nx">objects</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">base</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div><p>In the <a href="https://github.com/SirCmpwn/osuweb/tree/gh-pages/scripts/curves">curve
code</a>, a
series of points along each curve are generated for us to place sprites at.
These are precomputed like all other hit objects to save time during playback.
However, the render updater is still quite complicated:</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="k">this</span><span class="p">.</span><span class="nx">updateSlider</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">hit</span><span class="p">,</span> <span class="nx">time</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="nx">diff</span> <span class="o">=</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">time</span> <span class="o">-</span> <span class="nx">time</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">alpha</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="nx">diff</span> <span class="o">&lt;=</span> <span class="nx">NOTE_APPEAR</span> <span class="o">&amp;&amp;</span> <span class="nx">diff</span> <span class="o">&gt;</span> <span class="nx">NOTE_FULL_APPEAR</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// Fade in (before hit)
</span><span class="c1"></span>        <span class="nx">alpha</span> <span class="o">=</span> <span class="nx">diff</span> <span class="o">/</span> <span class="nx">NOTE_APPEAR</span><span class="p">;</span>
        <span class="nx">alpha</span> <span class="o">-=</span> <span class="mf">0.5</span><span class="p">;</span> <span class="nx">alpha</span> <span class="o">=</span> <span class="o">-</span><span class="nx">alpha</span><span class="p">;</span> <span class="nx">alpha</span> <span class="o">+=</span> <span class="mf">0.5</span><span class="p">;</span>

        <span class="nx">hit</span><span class="p">.</span><span class="nx">approach</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="p">((</span><span class="nx">diff</span> <span class="o">/</span> <span class="nx">NOTE_APPEAR</span> <span class="o">*</span> <span class="mi">2</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mf">0.9</span><span class="p">;</span>
        <span class="nx">hit</span><span class="p">.</span><span class="nx">approach</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="p">((</span><span class="nx">diff</span> <span class="o">/</span> <span class="nx">NOTE_APPEAR</span> <span class="o">*</span> <span class="mi">2</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mf">0.9</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">diff</span> <span class="o">&lt;=</span> <span class="nx">NOTE_FULL_APPEAR</span> <span class="o">&amp;&amp;</span> <span class="nx">diff</span> <span class="o">&gt;</span> <span class="o">-</span><span class="nx">hit</span><span class="p">.</span><span class="nx">sliderTimeTotal</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// During slide
</span><span class="c1"></span>        <span class="nx">alpha</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">diff</span> <span class="o">&gt;</span> <span class="nx">NOTE_DISAPPEAR</span> <span class="o">-</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">sliderTimeTotal</span> <span class="o">&amp;&amp;</span> <span class="nx">diff</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// Fade out (after slide)
</span><span class="c1"></span>        <span class="nx">alpha</span> <span class="o">=</span> <span class="nx">diff</span> <span class="o">/</span> <span class="p">(</span><span class="nx">NOTE_DISAPPEAR</span> <span class="o">-</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">sliderTimeTotal</span><span class="p">);</span>
        <span class="nx">alpha</span> <span class="o">-=</span> <span class="mf">0.5</span><span class="p">;</span> <span class="nx">alpha</span> <span class="o">=</span> <span class="o">-</span><span class="nx">alpha</span><span class="p">;</span> <span class="nx">alpha</span> <span class="o">+=</span> <span class="mf">0.5</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// Update approach circle
</span><span class="c1"></span>    <span class="k">if</span> <span class="p">(</span><span class="nx">diff</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">hit</span><span class="p">.</span><span class="nx">approach</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="p">((</span><span class="nx">diff</span> <span class="o">/</span> <span class="nx">NOTE_APPEAR</span> <span class="o">*</span> <span class="mi">2</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mf">0.9</span><span class="p">;</span>
        <span class="nx">hit</span><span class="p">.</span><span class="nx">approach</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="p">((</span><span class="nx">diff</span> <span class="o">/</span> <span class="nx">NOTE_APPEAR</span> <span class="o">*</span> <span class="mi">2</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mf">0.9</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">diff</span> <span class="o">&gt;</span> <span class="nx">NOTE_DISAPPEAR</span> <span class="o">-</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">sliderTimeTotal</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">hit</span><span class="p">.</span><span class="nx">approach</span><span class="p">.</span><span class="nx">visible</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
        <span class="nx">hit</span><span class="p">.</span><span class="nx">follow</span><span class="p">.</span><span class="nx">visible</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
        <span class="nx">hit</span><span class="p">.</span><span class="nx">follow</span><span class="p">.</span><span class="nx">alpha</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
        <span class="nx">hit</span><span class="p">.</span><span class="nx">ball</span><span class="p">.</span><span class="nx">visible</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
        <span class="nx">hit</span><span class="p">.</span><span class="nx">ball</span><span class="p">.</span><span class="nx">alpha</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

        <span class="c1">// Update ball and follow circle
</span><span class="c1"></span>        <span class="kd">var</span> <span class="nx">t</span> <span class="o">=</span> <span class="o">-</span><span class="nx">diff</span> <span class="o">/</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">sliderTimeTotal</span><span class="p">;</span>
        <span class="kd">var</span> <span class="nx">at</span> <span class="o">=</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">curve</span><span class="p">.</span><span class="nx">pointAt</span><span class="p">(</span><span class="nx">t</span><span class="p">);</span>
        <span class="kd">var</span> <span class="nx">at_next</span> <span class="o">=</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">curve</span><span class="p">.</span><span class="nx">pointAt</span><span class="p">(</span><span class="nx">t</span> <span class="o">+</span> <span class="mf">0.01</span><span class="p">);</span>
        <span class="nx">hit</span><span class="p">.</span><span class="nx">follow</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">at</span><span class="p">.</span><span class="nx">x</span> <span class="o">*</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">width</span> <span class="o">+</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">xoffset</span><span class="p">;</span>
        <span class="nx">hit</span><span class="p">.</span><span class="nx">follow</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="nx">at</span><span class="p">.</span><span class="nx">y</span> <span class="o">*</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">height</span> <span class="o">+</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">yoffset</span><span class="p">;</span>
        <span class="nx">hit</span><span class="p">.</span><span class="nx">ball</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">at</span><span class="p">.</span><span class="nx">x</span> <span class="o">*</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">width</span> <span class="o">+</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">xoffset</span><span class="p">;</span>
        <span class="nx">hit</span><span class="p">.</span><span class="nx">ball</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="nx">at</span><span class="p">.</span><span class="nx">y</span> <span class="o">*</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">height</span> <span class="o">+</span> <span class="nx">gfx</span><span class="p">.</span><span class="nx">yoffset</span><span class="p">;</span>
        <span class="kd">var</span> <span class="nx">deltaX</span> <span class="o">=</span> <span class="nx">at</span><span class="p">.</span><span class="nx">x</span> <span class="o">-</span> <span class="nx">at_next</span><span class="p">.</span><span class="nx">x</span><span class="p">;</span>
        <span class="kd">var</span> <span class="nx">deltaY</span> <span class="o">=</span> <span class="nx">at</span><span class="p">.</span><span class="nx">y</span> <span class="o">-</span> <span class="nx">at_next</span><span class="p">.</span><span class="nx">y</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">at</span><span class="p">.</span><span class="nx">x</span> <span class="o">!==</span> <span class="nx">at_next</span><span class="p">.</span><span class="nx">x</span> <span class="o">||</span> <span class="nx">at</span><span class="p">.</span><span class="nx">y</span> <span class="o">!==</span> <span class="nx">at_next</span><span class="p">.</span><span class="nx">y</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">hit</span><span class="p">.</span><span class="nx">ball</span><span class="p">.</span><span class="nx">rotation</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">atan2</span><span class="p">(</span><span class="nx">deltaY</span><span class="p">,</span> <span class="nx">deltaX</span><span class="p">)</span> <span class="o">+</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">PI</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">if</span> <span class="p">(</span><span class="nx">diff</span> <span class="o">&gt;</span> <span class="o">-</span><span class="nx">hit</span><span class="p">.</span><span class="nx">sliderTimeTotal</span><span class="p">)</span> <span class="p">{</span>
            <span class="kd">var</span> <span class="nx">index</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nx">t</span> <span class="o">*</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">sliderTime</span> <span class="o">*</span> <span class="mi">60</span> <span class="o">/</span> <span class="mi">1000</span><span class="p">)</span> <span class="o">%</span> <span class="mi">10</span><span class="p">;</span>
            <span class="nx">hit</span><span class="p">.</span><span class="nx">ball</span><span class="p">.</span><span class="nx">texture</span> <span class="o">=</span> <span class="nx">Resources</span><span class="p">[</span><span class="s2">&#34;sliderb&#34;</span> <span class="o">+</span> <span class="nx">index</span> <span class="o">+</span> <span class="s2">&#34;.png&#34;</span><span class="p">];</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">if</span> <span class="p">(</span><span class="nx">hit</span><span class="p">.</span><span class="nx">reverse</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">hit</span><span class="p">.</span><span class="nx">reverse</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">reverse</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">+</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">abs</span><span class="p">(</span><span class="nx">diff</span> <span class="o">%</span> <span class="mi">300</span><span class="p">)</span> <span class="o">*</span> <span class="mf">0.001</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">if</span> <span class="p">(</span><span class="nx">hit</span><span class="p">.</span><span class="nx">reverse_b</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">hit</span><span class="p">.</span><span class="nx">reverse_b</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">hit</span><span class="p">.</span><span class="nx">reverse_b</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">y</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">+</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">abs</span><span class="p">(</span><span class="nx">diff</span> <span class="o">%</span> <span class="mi">300</span><span class="p">)</span> <span class="o">*</span> <span class="mf">0.001</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="nx">_</span><span class="p">.</span><span class="nx">each</span><span class="p">(</span><span class="nx">hit</span><span class="p">.</span><span class="nx">objects</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">_</span><span class="p">.</span><span class="nx">isUndefined</span><span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">_manualAlpha</span><span class="p">))</span> <span class="p">{</span>
            <span class="nx">o</span><span class="p">.</span><span class="nx">alpha</span> <span class="o">=</span> <span class="nx">alpha</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">});</span>
<span class="p">}</span>
</code></pre></div><p>Much of this is the same as the hit circle updater, since we have a similar hit
circle at the start of the slider that needs to update in a similar fashion.
However, we also have to move the rolling ball and the follow circle along the
slider as the song progresses. This involves calling out to the curve code to
figure out what point is (<code>current_time / slider_end</code>) along the length of the
slider. We put the ball there, and we also ask for the point at (<code>(current_time + 0.01) / slider_end</code>) and make the ball rotate to face that direction.</p>
<h2 id="conclusions">Conclusions</h2>
<p>That&rsquo;s the bulk of the work neccessary to make an osu renderer. I&rsquo;ll have to add
spinners once I feel like the slider code is complete, and a friend is working
on adding hit sounds (sound effects that play when you correctly hit a note).
The biggest problem he&rsquo;s facing is that Web Audio has no good solution for
low-latency audio playback. On my side of things, though, everything is going
great. PIXI was a really good choice - it&rsquo;s an easy to use API and the WebGL
frontend is fast as hell. osu!web plays a map with performance that compares to
the performance of osu! native.</p>
<script src="https://drewdevault.com/js/osu.js"></script>
<script>
var xhr = new XMLHttpRequest();
xhr.open("GET", "/example.osu");
xhr.onload = function() {
    window.track = new Track(xhr.responseText);
    window.track.decode();
};
xhr.send();
</script>


guid: https://drewdevault.com/2015/07/20/A-practical-understanding-of-Flux.html
title: A practical understanding of Flux
url: https://drewdevault.com/2015/07/20/A-practical-understanding-of-Flux.html
feedurl: https://drewdevault.com/blog/index.xml
content:
<p><a href="https://facebook.github.io/react/">React.js</a> and the
<a href="https://facebook.github.io/flux/">Flux</a> are shaping up to be some of the most
important tools for web development in the coming years. The MVC model was
strong on the server when we decided to take the frontend seriously, and it was
shoehorned into the frontend since we didn&rsquo;t know any better. React and Flux
challenge that and I like where it&rsquo;s going very much. That being said, it was
very difficult for me to get into. I put together this blog post to serve as a
more <em>practical</em> guide - the upstream documentation tells you a lot of concepts
and expects you to put them together yourself. Hopefully at the end of this
blog post you can confidently start writing things with React+Flux instead of
reading brain-melting docs for a few hours like I did.</p>
<p>At the core of it, React and Flux are very simple and elegant. Far more simple
than the voodoo sales pitch upstream would have you believe. To be clear,
<strong>React</strong> is a framework-ish that lets you describe your UI through reusable
components, and includes <em>jsx</em> for describing HTML elements directly in your
JavaScript code. <strong>Flux</strong> is an <em>optional</em> architectural design philosophy that
you can adopt to help structure your applications. I have been using
<a href="https://babeljs.io/">Babel</a> to compile my React+Flux work, which gives me
ES6/ES7 support - I strongly suggest you do the same. This blog post assumes
you&rsquo;re doing so. For a crash course on ES6, <a href="http://git.io/es6features">read this entire
page</a>. Crash course for ES7 is omitted here for
brevity, but <a href="https://gist.github.com/SirCmpwn/2e8e455c91494b7c3713">click this</a>
if you&rsquo;re interested.</p>
<h2 id="flux-overview">Flux overview</h2>
<p>Flux is based on a unidirectional data flow. The direction is: dispatcher ➜
stores ➜ views, and the data is actions. At the stores or views level, you can
give actions to the dispatcher, which passes them down the line.</p>
<p>Let&rsquo;s explain exactly what piece is, and how it fits in to your application.
After this I&rsquo;ll tell you some specific details and I have a starter kit prepared
for you to grab as well.</p>
<h3 id="dispatcher">Dispatcher</h3>
<p>The dispatcher is very simple. Anything can register to receive a callback when
an &ldquo;action&rdquo; happens. There is one dispatcher and one set of callbacks, and
everything that registers for it will receive every action given to the
dispatcher, and can do with this as it pleases. Generally speaking you will only
have the stores listen to this. The kind of actions you will send along may look
something like this:</p>
<ul>
<li>Add a record</li>
<li>Delete a record</li>
<li>Fetch a record with a given ID</li>
<li>Refresh a store</li>
</ul>
<p>Anything that would change data is going to be given to the dispatcher and
passed along to the actions. Since everything receives every action you give to
the dispatcher, you have to encode something into each action that describes
what it&rsquo;s for. I use objects that look something like this:</p>
<div class="highlight"><pre class="chroma"><code class="language-json" data-lang="json"><span class="p">{</span>
    <span class="nt">&#34;action&#34;</span><span class="p">:</span> <span class="s2">&#34;STORE_NAME.ACTION_TYPE.ETC&#34;</span><span class="p">,</span>
    <span class="err">...</span>
<span class="p">}</span>
</code></pre></div><p>Where <code>...</code> is whatever extra data you need to include (the ID of the record
to fetch, the contents of the record to be added, the property that needs to
change, etc). Here&rsquo;s an example payload:</p>
<div class="highlight"><pre class="chroma"><code class="language-json" data-lang="json"><span class="p">{</span>
    <span class="nt">&#34;action&#34;</span><span class="p">:</span> <span class="s2">&#34;ACCOUNTS.CREATE.USER&#34;</span><span class="p">,</span>
    <span class="nt">&#34;username&#34;</span><span class="p">:</span> <span class="s2">&#34;SirCmpwn&#34;</span><span class="p">,</span>
    <span class="nt">&#34;email&#34;</span><span class="p">:</span> <span class="s2">&#34;sir@cmpwn.com&#34;</span><span class="p">,</span>
    <span class="nt">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;hunter2&#34;</span>
<span class="p">}</span>
</code></pre></div><p>The Accounts store is listening for actions that start with <code>ACCOUNTS.</code> and when
it sees <code>CREATE.USER</code>, it knows a new user needs to be created with these
details.</p>
<h3 id="stores">Stores</h3>
<p>The stores just have ownership of data and handle any changes that happen to
that data. When the data changes, they raise events that the views can subscribe
to to let them know what&rsquo;s up. There&rsquo;s nothing magic going on here (I initially
thought there was magic). Here&rsquo;s a really simple store:</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kr">import</span> <span class="nx">Dispatcher</span> <span class="nx">from</span> <span class="s2">&#34;whatever&#34;</span><span class="p">;</span>

<span class="kr">export</span> <span class="kr">class</span> <span class="nx">UserStore</span> <span class="p">{</span>
    <span class="nx">constructor</span><span class="p">()</span> <span class="p">{</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">_users</span> <span class="o">=</span> <span class="p">[];</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">action</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">action</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
        <span class="nx">Dispatcher</span><span class="p">.</span><span class="nx">register</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">action</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="nx">get</span> <span class="nx">Users</span><span class="p">()</span> <span class="p">{</span>
        <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">_users</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="nx">action</span><span class="p">(</span><span class="nx">payload</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">switch</span> <span class="p">(</span><span class="nx">payload</span><span class="p">.</span><span class="nx">action</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">case</span> <span class="s2">&#34;ACCOUNTS.CREATE.USER&#34;</span><span class="o">:</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">_users</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span> 
                <span class="s2">&#34;username&#34;</span><span class="o">:</span> <span class="nx">payload</span><span class="p">.</span><span class="nx">username</span><span class="p">,</span>
                <span class="s2">&#34;email&#34;</span><span class="o">:</span> <span class="nx">payload</span><span class="p">.</span><span class="nx">email</span><span class="p">,</span>
                <span class="s2">&#34;password&#34;</span><span class="o">:</span> <span class="nx">payload</span><span class="p">.</span><span class="nx">password</span>
            <span class="p">});</span>
            <span class="nx">raiseChangeEvent</span><span class="p">();</span> <span class="c1">// Exercise for the reader
</span><span class="c1"></span>            <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kd">let</span> <span class="nx">store</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">UserStore</span><span class="p">();</span>
<span class="kr">export</span> <span class="k">default</span> <span class="k">new</span> <span class="nx">UserStore</span><span class="p">();</span>
</code></pre></div><p>Yeah, that&rsquo;s all there is to it. Each store should be a singleton. You use it
like this:</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kr">import</span> <span class="nx">UserStore</span> <span class="nx">from</span> <span class="s2">&#34;whatever/UserStore&#34;</span><span class="p">;</span>

<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">UserStore</span><span class="p">.</span><span class="nx">Users</span><span class="p">);</span>

<span class="nx">UserStore</span><span class="p">.</span><span class="nx">registerChangeEvent</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">UserStore</span><span class="p">.</span><span class="nx">Users</span><span class="p">);</span> <span class="c1">// This has changed now
</span><span class="c1"></span><span class="p">});</span>
</code></pre></div><p>Stores end up having a lot of boilerplate. I haven&rsquo;t quite figured out the best
way to address that yet.</p>
<h3 id="views">Views</h3>
<p>Views are react components. What makes React components interesting is that they
re-render the whole thing when you call <code>setState</code>. If you want to change the
way it appears on the page for any reason, a call to <code>setState</code> will need to
happen. And here are the two circumstances under which they will change:</p>
<ul>
<li>In response to user input to change non-semantic view state</li>
<li>In response to a change event from a store</li>
</ul>
<p>The first bullet here means that you can call <code>setState</code> to change view states,
but not data. The second bullet is for when the data changes. When you change
view states, this refers to things like &ldquo;click button to reveal form&rdquo;. When you
change data, this refers to things like &ldquo;a new record was created, show it&rdquo;, or
even &ldquo;a single property of a record changed, show that change&rdquo;.</p>
<p><strong>Wrong way</strong>: you have a text box that updates the &ldquo;name&rdquo; of a record. When the
user presses the &ldquo;Apply&rdquo; key, the view will re-render itself with the new name.</p>
<p><strong>Right way</strong>: When you press &ldquo;Apply&rdquo;, the view sends an action to the
dispatcher to apply the change. The relevant store picks up the action, applies
the change to its own data store, and raises an event. Your view hears that
event and re-renders itself.</p>
<p><img src="https://facebook.github.io/flux/img/flux-simple-f8-diagram-1300w.png" alt=""></p>
<p><img src="https://facebook.github.io/flux/img/flux-simple-f8-diagram-with-client-action-1300w.png" alt=""></p>
<h3 id="why-bother">Why bother?</h3>
<ul>
<li>Easy to have stores depend on each other</li>
<li>All views that depend on the same stores are updated when it changes</li>
<li>It follows that all cross-store dependencies are updated in a similar fashion</li>
<li>Single source of truth for data</li>
<li>Easy as pie to pick up and maintain with little knowledge of the codebase</li>
</ul>
<h2 id="practical-problems">Practical problems</h2>
<p>Here are some problems I ran into, and the fluxy solution to each.</p>
<h3 id="need-to-load-data-async">Need to load data async</h3>
<p>You have a list of DNS records to show the user, but they&rsquo;re hanging out on the
server instead of in JavaScript objects. Here&rsquo;s how you accomodate for this:</p>
<ul>
<li>When you use a store, call <code>Store.fetchIfNecessary()</code> first.</li>
<li>When you pull data from the store, expect <code>null</code> and handle this elegantly.</li>
<li>When the initial fetch finishes in the store, raise a change event.</li>
</ul>
<p>From <code>fetchIfNecessary</code> in the store, go do the request unless it&rsquo;s in progress or
done. On the view side, show a loading spinner or something if you get <code>null</code>.
When the change event happens, whatever code set the state of your component
initially will be re-run, and this time it won&rsquo;t get <code>null</code> - deal with it
appropriately (show the actual UI).</p>
<p>This works for more than things that are well-defined at dev time. If you need
to, for example, fetch data for an arbitrary ID:</p>
<ul>
<li>View calls <code>Store.userById(10)</code> and gets <code>null</code>, renders lack of data
appropriately</li>
<li>Store is like &ldquo;my bad&rdquo; and fetches it from the server</li>
<li>Store raises change event when it arrives and the view re-renders</li>
</ul>
<h3 id="batteries-not-included">Batteries not included</h3>
<p>Upstream, in terms of actual usable code, flux just gives you a dispatcher. You
also need something to handle your events. This is easy to roll yourself, or you
can grab one of a bazillion things online that will do it for you. There is also
no base Store class for you, so make one of those. You should probably just
include some shared code for raising events and consuming actions. Mine looks
something like this:</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kr">class</span> <span class="nx">UserStore</span> <span class="kr">extends</span> <span class="nx">Store</span> <span class="p">{</span>
    <span class="nx">constructor</span><span class="p">()</span> <span class="p">{</span>
        <span class="kr">super</span><span class="p">(</span><span class="s2">&#34;USER&#34;</span><span class="p">);</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">_users</span> <span class="o">=</span> <span class="p">[];</span>
        <span class="kr">super</span><span class="p">.</span><span class="nx">action</span><span class="p">(</span><span class="s2">&#34;CREATE.USER&#34;</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">userCreated</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="nx">userCreated</span><span class="p">(</span><span class="nx">payload</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">_users</span><span class="p">.</span><span class="nx">push</span><span class="p">(...);</span>
        <span class="kr">super</span><span class="p">.</span><span class="nx">raiseChangeEvent</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="nx">get</span> <span class="nx">Users</span> <span class="p">{</span>
        <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">_users</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div><p>Do what works best for you.</p>
<h2 id="starter-kit">Starter Kit</h2>
<p>If you want something with the batteries in and a base to build from, I&rsquo;ve got
you covered. Head over to
<a href="https://github.com/SirCmpwn/react-starter-kit">SirCmpwn/react-starter-kit</a> on
Github.</p>
<h2 id="conclusion">Conclusion</h2>
<p>React and Flux are going to be big. This feels like the right way to build a
frontend. Hopefully I saved you from all the headache I went through trying to
&ldquo;get&rdquo; this stuff, and I hope it serves you well in the future. I&rsquo;m going to be
pushing pretty hard for this model at my new gig, so I may be writing more blog
posts as I explore it in a large-scale application - stay tuned.</p>


