[{"content":"I rode every single WeGo local/frequent/connector service bus route in one day, riding to at least one unique stop for that route.\nWhy? Why not! Also riding the bus is fun, but it can be boring during summer break and I wanna have some fun\nBackstory Last year I challenged myself to ride all 8 \u0026ldquo;frequent service\u0026rdquo; routes in at least one direction in one day, which took just under 8 hours. You can see the whole thing on my BlueSky page documented in realtime here and a summary here. Pre-planning the whole thing turned out to be an effective strategy, as with a bit of padding baked into every ride, it was easy to finish in well under the expected time for all 14 buses. But at the same. time, that\u0026rsquo;s only 8 routes, and most of the run was spent waiting on buses for a while, which isn\u0026rsquo;t really a \u0026ldquo;speedrun\u0026rdquo; in my eyes.\nPreplanning/Rules I\u0026rsquo;d had the idea ever since I completed the last run, but thought it\u0026rsquo;d be so complicated I put it of for months. But yesterday I was like \u0026ldquo;you know what, let\u0026rsquo;s just do it and see what happens\u0026rdquo;, as worst case scenario I try again next week, best case scenario I succeed today. So last night I printed out a copy of the \u0026ldquo;system timetable\u0026rdquo; (on the back side of the WeGo system map) and packed my bag with all the essentials, most of which I didn\u0026rsquo;t end up needing.\nMy rules were as follows:\nI must ride every WeGo bus route in one day I am excluding the express and Star-related buses, as they are \u0026ldquo;regional\u0026rdquo; and technically under the RTA\u0026rsquo;s authority (and would be a pain to do with 3 trips/day) I must visit at least one unique stop on each route (i.e. for a route to count, I must visit on the bus a stop whose sign only features that route\u0026rsquo;s number) Only WeGo buses and walking/running are allowed methods of transit Time starts when I step on the first bus and ends when I step off the last bus Detoured routes are allowed, provided I still visit a regularly scheduled \u0026ldquo;exclusive\u0026rdquo; stop. Data At the top of the page, you can see the mostly accurate map of all the buses I rode. Sadly, I didn\u0026rsquo;t have the battery life to do a full Strava-style GPS.\nAnd because of the Miles in Transit Discord/Ben Chase Transit Challenge, I also kept a spreadsheet of everything, excluding a datapoint I somehow missed: In order to show that I actually rode each bus, I generally took a photo when I got on the bus, while I was inside the bus, and when I got off the bus. Sometimes I didn\u0026rsquo;t use my phone\u0026rsquo;s camera properly or just forgot/was distracted, so there are a few missing ones.\nThe Story Quick Beginnings I woke up around 6:00 blah blah blah eventually I end up at the corner of Old Hickory Boulevard and Highway 70S to catch the 70 Bellevue. This route is the most difficult to catch due to it\u0026rsquo;s very infrequent scheduling and extremely far away route from downtown, hence why I am catching it now. From this point, I ride it over further away until getting off after a few miles.\nAt this point I cross the street and got onto the 3B West End heading inbound to downtown, and this is where I start the planning of what to do next, as I basically only had my first two routes pre-planned out at all. Eventually due to my impulsivity, I got off as soon as we intersected another route near Vanderbilt.\nI then got on the 77 Thompson/Wedgewood northbound to start working my way in a clockwise \u0026ldquo;orbit\u0026rdquo; of downtown. I always love how the 77 and 75 use the minibuses for some reason, as these routes are very useful for quickly getting around places without going downtown. Regardless, my time here is short so I eventually get off.\nA block over I get on a 19 Herman inbound to downtown due to a well-lucked transfer, which I stay on for about a mile to reach the general hospital near Fisk, before getting off to continue working my way north (we can\u0026rsquo;t go downtown quite yet).\nHints of Chaos As I\u0026rsquo;m running up north to catch the 29 Jefferson, I\u0026rsquo;m only about a block away before I see it fly by, at which point I know I\u0026rsquo;m in kind of a terrible position. Do I wait for another 30 minutes to catch it or do I cut my losses and just revisit it later in the day? Luckily, I notice a rapidly approaching southbound 75 Midtown, which I quickly get on.\nAfter a stop I get off (just so I could nab the route), and make my way back up to the main road, where I\u0026rsquo;m in a bit of a predicament, but I just decided to wait it out for a few minutes to catch the next 29, since even at this pace, I\u0026rsquo;d still finish decently early. Eventually that bus comes, so I get on it for a few stops, securing another local route.\nOf course, I had about half a mile walk back (I missed the first stop I could get off on), but proceeded to make it back to where the 75 Midtown intersected Jefferson, where I go on it and made my way northbound all the way to the new North Nashville Transit Center.\nNNTC Groove At NNTC, I have ton of options to do, so after checking the departures, I get on the 42 Cumberland and basically immediately get off at the first stop (it shares no stops with other routes due to a weird map layout), and walked back to NNTC.\nIn the next moment, I realize that catching a 22 Bordeaux would be kind of stupid right now, since it has 10 minute frequencies all day and goes downtown with a almost entirely unique route, making it especially well-suited for towards the end of the day. Ideally I could\u0026rsquo;ve fit the 9 Metrocenter with a quick \u0026ldquo;out and back\u0026rdquo;, but sadly the scheduling didn\u0026rsquo;t work out too well for now. Instead I just get on a 14 Whites Creek for a mile or so, reaching the point where it branches off from the 77 and 71.\nLuckily for me a 71 Trinity, with 30 minute headways, was on the way, so with a quick rush down the road, I got on it and proceeded to start the real orbit around the northern side of town.\nJourney East The 71 actually led me perfectly, route-wise, into the 41 Golden Valley\u0026rsquo;s territory, which is quite the route. The 60 minute frequencies during the midday meant I had to wait for a good 15 minutes or so to catch it (it could\u0026rsquo;ve been far worse without planning), and then the route itself it this extremely weird zigzag pattern. The driver said it was the most difficult route, and that they don\u0026rsquo;t even get many breaks for it, which definitely needs to be addressed.\nForgot to take one inside\nI got off on this perfect corner on the map where the 23B Dickerson Pike and 41 meet up but don\u0026rsquo;t touch, and then made my way further northwest on yet another incredibly zigzagy route to the Dickerson Walmart.\nExcluding the trash (which it odes feel like there\u0026rsquo;s an abnormally high amount of here), it was a fairly decently little waiting area, where I stay for a little while to catch the 79 Skyline that turns into a 76 Madison, so staying on that one bus knocked out two routes with one bus ride. Despite that, the scheduling and mapping situation for the 79/76 is incredibly frustrating, as even myself using WeGo\u0026rsquo;s website, the GTFS feed, and the Transit App could barely figure out if I was on the right path. It really should just be one number, but regardless I still made it and eventually reached just past where the 76 splits off from Gallatin Pike.\nWay to Central The most efficient way to downtown would be to take a 56 Gallatin Pike, but that\u0026rsquo;d remove my ability to get the 34 and 4 (two routes with highish headways), so I instead get on the 56 from my location down to where both the 34 and 4 intersect its route, in hopes the scheduling gods will have at least one of those routes come soonish in one direction.\nForgot to take one when I got off\nFrom there, my schedule suggests the best plan of action is to run off onto a side street to catch an outbound 34 Opry Mills before it merged onto Gallatin, and given it\u0026rsquo;s the \u0026ldquo;rarer\u0026rdquo; of the two routes, it\u0026rsquo;s what I nab first.\nAfter that, all I needed was the 4 Shelby, which actually has a frequent variant that goes out just ot the park, and a less frequent variant that goes all the way out to where I am. Of course I needed the uncommon variant, so I do have to wait by a quite greenery-covered bus stop sign for a decent bit before making my way all the way to Central for the first time all day.\nSoutheast Chaos Central has dozens of buses to choose from, so essentially out of randomness (and to keep the clockwise orbit in a way), I chose the 6 Lebanon Pike to hop on to for a bit, which took a decent minute to hit its own stops, at which point I immediately hopped off since that road has tons of traffic otherwise.\nFrom here I wanted to catch a 52/55/18, so I start my way over to catch a 52 Nolensville Pike outbound for some reason. I was running and got very tired quite quickly, and then realized my silly mistake before having to run back in the opposite direction just to catch a proper inbound 52 within its \u0026ldquo;dedicated stop range\u0026rdquo; to take me back into Demonbreun and 8th, which turned out to be a decent mini-hub for today due to having lots of routes at it while not having as much traffic as Central.\nFrom there, I got on the 18 Airport (local variant), as it is the rarer of the 55/18 combo, and I ride it out for a decent way before it split off from the 55. Many of the stops after the split were unmarked, so I actually had to get off a lot later than I had intended since the driver (and myself) were a little confused. I actually met a non-driver WeGo employee there who seemed interested in my story, so hopefully they get to see this someday! Sadly it was a little distracting, and despite recording a video I somehow didn\u0026rsquo;t capture anything on this bus except a bit after I got off.\nForgot to take one when I got on\nForgot to take one inside\nAfter having to quickly wrap up the conversation, I have to make the extremely long journey back to the 55 Murfreesboro Pike due to the later than anticipated stop, which takes a little while, and I do start to run more just to make sure I can catch it. Turned out that the stop I wanted to use also had one of the express routes on it, and while I\u0026rsquo;m not riding them, that technically means it\u0026rsquo;s a \u0026ldquo;non-exclusive\u0026rdquo; stop. Due to this, I had to walk out another quarter/half mile or so to catch the next inbound 55, which I successfully do before getting off yet again at Demonbreun and 8th.\nSouth We Go My main plan from here on was to cover the southern routes, then go back and cover the northern routes I missed before finishing. To start, I continue the orbital by grabbing the first 8 8th Avenue South I can before taking it south a mile or two. Turns out I actually stayed on this one a bit longer than anticipated due to a lack of traffic.\nLuckily this didn\u0026rsquo;t affect my plans too much, as I still just ended up walking across where the 77 would go (versus the 75), not catching it of course due to scheduling/speed reasons. I knew the next bus I wanted, the 17 12th Avenue South, had quite a ways to go, so this was simply a nice long stroll through Nashville that was quite fun. I ended up waiting by some quite nice bicycle infrastructure by Nashville standards, especially due to the shade and wide protection curb. Of course I get on the outbound 17 and carry it all the way to Hillboro Transit Center since it\u0026rsquo;d be the easiest way to catch a 7.\nAfter a short break off the bus, I catch the inbound 7 Hillsboro Pike, which took a surprisingly long time to reach downtown due to all of the car traffic. I don\u0026rsquo;t know if it was all the side roads spoiling me, but it did take a fair bit, yet eventually we did reach downtown and Central.\nFinal Touchups At this point I just had to wrap up the northern routes I skipped earlier, starting with the 28 Meridian due to its lack of frequency in the midday. My plan was to get off as soon as it branched off the 9\u0026rsquo;s route (which they share for the first bit), but it turned out that it doesn\u0026rsquo;t have any stops until after it crosses the river for some reason, so I end up just getting off there instead.\nLuckily for me after crossing the road I\u0026rsquo;m able to catch an inbound 28 quite quickly, which I take back into downtown. For some reason, some of the 28/9 area inbound stops were unmarked, so the bus wasn\u0026rsquo;t able to stop at them, forcing me to travel back into Central even if it\u0026rsquo;d be easier to just catch a 9 there.\nSince we had just seen a 9 leave around the time my initial 28 left Central, the 9 Metrocenter I was going to catch just then hadn\u0026rsquo;t even left yet, allowing me to simply stroll over to it and hop on, before riding it in its entirety all the way up to the NNTC again. I probably could\u0026rsquo;ve gotten off and then walked to catch an inbound 22, but it would\u0026rsquo;ve had some issues to the the 22 and 42 sharing a bit of their \u0026ldquo;close to downtown\u0026rdquo; routes. NNTC is quite cool, and I actually had a second to peek a look inside the building this time, and I have to say it\u0026rsquo;s pretty cool.\nFrom there it was simply a matter of cruising on the next 22 Bordeaux through Nashville and into Central, with honesty not much to say due to it\u0026rsquo;s nature as basically just a shuttle between two transit centers (yet a very nice one).\nFinale At Central I make my way around to the bay for the 50 Charlotte Pike, and the last bus I need is right there and will leave soon! At least I though that\u0026rsquo;d happen, but it took quite a while to actually get a driver, to the point of almost being a bus and a half late. The Dunkin Donuts was right there, so I probably should\u0026rsquo;ve gotten something to be honest, but eventually our bus did board, and it was simply a matter of reaching the first 50-exclusive stop for the record to count. Although for the purposes of this, I had to reach the Charlotte Walmart, so the run actually ended there once I stepped off the bus.\nAnd with a final time of exactly 11 hours, that I exactly how long it takes you to ride every single local/MTA WeGo route in one day here in Nashville. What should you do with this information? I don\u0026rsquo;t know, I didn\u0026rsquo;t think we\u0026rsquo;d get this far. Maybe see if you can beat it sometime in the future? I\u0026rsquo;m pretty confident it could be reduced 1-2 hours with better luck and scheduling, although the nature of these runs is that they require a lot of \u0026ldquo;realtime strategy\u0026rdquo; to complete effectively with preplanning being almost useless outside niche scenarios.\n","permalink":"https://andw.me/posts/26-07-10-wego-all-routes-speedrun/","summary":"\u003cp\u003eI rode every single WeGo local/frequent/connector service bus route in one day, riding to at least one unique stop for that route.\u003c/p\u003e\n\u003cp\u003eWhy? Why not! Also riding the bus is fun, but it can be boring during summer break and I wanna have some fun\u003c/p\u003e\n\u003ch2 id=\"backstory\"\u003eBackstory\u003c/h2\u003e\n\u003cp\u003eLast year I challenged myself to ride all 8 \u0026ldquo;frequent service\u0026rdquo; routes in at least one direction in one day, which took just under 8 hours. You can see the whole thing on my BlueSky page documented in realtime \u003ca href=\"https://bsky.app/profile/andw.me/post/3m4if5eozis23\"\u003ehere\u003c/a\u003e and a summary \u003ca href=\"https://bsky.app/profile/andw.me/post/3m4jwekurac2z\"\u003ehere\u003c/a\u003e. Pre-planning the whole thing turned out to be an effective strategy, as with a bit of padding baked into every ride, it was easy to finish in well under the expected time for all 14 buses. But at the same. time, that\u0026rsquo;s only 8 routes, and most of the run was spent waiting on buses for a while, which isn\u0026rsquo;t really a \u0026ldquo;speedrun\u0026rdquo; in my eyes.\u003c/p\u003e","title":"WeGo All-Routes Speedrun"},{"content":"TLDR; I made the DVD bouncing logo in a lot of ways because I was bored (GitHub)\nStory About five years ago I was goofing around in Scratch while bored, and ended up making a lot of weird projects, one of which was a bouncing DVD screensaver logo with some not original music/SFX. Why? Why not! And that was (and still is) kind of my philosophy for these sorts of things.\nNow in the present day, I have a friend who does a lot of programming, but for me programming is more the sort of thing I do only when I have to. But since I\u0026rsquo;m on summer break with nothing better to do, I felt like I should brush up on my experience a little bit, so after a bit of review of Java to reinforce some OOP concepts, I decided to jump to C++.\nI\u0026rsquo;ve always heard C++ is one of the most difficult languages, so while I knew basic things like pointers and the std::cout/cin bitshift operator overload were weird, I truly had no idea what I was getting myself into. I was able to easily write a basic procedural version of the DVD bouncing in C++ with Raylib, which I found to just be a solid (but easy) library to use, and even add some fun features like adding more DVDs and bounce sound effects. All this really helped me understand those concepts (like how to use pointers and make memory-safe code).\nOf course my sneaky Java OOP-brained mind decided to make an entire lightweight \u0026ldquo;game engine wrapper\u0026rdquo; in C++ Raylib, which if you know anything about any of those words is just kind of a stupid idea. While the code ballooned in size, and I was able to get it to work, writing objects within my lifecycle system while also referencing back to the core assets was not only a spaghetti-code nightmare, but also had so many stupid C++ decisions I can\u0026rsquo;t even begin to decipher. Think \u0026ldquo;aimlessly passing around pointers that really didn\u0026rsquo;t need to exist and that likely cause memory leaks\u0026rdquo;. Basically I learned that C++ has 5,000 ways to do one thing, and each of them has major tradeoffs in readability, efficiency, and complexity.\nI then realized Raylib, being a C library, had Rust bindings, so I got my Cargo environment set up, and ported over the basis of the app. As with all beginners, the borrow checker was my enemy, but once you get used to it, it\u0026rsquo;s really nice to know that it prevents me from making all manner of stupid decisions. While things like anonymous functions and custom types are a bit weird compared to other languages, there\u0026rsquo;s also a lot of \u0026ldquo;why does no other language do this\u0026rdquo; things, especially with the numerical primitives (so nice compared to C++) and mutability of data.\nIn the middle of the Rust Raylib version, I did try out Macroquad, but given some issues like a weird 60Hz frame cap on my computer and the lack control over window resizing events, I decided to migrate back for now.\nOh yeah, also I ported it to plain-old C (literally copy-pasted the basic Rust version and adjusted the syntax) just for fun, but given there\u0026rsquo;s bindings in every language, maybe someday I\u0026rsquo;ll have to expand, while using the DVD logo to find my favorite one.\nI generally think taking a simple concept, like this DVD logo, and adding just a stupid amount of features like spamming thousands of DVDs, randomizing positions/speed, changing hue on bounces, fancy music/SFX, and more can just be a whole lot of fun. Who knows? Maybe I\u0026rsquo;ll make a worthwhile downloading app someday.\nDemo I\u0026rsquo;ll do this tomorrow lol.\nCode Here\u0026rsquo;s links to the GitHub repositories with the \u0026ldquo;main\u0026rdquo; versions I worked on.\nC++ Raylib (OOP weirdness) Rust Raylib (fullest) Rust Macroquad (bare-bones) C Raylib (bare-bones) I\u0026rsquo;ve embedded the latest code for the Raylib in Rust version (that has the most features) below for reference:\nuse rand::RngExt; use raylib::prelude::*; struct Dvd { position: Vector2, velocity: Vector2, size: Vector2, hue: f32 } impl Dvd { fn new(position: Vector2, velocity: Vector2, size: Vector2) -\u0026gt; Self { Self { position, velocity, size, hue: 0.0 } } fn new_random(size: Vector2, screen: \u0026amp;Vector2, rng: \u0026amp;mut rand::rngs::ThreadRng) -\u0026gt; Self { Self { position: Vector2::new(rng.random_range(0.0..(screen.x-size.x)), rng.random_range(0.0..(screen.y-size.y))), velocity: Vector2::new(rng.random_range(-1000.0..1000.0), rng.random_range(-800.0..800.0)), size, hue: 0.0 } } fn update(\u0026amp;mut self, screen: \u0026amp;Vector2, dt: f32, bounce_sound: \u0026amp;Sound, play_bounce_sound: bool) { let mut already_bounced: bool = false; let mut bounce_events = || { self.hue = (self.hue + 30.0) % 360.0; if play_bounce_sound \u0026amp;\u0026amp; !already_bounced { bounce_sound.play(); } already_bounced = true; }; self.position.x += self.velocity.x * dt; self.position.y += self.velocity.y * dt; if self.position.x \u0026lt;= 0.0 || self.position.x \u0026gt;= screen.x - self.size.x { self.velocity.x = -self.velocity.x; bounce_events(); } if self.position.y \u0026lt;= 0.0 || self.position.y \u0026gt;= screen.y - self.size.y { self.velocity.y = -self.velocity.y; bounce_events(); } self.position.x = self.position.x.clamp(0.0, screen.x - self.size.x); self.position.y = self.position.y.clamp(0.0, screen.y - self.size.y); } fn draw(\u0026amp;self, d: \u0026amp;mut RaylibDrawHandle, texture: \u0026amp;Texture2D, source: \u0026amp;Rectangle) { let dvd_logo: Rectangle = Rectangle::new(self.position.x, self.position.y, self.size.x, self.size.y); let current_color = Color::color_from_hsv(self.hue, 1.0, 1.0); d.draw_texture_pro(\u0026amp;texture, *source, dvd_logo, Vector2::new(0.0, 0.0), 0.0, current_color); } } fn main() { println!(\u0026#34;DVD App\u0026#34;); let (mut rl, thread) = init() .size(900, 600) .title(\u0026#34;DVD\u0026#34;) .resizable() .build(); let mut rng = rand::rng(); let dvd_texture: Texture2D = rl.load_texture(\u0026amp;thread, \u0026#34;assets/dvd.png\u0026#34;).unwrap(); let dvd_source: Rectangle = Rectangle::new(0.0, 0.0, dvd_texture.width as f32, dvd_texture.height as f32); let dvd_size: Vector2 = Vector2::new(150.0, 80.0); let mut dvds: Vec\u0026lt;Dvd\u0026gt; = Vec::new(); dvds.push(Dvd::new( Vector2::new(rl.get_screen_width() as f32 / 2.0 - dvd_size.x / 2.0, rl.get_screen_height() as f32 / 2.0 - dvd_size.y / 2.0), Vector2::new(600.0, 300.0), dvd_size )); let audio: RaylibAudio = RaylibAudio::init_audio_device().unwrap(); let music: Music = audio.new_music(\u0026#34;assets/music.ogg\u0026#34;).unwrap(); let bounce_sound: Sound = audio.new_sound(\u0026#34;assets/bounce.ogg\u0026#34;).unwrap(); bounce_sound.set_volume(0.1); let mut debug_overlay: bool = false; let mut spam_dvds: bool = false; let mut play_music: bool = true; let mut play_bounce_sound: bool = true; music.play_stream(); while !rl.window_should_close() { let dt: f32 = rl.get_frame_time(); let screen: Vector2 = Vector2::new(rl.get_screen_width() as f32, rl.get_screen_height() as f32); if rl.is_key_pressed(KeyboardKey::KEY_A) { dvds.push(Dvd::new_random(dvd_size, \u0026amp;screen, \u0026amp;mut rng)) } if rl.is_key_pressed(KeyboardKey::KEY_S) { spam_dvds = !spam_dvds; } if rl.is_key_pressed(KeyboardKey::KEY_C) { dvds.clear(); } if rl.is_key_pressed(KeyboardKey::KEY_D) { debug_overlay = !debug_overlay; } if rl.is_key_pressed(KeyboardKey::KEY_M) { play_music = !play_music; } if rl.is_key_pressed(KeyboardKey::KEY_B) { play_bounce_sound = !play_bounce_sound; } if rl.is_key_pressed(KeyboardKey::KEY_P) { dvds.sort_by(|a, b| a.position.x.partial_cmp(\u0026amp;b.position.x).unwrap()); } if play_music { if !music.is_stream_playing() { music.play_stream(); } music.update_stream(); } else { music.stop_stream(); } if spam_dvds { dvds.push(Dvd::new_random(dvd_size, \u0026amp;screen, \u0026amp;mut rng)) } for dvd in \u0026amp;mut dvds { dvd.update(\u0026amp;screen, dt, \u0026amp;bounce_sound, play_bounce_sound); } let mut d = rl.begin_drawing(\u0026amp;thread); d.clear_background(Color::BLACK); for dvd in \u0026amp;dvds { dvd.draw(\u0026amp;mut d, \u0026amp;dvd_texture, \u0026amp;dvd_source); } if debug_overlay { let debug_text = format!(\u0026#34;DVDs: {}, FPS: {}\u0026#34;, dvds.len(), d.get_fps()); d.draw_text(\u0026amp;*debug_text, 20, 10, 20, Color::WHITE); } } } Oh yeah, here\u0026rsquo;s the Scratch version for those of you interested in it.\n","permalink":"https://andw.me/posts/26-06-24-dvd-experiments/","summary":"\u003cp\u003eTLDR; I made the DVD bouncing logo in a lot of ways because I was bored (\u003ca href=\"https://github.com/darkbrave/raylibrust-dvd\"\u003eGitHub\u003c/a\u003e)\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"A handfull of colorful DVD logos bouncing around a black window, with the source code for the application in the background open in RustRover\" loading=\"lazy\" src=\"/posts/26-06-24-dvd-experiments/cover.png\"\u003e\u003c/p\u003e\n\u003ch2 id=\"story\"\u003eStory\u003c/h2\u003e\n\u003cp\u003eAbout five years ago I was goofing around in Scratch while bored, and ended up making a lot of weird projects, one of which was a \u003ca href=\"https://scratch.mit.edu/projects/572030152/\"\u003ebouncing DVD screensaver logo\u003c/a\u003e with some not original music/SFX. Why? Why not! And that was (and still is) kind of my philosophy for these sorts of things.\u003c/p\u003e","title":"DVD Experiments"},{"content":"TLDR; I\u0026rsquo;ve moved from the awyck.me domain to the andw.me domain.\nI kind of bought the awyck.me domain so I could mess around with DNS, having a proper website (hello!), and just have a nice universal shorthand on the internet. It was a perfectly fine domain, but it\u0026rsquo;s kind of hard to quickly tell someone and focuses more on my last name than my first name.\nI was looking around on my domain registrar, and randomly realized that andw.me was available. Since it was relatively low-cost, while also fixing my previous issues, all while being extremely satisfying to me, I bought it and migrated all my DNS/domain stuff over to it.\nI\u0026rsquo;m probably going to let the old domain expire, since I\u0026rsquo;ve removed all the important DNS stuff and mostly just configured it as a redirect to a rickroll for the memes. I will continue to renew this domain and use it, as I don\u0026rsquo;t really see any more good domains coming out of the blue into my face again.\n","permalink":"https://andw.me/posts/26-06-23-domain-change/","summary":"\u003cp\u003eTLDR; I\u0026rsquo;ve moved from the \u003ca href=\"https://awyck.me\"\u003eawyck.me\u003c/a\u003e domain to the \u003ca href=\"https://andw.me\"\u003eandw.me\u003c/a\u003e domain.\u003c/p\u003e\n\u003cp\u003eI kind of bought the \u003ca href=\"https://awyck.me\"\u003eawyck.me\u003c/a\u003e domain so I could mess around with DNS, having a proper website (hello!), and just have a nice universal shorthand on the internet. It was a perfectly fine domain, but it\u0026rsquo;s kind of hard to quickly tell someone and focuses more on my last name than my first name.\u003c/p\u003e\n\u003cp\u003eI was looking around on my domain registrar, and randomly realized that \u003ca href=\"https://andw.me\"\u003eandw.me\u003c/a\u003e was available. Since it was relatively low-cost, while also fixing my previous issues, all while being extremely satisfying to me, I bought it and migrated all my DNS/domain stuff over to it.\u003c/p\u003e","title":"Domain change"},{"content":"I wanted to extract the music from some Nintendo Switch games that hadn\u0026rsquo;t been ripped yet. I\u0026rsquo;m not a lawyer, but whole process should be completely legal, assuming you are using your own dumps, which you should be using regardless.\nSteps You will need your dumped ROM in either .xci or .nsp format, alongside your title.keys and prod.keys extracted from your console, as the dumps can be encrypted. I\u0026rsquo;m not going to say how to do these things, as I\u0026rsquo;m a bit worried by the Nintendo Ninjas.\nDownload/clone the NSTool repository to a folder on your computer, and put your prod.keys in that folder. There are other tools for doing this, I just like NSTools since it just kinda works in my experience. Place your title.keys file into the ~/.switch/title.keys location on your computer.\nExtract the base game .NSP/.XCI file using the following command, adjusted to your exact filenames:\n./nstool -k ./prod.keys -x extracted/ ./switchromdump.nsp This will extract many .NCA files (where the content is), .CNMT.NCA files (metadata) and .TIK/.CERT files (certificates/tickets). Generally your largest .NCA file will have the bulk of the music. If you want to dump an update, you may need to further extract the ticket files by running: ./nstool -k ./prod.keys ./extracted/[random stuff].tik and then add them all to new lines in the title.keys in step 2\u0026rsquo;s location formated like this:\n[RightsID from the previous command] = [Data from the previous command] Now you can extract the largest .NCA files from the dumps: ./nstool -k ./prod.keys -x extracted-assets/ ./extracted/[random stuff].nca All music will generally be stored in the extracted-assets/Sound/Resources/Stream/ folders.\nYou\u0026rsquo;ll need to download/install vgmstream from their website to actually extract the music to a usable format.\nConvert the music using the following command while inside a folder with the music:\nfor f in *.bwav; do vgmstream-cli -o \u0026#34;out/${f%.bwav}.wav\u0026#34; \u0026#34;$f\u0026#34;; done Replace .bwav with whatever format it comes in.\nIf needed, manually assign metadata using a tool like File Explorer or iTunes (I\u0026rsquo;m sure there\u0026rsquo;s a FOSS alternative), and potentially mix split-up tracks in Audacity. ","permalink":"https://andw.me/reference/extracting-music-from-nintendo-switch-games/","summary":"\u003cp\u003eI wanted to extract the music from some Nintendo Switch games that hadn\u0026rsquo;t been ripped yet. I\u0026rsquo;m not a lawyer, but whole process should be completely legal, assuming you are using your own dumps, which you should be using regardless.\u003c/p\u003e\n\u003ch2 id=\"steps\"\u003eSteps\u003c/h2\u003e\n\u003cp\u003eYou will need your dumped ROM in either \u003ccode\u003e.xci\u003c/code\u003e or .\u003ccode\u003ensp\u003c/code\u003e format, alongside your \u003ccode\u003etitle.keys\u003c/code\u003e and \u003ccode\u003eprod.keys\u003c/code\u003e extracted from your console, as the dumps can be encrypted. I\u0026rsquo;m not going to say how to do these things, as I\u0026rsquo;m a bit worried by the Nintendo Ninjas.\u003c/p\u003e","title":"Extracting Assets from Nintendo Switch Games"},{"content":"Obviously you\u0026rsquo;ll need ggplot2 installed in your R environment to do this. I\u0026rsquo;ve also generated some bogus data just to keep things simple for this.\nlibrary(ggplot2) FullData \u0026lt;- data.frame( name = c(\u0026#34;Alice\u0026#34;, \u0026#34;Bob\u0026#34;, \u0026#34;Charlie\u0026#34;, \u0026#34;David\u0026#34;), score = c(42, 37, 91, 58), food = c(\u0026#34;pizza\u0026#34;, \u0026#34;tacos\u0026#34;, \u0026#34;pizza\u0026#34;, \u0026#34;burger\u0026#34;) ) print(FullData) name score food 1 Alice 42 pizza 2 Bob 37 tacos 3 Charlie 91 pizza 4 David 58 burger The easy way to generate a basic bar chart is as follows, which most of you should know by now.\nggplot(data=FullData, aes(x=name, y=score))+ geom_col() Now let\u0026rsquo;s say I want to color-code them to each type of food, with the following order: blue for pizza, red for tacos, and green for burger.\nThe easiest way to accomplish that is simply by manually assigning it in the \u0026ldquo;fill\u0026rdquo; field by combining them all into a vector (vectors are when you use a c(1, 2, 3) to define a list of values), listing the colors you want from left to right, as I have done below.\nggplot(data=FullData, aes(x=name, y=score))+ geom_col(fill=c(\u0026#34;blue\u0026#34;, \u0026#34;red\u0026#34;, \u0026#34;blue\u0026#34;, \u0026#34;green\u0026#34;)) Now this does work, but there isn\u0026rsquo;t a key on this graph, so viewers have no idea what the color means in the first place. Likewise, since the colors are hard-coded, if any one person\u0026rsquo;s food changes or we insert someone else in the middle, we have to manually adjust the list of colors to prevent blank/misassigned entries.\nInstead, we can use the aesthetic mapping (values stored in the aes(field1=data1, field2=data2) format that tells ggplot how to use data-driven variables to describe your graph), specifically for the \u0026ldquo;fill\u0026rdquo; value field.\nggplot(data=FullData, aes(x=name, y=score, fill=food))+ geom_col() Now this fixes the \u0026ldquo;there\u0026rsquo;s no key\u0026rdquo; and \u0026ldquo;need to manually update colors manually\u0026rdquo; problems, but now the colors are randomly chosen by ggplot instead of by us!\nTo set them ourselves, we can use the \u0026ldquo;scale_fill_manual\u0026rdquo; tool to define what colors we want to be assigned to each type of food. This also takes a vector, and for simplicity (also so it can be reused in the code), I\u0026rsquo;ve split it into its own variable.\nColorCode = c(\u0026#34;pizza\u0026#34; = \u0026#34;blue\u0026#34;, \u0026#34;tacos\u0026#34; = \u0026#34;red\u0026#34;, \u0026#34;burger\u0026#34; = \u0026#34;green\u0026#34;) ggplot(data=FullData, aes(x=name, y=score, fill=food))+ geom_col()+ scale_fill_manual(values=ColorCode) This is about as good as we can get it to be for now. Of course if this graph were to be presented, you should fix up the axes titles and do some light theming, but the core of these features can be applied to any graph you want to!\n","permalink":"https://andw.me/reference/r/custom-data-driven-colors-in-ggplot2/","summary":"\u003cp\u003eObviously you\u0026rsquo;ll need ggplot2 installed in your R environment to do this. I\u0026rsquo;ve also generated some bogus data just to keep things simple for this.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-r\" data-lang=\"r\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003elibrary\u003c/span\u003e(ggplot2)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eFullData \u003cspan style=\"color:#f92672\"\u003e\u0026lt;-\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003edata.frame\u003c/span\u003e(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  name \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ec\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Alice\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Bob\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Charlie\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;David\u0026#34;\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  score \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ec\u003c/span\u003e(\u003cspan style=\"color:#ae81ff\"\u003e42\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e37\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e91\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e58\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  food \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ec\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;pizza\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;tacos\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;pizza\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;burger\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003eprint\u003c/span\u003e(FullData)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e     name score   food\n1   Alice    42  pizza\n2     Bob    37  tacos\n3 Charlie    91  pizza\n4   David    58 burger\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eThe easy way to generate a basic bar chart is as follows, which most of you should know by now.\u003c/p\u003e","title":"Custom Data-Driven Colors in ggplot2"},{"content":"Caddy is a super easy to use web server that manages all the boring stuff for you, and because my Oracle always-free server\u0026rsquo;s port HTTP/HTTPS ports (80 and 443) were already in use by Caddy to hook up some webpages for my Minecraft servers, I needed a better way.\nSteps I will be assuming you already have Caddy setup, alongside that your server/network has some sort of firewall system in place to only allow desired ports. You should also have set up your DNS A record on your domain to redirect to your server\u0026rsquo;s IP address.\nAdd the following to your Caddyfile (/etc/caddy/Caddyfile), being sure to replace the domain with yours: discourse.example.com { reverse_proxy 127.0.0.1:8080 } Follow the beginner Discourse install guide and run the installer command, completing the configuration as normal. This will fail to complete, as we need to fix the configuration. wget -qO- https://raw.githubusercontent.com/discourse/discourse_docker/main/install-discourse | sudo bash This gets the basic installation of Discourse onto your server, which then lets us edit the configuration to work. Edit the Discourse docker configuration (/etc/discourse/containers/app.yml) to have the following edits: expose: - 8080:80 # - 443:443 env: DISCOURSE_FORCE_HTTPS: true This removes HTTPS from Discourse (Caddy will be managing that with Let\u0026rsquo;s Encrypt) and remaps the HTTP port to 8080 (so that Caddy can reverse-proxy it to port 80 externally). Finish your Discourse install by running the following command: sudo ./launcher rebuild app You should now be able to follow through the rest of the Discourse install process as normal to use your forum. Email me (link on main page) if there\u0026rsquo;s any problems with/fixes needed for this guide.\n","permalink":"https://andw.me/reference/discourse-with-caddy/","summary":"\u003cp\u003eCaddy is a super easy to use web server that manages all the boring stuff for you, and because my Oracle always-free server\u0026rsquo;s port HTTP/HTTPS ports (80 and 443) were already in use by Caddy to hook up some webpages for my Minecraft servers, I needed a better way.\u003c/p\u003e\n\u003ch2 id=\"steps\"\u003eSteps\u003c/h2\u003e\n\u003cp\u003eI will be assuming you already have Caddy setup, alongside that your server/network has some sort of firewall system in place to only allow desired ports. You should also have set up your DNS A record on your domain to redirect to your server\u0026rsquo;s IP address.\u003c/p\u003e","title":"Discourse with Caddy"},{"content":"Hello world!\nThis is mostly just a placeholder, but as the first post I would be remiss if I didn\u0026rsquo;t mention I won\u0026rsquo;t be taking this place super seriously. It\u0026rsquo;s mostly just a place for me to dump thoughts/ideas/opinions where I know someone, somewhere can read them. Oh yeah also there\u0026rsquo;s gonna be a lot of quick tips and tutorials as well in the reference section, mostly of things I keep forgetting how to do and want to put somewhere for future me. Do I expect this website to take off? Heck no! But being here is mostly about having fun and keeping a constant archive, while also acting as a personal landing page. So in that way, this website is already a success.\nI\u0026rsquo;ll see you all (or few) again next time, likely anytime between tomorrow morning and in five years.\n","permalink":"https://andw.me/posts/26-06-05-hello-world/","summary":"\u003cp\u003eHello world!\u003c/p\u003e\n\u003cp\u003eThis is mostly just a placeholder, but as the first post I would be remiss if I didn\u0026rsquo;t mention I won\u0026rsquo;t be taking this place super seriously. It\u0026rsquo;s mostly just a place for me to dump thoughts/ideas/opinions where I know someone, somewhere can read them. Oh yeah also there\u0026rsquo;s gonna be a lot of quick tips and tutorials as well in the \u003ca href=\"https://awyck.me/reference\"\u003ereference section\u003c/a\u003e, mostly of things I keep forgetting how to do and want to put somewhere for future me. Do I expect this website to take off? Heck no! But being here is mostly about having fun and keeping a constant archive, while also acting as a personal landing page. So in that way, this website is already a success.\u003c/p\u003e","title":"Hello world!"},{"content":"Welp, that\u0026rsquo;s why I\u0026rsquo;m here!\nTo be honest, just check this website\u0026rsquo;s GitHub repository if you wanna see my goofy code magic. Especially when it comes to the stupid dual-list view I had to hack together for the front page to keep References and Articles separate. I still can\u0026rsquo;t figure out how to do a proper search bar in Hugo with PaperMod, but I\u0026rsquo;m okay with a basic search page and relying on Google/other search providers for most access to the content.\n","permalink":"https://andw.me/reference/setting-up-hugo/","summary":"\u003cp\u003eWelp, that\u0026rsquo;s why I\u0026rsquo;m here!\u003c/p\u003e\n\u003cp\u003eTo be honest, just check this website\u0026rsquo;s \u003ca href=\"https://github.com/DarkBrave/awyck.me\"\u003eGitHub repository\u003c/a\u003e if you wanna see my goofy code magic. Especially when it comes to the stupid dual-list view I had to hack together for the front page to keep References and Articles separate. I still can\u0026rsquo;t figure out how to do a proper search bar in Hugo with PaperMod, but I\u0026rsquo;m okay with a basic search page and relying on Google/other search providers for most access to the content.\u003c/p\u003e","title":"Setting up Hugo"}]