diff --git a/_media b/_media new file mode 120000 index 0000000..cfa6a36 --- /dev/null +++ b/_media @@ -0,0 +1 @@ +public/media \ No newline at end of file diff --git a/_pages/about.yaml b/_pages/about.yaml new file mode 100755 index 0000000..ed21121 --- /dev/null +++ b/_pages/about.yaml @@ -0,0 +1,10 @@ +--- +title: About me +url: /about/ +slug: about +--- + +This about page was incredibly out-of-date, so I removed it. If you want to know who I am or what I'm up to, check out these links: + +* [Twitter](https://twitter.com/nickpegg) +* [GitHub](https://github.com/nickpegg) diff --git a/_pages/projects.yaml b/_pages/projects.yaml new file mode 100644 index 0000000..5b545de --- /dev/null +++ b/_pages/projects.yaml @@ -0,0 +1,73 @@ +--- +title: Projects +url: /projects/ +--- +Here's a decent number of the projects I've worked on in the past. +**This is mostly ancient and you should probably check out my [GitHub](https://github.com/nickpegg) profile instead** + +### Posty (2010) +Links: [GitHub](https://github.com/nickpegg/posty) + +Just a little static page generator I wrote when I got sick of using +Wordpress. It's quick, it's dirty, but it does what I need it to. + +I guess I'm just never satisfied with using pre-made software packages +to run my personal website. + +### Beertraq (2009) +Links: [Website](https://beertraq.com/) + +A website to keep track of which beers you've tried, compare with others, +read their reviews, and discover new beer. Started in the summer of 2009, +inspired by The Flying Saucer's UFO Club. + +### Intelligent Drink Dispenser (2009) +(No code available, sorry) + +This is my Computer Engineering Senior Design project at the University of +Missouri-Rolla. It's basically a robotic bartender which keeps track of +customers (via RFID) and their purchases. This was an idea that Richard Allen +and I have been kicking around for a few years, but it's finally come to life. + +### Nick Tracker (Python, Java) (2008) +(No code available, sorry) + +Keeps track of where my phone's at, which is usually where I am. Server side +script written in Python, client written in Java for the Android phone platform. +Since I've written this, two better applications have hit the Android Market, +including Google Latitude. I've stopped work on this because I don't feel like +re-inventing the wheel. + +### CPU Usage Meter (2006) +Links: [Project page](/cpu-usage-meter/), [Linux source](/media/projects/cpu_meter.tar.gz) + +LEDs on the front of my computer case displaying the CPU load. + +### Serial IR Receiver (2006) +Links: [Project page](/ir-receiver/) + +A simple serial-based LIRC-compatible IR reciever. + +### ServCheck (PHP) +Links: [servCheck.tar.gz](/media/projects/servCheck.tar.gz) + +A simple service checker written in PHP. Attempts to open a socket with the +configured hosts and ports, and outputs an HTML file showing which services +are up and down. I originally wrote this for the TerminalUnix site to show what's +working and what isn't. + +### TerminalUnix (PHP) +A PHP and MySQL driven site, functioning as a web front-end and community site for +the TerminalUnix server. I started it because I was sick of all of these Content +Management Systems having features that I didn't want. I sat down during Spring Break +of 2006 and coded a PHP login system, not knowing about the wonders of some of the PHP +features. Eventually I coded nice things in such as MySQL access (instead of a flat +text file), a user adminstration system, and even a news sytem. + +Unfortunately I don't plan on releasing the source code since it's a big hard-coded mess. + +### N-Queens solver (C++) +Links: [nqueens.tar.gz](/media/projects/nqueens.tar.gz) + +Another Data Structures homework assignment. This solves (brute-forces) the +[N-Queens Problem](https://www.google.com/search?q=n-queens+problem) using recursion and backtracking. diff --git a/_pages/projects__kegerator.yaml b/_pages/projects__kegerator.yaml new file mode 100644 index 0000000..cafb618 --- /dev/null +++ b/_pages/projects__kegerator.yaml @@ -0,0 +1,174 @@ +--- +title: Kegerator +url: /projects/kegerator/ +parent: Projects +--- +I've been homebrewing for a couple of years now, and my least favorite part of +the whole process is definitely the bottling. Each 5 gallon batch has +approximately 55 bottles that you have to clean, santize, fill, cap, clean +again, and put in boxes. I've gotten sick and tired of doing that for every +batch of beer, so I decided to make the jump and build myself a kegerator. + +![Kegerator mostly finished][0] + +Building a kegerator is fairly simple, only requiring some plumbing and +woodworking. The only hard part is the cost. Below is the cost for a +three-keg setup similar to my current two-keg setup. + +### Updates + +#### Feb 20, 2011 +Got the kegerator built yesterday minus a temperature controller. I got a +little drill-happy and accidentally made three faucet holes instead of two. +Oops, I guess I'll have to put in that third faucet. + +### Links +* [Flickr set](https://www.flickr.com/photos/nickpegg/sets/72157625971333921/) + +### Bill of Materials + +
| Qty | +Cost Each | +Item | +
|---|---|---|
| 1 + | $198 | +GE 7.0 cubic ft freezer | +
| 1 | +$90 | +5 pound CO2 tank | +
| 1 | +$75 | +Dual gauge CO2 regulator | +
| 1 | +$47 | +3-way CO2 distributor | +
| 3 | +$40 | +Used 5 gallon soda keg | +
| 3 | +$6.50 | +Ball lock gas disconnect - MFL | +
| 3 | +$6.50 | +Ball lock liquid disconnect - MFL | +
| 7 | +$1.30 | +1/4" barb-to-MFL connector | +
| 7 | +$0.25 | +Flared nylon washers for MFL connections | +
| 3 | +$20 | +Stainless steel faucet shank | +
| 3 | +$2.25 | +1/4" barbed shank tail piece and hex nut | +
| 3 | +$0.10 | +Rubber shank washer | +
| 3 | +$31.50 | +Perlick beer faucet | +
| 3 | +$2 | +Economy tap handle | +
| 1 | +$6.42 | +12' 2x8 | +
| 1 | +$3.37 | +Roll of weather stripping | +
| 2 | +$5.65 | +25' roll of poly ice maker tubing | +
| 14 | +$0.65 | +1/4" to 1/2" hose clamp | +
| Total | +$758.09 | ++ |
(click for full-sized version, warning: LARGE image)
+ +Here, the yellow boxes are center switches/routers, the green boxes are switches, +and the peach-colored nodes are hosts. Also, red lines are switch-to-switch +connections and blue lines are switch-to-host connections. + +Another somewhat off-topic thing about these graphs is that the manager of IT at +Nucor-Yamato is interested in open-sourcing the code that manages all of the data +and generates these graphs, AND let me use company time to work on and manage the +project. If anyone knows of any open-source project (or software that doesn't cost +an arm and a leg) that already does network discovery, data collection, and automated +mapping then please let me know! If I'm not going to be re-inventing the wheel, then +I'll probably be kicking the project off shortly after I start working full-time in +June 2010. diff --git a/_posts/2009-12-25_holiday_ham_recipe..yaml b/_posts/2009-12-25_holiday_ham_recipe..yaml new file mode 100644 index 0000000..382ced2 --- /dev/null +++ b/_posts/2009-12-25_holiday_ham_recipe..yaml @@ -0,0 +1,21 @@ +date: 2009-12-25 +tags: + - cooking +title: Holiday Ham Recipe +--- +I don't cook/bake all that often, but when I do I like to have some fun +with it. I came up with a ham recipe that turned out well, so I figured +I'd share it with everyone. +--- +First, put your ham in a baking pan and cut the diamond pattern into it. Trust +Alton Brown when he says that utility knives work well for this. Then, mix the +following in a bowl + +* 1 cup brown sugar +* 1/2 teaspoon ground mustard +* 4 ounces of fine bourbon. My preference is Maker's Mark. + +Once you have that all mixed up, pack it gently onto the ham. Uniformity is nice, +but not required. Then cook the ham at 325 degrees Fahrenheit until the inside +meat temperature reaches 150 degrees (about 3 hours with a 20 pound ham). I +guarantee that it'll be tasty when it's done. diff --git a/_posts/2009-12-5_beertraq_beta.yaml b/_posts/2009-12-5_beertraq_beta.yaml new file mode 100644 index 0000000..74867bc --- /dev/null +++ b/_posts/2009-12-5_beertraq_beta.yaml @@ -0,0 +1,32 @@ +date: 2009-12-05 +tags: + - programming + - beertraq +title: Beertraq Beta! +--- +I'm glad to announce that my recent pet project, Beertraq, is now in a +(somewhat closed) beta stage! The basic idea is there and functioning, +but the extra functionality isn't done and it's far from polished. +Nonetheless, it's time to take her for a test drive! +--- + +> Note from future-Nick +> +> I got lazy and never finished Beertraq, and Untappd ended up releasing not long after. Though it took them _years_ to implement a barcode scanner in the app, which was going to be a core thing in Beertraq. + + +So what is Beertraq, you ask? It's a way for you to keep track of which +beers you've tasted, compare those with others, read beer reviews, and +most importantly discover new beers to try. I originally got the idea +from The Flying Saucer's UFO Club, where members work toward a goal of +drinking 200 different beers. Once they complete the task, they get their +name on a plate which gets put on the wall of the bar. The cool part about +the UFO Club is that it's all computerized, using a magstripe card to login +at a kiosk in the bar. You can also log in to their website to check your +progress and read reviews on there. I figured that if The Flying Saucer can +have that system for their bar, I could do the same for the world. + +If you're interested in becoming a BeerTraq beta user, send an email to +beertraq (at) beertraq (dot) com with the email address you want to use for +your account. All I ask is that you give feedback by filling out issue requests +with bugs you find or suggestions you might have. diff --git a/_posts/2010-02-09_whiteboard.yaml b/_posts/2010-02-09_whiteboard.yaml new file mode 100644 index 0000000..8cf660f --- /dev/null +++ b/_posts/2010-02-09_whiteboard.yaml @@ -0,0 +1,20 @@ +date: 2010-02-09 +tags: [] +title: Whiteboard +--- +If you know me personally, you know that I can be pretty scatterbrained from +time to time. I've desperately needed a whiteboard to keep my thoughts +organized, and I've finally gotten one. I know, it's not the +most exciting thing in the world to talk about, but it should be a change +in the right direction for me. +--- +[](/media/img/whiteboard1.jpg) + +But, wait. What's this? "Beertraq Road to Stable"? + +[](/media/img/whiteboard2.jpg) + +Part of why I want to get my thoughts organized is because I want a good +view of what all is left before I fully release Beertraq to the public. +With this list looming over my head (literally) it will hopefully get my +butt in gear to reach a stable release. diff --git a/_posts/2010-04-07_new_car.yaml b/_posts/2010-04-07_new_car.yaml new file mode 100644 index 0000000..83102d6 --- /dev/null +++ b/_posts/2010-04-07_new_car.yaml @@ -0,0 +1,60 @@ +date: 2010-04-07 +tags: + - car +title: New Car +--- +It was the Friday before my Spring Break and quite possibly the worst thing in the world happened to me: I got rear-ended while at a stop. +Well, okay, it's not the worst thing in the world but to a college student who loves his car, it was pretty bad. The lady who hit me did quite a +number on my back end, and then pushed me into the car in front of me. Despite my airbags not going off, my car was totaled. The damage to the bumper, +right rear quarter panel, and unibody frame were just too much. +--- +[![Damage to the Jetta][4]][3] + +With the Jetta totaled I had three options: Buy it back and spend the $1000 left over on repairs/hookers, give it away to the insurance company and +spend <$2400 on a beater from Craigslist, or do the financially irresponsible thing and buy the new car I've been dreaming of, going into debt even +further than I already was. + +Guess which option I chose: + +[![2010 VW GTI][2]][1] + + +Yes, that's right. I bought myself a new MkVI GTI. Since I had some money saved up from my recent internship, will be starting work in a couple of months, +and was planning on buying one within a year I decided to go for it. I ended up paying $22,500 for it, which is a few hundred below dealer invoice for the +options that I wanted on it. I won't go into any car buying tips here, I'll save that for another post. + +Overall, I'm very pleased with my purchase. Here's why: + +**Performance:** It's got the VW 2.0L TSI turbocharged engine in it which puts out 200 hp. That's only a little more than my old VR6 Jetta, but the lighter +engine makes a difference. I'm still breaking the engine in, but from what I can tell from accidentally giving too much gas, it can put down some power. + +**Handling:** With the sport-tuned suspension, this thing handles like a beast. With simply taking corners quickly and turning smoothly, I have yet to break +the tires loose from the road. There's also a roundabout here in Rolla which I took at speeds that I'm not at liberty to discuss publicly since I'm sure that +the city police would frown upon that. + +The car also has a pseudo-locking differential called XDS. This is part of the electronic stability control system. What XDS does is when it senses that one +wheel is getting too much power compared to the other, it applies the brakes to that first wheel to slow it down, giving more power to the second wheel. I +haven't noticed this kick in yet, but probably because I'm not giving it full throttle due to the break-in period + +**Electronics:** Included standard on the car is a touchscreen radio with Volkswagen's MDI interface. The MDI interface provides a port in the arm rest where +different devices can be plugged in, such as an iPod or USB drive. With the addition of an SD card slot right in the radio, with support up to 32 GB, I no +longer need a car computer. The software can be a little flaky at times and could use certain features (like creating an on-the-go playlist), but it suits my needs fine. + +Also included is the MFI, which is essentially a trip computer. It tells you trip time, distance, fuel consumption, range left on the tank of gas, etc. The cool +part about this is that in the settings menu, you can adjust some convenience settings which normally could only be done using a VAG-COM, such as which doors +unlock when you use the keyfob, rolling windows down with the key, etc. + +**Practicality:** The folks on Top Gear always talk about the practicality of a car whenever they review something the average person could buy. Since I'm not +going through a mid-life crisis, something practical is what I need. The GTI fits this bill nicely. + +There's plenty of room for passengers in the back (a change VW made starting with the MkV) along with all of the creature comforts you would expect from sitting +in the front. There's also a good amount of space in the hatch area, and the back seats fold down in case I need to haul anything big. I was able to fit a whole +recliner in the back with room to spare, for example. + +All in all, I really love this car. It's quick, fun to drive, can get good gas mileage, and it's still useful for when I need it. + + +[1]:/media/img/GTI.jpg +[2]:/media/img/GTI-thumb.jpg +[3]:/media/img/jetta.jpg +[4]:/media/img/jetta-thumb.jpg diff --git a/_posts/2010-06-19_frustrations_with_xbmc.yaml b/_posts/2010-06-19_frustrations_with_xbmc.yaml new file mode 100644 index 0000000..9b74bd6 --- /dev/null +++ b/_posts/2010-06-19_frustrations_with_xbmc.yaml @@ -0,0 +1,99 @@ +date: 2010-06-19 +tags: + - linux + - htpc +title: LIRC and XBMC +--- +Those of you who know me fairly well know that I'm a total HTPC +geek. It's to the point where I outright refuse to subscribe to cable television +or even hook up an antenna to my TV. This geekery combined with my affinity +for Linux leads me to running XBMC on Linux on my little home theater machine. +It's been a pretty smooth experience with the exception of getting my remote +work with it. If you're struggling with it too, hopefully my tales will help you +get it going. +--- +So, here's my setup. I've got an Antec Fusion 430 (a silver one +with the VFD), a Logitech Harmony remote, and Ubuntu 10.04. The Antec case is +pretty cool since it looks like it belongs +in my home theater setup, and it +even includes an IR receiver built right into the case! Cool! It should accept +signals from any IR remote, right? + +*Wrong* + +In the hardware developer's infinite +wisdom, they made it only work with Windows Media Center remotes instead of just +making it a dumb device that passes data along. They actually put +**more** effort +into designing the thing just to make my life harder. Augh! Luckily, when I got +this case my [then-roommate](http://benmurrell.com/) had an Xbox 360 remote which +magically +worked! So I eventually got a Logitech Harmony remote and told it +that my HTPC was actually an Xbox 360. Step one complete. + +The next step was +to get LIRC to accept the remote. This is a bit tricky, but luckily I had backed +up my configs. If you're starting out from scratch, here's how to do it in an +Ubuntu system. + +First of all, you need to install LIRC: + + sudo aptitude + install lirc + +During the configuration phase of the install, it'll ask you for +what kind of device you have. I selected *Soundgraph iMON PAD IR/VFD*, which uses +the lirc_imon driver. Unfortunately, since I have the silver Antec Fusion +430 I have the VFD and not the LCD display, which has a slightly different IR +receiver. You have to specify the display_type=1 when the module is loaded. +You can do this by adding a file called lirc-imon.conf to /etc/modprobe.d/ with +[these contents](http://nickpegg.com/stuff/lirc/modprobe.d-lirc-imon.conf). + +If you don't want to restart, you'll have to throw commands at the system to reload +the module with the correct options. + + sudo service lirc stop + sudo rmmod lirc_imon + sudo modprobe lirc_imon display_type=1 + +While you have LIRC stopped, you might as well double-check that the IR receiver is +actually receiving data with the following command (hit Ctrl-C to stop): + + sudo cat /dev/lirc0 + +You should see a bunch of garbage get printed to +the terminal when you press buttons on your remote. If you don't, then either +you have the wrong type of remote or you don't need the +display_type argument to modprobe. + +Next, you need to setup the button config for your remote. Since +I'm using a Logitech Harmony remote to emulate an Xbox 360 remote, I used the +irrecord command to generate [my config](http://nickpegg.com/stuff/lirc/xbox360.conf). +Luckily there's [plenty of people out there](http://www.google.com/search?&q=lirc++microsoft+remote+config) +who have already done this for you for a large amount of remotes +([here's a good list](http://lirc.sourceforge.net/remotes/), for example). +Once you have the remote config file downloaded or created, +add an include to your [lircd.conf](http://nickpegg.com/stuff/lirc/lircd.conf) +for it, fire up LIRC, and test it out with the irw command. + + sudo service + lirc start + irw + +When you press buttons, you should see the button commands +scroll by in the terminal. + +*\*whew\** Almost there. Still with me? Good, because +we only have one thing left, the XBMC Lircmap.xml file! I'll spare you the nitty-girtty +of it and just give you +[mine](http://nickpegg.com/stuff/lirc/Lircmap.xml) (right-click +and save it). If you feel like making your own or need to tweak mine a bit, the +XBMC wiki has some +[good information](http://wiki.xbmc.org/index.php?title=Lirc_and_Lircmap.xml) +on how to do it. + +### For the impatient, here's all of my files associated with getting this to work: +[lircd.conf](http://nickpegg.com/stuff/lirc/lircd.conf) (LIRC) +[hardware.conf](http://nickpegg.com/stuff/lirc/hardware.conf) (LIRC) +[xbox360.conf](http://nickpegg.com/stuff/lirc/xbox360.conf) (remote) +[Lircmap.xml](http://nickpegg.com/stuff/lirc/Lircmap.xml)(XBMC) diff --git a/_posts/2010-06-23_verifying_google_voice.yaml b/_posts/2010-06-23_verifying_google_voice.yaml new file mode 100644 index 0000000..eb2e4f0 --- /dev/null +++ b/_posts/2010-06-23_verifying_google_voice.yaml @@ -0,0 +1,11 @@ +date: 2010-06-23 +tags: [] +title: Verifying Google Voice +--- +I've been struggling getting my work phone number verified with Google Voice. The way that number verification works is that Google Voice calls you and asks +you to enter the two-digit code that's displayed on the website. But for some reason when I get a call on my outside line and I press a number button, it +doesn't send that DTMF tone. Instead it tries to place another call. + +My solution? I found a DTMF tone generator online and I played the code DTMF tones through my computer speakers. + +It's nice to see that these old phone tricks still work. diff --git a/_posts/2010-10-22_new_website_again.yaml b/_posts/2010-10-22_new_website_again.yaml new file mode 100644 index 0000000..343fa27 --- /dev/null +++ b/_posts/2010-10-22_new_website_again.yaml @@ -0,0 +1,15 @@ +date: 2010-10-22 +tags: + - programming +title: New Website (Again!) +--- +Yes, it's that time of year. Time to change my website design + _yet again_! + +I got tired of dealing with Wordpress and wrote my own static page generator +in Python, dubbed [Posty](http://github.com/nickpegg/posty). I know, I'm +kind of [re-inventing the wheel](http://ringce.com/hyde) here and there +are some [really nice solutions](http://github.com/mojombo/jekyll/wiki) to +this problem, but why not just make something for making's sake? + +Plus, I just feel _cool_ using Markdown and YAML to update my website. diff --git a/_posts/2011-02-20_kegerator.yaml b/_posts/2011-02-20_kegerator.yaml new file mode 100644 index 0000000..f5ff2b3 --- /dev/null +++ b/_posts/2011-02-20_kegerator.yaml @@ -0,0 +1,12 @@ +date: 2011-02-20 +tags: + - beer +title: Kegerator +--- +After getting my tax refund and being sick and tired of bottling my homebrew +beer, I've built myself a kegerator! + +[](http://www.flickr.com/photos/nickpegg/sets/72157625971333921/) + +Details are over at my [project page](/projects/kegerator/), or if you'd +rather just gawk at some pictures, check out the [Flickr set](http://www.flickr.com/photos/nickpegg/sets/72157625971333921/)! diff --git a/_posts/2011-11-25_Syncing_Minecraft_with_git.yaml b/_posts/2011-11-25_Syncing_Minecraft_with_git.yaml new file mode 100644 index 0000000..abadfb4 --- /dev/null +++ b/_posts/2011-11-25_Syncing_Minecraft_with_git.yaml @@ -0,0 +1,78 @@ +date: 2011-11-25 +tags: + - git + - games +title: Syncing Minecraft Saves with Git +--- +I've been playing Minecraft for a while and after doing some travelling, I've +ran into the issue where I'd like to syncronize my Minecraft saves across +computers. +--- +I already use git for software version control, so why not shoehorn Minecraft +into it? Not only would I get easy syncronization, I would also get version +control so if I seriously mung something up, I can revert back to a previous +save! Here's how I did it. + +First, I had to make sure git was installed on all of my machines. Luckily +on Linux git is usually provided in the package repository (git-core), but +since my desktop also runs Windows (for gaming), I use +[msysgit](http://code.google.com/p/msysgit/). For example, +on Debian/Ubuntu all you need to do is: + +``` +sudo apt-get install git-core +``` + +Once git was installed, I decided to go with a centralized approach since I +want one 'official' spot where I can push and pull my Mincraft saves to. +I already have a server +from the wonderful folks at [Linode](http://linode.com), so I just +initialized a bare (centralized) repository on there: + +``` +cd /path/to/repos/minecraft +git init --bare +``` + +Then, since I already have Minecraft installed on my desktop with quite a few +saves, I had to clone the central repository, add my saves, commit, and then +push back to the central repository. + +``` +cd /home/nick/.minecraft/ +git clone nick@nickpegg.com:/path/to/repos/minecraft temp +mv temp/.git ./ +``` + +Since you can't clone a repository into a non-empty folder, I had to clone it +to a temporary folder and then copy the .git folder from there into my +.minecraft folder. Now that my local repository was setup, I added the files +I wanted to syncronize. + +``` +git add saves screenshots stats texturepacks options.txt servers.dat +git commit -m 'Initial commit' +``` + +Once I had the files commited, all I needed to do was push them up to the +central repository on my server. + +``` +git push +``` + +And now I have my Minecraft files in a central spot! Now every time I'm done +playing a bit, all I have to do to sync my files up is: + +``` +git commit -a -m 'Played a bit' +git push +``` + +Now, on other machines, all I need to do is clone once, ``git pull`` +before playing, +and then commit and push when I'm done playing! + +Easy peasy. Of course, you can do more fancy things with git since it's a +full-blown version control system. If you feel inlined to play with those +features, go read some [documentation](http://gitref.org/). diff --git a/_posts/2014-08-17_building_my_own_router.yaml b/_posts/2014-08-17_building_my_own_router.yaml new file mode 100644 index 0000000..46412d6 --- /dev/null +++ b/_posts/2014-08-17_building_my_own_router.yaml @@ -0,0 +1,132 @@ +date: 2014-08-19 +tags: + - linux + - networking +title: Building My Own Home Router, Part 1 +--- +This is the first of a series of blog posts on building my own home router from scratch using Debian. My hopes are that by sharing my experiences, it can help others in this endeavor. +--- +I've been kicking around the idea of building my own router for a while now, mostly due to the fact that my trusty [WRT54GL][1] is grealy limted by what it can do with its measly 4 MB of flash and weak CPU. After months of casually searching and trying (unsuccessfully) to re-purpose some old hardware, I finally found what I've been looking for: a cheap-ish, low-power, rackmount server with more than one NIC. + +# The Hardware + +* [Intel D2500CCE Mini-ITX motherboard in a rackmount case][2] +* [Intel 7260-ac Mini-PCIe card with antenna][3] - there are some issues with this, which I'll cover in a later post + +I can't believe that I didn't think to check the various Mini-ITX resellers for something like this, because this is almost exactly what I've always been looking for. I got a 2-NIC board since I'm cheap and already have a gigabit switch, but you can easily find boards with more ports if you don't mind shelling out the extra cash. + +Once the equipment got to my apartment, I slapped in some old laptop RAM and a spare 2.5" drive and got Debian installed. + + +# 802.3 and IPv4 + +The first order of business was to replicate the core functionality of my old router: IPv4 routing and Ethernet connectivity. The plan was to use eth0 as my public interface (plugged into my cable modem) and eth1 as my internal interface. Before I even plugged in anything, I wrote a basic `/etc/network/interfaces` file. + +``` +auto lo +iface lo inet loopback + +# outside +allow-hotplug eth0 +iface eth0 inet dhcp + hwaddress ether AA:BB:CC:DD:EE:FF + dns-search home.nickpegg.com nickpegg.com + dns-nameservers 8.8.8.8 8.8.4.4 + +# inside +auto eth1 +iface eth1 inet static + address 10.0.0.1 + netmask 255.255.255.0 +``` + +Note the `hwaddress ether` line there. Since my ISP (whose name shall not be spoken (not Voldemort, but [just as evil][4])) locks me to a single MAC address, my new router had to spoof my old router's MAC address, which was spoofed from my laptop that I originally set the connection up with. If you seemingly can't get a DHCP lease on your public interface, this is likely the problem. + + +Now that I had my interfaces configured and rarin' to go, I had to make sure that my ip{,6}tables rules were in order before plugging in. + +#### rules.v4 +``` +*nat +:PREROUTING ACCEPT [2:125] +:INPUT ACCEPT [1:65] +:OUTPUT ACCEPT [4:260] +:POSTROUTING ACCEPT [0:0] +-A POSTROUTING -o eth0 -j MASQUERADE +COMMIT +*filter +:INPUT DROP [0:0] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] +-A INPUT -i lo -j ACCEPT +-A INPUT -i eth1 -j ACCEPT +-A INPUT -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT +-A INPUT -i eth0 -p icmp -m icmp --icmp-type 8 -j ACCEPT +-A FORWARD -i eth0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT +-A FORWARD -i eth1 -o eth0 -j ACCEPT +COMMIT +``` + +#### rules.v6 +``` +*filter +:INPUT DROP [0:0] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] +-A INPUT -i lo -j ACCEPT +-A INPUT -i eth1 -j ACCEPT +COMMIT +``` + +The above rules are my output from `iptables-save` and `ip6tables-save`, and are fully compatible with the respective restore programs. Debian even has a nice package called `iptables-persistent` which will load these rules on boot if you stash them as `rules.v4` and `rules.v6` in `/etc/iptables`! + +To better understand these rules, it helps to have the [Netfilter packet flow diagram][5] in front of you. There are some simple goals with these: + +## IPv4 Filters + +* Allow traffic coming from loopback or the inside interface +* Only allow traffic outside->inside if it pertains to an existing in->out connection +* **Secret sauce** - that MASQURADE line enables NAT, so my private addresses can hide behind the one public address that my ISP gives me + + +## IPv6 Filters + +* Just drop everything for now unless it comes from the inside and is destined for the router itself + + +Of course, before I could have a fully-functional internet connection, I had to get DNS set up. And I guess a DHCP server would be nice to have before my leases all expire and everything drops its IP. + +Luckily, there's a software package which is geared towards these very tasks: `dnsmasq`! Getting it running was as easy as running `apt-get install dnsmasq` and `service dnsmasq start`, which was enough to get DNS working. To get DHCP working, I created two config files in `/etc/dnsmasq.d/`: + +#### dhcp.conf +``` +# My DHCP configs +dhcp-range=10.0.0.110,10.0.0.250,12h + +# options for DNS +dhcp-option=option:domain-search,home.nickpegg.com,nickpegg.com + +# Static DHCP entries +dhcp-host=00:24:1D:7D:5F:C3,10.0.0.10,host1 +dhcp-host=88:30:8A:22:2E:74,10.0.0.11,host2 +dhcp-host=00:23:54:1A:16:2D,10.0.0.12,host3 +``` + +#### interface.conf +``` +# Only allow DNS/DHCP requests from the inside interface +interface=eth1 +``` + +With all of that, I had a functioning IPv4 router and could do important things again, like idle on IRC and browse Reddit. + +This is just the beginning though! You should go check out [part 2][6] of this series where I get 802.11 working. + + + +[1]: http://en.wikipedia.org/wiki/Wrt54gl +[2]: http://mitxpc.com/proddetail.asp?prod=ER1UD2500DLM02 +[3]: http://mitxpc.com/proddetail.asp?prod=INTWIFI7260AC +[4]: http://www.comcast.com/ +[5]: http://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg +[6]: http://nickpegg.com/2014/8/building_my_own_home_router,_part_2_-_802.11.html diff --git a/_posts/2014-08-22_building_my_own_router2.yaml b/_posts/2014-08-22_building_my_own_router2.yaml new file mode 100644 index 0000000..e4cc4ee --- /dev/null +++ b/_posts/2014-08-22_building_my_own_router2.yaml @@ -0,0 +1,151 @@ +date: 2014-08-22 +tags: + - linux + - networking +title: Building My Own Home Router, Part 2 - 802.11 +--- +In my [last post](http://nickpegg.com/2014/8/building_my_own_home_router,_part_1.html) I talked about getting my home router up and forwarding packets from nothing and getting my computers connected via Ethernet. The next step is to get 802.11 (WiFi) working. +--- + +# Hardware Caveats + +In my last post, I mentioned that I got the Intel 7260-ac card, which I've had some problems with. Intel decided to code into the EEPROM that the card can only use channels that make it compliant with *every* country's laws, and the firmware and Linux driver dutifully read this information and comply. This means that the card can only work in AP mode on channels 1-11, and will NOT in the 5GHz band. This means that you're stuck to the noisy 2.4 GHz band and can't even use 802.11ac (since it requires 5GHz). + +I've seen some various blog and forum posts where the OpenWRT people have gotten around this on cards with atheros chipsets since it's just a check in the driver. However, in the small amount of kernel driver hacking I've done, I've been unsuccessful. + +**Long story short**, watch which card you pick up and make sure people have had luck making it do what you want to, preferrably without having to patch kernel drivers. + + +# Network Changes + +Since you're turning your router into a wireless access point, you have two options to connect clients to your network: split them off into their own network segment in a different subnet, or bridge the wireless interface in with your inside network and let wireless users mingle with your wired users. I chose the latter, since it was simpler. + +The basic idea is that you create a bridge device (`br0`) and bridge in your `eth1` and `wlan0` interfaces. My updated config shows the changes you need to make to `/etc/network/interfaces`: + +``` +auto lo +iface lo inet loopback + +# outside +allow-hotplug eth0 +iface eth0 inet dhcp + hwaddress ether AA:BB:CC:DD:EE:FF + dns-search home.nickpegg.com nickpegg.com + dns-nameservers 8.8.8.8 8.8.4.4 + +# inside +iface eth1 inet manual +iface wlan0 inet manual + +auto br0 +iface br0 inet static + address 10.0.0.1 + netmask 255.255.255.0 + bridge_ports eth1 +``` + +Note that `br0` has pretty much taken the place of `eth1` in the config. Also, we don't bridge in `wlan0` since our access point daemon will take care of that. + +Along with this change in `/etc/network/interfaces`, don't forget to also change your dnsmasq settings so that it listens on `br0` instead of `eth1`. + +Install the `bridge-utils` package if you haven't already and restart networking. Congrats, your router is now a one port network switch! + + +# Firewall Changes + +Since our inside interface is now `br0`, we have to tweak our firewall rules a bit. + +#### rules.v4 +``` +*nat +:PREROUTING ACCEPT [0:0] +:INPUT ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] +:POSTROUTING ACCEPT [0:0] +-A POSTROUTING -o eth0 -j MASQUERADE +COMMIT +*filter +:INPUT DROP [0:0] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] +-A INPUT -i lo -j ACCEPT +-A INPUT -i eth1 -j ACCEPT +-A INPUT -i br0 -j ACCEPT +-A INPUT -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT +-A INPUT -i eth0 -p icmp -m icmp --icmp-type 8 -j ACCEPT +-A FORWARD -i eth0 -o br0 -m state --state RELATED,ESTABLISHED -j ACCEPT +-A FORWARD -i br0 -o eth0 -j ACCEPT +COMMIT +``` + +#### rules.v6 +``` +*filter +:INPUT DROP [0:0] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] +-A INPUT -i lo -j ACCEPT +-A INPUT -i eth1 -j ACCEPT +-A INPUT -i br0 -j ACCEPT +COMMIT +``` + + +# HostAPd Config + +Thanks to [`hostapd`][2], getting your wireless card running in AP mode is a cinch! It's just a package install away in most cases, and the configuration isn't *too* terrible. Below is my config, annotated to make it easier to understand. + +``` +# Set up some logging. VERY useful to see why things aren't working. +logger_syslog=-1 +logger_syslog_level=2 +logger_stdout=-1 +logger_stdout_level=2 + +# Which interface to use and which bridge to join +interface=wlan0 +bridge=br0 + +# Use this driver for AP stuff. This corresponds to the mac80211 driver +# which most newer cards support. +driver=nl80211 + +# 802.11 mode and channel, pretty self-explanatory +hw_mode=g +country_code=US +channel=11 + + +# Set and broadcast the SSID. Stupid double-negatives... +ssid=test_net +ignore_broadcast_ssid=0 + +# 802.11N stuff - Try 40 MHz channels, fall back to 20 MHz +ieee80211n=1 +ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40] + +# WPA Authentication +auth_algs=1 # Open authentication, no WEP +wpa=2 # WPA2 only, set to 3 for WPA+WPA2 +wpa_passphrase=xxxxxxxxxxx # Hah! Like I'd put this in a gist. +wpa_key_mgmt=WPA-PSK +rsn_pairwise=CCMP # Cipher for WPA2 (AES in this case) + +# Don't use a MAC ACL +macaddr_acl=0 +``` + +The things to watch out for are the settings that are ORs of bits, like `auth_algs` and `wpa`. When setting up your own AP, it's a good idea to check out the [example config][3] to see what each setting does and what the defaults are. + +My config doesn't include any 5 GHz settings, so you'll have to figure those out on your own if you're lucky enough to have a card that supports it. If I get mine working, I'll make another post with those settings. + +Once you're done with configuration, fire up `hostapd` with `service hostpad start`. If everything was successful, you should see `wlan0` bridged in (use the `brctl show` command to check) and the network should be joinable by one of your wireless devices. If you don't see that, you'll want to check `/var/log/syslog` to see what hostapd is complaining about. + + +And there you have it, a router with wireless! Next up is IPv6 support, so stay tuned for part 3. + + + +[1]: http://nickpegg.com/2014/8/building_my_own_home_router,_part_1.html +[2]: http://wireless.kernel.org/en/users/Documentation/hostapd +[3]: http://w1.fi/gitweb/gitweb.cgi?p=hostap.git;a=blob_plain;f=hostapd/hostapd.conf diff --git a/_posts/2015-08-16_building_my_own_router_ipv6_tunnel.yaml b/_posts/2015-08-16_building_my_own_router_ipv6_tunnel.yaml new file mode 100644 index 0000000..481a33e --- /dev/null +++ b/_posts/2015-08-16_building_my_own_router_ipv6_tunnel.yaml @@ -0,0 +1,136 @@ +date: 2015-08-16 +tags: + - linux + - networking + - ipv6 +title: Building My Own Home Router - IPv6 Tunnel +--- +Continuing on my adventure of running my own self-built router at home, I decided to get IPv6 running on my home network. As of writing this blog post, my ISP doesn't do native IPv6 yet so I decided to go with Hurricane Electric's [IPv6 Tunnel Broker](https://tunnelbroker.net) service, which provides you with an IPv6-in-IPv4 tunnel. +--- +# Creating the tunnel + +The first step is going to [HE's Tunnel Broker website][1] and creating a regular tunnel. Set your IPv4 endpoint to your router's public IP address and be sure to pick a tunnel server close to you. + +Once the tunnel's been created, you'll want to grab the following information: + +* Server IPv4 address +* Server IPv6 Address (this will be your route to the outside world) +* Client IPv6 Address (this will be your router's address) +* Routed /64 (this is the block of IPv6 addresses for your network) + +If you run multiple subnets, you can create a /48 block, but for my uses I just need a single subnet (/64 block), so that's what I'll be covering. + + +# Updating the firewall + +Before we even fire up the tunnel, we want to make sure it'll be secure when it comes up. This is a little different from my [first post][2] which covered IPv4 since we won't be using a NAT, but instead directly routing packets. + +The goals of these firewall rules will be to: + +* Allow traffic related to already-established outbound connections +* Allow ICMPv6 Destination Unreachable +* Allow ICMPv6 Echo Request +* Allow ICMPv6 Neighbor Soliciation and Advertisement on the local network (interface br0) +* Allow all traffic coming from the local network (interface br0) out the world (interface he-ipv6) +* Drop everything else + +Since we are doing regular routing, all rules on the INPUT chain will manage traffic directed to the router itself and all rules on the FORWARD chain will manage routed traffic (between the local network and the internet). + +Here's what my `/etc/iptables/rules.v6` file looks like with all these rules applied. Note that the default policy on `INPUT` and `FORWARD` are `DROP`. + +``` +*filter +:INPUT DROP [0:0] +:FORWARD DROP [0:0] +:OUTPUT ACCEPT [0:0] +-A INPUT -i lo -j ACCEPT +-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT +-A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type echo-request -j ACCEPT +-A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type destination-unreachable -j ACCEPT +-A INPUT -i br0 -p ipv6-icmp -m icmp6 --icmpv6-type neighbour-solicitation -j ACCEPT +-A INPUT -i br0 -p ipv6-icmp -m icmp6 --icmpv6-type neighbour-advertisement -j ACCEPT +-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT +-A FORWARD -p ipv6-icmp -m icmp6 --icmpv6-type echo-request -j ACCEPT +-A FORWARD -p ipv6-icmp -m icmp6 --icmpv6-type destination-unreachable -j ACCEPT +-A FORWARD -i br0 -o he-ipv6 -j ACCEPT +COMMIT +``` + + +# Updating the `interfaces` file + +Once you have the firewall rules in place, it's time to update the `/etc/network/interfaces` file for the tunnel. There are two additions that we need to make: An IPv6 address for your internal network's interface and a virtual interface for the tunnel. + +This is where you'll use the details you got from the Tunnel Broker website. Everything will mostly be directly used, however you need to choose an address from the Routed /64 block for your router's internal interface. The first one in the block is convenient, so if your block is `2001:470:6661:7274::/64` then your router's address will be `2001:470:6661:7274::1` (`2001:470:6661:7274::0` is technically the first address, but using 1 is less confusing since it's similar to IPv4 addressing). + +Here's what my `/etc/network/interfaces` files looks like after those changes, the IPv6 additions at the end. Be sure to replace the variables in the file with the values you got from the Tunnel Broker website. + +``` +# The loopback network interface +auto lo +iface lo inet loopback + +# outside +allow-hotplug eth0 +iface eth0 inet dhcp + hwaddress ether AA:BB:CC:DD:EE:FF + dns-search home.nickpegg.com nickpegg.com + dns-nameservers 8.8.8.8 8.8.4.4 + +iface eth0 inet6 auto + +iface eth1 inet manual +iface wlan0 inet manual + +auto br0 +iface br0 inet static + address 10.0.0.1 + netmask 255.255.255.0 + bridge_ports eth1 + +iface br0 inet6 static + address 2001:470:6661:7274::1 + netmask 64 + +auto he-ipv6 +iface he-ipv6 inet6 v4tunnel + address $CLIENT_IPV6_ADDRESS + netmask 64 + endpoint $SERVER_IPV4_ADDRESS + gateway $SERVER_IPV6_ADDRESS +``` + +Once you make these changes you'll be able to run these commands to start/restart your interfaces to fire up the tunnel: + +* `sudo ifdown br0; sudo ifup br0` +* `sudo ifup he-ipv6` + +Note that if you're SSH'd into your server, you should run the first command in screen because you're going to lose connectivity for a few seconds. Once your tunnel's up, you should be able to `ping6 ipv6.google.com` and get a response. + + +# Setting up Router Advertisements +Getting the router talking IPv6 is only the first half. Now we need to have the devices on our local network pick up IPv6 addresses using a mechanism called [Router Advertisement][3]. Fortunately there's a Linux package called `radvd` which is incredibly easy to set up. + +Here's what a basic `/etc/radvd.conf` will look like. Again, be sure to replace `$ROUTED_64` with the block you were assigned via the Tunnel Broker website. + +``` +interface br0 +{ + AdvSendAdvert on; + + prefix $ROUTED_64 + { + }; +}; +``` + +Yeah, that's it. Start the `radvd` service and everything should get an IPv6 address. From a machine that's not your router, you can `ping ipv6.google.com` to verify that connectivity's working. + + +Now that's all done, you have a router that talks IPv6 with the world and you can feel a little bit better about the whole [IPv4 exhaustion][4] issue. + + +[1]: https://tunnelbroker.net/ +[2]: https://nickpegg.com/2014/8/building_my_own_home_router,_part_1.html +[3]: https://tools.ietf.org/html/rfc4861#section-6 +[4]: https://en.wikipedia.org/wiki/IPv4_address_exhaustion diff --git a/_posts/2017-06-25_north_bay_area_bike_touring_log.yaml b/_posts/2017-06-25_north_bay_area_bike_touring_log.yaml new file mode 100644 index 0000000..996b033 --- /dev/null +++ b/_posts/2017-06-25_north_bay_area_bike_touring_log.yaml @@ -0,0 +1,160 @@ +date: 2017-06-25 +tags: + - bike + - touring +title: North Bay Area Bike Tour Log +--- +In April of this year, I attempted to bike the [Katy Trail](https://mostateparks.com/park/katy-trail-state-park), but I forgot how unpredictable weather could be in Missouri that time of year and got rained out. While visiting with my parents waiting for my flight back to California, I decided to do a short bike tour in the San Francisco Bay Area where at the very least I wouldn't have to deal with rain. +--- +Set out on this trip on July 21 and returned to my home in Berkeley on July 24. This is the log I kept while on the road, transcribed with minimal editing from the notebook I kept with me. + +In addition to my notes, I also took a bunch of pictures which you can find on [Flickr][9]. + +# The Plan +* Day 1 ([Google maps][2]) + * Start in Berkeley, ride to Oakland + * Take the ferry from Oakland to SF + * Ride up to Samuel P Taylor State Park and camp +* Day 2 ([Google maps][3]) + * Ride over to CA Highway 1 (the Pacific Coast Highway) + * Follow Highway 1 to Bodega Dunes State Park and camp +* Day 3 ([Google maps][4]) + * Ride east to Santa Rosa, get lunch + * Make the climb over the mountains to Calistoga + * Camp at Bothe-Napa State Park +* Day 4 ([Google maps][5]) + * Ride south to Napa, get lunch there + * Ride all the way back home + +# Day 1 +This is abridged since I'm writing this after the fact + +Rolled out @ 08:00, hit up Suzette Crepe Cafe and then Safeway for food. Got some tortillas, bananas, and Nutella. That combo makes for a killer snack! + +Caught the 10:15 ferry from Oakland to SF. More crowded than expected, probably because it's summer and kids are out of school. Was on the Gemini which was a fast ride (faster that weekends). + +SF was uneventful, normal tourists on their way to the bridge. The west path was closed, so it was more of a shitshow than usual getting across (with not only biking tourists, but pedestrians too). Plus it was foggy and freezing. It felt like a 20 degrees warmer after the bridge. The east path meant I came down Alexander Drive which saved the climb up the hill before Sausilito. + +Got lunch at Sausilito Gourmet Deli. Had a _really_ nice backyard seating area. Ended up [taking El Camino Alto][6] up as a challenge, wasn't too bad and dumped me right into Corte Madera. + +Took (bicycle) Route 20 along the creek to Fairfax, was really nice. + +Stopped on a park bench at Fairfax to rest in the mid-afternoon. + +Fucking hot. + +And that fucking climb out of Fairfax! Holy crap!! It was tough in the heat. While I was stopped just before the crest, a mountain biker stopped to make sure I was good. Really lifted my spirits. He mentioned a shady way parallel to Sir Francis Drake Blvd. I should have followed his advice! + +Got to Sam P. Taylor alright after that. + +At camp, I met: + +* __Quinn__ - He hitched a ride via Craiglist from North Carolina to Portland, bought a bike and was riding down the Pacific Coast Highway to SF +* __Don__ - Last lived in St. Louis (Richmond Heights) but used to live in the Bay Area. 70 years old! Chill dude, was drinking Old English when I showed up. Used to work in the fish business. +* __French guy__ - was with his two sons, from Mill Valley, works as a software engineer for Salesforce. + +# Day 2 +Departed Sam P Taylor, got the anxious feeling of venturing somehwere new (since I had been to Sam P Taylor before and knew my way there). Took the bike path to the end, then a serious climb up Sir Francis Drake with _zero_ shoulder and a 55 mph speed limit. Yikes! The descent into Olema was gorgeous though! + +Highway 1 was smooth going, shady, and cool. Nice change. Scenery of Tomales Bay was nice, got breakfast at Bovine Bakery in Pt. Reyes Station. Giant scone! + +Biking right along the coast was really nice. Found a place on the side of the road that was shady. Took a quick rest there, almost fell asleep! + +Got to Tomales, got some early lunch (lamb sandwich with feta, onions, pepperocini, and horseradish sauce, yum!). As usual, had a giant climb after the town. Bunch of ups and downs that I'll probably have to re-visit tomorrow. + +Headwind from Tomales. :( I'd rather have a headwind than that oppressive heat! No shoulder on Highway 1 in many places, even on tough climbs. + +Gentle coast down toward the coast, which gave me a second wind! Grass got greener, could smell the ocean breeze, it was lovely. + +Decent climbs into Bodega Bay, again no shoulder, but at least the speed limit was 25 mph. + +The guys I met at Sam P Taylor warned me about the sand at Bodega Dunes State Park, they weren't kidding. Nice big hiker/biker site. Lots of people wrote stuff on the food locker there, mostly names, dates, and their route (and some words of wisdom, like "count the smiles, not the miles"). Got dinner at Spud Point Crab Co. Crab roll and clam chowder. Good stuff. + +Beach was a short ride away. Nice but kinda hot. Water was feezing as expected. Chilled there for about an hour before coming back to camp. + +No other cyclists. At least I still have Caliban's War to finish reading. + +Late, like 8 pm or so a couple showed up who were from Quebec City. They were going from Portland to SF, doing about 70 miles a day! They're getting married in the fall. That's about the extent of the conversation I was able to get out of them, they just hung out in their tent as soon as they got that set up. + +# Day 3 +Writing this at Bothe-Napa State Park. Hot but fun day. About 2500 feet of climbing, but nothing demoralizing. Maybe it gets easier past day 2! + +Woke up to it raining on my tent! It was misting and droplets were falling from the trees. Cold morning, but after about a mile had to take my jacket off. + +Took Highway 1 (back the way I came) to Bodega Highway. While on Bodega Highway a truck passed me kicking up all kinds of crud and I got something stuck in my eye. Had to stop and flush it out with water, I'm sure I looked like a goofball. Tip: wear sunglasses, even when it's foggy. + +Got second breakfast at a bakery (Wild Flour Bread) in Freehold. Popular place. Met some poeple on a supported bike tour coming from Tahoe. + +As usual, had a big climb out of the town I stopped in. Nothing stressful though, despite the 6-8% grade according to the map. Took windy back roads after the climb. Much less traffic and amazing views. Lots of vineyards and giant homes up there. + +Rode down into Sebastopol and jumped on the Joe Rodota Trail into Santa Rosa. That was super-chill, but turned into a hobo highway in Santa Rosa city limits. + +Ate at Franchettis' which Jason Wilson from Dropbox recommended. Was great, but I was out of place as the smelly cyclist, hah! + +Went north out of town and took the Mark West Springs, Porter Creek, Petrified Forest route. I didn't pay to see the petrified forest but made a water stop. + +Honestly, the climbing wasn't all that bad. The descent was _crazy_ though. Gorgeous and fast. I should have turned Strava on, I must have exceeded my record speed and hit 40 mph. On a touring bike no less! I had a stupid grin on my face the entire way down. + +Once in Calistoga, I went to go see Old Faithful. Not _that_ Old Faithful, just the California knock-off. Still neat, but I wouldn't go again. + +Got a carnitas super burrito and a six pack of 21st Amendment's Hell or High Watermelon from a taqueria/bodega combo. Dug into that right before writing this. Life is good. + +# Day 4 +I slept like a baby. Either I'm getting used to camping, or it was the beer. + +According to Google Maps: + + * 65 miles + * 1100 feet climbing + * 1500 feet descending + +__OH YEAH__ + +The elevation profile shows a nice gentle descent through the Napa Valley. Gonna be a fun day albiet maybe long. + +Camp breakfast was oatmeal with peanut butter mixed in. How did I not think of this earlier? + +Jumped north to catch Silverado Trail Road. It's a cyclist's paradise: little traffic, rolling hills, shade, decent "bike lane" (shoulder). + +Got a pastry and cup of coffee at Napa Valley Coffee Roasting Company in St. Helena. Damn good coffee. + +Decent headwind, but still downhill. Awesome view of vineyeards. So many cyclists that I'm getting tired of waving at all of them. + +Got into Napa at 11:00 on the dot. Nice and cool compared to Marin County! Hung out for a bit and got a couple of slices at Velo Pizzeria, which has the most legit NY style I've had in California. + +Riding south of Napa is all along California Highway 29, with some side roads. The shoulder is nice and wide, but it's still stressful having cars fly by at 55 mph. + +American Canyon feels like American Dream-land. Reminds me of pictures of neighborhoods from the 1950s. + +Vallejo has some decent riding on trails or bike lanes near Napa River. But then it's back on CA-29. Took some side roads before the bridge, but with some annoying hills. + +The Carquinez Bridge Trail is a nice, chill ride. San Pablo Ave up from Crockett is the opposite, but no traffic. + +This part of the Bay Area is so weird, vastly different towns right next to each other. + +* Crockett - feels like a small fishing village +* Rodeo - feels like a dead midwestern town. Seemed like 50% of downtown was empty storefronts. +* Hercules - affluent, new, shiny. Good biking +* Pinole - suburban, standard + +Starts getting sketchier the closer you get to Richmond. + +Starting to get angry at hills. + +Google Maps is an asshole. Why does it think that [Sarah Drive in Pinole][7] is an acceptible bike route? It's like a 10+% grande. Should have followed the Krebs map through Richmond. + +San Pablo Dam Road sucks. Horrible, narrow shoulder, I think they consider it a bike lane. I almost flipped catching a wheel in a grate. + +Stupid hills. + +I could hear the BART trains as I approached the Ohlone Greenway. Oddly soothing after travelling 200 miles. Once I hit the greenway, I played [some punk][8] from my phone and pounded out the last few miles home. + +[1]: https://mostateparks.com/park/katy-trail-state-park +[2]: https://goo.gl/maps/yNz9rwYTapm +[3]: https://goo.gl/maps/CvzrM19eSns +[4]: https://goo.gl/maps/AxF8DUd7yMQ2 +[5]: https://goo.gl/maps/EP2WcASHwos +[6]: https://www.strava.com/activities/1047975978 +[7]: https://goo.gl/maps/dweuGANk6D72 +[8]: https://www.youtube.com/watch?v=sxLEuoK0xFs +[9]: https://www.flickr.com/photos/nickpegg/sets/72157682416796352/ diff --git a/_posts/2017-09-05_visualizing_web_design_evolution_using_git.yaml b/_posts/2017-09-05_visualizing_web_design_evolution_using_git.yaml new file mode 100644 index 0000000..bb16ea3 --- /dev/null +++ b/_posts/2017-09-05_visualizing_web_design_evolution_using_git.yaml @@ -0,0 +1,72 @@ +date: 2017-09-05 +tags: + - linux + - git +title: Visualizing Web Design Evolution Using Git +--- + +My website here, as of the time of writing this, is still based on a design I made back in 2010, and is rendered using my [static site generator](http://github.com/nickpegg/posty) that I haven't touched in nearly as long. The site's served its purpose pretty well, but it's kind of a mess; It's unreadable on mobile devices, the CSS causes some weird inconsistencies, and the static site generator is no where near my current standards. So since this is a personal project I have the liberty of throwing it all in the trash and starting over (and learning new things along the way!). +--- +Since my weakest area is front-end (design, Javascript, CSS that doesn't look like it was written by a crazy person, etc.), I decided to jump in there, doing a couple of experiments. I ended up spending the better part of a weekend fiddling with HTML, playing with a couple of CSS frameworks to see what I liked, and incessantly bugging my friend [Brian](https://bokstuff.com) for help. Eventually I got something that I thought looked pretty good and got the 'final' version checked into git. + +So you want to know the cool part about git? If you use it right, you have a bunch of commits containing the full history of what you're building! And with a bit of magic you can come up with something like this: + +[](/media/img/design_vis/progress.gif) + +(click on image to see the full size version) + +Neat, huh? So how the heck did I manage to pull this off? With some shell scripting wizardry! + +Since all of my design is in a single HTML file, `index.html`, it's easy to comb through the history with the `git log` command. And to get the commit hashes to iterate over them, just add in some `grep`, `awk`, and `tac` to reverse-sort them (from oldest to newest). + +``` +git log -- index.html | grep commit | grep -v initial | awk '{print $2}' | tac +``` + +Okay, cool, so now we can flip through the history of our `index.html`, now how do we make an animated GIF of it? Well, an animation is just a set of images, so we need to figure out how to turn our HTML into an image a bunch of times. This is where [wkhtmltopdf](https://wkhtmltopdf.org/) comes in handy! The name's kind of a mouthful, but it's a tool that uses WebKit to render HTML and output that to a PDF (or an image). It's super simple to use! Just give it a URL or file name, and then a file to output to, and it does the rest. + +``` +wkhtmltoimage --width 1920 --height 1080 index.html index${NUM}.png +``` + +Alright, now we've got a bunch of images, how do we string those together into a GIF? For things like this, I always turn to ImageMagick's `convert` tool, which is the swiss-army-knife of image manipulation. It turns out that if you pass it a bunch of still images and a filename that ends in `.gif`, it just knows to make a GIF! Incredible! Since we want it to slowly go through the changes so you can play spot-the-difference, we add in a `-delay 100` to the command to tell it to wait 100 tens of milliseconds between each frame. + +``` +convert -delay 100 index*.png progress.gif +``` + +Add in some hackery to remove duplicates (because the rendered page may not change if you change the HTML) and to add a pause of the last frame, and this is what I came up with: + +``` +#!/bin/bash + +# requires that imagemagick and wkhtmltopdf are installed + +mkdir -p progress +git checkout master + +mkhtmltoimage --crop-w 1920 --crop-h 1080 https://nickpegg.com progress/0000.png + +count=0 +commits=$(git log | grep commit | grep -v initial | awk '{print $2}' | tac) + +for commit in $(echo $commits | xargs); do + git checkout "$commit" + i=$((++count)) + wkhtmltoimage --crop-w 1920 --crop-h 1080 index.html "progress/$(printf "%04d" "$count").png" +done + +# Magical one-liner to remove duplicates +md5sum progress/* | \ + sort | \ + awk 'BEGIN{lasthash = ""} $1 == lasthash {print $2} {lasthash = $1}' | \ + xargs rm + +# Add an artificial pause by copying the last file a few times +for i in $(seq $((count+1)) $((count+5))); do + cp progress/$(printf "%04d" "$count").png progress/$(printf "%04d" "$i").png +done + +convert -delay 100 progress/*png progress.gif +git checkout master +``` diff --git a/public/media/img/GTI-thumb.jpg b/public/media/img/GTI-thumb.jpg new file mode 100644 index 0000000..096d9fa Binary files /dev/null and b/public/media/img/GTI-thumb.jpg differ diff --git a/public/media/img/GTI.jpg b/public/media/img/GTI.jpg new file mode 100644 index 0000000..9e799ce Binary files /dev/null and b/public/media/img/GTI.jpg differ diff --git a/public/media/img/compaq.jpg b/public/media/img/compaq.jpg new file mode 100644 index 0000000..f7bf527 Binary files /dev/null and b/public/media/img/compaq.jpg differ diff --git a/public/media/img/cpu_meter/1.jpg b/public/media/img/cpu_meter/1.jpg new file mode 100644 index 0000000..dd7cc24 Binary files /dev/null and b/public/media/img/cpu_meter/1.jpg differ diff --git a/public/media/img/cpu_meter/2.jpg b/public/media/img/cpu_meter/2.jpg new file mode 100644 index 0000000..ae299ba Binary files /dev/null and b/public/media/img/cpu_meter/2.jpg differ diff --git a/public/media/img/cpu_meter/3.jpg b/public/media/img/cpu_meter/3.jpg new file mode 100644 index 0000000..b6a5030 Binary files /dev/null and b/public/media/img/cpu_meter/3.jpg differ diff --git a/public/media/img/cpu_meter/4.jpg b/public/media/img/cpu_meter/4.jpg new file mode 100644 index 0000000..f6a3261 Binary files /dev/null and b/public/media/img/cpu_meter/4.jpg differ diff --git a/public/media/img/cpu_meter/5.jpg b/public/media/img/cpu_meter/5.jpg new file mode 100644 index 0000000..1b23b59 Binary files /dev/null and b/public/media/img/cpu_meter/5.jpg differ diff --git a/public/media/img/cpu_meter/circuit.png b/public/media/img/cpu_meter/circuit.png new file mode 100644 index 0000000..0e19cb7 Binary files /dev/null and b/public/media/img/cpu_meter/circuit.png differ diff --git a/public/media/img/cpu_meter/testing.jpg b/public/media/img/cpu_meter/testing.jpg new file mode 100644 index 0000000..a0ccae9 Binary files /dev/null and b/public/media/img/cpu_meter/testing.jpg differ diff --git a/public/media/img/design_vis/progress.gif b/public/media/img/design_vis/progress.gif new file mode 100644 index 0000000..e543378 Binary files /dev/null and b/public/media/img/design_vis/progress.gif differ diff --git a/public/media/img/design_vis/progress.small.gif b/public/media/img/design_vis/progress.small.gif new file mode 100644 index 0000000..f864426 Binary files /dev/null and b/public/media/img/design_vis/progress.small.gif differ diff --git a/public/media/img/fun_with_graphs/nys-network-thumb.png b/public/media/img/fun_with_graphs/nys-network-thumb.png new file mode 100644 index 0000000..fcb755d Binary files /dev/null and b/public/media/img/fun_with_graphs/nys-network-thumb.png differ diff --git a/public/media/img/fun_with_graphs/nys-network.png b/public/media/img/fun_with_graphs/nys-network.png new file mode 100644 index 0000000..e0c4aeb Binary files /dev/null and b/public/media/img/fun_with_graphs/nys-network.png differ diff --git a/public/media/img/idd_hardware/FinalDesign.png b/public/media/img/idd_hardware/FinalDesign.png new file mode 100644 index 0000000..c07da32 Binary files /dev/null and b/public/media/img/idd_hardware/FinalDesign.png differ diff --git a/public/media/img/idd_hardware/traffic_graph.png b/public/media/img/idd_hardware/traffic_graph.png new file mode 100644 index 0000000..bcaddb1 Binary files /dev/null and b/public/media/img/idd_hardware/traffic_graph.png differ diff --git a/public/media/img/idd_software/db.png b/public/media/img/idd_software/db.png new file mode 100644 index 0000000..8cdc990 Binary files /dev/null and b/public/media/img/idd_software/db.png differ diff --git a/public/media/img/ir_receiver_schematic.png b/public/media/img/ir_receiver_schematic.png new file mode 100644 index 0000000..34fa0fd Binary files /dev/null and b/public/media/img/ir_receiver_schematic.png differ diff --git a/public/media/img/jetta-thumb.jpg b/public/media/img/jetta-thumb.jpg new file mode 100644 index 0000000..2204e7c Binary files /dev/null and b/public/media/img/jetta-thumb.jpg differ diff --git a/public/media/img/jetta.jpg b/public/media/img/jetta.jpg new file mode 100644 index 0000000..ddaec23 Binary files /dev/null and b/public/media/img/jetta.jpg differ diff --git a/public/media/img/more_fun_with_graphs/nys-super-sanitized-thumb.png b/public/media/img/more_fun_with_graphs/nys-super-sanitized-thumb.png new file mode 100644 index 0000000..d810611 Binary files /dev/null and b/public/media/img/more_fun_with_graphs/nys-super-sanitized-thumb.png differ diff --git a/public/media/img/more_fun_with_graphs/nys-super-sanitized.png b/public/media/img/more_fun_with_graphs/nys-super-sanitized.png new file mode 100644 index 0000000..226da5a Binary files /dev/null and b/public/media/img/more_fun_with_graphs/nys-super-sanitized.png differ diff --git a/public/media/img/whiteboard1-thumb.jpg b/public/media/img/whiteboard1-thumb.jpg new file mode 100644 index 0000000..701534b Binary files /dev/null and b/public/media/img/whiteboard1-thumb.jpg differ diff --git a/public/media/img/whiteboard1.jpg b/public/media/img/whiteboard1.jpg new file mode 100644 index 0000000..4fcda9a Binary files /dev/null and b/public/media/img/whiteboard1.jpg differ diff --git a/public/media/img/whiteboard2-thumb.jpg b/public/media/img/whiteboard2-thumb.jpg new file mode 100644 index 0000000..ab8301d Binary files /dev/null and b/public/media/img/whiteboard2-thumb.jpg differ diff --git a/public/media/img/whiteboard2.jpg b/public/media/img/whiteboard2.jpg new file mode 100644 index 0000000..210eafe Binary files /dev/null and b/public/media/img/whiteboard2.jpg differ diff --git a/public/media/projects/cpu_meter.tar.gz b/public/media/projects/cpu_meter.tar.gz new file mode 100644 index 0000000..7c89e92 Binary files /dev/null and b/public/media/projects/cpu_meter.tar.gz differ diff --git a/public/media/projects/nicklib.tar.gz b/public/media/projects/nicklib.tar.gz new file mode 100644 index 0000000..197ffc5 Binary files /dev/null and b/public/media/projects/nicklib.tar.gz differ diff --git a/public/media/projects/nqueens.tar.gz b/public/media/projects/nqueens.tar.gz new file mode 100644 index 0000000..d5d3ab8 Binary files /dev/null and b/public/media/projects/nqueens.tar.gz differ diff --git a/public/media/projects/servCheck.tar.gz b/public/media/projects/servCheck.tar.gz new file mode 100644 index 0000000..13249df Binary files /dev/null and b/public/media/projects/servCheck.tar.gz differ diff --git a/public/site.json b/public/site.json index 89b280e..81d8356 100644 --- a/public/site.json +++ b/public/site.json @@ -1 +1 @@ -{"posts": [{"date": "1970-01-01", "body": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n# h1 header\n\n```\n#!/bin/bash\necho \"This is a code block!\"\n```\n\n## h2 header\n\n> # Woah\n> Oh and look at this\n>\n> It's a block quote\n\n", "tags": ["tag1", "tag2", "multi word tag"], "blurb": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n", "title": "Test post 0"}, {"date": "1970-01-01", "body": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n# h1 header\n\n```\n#!/bin/bash\necho \"This is a code block!\"\n```\n\n## h2 header\n\n> # Woah\n> Oh and look at this\n>\n> It's a block quote\n\n", "tags": ["tag1", "tag2", "multi word tag"], "blurb": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n", "title": "Test post 1"}, {"date": "1970-01-01", "body": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n# h1 header\n\n```\n#!/bin/bash\necho \"This is a code block!\"\n```\n\n## h2 header\n\n> # Woah\n> Oh and look at this\n>\n> It's a block quote\n\n", "tags": ["tag1", "tag2", "multi word tag"], "blurb": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n", "title": "Test post 2"}, {"date": "1970-01-01", "body": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n# h1 header\n\n```\n#!/bin/bash\necho \"This is a code block!\"\n```\n\n## h2 header\n\n> # Woah\n> Oh and look at this\n>\n> It's a block quote\n\n", "tags": ["tag1", "tag2", "multi word tag"], "blurb": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n", "title": "Test post 3"}, {"date": "1970-01-01", "body": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n# h1 header\n\n```\n#!/bin/bash\necho \"This is a code block!\"\n```\n\n## h2 header\n\n> # Woah\n> Oh and look at this\n>\n> It's a block quote\n\n", "tags": ["tag1", "tag2", "multi word tag"], "blurb": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n", "title": "Test post 4"}, {"date": "1970-01-01", "body": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n# h1 header\n\n```\n#!/bin/bash\necho \"This is a code block!\"\n```\n\n## h2 header\n\n> # Woah\n> Oh and look at this\n>\n> It's a block quote\n\n", "tags": ["tag1", "tag2", "multi word tag"], "blurb": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n", "title": "Test post 5"}, {"date": "1970-01-01", "body": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n# h1 header\n\n```\n#!/bin/bash\necho \"This is a code block!\"\n```\n\n## h2 header\n\n> # Woah\n> Oh and look at this\n>\n> It's a block quote\n\n", "tags": ["tag1", "tag2", "multi word tag"], "blurb": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n", "title": "Test post 6"}, {"date": "1970-01-01", "body": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n# h1 header\n\n```\n#!/bin/bash\necho \"This is a code block!\"\n```\n\n## h2 header\n\n> # Woah\n> Oh and look at this\n>\n> It's a block quote\n\n", "tags": ["tag1", "tag2", "multi word tag"], "blurb": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n", "title": "Test post 7"}, {"date": "1970-01-01", "body": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n# h1 header\n\n```\n#!/bin/bash\necho \"This is a code block!\"\n```\n\n## h2 header\n\n> # Woah\n> Oh and look at this\n>\n> It's a block quote\n\n", "tags": ["tag1", "tag2", "multi word tag"], "blurb": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n", "title": "Test post 8"}, {"date": "1970-01-01", "body": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n# h1 header\n\n```\n#!/bin/bash\necho \"This is a code block!\"\n```\n\n## h2 header\n\n> # Woah\n> Oh and look at this\n>\n> It's a block quote\n\n", "tags": ["tag1", "tag2", "multi word tag"], "blurb": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n", "title": "Test post 9"}, {"date": "1970-01-01", "body": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n# h1 header\n\n```\n#!/bin/bash\necho \"This is a code block!\"\n```\n\n## h2 header\n\n> # Woah\n> Oh and look at this\n>\n> It's a block quote\n\n", "tags": ["tag1", "tag2", "multi word tag"], "blurb": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n", "title": "Test post 10"}, {"date": "1970-01-01", "body": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n# h1 header\n\n```\n#!/bin/bash\necho \"This is a code block!\"\n```\n\n## h2 header\n\n> # Woah\n> Oh and look at this\n>\n> It's a block quote\n\n", "tags": ["tag1", "tag2", "multi word tag"], "blurb": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n", "title": "Test post 11"}, {"date": "1970-01-01", "body": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n# h1 header\n\n```\n#!/bin/bash\necho \"This is a code block!\"\n```\n\n## h2 header\n\n> # Woah\n> Oh and look at this\n>\n> It's a block quote\n\n", "tags": ["tag1", "tag2", "multi word tag"], "blurb": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n", "title": "Test post 12"}, {"date": "1970-01-01", "body": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n# h1 header\n\n```\n#!/bin/bash\necho \"This is a code block!\"\n```\n\n## h2 header\n\n> # Woah\n> Oh and look at this\n>\n> It's a block quote\n\n", "tags": ["tag1", "tag2", "multi word tag"], "blurb": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n", "title": "Test post 13"}, {"date": "1970-01-01", "body": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n# h1 header\n\n```\n#!/bin/bash\necho \"This is a code block!\"\n```\n\n## h2 header\n\n> # Woah\n> Oh and look at this\n>\n> It's a block quote\n\n", "tags": ["tag1", "tag2", "multi word tag"], "blurb": "Lorem ipsum `dolor sit amet`, sale fugit ea ius, ut eam alii duis, quaeque salutandi cu mea. His quot doming cu, usu labore antiopam appellantur at, in vidit democritum has. Prompta sententiae duo ut. Nam ne iisque repudiare repudiandae, an mel duis ullum posidonium.\n\n", "title": "Test post 14"}], "pages": [{"body": "Wowzers, this is an about page!", "slug": "about", "parent": null, "title": "About me"}, {"body": "Projects page! woop woop", "parent": null, "title": "Projects"}, {"body": "Page for some project, it is a child of Projects", "parent": "Projects", "title": "Some Project"}], "tags": ["tag1", "tag2Long tag", "Really really really long tag", "Another tag"]} \ No newline at end of file +{"posts": [{"date": "2017-09-05", "blurb": "My website here, as of the time of writing this, is still based on a design I made back in 2010, and is rendered using my [static site generator](http://github.com/nickpegg/posty) that I haven't touched in nearly as long. The site's served its purpose pretty well, but it's kind of a mess; It's unreadable on mobile devices, the CSS causes some weird inconsistencies, and the static site generator is no where near my current standards. So since this is a personal project I have the liberty of throwing it all in the trash and starting over (and learning new things along the way!).", "tags": ["linux", "git"], "body": "My website here, as of the time of writing this, is still based on a design I made back in 2010, and is rendered using my [static site generator](http://github.com/nickpegg/posty) that I haven't touched in nearly as long. The site's served its purpose pretty well, but it's kind of a mess; It's unreadable on mobile devices, the CSS causes some weird inconsistencies, and the static site generator is no where near my current standards. So since this is a personal project I have the liberty of throwing it all in the trash and starting over (and learning new things along the way!).\n\nSince my weakest area is front-end (design, Javascript, CSS that doesn't look like it was written by a crazy person, etc.), I decided to jump in there, doing a couple of experiments. I ended up spending the better part of a weekend fiddling with HTML, playing with a couple of CSS frameworks to see what I liked, and incessantly bugging my friend [Brian](https://bokstuff.com) for help. Eventually I got something that I thought looked pretty good and got the 'final' version checked into git.\n\nSo you want to know the cool part about git? If you use it right, you have a bunch of commits containing the full history of what you're building! And with a bit of magic you can come up with something like this:\n\n[](/media/img/design_vis/progress.gif)\n\n(click on image to see the full size version)\n\nNeat, huh? So how the heck did I manage to pull this off? With some shell scripting wizardry!\n\nSince all of my design is in a single HTML file, `index.html`, it's easy to comb through the history with the `git log` command. And to get the commit hashes to iterate over them, just add in some `grep`, `awk`, and `tac` to reverse-sort them (from oldest to newest).\n\n```\ngit log -- index.html | grep commit | grep -v initial | awk '{print $2}' | tac\n```\n\nOkay, cool, so now we can flip through the history of our `index.html`, now how do we make an animated GIF of it? Well, an animation is just a set of images, so we need to figure out how to turn our HTML into an image a bunch of times. This is where [wkhtmltopdf](https://wkhtmltopdf.org/) comes in handy! The name's kind of a mouthful, but it's a tool that uses WebKit to render HTML and output that to a PDF (or an image). It's super simple to use! Just give it a URL or file name, and then a file to output to, and it does the rest.\n\n```\nwkhtmltoimage --width 1920 --height 1080 index.html index${NUM}.png\n```\n\nAlright, now we've got a bunch of images, how do we string those together into a GIF? For things like this, I always turn to ImageMagick's `convert` tool, which is the swiss-army-knife of image manipulation. It turns out that if you pass it a bunch of still images and a filename that ends in `.gif`, it just knows to make a GIF! Incredible! Since we want it to slowly go through the changes so you can play spot-the-difference, we add in a `-delay 100` to the command to tell it to wait 100 tens of milliseconds between each frame.\n\n```\nconvert -delay 100 index*.png progress.gif\n```\n\nAdd in some hackery to remove duplicates (because the rendered page may not change if you change the HTML) and to add a pause of the last frame, and this is what I came up with:\n\n```\n#!/bin/bash\n\n# requires that imagemagick and wkhtmltopdf are installed\n\nmkdir -p progress\ngit checkout master\n\nmkhtmltoimage --crop-w 1920 --crop-h 1080 https://nickpegg.com progress/0000.png\n\ncount=0\ncommits=$(git log | grep commit | grep -v initial | awk '{print $2}' | tac)\n\nfor commit in $(echo $commits | xargs); do\n git checkout \"$commit\"\n i=$((++count))\n wkhtmltoimage --crop-w 1920 --crop-h 1080 index.html \"progress/$(printf \"%04d\" \"$count\").png\"\ndone\n\n# Magical one-liner to remove duplicates\nmd5sum progress/* | \\\n sort | \\\n awk 'BEGIN{lasthash = \"\"} $1 == lasthash {print $2} {lasthash = $1}' | \\\n xargs rm\n\n# Add an artificial pause by copying the last file a few times\nfor i in $(seq $((count+1)) $((count+5))); do\n cp progress/$(printf \"%04d\" \"$count\").png progress/$(printf \"%04d\" \"$i\").png\ndone\n\nconvert -delay 100 progress/*png progress.gif\ngit checkout master\n```", "title": "Visualizing Web Design Evolution Using Git"}, {"date": "2017-06-25", "blurb": "In April of this year, I attempted to bike the [Katy Trail](https://mostateparks.com/park/katy-trail-state-park), but I forgot how unpredictable weather could be in Missouri that time of year and got rained out. While visiting with my parents waiting for my flight back to California, I decided to do a short bike tour in the San Francisco Bay Area where at the very least I wouldn't have to deal with rain.", "tags": ["bike", "touring"], "body": "In April of this year, I attempted to bike the [Katy Trail](https://mostateparks.com/park/katy-trail-state-park), but I forgot how unpredictable weather could be in Missouri that time of year and got rained out. While visiting with my parents waiting for my flight back to California, I decided to do a short bike tour in the San Francisco Bay Area where at the very least I wouldn't have to deal with rain.\n\nSet out on this trip on July 21 and returned to my home in Berkeley on July 24. This is the log I kept while on the road, transcribed with minimal editing from the notebook I kept with me.\n\nIn addition to my notes, I also took a bunch of pictures which you can find on [Flickr][9].\n\n# The Plan\n* Day 1 ([Google maps][2])\n * Start in Berkeley, ride to Oakland\n * Take the ferry from Oakland to SF\n * Ride up to Samuel P Taylor State Park and camp\n* Day 2 ([Google maps][3])\n * Ride over to CA Highway 1 (the Pacific Coast Highway)\n * Follow Highway 1 to Bodega Dunes State Park and camp\n* Day 3 ([Google maps][4])\n * Ride east to Santa Rosa, get lunch\n * Make the climb over the mountains to Calistoga\n * Camp at Bothe-Napa State Park\n* Day 4 ([Google maps][5])\n * Ride south to Napa, get lunch there\n * Ride all the way back home\n\n# Day 1\nThis is abridged since I'm writing this after the fact\n\nRolled out @ 08:00, hit up Suzette Crepe Cafe and then Safeway for food. Got some tortillas, bananas, and Nutella. That combo makes for a killer snack!\n\nCaught the 10:15 ferry from Oakland to SF. More crowded than expected, probably because it's summer and kids are out of school. Was on the Gemini which was a fast ride (faster that weekends).\n\nSF was uneventful, normal tourists on their way to the bridge. The west path was closed, so it was more of a shitshow than usual getting across (with not only biking tourists, but pedestrians too). Plus it was foggy and freezing. It felt like a 20 degrees warmer after the bridge. The east path meant I came down Alexander Drive which saved the climb up the hill before Sausilito.\n\nGot lunch at Sausilito Gourmet Deli. Had a _really_ nice backyard seating area. Ended up [taking El Camino Alto][6] up as a challenge, wasn't too bad and dumped me right into Corte Madera.\n\nTook (bicycle) Route 20 along the creek to Fairfax, was really nice.\n\nStopped on a park bench at Fairfax to rest in the mid-afternoon.\n\nFucking hot.\n\nAnd that fucking climb out of Fairfax! Holy crap!! It was tough in the heat. While I was stopped just before the crest, a mountain biker stopped to make sure I was good. Really lifted my spirits. He mentioned a shady way parallel to Sir Francis Drake Blvd. I should have followed his advice!\n\nGot to Sam P. Taylor alright after that.\n\nAt camp, I met:\n\n* __Quinn__ - He hitched a ride via Craiglist from North Carolina to Portland, bought a bike and was riding down the Pacific Coast Highway to SF\n* __Don__ - Last lived in St. Louis (Richmond Heights) but used to live in the Bay Area. 70 years old! Chill dude, was drinking Old English when I showed up. Used to work in the fish business.\n* __French guy__ - was with his two sons, from Mill Valley, works as a software engineer for Salesforce.\n\n# Day 2\nDeparted Sam P Taylor, got the anxious feeling of venturing somehwere new (since I had been to Sam P Taylor before and knew my way there). Took the bike path to the end, then a serious climb up Sir Francis Drake with _zero_ shoulder and a 55 mph speed limit. Yikes! The descent into Olema was gorgeous though!\n\nHighway 1 was smooth going, shady, and cool. Nice change. Scenery of Tomales Bay was nice, got breakfast at Bovine Bakery in Pt. Reyes Station. Giant scone!\n\nBiking right along the coast was really nice. Found a place on the side of the road that was shady. Took a quick rest there, almost fell asleep!\n\nGot to Tomales, got some early lunch (lamb sandwich with feta, onions, pepperocini, and horseradish sauce, yum!). As usual, had a giant climb after the town. Bunch of ups and downs that I'll probably have to re-visit tomorrow.\n\nHeadwind from Tomales. :( I'd rather have a headwind than that oppressive heat! No shoulder on Highway 1 in many places, even on tough climbs.\n\nGentle coast down toward the coast, which gave me a second wind! Grass got greener, could smell the ocean breeze, it was lovely.\n\nDecent climbs into Bodega Bay, again no shoulder, but at least the speed limit was 25 mph.\n\nThe guys I met at Sam P Taylor warned me about the sand at Bodega Dunes State Park, they weren't kidding. Nice big hiker/biker site. Lots of people wrote stuff on the food locker there, mostly names, dates, and their route (and some words of wisdom, like \"count the smiles, not the miles\"). Got dinner at Spud Point Crab Co. Crab roll and clam chowder. Good stuff.\n\nBeach was a short ride away. Nice but kinda hot. Water was feezing as expected. Chilled there for about an hour before coming back to camp.\n\nNo other cyclists. At least I still have Caliban's War to finish reading.\n\nLate, like 8 pm or so a couple showed up who were from Quebec City. They were going from Portland to SF, doing about 70 miles a day! They're getting married in the fall. That's about the extent of the conversation I was able to get out of them, they just hung out in their tent as soon as they got that set up.\n\n# Day 3\nWriting this at Bothe-Napa State Park. Hot but fun day. About 2500 feet of climbing, but nothing demoralizing. Maybe it gets easier past day 2!\n\nWoke up to it raining on my tent! It was misting and droplets were falling from the trees. Cold morning, but after about a mile had to take my jacket off.\n\nTook Highway 1 (back the way I came) to Bodega Highway. While on Bodega Highway a truck passed me kicking up all kinds of crud and I got something stuck in my eye. Had to stop and flush it out with water, I'm sure I looked like a goofball. Tip: wear sunglasses, even when it's foggy.\n\nGot second breakfast at a bakery (Wild Flour Bread) in Freehold. Popular place. Met some poeple on a supported bike tour coming from Tahoe.\n\nAs usual, had a big climb out of the town I stopped in. Nothing stressful though, despite the 6-8% grade according to the map. Took windy back roads after the climb. Much less traffic and amazing views. Lots of vineyards and giant homes up there.\n\nRode down into Sebastopol and jumped on the Joe Rodota Trail into Santa Rosa. That was super-chill, but turned into a hobo highway in Santa Rosa city limits.\n\nAte at Franchettis' which Jason Wilson from Dropbox recommended. Was great, but I was out of place as the smelly cyclist, hah!\n\nWent north out of town and took the Mark West Springs, Porter Creek, Petrified Forest route. I didn't pay to see the petrified forest but made a water stop.\n\nHonestly, the climbing wasn't all that bad. The descent was _crazy_ though. Gorgeous and fast. I should have turned Strava on, I must have exceeded my record speed and hit 40 mph. On a touring bike no less! I had a stupid grin on my face the entire way down.\n\nOnce in Calistoga, I went to go see Old Faithful. Not _that_ Old Faithful, just the California knock-off. Still neat, but I wouldn't go again.\n\nGot a carnitas super burrito and a six pack of 21st Amendment's Hell or High Watermelon from a taqueria/bodega combo. Dug into that right before writing this. Life is good.\n\n# Day 4\nI slept like a baby. Either I'm getting used to camping, or it was the beer.\n\nAccording to Google Maps:\n\n * 65 miles\n * 1100 feet climbing\n * 1500 feet descending\n\n__OH YEAH__\n\nThe elevation profile shows a nice gentle descent through the Napa Valley. Gonna be a fun day albiet maybe long.\n\nCamp breakfast was oatmeal with peanut butter mixed in. How did I not think of this earlier?\n\nJumped north to catch Silverado Trail Road. It's a cyclist's paradise: little traffic, rolling hills, shade, decent \"bike lane\" (shoulder).\n\nGot a pastry and cup of coffee at Napa Valley Coffee Roasting Company in St. Helena. Damn good coffee.\n\nDecent headwind, but still downhill. Awesome view of vineyeards. So many cyclists that I'm getting tired of waving at all of them.\n\nGot into Napa at 11:00 on the dot. Nice and cool compared to Marin County! Hung out for a bit and got a couple of slices at Velo Pizzeria, which has the most legit NY style I've had in California.\n\nRiding south of Napa is all along California Highway 29, with some side roads. The shoulder is nice and wide, but it's still stressful having cars fly by at 55 mph.\n\nAmerican Canyon feels like American Dream-land. Reminds me of pictures of neighborhoods from the 1950s.\n\nVallejo has some decent riding on trails or bike lanes near Napa River. But then it's back on CA-29. Took some side roads before the bridge, but with some annoying hills.\n\nThe Carquinez Bridge Trail is a nice, chill ride. San Pablo Ave up from Crockett is the opposite, but no traffic.\n\nThis part of the Bay Area is so weird, vastly different towns right next to each other.\n\n* Crockett - feels like a small fishing village\n* Rodeo - feels like a dead midwestern town. Seemed like 50% of downtown was empty storefronts.\n* Hercules - affluent, new, shiny. Good biking\n* Pinole - suburban, standard\n\nStarts getting sketchier the closer you get to Richmond.\n\nStarting to get angry at hills.\n\nGoogle Maps is an asshole. Why does it think that [Sarah Drive in Pinole][7] is an acceptible bike route? It's like a 10+% grande. Should have followed the Krebs map through Richmond.\n\nSan Pablo Dam Road sucks. Horrible, narrow shoulder, I think they consider it a bike lane. I almost flipped catching a wheel in a grate.\n\nStupid hills.\n\nI could hear the BART trains as I approached the Ohlone Greenway. Oddly soothing after travelling 200 miles. Once I hit the greenway, I played [some punk][8] from my phone and pounded out the last few miles home.\n\n[1]: https://mostateparks.com/park/katy-trail-state-park\n[2]: https://goo.gl/maps/yNz9rwYTapm\n[3]: https://goo.gl/maps/CvzrM19eSns\n[4]: https://goo.gl/maps/AxF8DUd7yMQ2\n[5]: https://goo.gl/maps/EP2WcASHwos\n[6]: https://www.strava.com/activities/1047975978\n[7]: https://goo.gl/maps/dweuGANk6D72\n[8]: https://www.youtube.com/watch?v=sxLEuoK0xFs\n[9]: https://www.flickr.com/photos/nickpegg/sets/72157682416796352/", "title": "North Bay Area Bike Tour Log"}, {"date": "2015-08-16", "blurb": "Continuing on my adventure of running my own self-built router at home, I decided to get IPv6 running on my home network. As of writing this blog post, my ISP doesn't do native IPv6 yet so I decided to go with Hurricane Electric's [IPv6 Tunnel Broker](https://tunnelbroker.net) service, which provides you with an IPv6-in-IPv4 tunnel.", "tags": ["linux", "networking", "ipv6"], "body": "Continuing on my adventure of running my own self-built router at home, I decided to get IPv6 running on my home network. As of writing this blog post, my ISP doesn't do native IPv6 yet so I decided to go with Hurricane Electric's [IPv6 Tunnel Broker](https://tunnelbroker.net) service, which provides you with an IPv6-in-IPv4 tunnel.\n\n# Creating the tunnel\n\nThe first step is going to [HE's Tunnel Broker website][1] and creating a regular tunnel. Set your IPv4 endpoint to your router's public IP address and be sure to pick a tunnel server close to you.\n\nOnce the tunnel's been created, you'll want to grab the following information:\n\n* Server IPv4 address\n* Server IPv6 Address (this will be your route to the outside world)\n* Client IPv6 Address (this will be your router's address)\n* Routed /64 (this is the block of IPv6 addresses for your network)\n\nIf you run multiple subnets, you can create a /48 block, but for my uses I just need a single subnet (/64 block), so that's what I'll be covering.\n\n\n# Updating the firewall\n\nBefore we even fire up the tunnel, we want to make sure it'll be secure when it comes up. This is a little different from my [first post][2] which covered IPv4 since we won't be using a NAT, but instead directly routing packets.\n\nThe goals of these firewall rules will be to:\n\n* Allow traffic related to already-established outbound connections\n* Allow ICMPv6 Destination Unreachable\n* Allow ICMPv6 Echo Request\n* Allow ICMPv6 Neighbor Soliciation and Advertisement on the local network (interface br0)\n* Allow all traffic coming from the local network (interface br0) out the world (interface he-ipv6)\n* Drop everything else\n\nSince we are doing regular routing, all rules on the INPUT chain will manage traffic directed to the router itself and all rules on the FORWARD chain will manage routed traffic (between the local network and the internet).\n\nHere's what my `/etc/iptables/rules.v6` file looks like with all these rules applied. Note that the default policy on `INPUT` and `FORWARD` are `DROP`.\n\n```\n*filter\n:INPUT DROP [0:0]\n:FORWARD DROP [0:0]\n:OUTPUT ACCEPT [0:0]\n-A INPUT -i lo -j ACCEPT\n-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n-A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type echo-request -j ACCEPT\n-A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type destination-unreachable -j ACCEPT\n-A INPUT -i br0 -p ipv6-icmp -m icmp6 --icmpv6-type neighbour-solicitation -j ACCEPT\n-A INPUT -i br0 -p ipv6-icmp -m icmp6 --icmpv6-type neighbour-advertisement -j ACCEPT\n-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT\n-A FORWARD -p ipv6-icmp -m icmp6 --icmpv6-type echo-request -j ACCEPT\n-A FORWARD -p ipv6-icmp -m icmp6 --icmpv6-type destination-unreachable -j ACCEPT\n-A FORWARD -i br0 -o he-ipv6 -j ACCEPT\nCOMMIT\n```\n\n\n# Updating the `interfaces` file\n\nOnce you have the firewall rules in place, it's time to update the `/etc/network/interfaces` file for the tunnel. There are two additions that we need to make: An IPv6 address for your internal network's interface and a virtual interface for the tunnel.\n\nThis is where you'll use the details you got from the Tunnel Broker website. Everything will mostly be directly used, however you need to choose an address from the Routed /64 block for your router's internal interface. The first one in the block is convenient, so if your block is `2001:470:6661:7274::/64` then your router's address will be `2001:470:6661:7274::1` (`2001:470:6661:7274::0` is technically the first address, but using 1 is less confusing since it's similar to IPv4 addressing).\n\nHere's what my `/etc/network/interfaces` files looks like after those changes, the IPv6 additions at the end. Be sure to replace the variables in the file with the values you got from the Tunnel Broker website.\n\n```\n# The loopback network interface\nauto lo\niface lo inet loopback\n\n# outside\nallow-hotplug eth0\niface eth0 inet dhcp\n hwaddress ether AA:BB:CC:DD:EE:FF\n\tdns-search home.nickpegg.com nickpegg.com\n\tdns-nameservers 8.8.8.8 8.8.4.4\n\niface eth0 inet6 auto\n\niface eth1 inet manual\niface wlan0 inet manual\n\nauto br0\niface br0 inet static\n\taddress 10.0.0.1\n\tnetmask 255.255.255.0\n\tbridge_ports eth1\n\niface br0 inet6 static\n\taddress 2001:470:6661:7274::1\n\tnetmask 64\n\nauto he-ipv6\niface he-ipv6 inet6 v4tunnel\n\taddress $CLIENT_IPV6_ADDRESS\n\tnetmask 64\n\tendpoint $SERVER_IPV4_ADDRESS\n\tgateway $SERVER_IPV6_ADDRESS\n```\n\nOnce you make these changes you'll be able to run these commands to start/restart your interfaces to fire up the tunnel:\n\n* `sudo ifdown br0; sudo ifup br0`\n* `sudo ifup he-ipv6`\n\nNote that if you're SSH'd into your server, you should run the first command in screen because you're going to lose connectivity for a few seconds. Once your tunnel's up, you should be able to `ping6 ipv6.google.com` and get a response.\n\n\n# Setting up Router Advertisements\nGetting the router talking IPv6 is only the first half. Now we need to have the devices on our local network pick up IPv6 addresses using a mechanism called [Router Advertisement][3]. Fortunately there's a Linux package called `radvd` which is incredibly easy to set up.\n\nHere's what a basic `/etc/radvd.conf` will look like. Again, be sure to replace `$ROUTED_64` with the block you were assigned via the Tunnel Broker website.\n\n```\ninterface br0\n{\n AdvSendAdvert on;\n\n prefix $ROUTED_64\n {\n };\n};\n```\n\nYeah, that's it. Start the `radvd` service and everything should get an IPv6 address. From a machine that's not your router, you can `ping ipv6.google.com` to verify that connectivity's working.\n\n\nNow that's all done, you have a router that talks IPv6 with the world and you can feel a little bit better about the whole [IPv4 exhaustion][4] issue.\n\n\n[1]: https://tunnelbroker.net/\n[2]: https://nickpegg.com/2014/8/building_my_own_home_router,_part_1.html\n[3]: https://tools.ietf.org/html/rfc4861#section-6\n[4]: https://en.wikipedia.org/wiki/IPv4_address_exhaustion", "title": "Building My Own Home Router - IPv6 Tunnel"}, {"date": "2014-08-22", "blurb": "In my [last post](http://nickpegg.com/2014/8/building_my_own_home_router,_part_1.html) I talked about getting my home router up and forwarding packets from nothing and getting my computers connected via Ethernet. The next step is to get 802.11 (WiFi) working.", "tags": ["linux", "networking"], "body": "In my [last post](http://nickpegg.com/2014/8/building_my_own_home_router,_part_1.html) I talked about getting my home router up and forwarding packets from nothing and getting my computers connected via Ethernet. The next step is to get 802.11 (WiFi) working.\n\n\n# Hardware Caveats\n\nIn my last post, I mentioned that I got the Intel 7260-ac card, which I've had some problems with. Intel decided to code into the EEPROM that the card can only use channels that make it compliant with *every* country's laws, and the firmware and Linux driver dutifully read this information and comply. This means that the card can only work in AP mode on channels 1-11, and will NOT in the 5GHz band. This means that you're stuck to the noisy 2.4 GHz band and can't even use 802.11ac (since it requires 5GHz).\n\nI've seen some various blog and forum posts where the OpenWRT people have gotten around this on cards with atheros chipsets since it's just a check in the driver. However, in the small amount of kernel driver hacking I've done, I've been unsuccessful.\n\n**Long story short**, watch which card you pick up and make sure people have had luck making it do what you want to, preferrably without having to patch kernel drivers.\n\n\n# Network Changes\n\nSince you're turning your router into a wireless access point, you have two options to connect clients to your network: split them off into their own network segment in a different subnet, or bridge the wireless interface in with your inside network and let wireless users mingle with your wired users. I chose the latter, since it was simpler.\n\nThe basic idea is that you create a bridge device (`br0`) and bridge in your `eth1` and `wlan0` interfaces. My updated config shows the changes you need to make to `/etc/network/interfaces`:\n\n```\nauto lo\niface lo inet loopback\n\n# outside\nallow-hotplug eth0\niface eth0 inet dhcp\n hwaddress ether AA:BB:CC:DD:EE:FF\n dns-search home.nickpegg.com nickpegg.com\n dns-nameservers 8.8.8.8 8.8.4.4\n\n# inside\niface eth1 inet manual\niface wlan0 inet manual\n\nauto br0\niface br0 inet static\n address 10.0.0.1\n netmask 255.255.255.0\n bridge_ports eth1\n```\n\nNote that `br0` has pretty much taken the place of `eth1` in the config. Also, we don't bridge in `wlan0` since our access point daemon will take care of that.\n\nAlong with this change in `/etc/network/interfaces`, don't forget to also change your dnsmasq settings so that it listens on `br0` instead of `eth1`.\n\nInstall the `bridge-utils` package if you haven't already and restart networking. Congrats, your router is now a one port network switch!\n\n\n# Firewall Changes\n\nSince our inside interface is now `br0`, we have to tweak our firewall rules a bit.\n\n#### rules.v4\n```\n*nat\n:PREROUTING ACCEPT [0:0]\n:INPUT ACCEPT [0:0]\n:OUTPUT ACCEPT [0:0]\n:POSTROUTING ACCEPT [0:0]\n-A POSTROUTING -o eth0 -j MASQUERADE\nCOMMIT\n*filter\n:INPUT DROP [0:0]\n:FORWARD ACCEPT [0:0]\n:OUTPUT ACCEPT [0:0]\n-A INPUT -i lo -j ACCEPT\n-A INPUT -i eth1 -j ACCEPT\n-A INPUT -i br0 -j ACCEPT\n-A INPUT -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT\n-A INPUT -i eth0 -p icmp -m icmp --icmp-type 8 -j ACCEPT\n-A FORWARD -i eth0 -o br0 -m state --state RELATED,ESTABLISHED -j ACCEPT\n-A FORWARD -i br0 -o eth0 -j ACCEPT\nCOMMIT\n```\n\n#### rules.v6\n```\n*filter\n:INPUT DROP [0:0]\n:FORWARD ACCEPT [0:0]\n:OUTPUT ACCEPT [0:0]\n-A INPUT -i lo -j ACCEPT\n-A INPUT -i eth1 -j ACCEPT\n-A INPUT -i br0 -j ACCEPT\nCOMMIT\n```\n\n\n# HostAPd Config\n\nThanks to [`hostapd`][2], getting your wireless card running in AP mode is a cinch! It's just a package install away in most cases, and the configuration isn't *too* terrible. Below is my config, annotated to make it easier to understand.\n\n```\n# Set up some logging. VERY useful to see why things aren't working.\nlogger_syslog=-1\nlogger_syslog_level=2\nlogger_stdout=-1\nlogger_stdout_level=2\n\n# Which interface to use and which bridge to join\ninterface=wlan0\nbridge=br0\n\n# Use this driver for AP stuff. This corresponds to the mac80211 driver\n# which most newer cards support.\ndriver=nl80211\n\n# 802.11 mode and channel, pretty self-explanatory\nhw_mode=g\ncountry_code=US\nchannel=11\n\n\n# Set and broadcast the SSID. Stupid double-negatives...\nssid=test_net\nignore_broadcast_ssid=0\n\n# 802.11N stuff - Try 40 MHz channels, fall back to 20 MHz\nieee80211n=1\nht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40]\n\n# WPA Authentication\nauth_algs=1 # Open authentication, no WEP\nwpa=2 # WPA2 only, set to 3 for WPA+WPA2\nwpa_passphrase=xxxxxxxxxxx # Hah! Like I'd put this in a gist.\nwpa_key_mgmt=WPA-PSK\nrsn_pairwise=CCMP # Cipher for WPA2 (AES in this case)\n\n# Don't use a MAC ACL\nmacaddr_acl=0\n```\n\nThe things to watch out for are the settings that are ORs of bits, like `auth_algs` and `wpa`. When setting up your own AP, it's a good idea to check out the [example config][3] to see what each setting does and what the defaults are.\n\nMy config doesn't include any 5 GHz settings, so you'll have to figure those out on your own if you're lucky enough to have a card that supports it. If I get mine working, I'll make another post with those settings.\n\nOnce you're done with configuration, fire up `hostapd` with `service hostpad start`. If everything was successful, you should see `wlan0` bridged in (use the `brctl show` command to check) and the network should be joinable by one of your wireless devices. If you don't see that, you'll want to check `/var/log/syslog` to see what hostapd is complaining about.\n\n\nAnd there you have it, a router with wireless! Next up is IPv6 support, so stay tuned for part 3.\n\n\n\n[1]: http://nickpegg.com/2014/8/building_my_own_home_router,_part_1.html\n[2]: http://wireless.kernel.org/en/users/Documentation/hostapd\n[3]: http://w1.fi/gitweb/gitweb.cgi?p=hostap.git;a=blob_plain;f=hostapd/hostapd.conf", "title": "Building My Own Home Router, Part 2 - 802.11"}, {"date": "2014-08-19", "blurb": "This is the first of a series of blog posts on building my own home router from scratch using Debian. My hopes are that by sharing my experiences, it can help others in this endeavor.", "tags": ["linux", "networking"], "body": "This is the first of a series of blog posts on building my own home router from scratch using Debian. My hopes are that by sharing my experiences, it can help others in this endeavor.\n\nI've been kicking around the idea of building my own router for a while now, mostly due to the fact that my trusty [WRT54GL][1] is grealy limted by what it can do with its measly 4 MB of flash and weak CPU. After months of casually searching and trying (unsuccessfully) to re-purpose some old hardware, I finally found what I've been looking for: a cheap-ish, low-power, rackmount server with more than one NIC.\n\n# The Hardware\n\n* [Intel D2500CCE Mini-ITX motherboard in a rackmount case][2]\n* [Intel 7260-ac Mini-PCIe card with antenna][3] - there are some issues with this, which I'll cover in a later post\n\nI can't believe that I didn't think to check the various Mini-ITX resellers for something like this, because this is almost exactly what I've always been looking for. I got a 2-NIC board since I'm cheap and already have a gigabit switch, but you can easily find boards with more ports if you don't mind shelling out the extra cash.\n\nOnce the equipment got to my apartment, I slapped in some old laptop RAM and a spare 2.5\" drive and got Debian installed.\n\n\n# 802.3 and IPv4\n\nThe first order of business was to replicate the core functionality of my old router: IPv4 routing and Ethernet connectivity. The plan was to use eth0 as my public interface (plugged into my cable modem) and eth1 as my internal interface. Before I even plugged in anything, I wrote a basic `/etc/network/interfaces` file.\n\n```\nauto lo\niface lo inet loopback\n\n# outside\nallow-hotplug eth0\niface eth0 inet dhcp\n hwaddress ether AA:BB:CC:DD:EE:FF\n dns-search home.nickpegg.com nickpegg.com\n dns-nameservers 8.8.8.8 8.8.4.4\n\n# inside\nauto eth1\niface eth1 inet static\n address 10.0.0.1\n netmask 255.255.255.0\n```\n\nNote the `hwaddress ether` line there. Since my ISP (whose name shall not be spoken (not Voldemort, but [just as evil][4])) locks me to a single MAC address, my new router had to spoof my old router's MAC address, which was spoofed from my laptop that I originally set the connection up with. If you seemingly can't get a DHCP lease on your public interface, this is likely the problem.\n\n\nNow that I had my interfaces configured and rarin' to go, I had to make sure that my ip{,6}tables rules were in order before plugging in.\n\n#### rules.v4\n```\n*nat\n:PREROUTING ACCEPT [2:125]\n:INPUT ACCEPT [1:65]\n:OUTPUT ACCEPT [4:260]\n:POSTROUTING ACCEPT [0:0]\n-A POSTROUTING -o eth0 -j MASQUERADE\nCOMMIT\n*filter\n:INPUT DROP [0:0]\n:FORWARD ACCEPT [0:0]\n:OUTPUT ACCEPT [0:0]\n-A INPUT -i lo -j ACCEPT\n-A INPUT -i eth1 -j ACCEPT\n-A INPUT -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT\n-A INPUT -i eth0 -p icmp -m icmp --icmp-type 8 -j ACCEPT\n-A FORWARD -i eth0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT\n-A FORWARD -i eth1 -o eth0 -j ACCEPT\nCOMMIT\n```\n\n#### rules.v6\n```\n*filter\n:INPUT DROP [0:0]\n:FORWARD ACCEPT [0:0]\n:OUTPUT ACCEPT [0:0]\n-A INPUT -i lo -j ACCEPT\n-A INPUT -i eth1 -j ACCEPT\nCOMMIT\n```\n\nThe above rules are my output from `iptables-save` and `ip6tables-save`, and are fully compatible with the respective restore programs. Debian even has a nice package called `iptables-persistent` which will load these rules on boot if you stash them as `rules.v4` and `rules.v6` in `/etc/iptables`!\n\nTo better understand these rules, it helps to have the [Netfilter packet flow diagram][5] in front of you. There are some simple goals with these:\n\n## IPv4 Filters\n\n* Allow traffic coming from loopback or the inside interface\n* Only allow traffic outside->inside if it pertains to an existing in->out connection\n* **Secret sauce** - that MASQURADE line enables NAT, so my private addresses can hide behind the one public address that my ISP gives me\n\n\n## IPv6 Filters\n\n* Just drop everything for now unless it comes from the inside and is destined for the router itself\n\n\nOf course, before I could have a fully-functional internet connection, I had to get DNS set up. And I guess a DHCP server would be nice to have before my leases all expire and everything drops its IP.\n\nLuckily, there's a software package which is geared towards these very tasks: `dnsmasq`! Getting it running was as easy as running `apt-get install dnsmasq` and `service dnsmasq start`, which was enough to get DNS working. To get DHCP working, I created two config files in `/etc/dnsmasq.d/`:\n\n#### dhcp.conf\n```\n# My DHCP configs\ndhcp-range=10.0.0.110,10.0.0.250,12h\n\n# options for DNS\ndhcp-option=option:domain-search,home.nickpegg.com,nickpegg.com\n\n# Static DHCP entries\ndhcp-host=00:24:1D:7D:5F:C3,10.0.0.10,host1\ndhcp-host=88:30:8A:22:2E:74,10.0.0.11,host2\ndhcp-host=00:23:54:1A:16:2D,10.0.0.12,host3\n```\n\n#### interface.conf\n```\n# Only allow DNS/DHCP requests from the inside interface\ninterface=eth1\n```\n\nWith all of that, I had a functioning IPv4 router and could do important things again, like idle on IRC and browse Reddit.\n\nThis is just the beginning though! You should go check out [part 2][6] of this series where I get 802.11 working.\n\n\n\n[1]: http://en.wikipedia.org/wiki/Wrt54gl\n[2]: http://mitxpc.com/proddetail.asp?prod=ER1UD2500DLM02\n[3]: http://mitxpc.com/proddetail.asp?prod=INTWIFI7260AC\n[4]: http://www.comcast.com/\n[5]: http://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg\n[6]: http://nickpegg.com/2014/8/building_my_own_home_router,_part_2_-_802.11.html", "title": "Building My Own Home Router, Part 1"}, {"date": "2011-11-25", "blurb": "I've been playing Minecraft for a while and after doing some travelling, I've\nran into the issue where I'd like to syncronize my Minecraft saves across\ncomputers.", "tags": ["git", "games"], "body": "I've been playing Minecraft for a while and after doing some travelling, I've\nran into the issue where I'd like to syncronize my Minecraft saves across\ncomputers.\n\nI already use git for software version control, so why not shoehorn Minecraft\ninto it? Not only would I get easy syncronization, I would also get version\ncontrol so if I seriously mung something up, I can revert back to a previous\nsave! Here's how I did it.\n\nFirst, I had to make sure git was installed on all of my machines. Luckily\non Linux git is usually provided in the package repository (git-core), but\nsince my desktop also runs Windows (for gaming), I use\n[msysgit](http://code.google.com/p/msysgit/). For example,\non Debian/Ubuntu all you need to do is:\n\n```\nsudo apt-get install git-core\n```\n\nOnce git was installed, I decided to go with a centralized approach since I\nwant one 'official' spot where I can push and pull my Mincraft saves to.\nI already have a server\nfrom the wonderful folks at [Linode](http://linode.com), so I just\ninitialized a bare (centralized) repository on there:\n\n```\ncd /path/to/repos/minecraft\ngit init --bare\n```\n\nThen, since I already have Minecraft installed on my desktop with quite a few\nsaves, I had to clone the central repository, add my saves, commit, and then\npush back to the central repository.\n\n```\ncd /home/nick/.minecraft/\ngit clone nick@nickpegg.com:/path/to/repos/minecraft temp\nmv temp/.git ./\n```\n\nSince you can't clone a repository into a non-empty folder, I had to clone it\nto a temporary folder and then copy the .git folder from there into my\n.minecraft folder. Now that my local repository was setup, I added the files\nI wanted to syncronize.\n\n```\ngit add saves screenshots stats texturepacks options.txt servers.dat\ngit commit -m 'Initial commit'\n```\n\nOnce I had the files commited, all I needed to do was push them up to the\ncentral repository on my server.\n\n```\ngit push\n```\n\nAnd now I have my Minecraft files in a central spot! Now every time I'm done\nplaying a bit, all I have to do to sync my files up is:\n\n```\ngit commit -a -m 'Played a bit'\ngit push\n```\n\nNow, on other machines, all I need to do is clone once, ``git pull``\nbefore playing,\nand then commit and push when I'm done playing!\n\nEasy peasy. Of course, you can do more fancy things with git since it's a\nfull-blown version control system. If you feel inlined to play with those\nfeatures, go read some [documentation](http://gitref.org/).", "title": "Syncing Minecraft Saves with Git"}, {"date": "2011-02-20", "blurb": "After getting my tax refund and being sick and tired of bottling my homebrew\nbeer, I've built myself a kegerator!\n\n[](http://www.flickr.com/photos/nickpegg/sets/72157625971333921/)\n\nDetails are over at my [project page](/projects/kegerator/), or if you'd\nrather just gawk at some pictures, check out the [Flickr set](http://www.flickr.com/photos/nickpegg/sets/72157625971333921/)!", "tags": ["beer"], "body": "After getting my tax refund and being sick and tired of bottling my homebrew\nbeer, I've built myself a kegerator!\n\n[](http://www.flickr.com/photos/nickpegg/sets/72157625971333921/)\n\nDetails are over at my [project page](/projects/kegerator/), or if you'd\nrather just gawk at some pictures, check out the [Flickr set](http://www.flickr.com/photos/nickpegg/sets/72157625971333921/)!", "title": "Kegerator"}, {"date": "2010-10-22", "blurb": "Yes, it's that time of year. Time to change my website design\n _yet again_!\n\nI got tired of dealing with Wordpress and wrote my own static page generator\nin Python, dubbed [Posty](http://github.com/nickpegg/posty). I know, I'm\nkind of [re-inventing the wheel](http://ringce.com/hyde) here and there\nare some [really nice solutions](http://github.com/mojombo/jekyll/wiki) to\nthis problem, but why not just make something for making's sake?\n\nPlus, I just feel _cool_ using Markdown and YAML to update my website.", "tags": ["programming"], "body": "Yes, it's that time of year. Time to change my website design\n _yet again_!\n\nI got tired of dealing with Wordpress and wrote my own static page generator\nin Python, dubbed [Posty](http://github.com/nickpegg/posty). I know, I'm\nkind of [re-inventing the wheel](http://ringce.com/hyde) here and there\nare some [really nice solutions](http://github.com/mojombo/jekyll/wiki) to\nthis problem, but why not just make something for making's sake?\n\nPlus, I just feel _cool_ using Markdown and YAML to update my website.", "title": "New Website (Again!)"}, {"date": "2010-06-23", "blurb": "I've been struggling getting my work phone number verified with Google Voice. The way that number verification works is that Google Voice calls you and asks\nyou to enter the two-digit code that's displayed on the website. But for some reason when I get a call on my outside line and I press a number button, it\ndoesn't send that DTMF tone. Instead it tries to place another call.\n\nMy solution? I found a DTMF tone generator online and I played the code DTMF tones through my computer speakers.\n\nIt's nice to see that these old phone tricks still work.", "tags": [], "body": "I've been struggling getting my work phone number verified with Google Voice. The way that number verification works is that Google Voice calls you and asks\nyou to enter the two-digit code that's displayed on the website. But for some reason when I get a call on my outside line and I press a number button, it\ndoesn't send that DTMF tone. Instead it tries to place another call.\n\nMy solution? I found a DTMF tone generator online and I played the code DTMF tones through my computer speakers.\n\nIt's nice to see that these old phone tricks still work.", "title": "Verifying Google Voice"}, {"date": "2010-06-19", "blurb": "Those of you who know me fairly well know that I'm a total HTPC\ngeek. It's to the point where I outright refuse to subscribe to cable television\nor even hook up an antenna to my TV. This geekery combined with my affinity\nfor Linux leads me to running XBMC on Linux on my little home theater machine.\nIt's been a pretty smooth experience with the exception of getting my remote\nwork with it. If you're struggling with it too, hopefully my tales will help you\nget it going.", "tags": ["linux", "htpc"], "body": "Those of you who know me fairly well know that I'm a total HTPC\ngeek. It's to the point where I outright refuse to subscribe to cable television\nor even hook up an antenna to my TV. This geekery combined with my affinity\nfor Linux leads me to running XBMC on Linux on my little home theater machine.\nIt's been a pretty smooth experience with the exception of getting my remote\nwork with it. If you're struggling with it too, hopefully my tales will help you\nget it going.\n\nSo, here's my setup. I've got an Antec Fusion 430 (a silver one\nwith the VFD), a Logitech Harmony remote, and Ubuntu 10.04. The Antec case is\npretty cool since it looks like it belongs \nin my home theater setup, and it\neven includes an IR receiver built right into the case! Cool! It should accept\nsignals from any IR remote, right?\n\n*Wrong*\n\nIn the hardware developer's infinite\nwisdom, they made it only work with Windows Media Center remotes instead of just\nmaking it a dumb device that passes data along. They actually put \n**more** effort\ninto designing the thing just to make my life harder. Augh! Luckily, when I got\nthis case my [then-roommate](http://benmurrell.com/) had an Xbox 360 remote which\nmagically \nworked! So I eventually got a Logitech Harmony remote and told it\nthat my HTPC was actually an Xbox 360. Step one complete.\n\nThe next step was\nto get LIRC to accept the remote. This is a bit tricky, but luckily I had backed\nup my configs. If you're starting out from scratch, here's how to do it in an\nUbuntu system.\n\nFirst of all, you need to install LIRC:\n\n sudo aptitude\n install lirc\n\nDuring the configuration phase of the install, it'll ask you for\nwhat kind of device you have. I selected *Soundgraph iMON PAD IR/VFD*, which uses\nthe lirc_imon driver. Unfortunately, since I have the silver Antec Fusion\n430 I have the VFD and not the LCD display, which has a slightly different IR\nreceiver. You have to specify the display_type=1 when the module is loaded.\nYou can do this by adding a file called lirc-imon.conf to /etc/modprobe.d/ with\n[these contents](http://nickpegg.com/stuff/lirc/modprobe.d-lirc-imon.conf). \n\nIf you don't want to restart, you'll have to throw commands at the system to reload\nthe module with the correct options.\n\n sudo service lirc stop\n sudo rmmod lirc_imon\n sudo modprobe lirc_imon display_type=1\n\nWhile you have LIRC stopped, you might as well double-check that the IR receiver is\nactually receiving data with the following command (hit Ctrl-C to stop):\n\n sudo cat /dev/lirc0\n\nYou should see a bunch of garbage get printed to\nthe terminal when you press buttons on your remote. If you don't, then either\nyou have the wrong type of remote or you don't need the \ndisplay_type argument to modprobe.\n\nNext, you need to setup the button config for your remote. Since\nI'm using a Logitech Harmony remote to emulate an Xbox 360 remote, I used the\nirrecord command to generate [my config](http://nickpegg.com/stuff/lirc/xbox360.conf).\nLuckily there's [plenty of people out there](http://www.google.com/search?&q=lirc++microsoft+remote+config)\nwho have already done this for you for a large amount of remotes \n([here's a good list](http://lirc.sourceforge.net/remotes/), for example). \nOnce you have the remote config file downloaded or created, \nadd an include to your [lircd.conf](http://nickpegg.com/stuff/lirc/lircd.conf)\nfor it, fire up LIRC, and test it out with the irw command.\n\n sudo service\n lirc start\n irw\n\nWhen you press buttons, you should see the button commands\nscroll by in the terminal.\n\n*\\*whew\\** Almost there. Still with me? Good, because\nwe only have one thing left, the XBMC Lircmap.xml file! I'll spare you the nitty-girtty\nof it and just give you \n[mine](http://nickpegg.com/stuff/lirc/Lircmap.xml) (right-click\nand save it). If you feel like making your own or need to tweak mine a bit, the\nXBMC wiki has some \n[good information](http://wiki.xbmc.org/index.php?title=Lirc_and_Lircmap.xml)\non how to do it.\n\n### For the impatient, here's all of my files associated with getting this to work:\n[lircd.conf](http://nickpegg.com/stuff/lirc/lircd.conf) (LIRC) \n[hardware.conf](http://nickpegg.com/stuff/lirc/hardware.conf) (LIRC) \n[xbox360.conf](http://nickpegg.com/stuff/lirc/xbox360.conf) (remote) \n[Lircmap.xml](http://nickpegg.com/stuff/lirc/Lircmap.xml)(XBMC)", "title": "LIRC and XBMC"}, {"date": "2010-04-07", "blurb": "It was the Friday before my Spring Break and quite possibly the worst thing in the world happened to me: I got rear-ended while at a stop.\nWell, okay, it's not the worst thing in the world but to a college student who loves his car, it was pretty bad. The lady who hit me did quite a\nnumber on my back end, and then pushed me into the car in front of me. Despite my airbags not going off, my car was totaled. The damage to the bumper,\nright rear quarter panel, and unibody frame were just too much.", "tags": ["car"], "body": "It was the Friday before my Spring Break and quite possibly the worst thing in the world happened to me: I got rear-ended while at a stop.\nWell, okay, it's not the worst thing in the world but to a college student who loves his car, it was pretty bad. The lady who hit me did quite a\nnumber on my back end, and then pushed me into the car in front of me. Despite my airbags not going off, my car was totaled. The damage to the bumper,\nright rear quarter panel, and unibody frame were just too much.\n\n[![Damage to the Jetta][4]][3]\n\nWith the Jetta totaled I had three options: Buy it back and spend the $1000 left over on repairs/hookers, give it away to the insurance company and\nspend <$2400 on a beater from Craigslist, or do the financially irresponsible thing and buy the new car I've been dreaming of, going into debt even\nfurther than I already was.\n\nGuess which option I chose:\n\n[![2010 VW GTI][2]][1]\n\n\nYes, that's right. I bought myself a new MkVI GTI. Since I had some money saved up from my recent internship, will be starting work in a couple of months,\nand was planning on buying one within a year I decided to go for it. I ended up paying $22,500 for it, which is a few hundred below dealer invoice for the\noptions that I wanted on it. I won't go into any car buying tips here, I'll save that for another post.\n\nOverall, I'm very pleased with my purchase. Here's why:\n\n**Performance:** It's got the VW 2.0L TSI turbocharged engine in it which puts out 200 hp. That's only a little more than my old VR6 Jetta, but the lighter\nengine makes a difference. I'm still breaking the engine in, but from what I can tell from accidentally giving too much gas, it can put down some power.\n\n**Handling:** With the sport-tuned suspension, this thing handles like a beast. With simply taking corners quickly and turning smoothly, I have yet to break\nthe tires loose from the road. There's also a roundabout here in Rolla which I took at speeds that I'm not at liberty to discuss publicly since I'm sure that\nthe city police would frown upon that.\n\nThe car also has a pseudo-locking differential called XDS. This is part of the electronic stability control system. What XDS does is when it senses that one\nwheel is getting too much power compared to the other, it applies the brakes to that first wheel to slow it down, giving more power to the second wheel. I\nhaven't noticed this kick in yet, but probably because I'm not giving it full throttle due to the break-in period\n\n**Electronics:** Included standard on the car is a touchscreen radio with Volkswagen's MDI interface. The MDI interface provides a port in the arm rest where\ndifferent devices can be plugged in, such as an iPod or USB drive. With the addition of an SD card slot right in the radio, with support up to 32 GB, I no\nlonger need a car computer. The software can be a little flaky at times and could use certain features (like creating an on-the-go playlist), but it suits my needs fine.\n\nAlso included is the MFI, which is essentially a trip computer. It tells you trip time, distance, fuel consumption, range left on the tank of gas, etc. The cool\npart about this is that in the settings menu, you can adjust some convenience settings which normally could only be done using a VAG-COM, such as which doors\nunlock when you use the keyfob, rolling windows down with the key, etc.\n\n**Practicality:** The folks on Top Gear always talk about the practicality of a car whenever they review something the average person could buy. Since I'm not\ngoing through a mid-life crisis, something practical is what I need. The GTI fits this bill nicely.\n\nThere's plenty of room for passengers in the back (a change VW made starting with the MkV) along with all of the creature comforts you would expect from sitting\nin the front. There's also a good amount of space in the hatch area, and the back seats fold down in case I need to haul anything big. I was able to fit a whole\nrecliner in the back with room to spare, for example.\n\nAll in all, I really love this car. It's quick, fun to drive, can get good gas mileage, and it's still useful for when I need it.\n\n\n[1]:/media/img/GTI.jpg\n[2]:/media/img/GTI-thumb.jpg\n[3]:/media/img/jetta.jpg\n[4]:/media/img/jetta-thumb.jpg", "title": "New Car"}, {"date": "2010-02-09", "blurb": "If you know me personally, you know that I can be pretty scatterbrained from\ntime to time. I've desperately needed a whiteboard to keep my thoughts\norganized, and I've finally gotten one. I know, it's not the\nmost exciting thing in the world to talk about, but it should be a change\nin the right direction for me.", "tags": [], "body": "If you know me personally, you know that I can be pretty scatterbrained from\ntime to time. I've desperately needed a whiteboard to keep my thoughts\norganized, and I've finally gotten one. I know, it's not the\nmost exciting thing in the world to talk about, but it should be a change\nin the right direction for me.\n\n[](/media/img/whiteboard1.jpg)\n\nBut, wait. What's this? \"Beertraq Road to Stable\"?\n\n[](/media/img/whiteboard2.jpg)\n\nPart of why I want to get my thoughts organized is because I want a good\nview of what all is left before I fully release Beertraq to the public.\nWith this list looming over my head (literally) it will hopefully get my\nbutt in gear to reach a stable release.", "title": "Whiteboard"}, {"date": "2009-12-25", "blurb": "I don't cook/bake all that often, but when I do I like to have some fun\nwith it. I came up with a ham recipe that turned out well, so I figured\nI'd share it with everyone.", "tags": ["cooking"], "body": "I don't cook/bake all that often, but when I do I like to have some fun\nwith it. I came up with a ham recipe that turned out well, so I figured\nI'd share it with everyone.\n\nFirst, put your ham in a baking pan and cut the diamond pattern into it. Trust\nAlton Brown when he says that utility knives work well for this. Then, mix the\nfollowing in a bowl\n\n* 1 cup brown sugar\n* 1/2 teaspoon ground mustard\n* 4 ounces of fine bourbon. My preference is Maker's Mark.\n\nOnce you have that all mixed up, pack it gently onto the ham. Uniformity is nice,\nbut not required. Then cook the ham at 325 degrees Fahrenheit until the inside\nmeat temperature reaches 150 degrees (about 3 hours with a 20 pound ham). I\nguarantee that it'll be tasty when it's done.", "title": "Holiday Ham Recipe"}, {"date": "2009-12-18", "blurb": "I figured I'd post the latest graph magic from my work at Nucor-Yamato Steel.\nThis is a graph of the entire network, switches AND hosts!", "tags": ["programming", "networking"], "body": "I figured I'd post the latest graph magic from my work at Nucor-Yamato Steel.\nThis is a graph of the entire network, switches AND hosts!\n\n[](/media/img/more_fun_with_graphs/nys-super-sanitized.png)\n(click for full-sized version, warning: LARGE image)
\n\nHere, the yellow boxes are center switches/routers, the green boxes are switches,\nand the peach-colored nodes are hosts. Also, red lines are switch-to-switch\nconnections and blue lines are switch-to-host connections.\n\nAnother somewhat off-topic thing about these graphs is that the manager of IT at\nNucor-Yamato is interested in open-sourcing the code that manages all of the data\nand generates these graphs, AND let me use company time to work on and manage the\nproject. If anyone knows of any open-source project (or software that doesn't cost\nan arm and a leg) that already does network discovery, data collection, and automated\nmapping then please let me know! If I'm not going to be re-inventing the wheel, then\nI'll probably be kicking the project off shortly after I start working full-time in\nJune 2010.", "title": "More Fun With Graphs"}, {"date": "2009-12-05", "blurb": "I'm glad to announce that my recent pet project, Beertraq, is now in a\n(somewhat closed) beta stage! The basic idea is there and functioning,\nbut the extra functionality isn't done and it's far from polished.\nNonetheless, it's time to take her for a test drive!", "tags": ["programming", "beertraq"], "body": "I'm glad to announce that my recent pet project, Beertraq, is now in a\n(somewhat closed) beta stage! The basic idea is there and functioning,\nbut the extra functionality isn't done and it's far from polished.\nNonetheless, it's time to take her for a test drive!\n\n\n> Note from future-Nick\n>\n> I got lazy and never finished Beertraq, and Untappd ended up releasing not long after. Though it took them _years_ to implement a barcode scanner in the app, which was going to be a core thing in Beertraq.\n\n\nSo what is Beertraq, you ask? It's a way for you to keep track of which\nbeers you've tasted, compare those with others, read beer reviews, and\nmost importantly discover new beers to try. I originally got the idea\nfrom The Flying Saucer's UFO Club, where members work toward a goal of\ndrinking 200 different beers. Once they complete the task, they get their\nname on a plate which gets put on the wall of the bar. The cool part about\nthe UFO Club is that it's all computerized, using a magstripe card to login\nat a kiosk in the bar. You can also log in to their website to check your\nprogress and read reviews on there. I figured that if The Flying Saucer can\nhave that system for their bar, I could do the same for the world.\n\nIf you're interested in becoming a BeerTraq beta user, send an email to\nbeertraq (at) beertraq (dot) com with the email address you want to use for\nyour account. All I ask is that you give feedback by filling out issue requests\nwith bugs you find or suggestions you might have.", "title": "Beertraq Beta!"}, {"date": "2009-11-30", "blurb": "I've always been utterly fascinated with graph theory, mostly with its\napplications to networks. As an added bonus, they can be represented with\npretty pictures!", "tags": ["programming", "networking"], "body": "I've always been utterly fascinated with graph theory, mostly with its\napplications to networks. As an added bonus, they can be represented with\npretty pictures!\n\n[](/media/img/fun_with_graphs/nys-network.png)\n(click on image for full-sized version)\n\nThat graph represents the network behind Nucor-Yamato Steel and Nucor Castrip\nArkansas, sanitized of sensitive information of course. All of the nodes are\nCisco switches, the yellow boxes representing backbone switches (6500 series\nto be exact). This graph is part of the network information system that I've\nbeen working on during the majority of my internship at NYS and gets auto-generated\nevery day, along with more centralized graphs on a per-switch basis.\nThe way the system works is that a periodic Python script goes out to a list of\nknown switches and gathers CDP neighbor information as well as the MAC address\ntables. Then Nmap scans are ran every 6 hours to scan for hosts, gathering IP\naddresses, hostnames, and MAC addresses. These MAC addresses are correlated with\nthe MAC tables from the switches to determine which hosts are connected to which\nports on what switches. The CDP neighbor information also gives which switches\nare connected to each other, giving a full scope of how the network's connected.\nThe script which generates the graphs grabs all of that information out of the\ndatabase, uses NetworkX and pydot to create the graph, and then graphviz to render\nit into a PNG image. The graph is pretty plain, though. The real version shows\nswitch names and IP addresses. Since the time between graph generation is so long,\nany more useful information that I could throw onto the graph would quickly become\noutdated. My grand scheme is to make a quickly-updated graph showing live stats like\nswitch load, link load, link types (fiber, twisted pair, wireless), downed switches,\netc. That way, I (or the network supervisor, I guess...) could have a big-screen TV\ndisplaying the live health of the network.\n\nI've been asked what parameters I set to get that graph to look that way. I didn't set anything special in code, it's all in the command line:\n\n twopi -q -Ksfdp -Tpng -Goverlap=\"prism\" -Eoverlap=\"prism\" -Gsplines=\"true\" -Gratio=\"compress\" -oclean.png clean.dot\n\nReally, I'm just a data visualization nerd looking to get a fix.", "title": "Fun With Graphs"}, {"date": "2009-11-26", "blurb": "Well, I finally bit the bullet and got a Linode account. So far I'm pretty\nhappy with it. I figured that with the costs of power and bandwidth, I was\nalmost spending $20/month to run my old server on my own hardware.\nIncidentally, the lowest-grade Linode VM costs that much and is enough to\nsuit my needs.", "tags": ["servers", "linux"], "body": "Well, I finally bit the bullet and got a Linode account. So far I'm pretty\nhappy with it. I figured that with the costs of power and bandwidth, I was\nalmost spending $20/month to run my old server on my own hardware.\nIncidentally, the lowest-grade Linode VM costs that much and is enough to\nsuit my needs.\n\nSo now that I've been setting up a webserver from scratch again, I'm doing\nit right this time. I'm setting up some monitoring software to notify me when\nthings go down, I'm no longer relying on myself for DNS (no more dynamic IPs!),\nand I'm also branching out and trying an alternative webserver.\n\nThe webserver in question is [Cherokee](http://cherokee-project.com/) which claims\nto use less memory and\nperform better than Apache. It sure does use less memory, but as a down side\nit doesn't have a native PHP module, so I'm required to use FastCGI for that\npurpose. Right now, there's five php-cgi processes running each using about\n25-30 MB. This wouldn't be a problem except that I've only got 360 MB of memory\nto play with. On the plus side its got a pretty sweet admin interface with wizards\nto help you set up things like WordPress, Drupal, Ruby on Rails, Django, etc. and\nyou can setup some pretty complex rules for what and how files should be hosted.\n\nOn the monitoring side of things, I'm using [Munin](http://munin.projects.linpro.no/) to monitor the various\n[stats on the server](http://terminalunix.com/munin/), [Piwik](http://piwik.org/) for website visit statistics, and I plan on getting [Monit](http://mmonit.com/monit/) going\nfor service monitoring. It's a bit more important now that I keep and eye on memory\nand data transfer now that I'm limited on that. Also, if some process goes wild and\nstarts using crazy amounts of CPU power and memory, I'll be able to catch it.\n\nUnfortunately when you move servers, you have to move everything that was running\non them. I'm still in that process, but it's been going pretty smoothly.", "title": "Moving Servers and Doing It Right"}, {"date": "2009-08-18", "blurb": "Want to share what you're doing with another person logged into the same system? All you need is a FIFO, cat, and script.\n\nOn your session:\n mkfifo foo\n script -f foo\n\nOn the viewer's session:\n\n cat foo\n\nThe viewer can then see everything that you're doing as if they're looking over your shoulder!", "tags": ["linux"], "body": "Want to share what you're doing with another person logged into the same system? All you need is a FIFO, cat, and script.\n\nOn your session:\n mkfifo foo\n script -f foo\n\nOn the viewer's session:\n\n cat foo\n\nThe viewer can then see everything that you're doing as if they're looking over your shoulder!", "title": "Stupid Linux Trick #5245"}, {"tags": [], "blurb": "The other major half of the Intelligent Drink Dispenser project was the software side\nof things. As with the hardware, there were some things we had to consider when\nbeginning the design of things.", "date": "2009-06-21", "body": "The other major half of the Intelligent Drink Dispenser project was the software side\nof things. As with the hardware, there were some things we had to consider when\nbeginning the design of things.\n\n\nWhat language should we use? Should this be a GUI\napplication or web application? If we go with a GUI application, what operating system\nshould we target?\n\nWe decided that since we only had a semester to get everything done, we needed a\nframework to take care of the more nitty-gritty stuff. We eventually decided to go\nwith the Django web framework, which uses the Python programming language. Python is\na language we all knew and Jon and I had used Django in the past. Also, since our\n'final product' would be highly based on a client-server model, it makes sense to\ngo with a web app since the server can be in a central location with many clients\nconnecting to it.\n\nThe most important thing to us was the fact that Django abstracts the database into models\nfor us. No having to mess around with raw SQL, we just run some queries and get our data\nfrom the models as if they're just plain ol' objects. After some thought, we came up with\nour models and their relationships:\n\n\n\nThe development of the application was fairly straight-forward. It was just a standard\nDjango app after all. The interesting part was interfacing with the hardware.\n\nIf you remember from my post talking about the hardware side, we used an FTDI UM232\nUSB-to-serial converter. Lucky for us, there's a Linux kernel module which represents this\ndevice as a virtual serial port, which made our jobs a whole lot easier since there's\nexisting serial libraries for Python (like pyserial). We ended up just writing a couple of\nfunctions, one to read the RFID tag from the serial port, and one that takes in a Drink id\nand then communicates to the microcontroller to pour it. The microcontroller's fairly dumb,\njust taking a number and turning that pin on, or turning all of the pins off if a non-valid\ncharacter is sent, as you can see in the pourDrink function:\n\n def pourDrink(id, serialPort=DEVICE):\n \"\"\"Pours the drink given by the specified ID\"\"\"\n\n # Seconds per mL of the motors, found experimentally\n # These should be in the database or a config file instead of hardcoded...\n secondsPerML = []\n secondsPerML.append(9.858/350.0) # Pump 0\n secondsPerML.append(9.858/350.0) # Pump 1\n secondsPerML.append(6.385/210.0) # Pump 2\n\n components = DrinkComponent.objects.filter(drink=id)\n\n for c in components:\n stock = IngredientStock.objects.filter(ingredient=c.ingredient)\n total = 0\n\n for s in stock:\n total += s.amount\n\n if total < c.amount:\n raise UnableToPour(\"Not enough \" + c.ingredient.name + \" to pour drink!\")\n\n port = serial.Serial(serialPort, 2400)\n if not port.isOpen():\n raise UnableToPour(\"Unable to open serial port!\")\n\n for c in components:\n stock = IngredientStock.objects.filter(ingredient=c.ingredient)\n leftToPour = c.amount\n\n startTime = time.time()\n\n for s in stock:\n port.write(str(s.slot))\n if leftToPour < s.amount:\n time.sleep(secondsPerML[s.slot]*leftToPour)\n s.amount = s.amount - leftToPour\n s.save()\n\n break\n else:\n time.sleep(secondsPerML[s.slot]*(s.amount - ))\n leftToPour = leftToPour - s.amount - 30\n\n s.amount = 0\n s.save()\n\n print \"Time to pour:\" + str(time.time() - startTime)\n port.write(\"\\n\")\n port.close()\n\nNot exactly the most precise in terms of pouring accuracy, but it gets the job\ndone as a prototype. As for the rest of the code, there's not too much else that's\nvery interesting. I may release the code at some point in the future.", "title": "Intelligent Drink Dispenser - Software Design"}, {"tags": [], "blurb": "I said that I'd post details on my Intelligent Drink Dispenser project \"soon\". That\nwas over a month ago. Whoops. I blame my [new internship](http://nucoryamato.com/) for that.\n\nFor those of you not in the know, the Intelligent Drink Dispenser was my senior design\nproject at Missouri University of Science and Technology (which will forever in my heart\nbe University of Missouri-Rolla). It's basically a smart drink dispenser that's capable\nof mixing, charging customers, telling the bar/restaurant owner when they need to refill\nthe machine, etc.", "date": "2009-06-21", "body": "I said that I'd post details on my Intelligent Drink Dispenser project \"soon\". That\nwas over a month ago. Whoops. I blame my [new internship](http://nucoryamato.com/) for that.\n\nFor those of you not in the know, the Intelligent Drink Dispenser was my senior design\nproject at Missouri University of Science and Technology (which will forever in my heart\nbe University of Missouri-Rolla). It's basically a smart drink dispenser that's capable\nof mixing, charging customers, telling the bar/restaurant owner when they need to refill\nthe machine, etc.\n\nIf you don't feel like reading the details and just want to look at the pretty pictures,\nyou can check out my [Picasa album](http://picasaweb.google.com/nick.pegg/IntelligentDrinkDispenser)\nor watch the [Youtube video](http://www.youtube.com/watch?v=79H5oAS_Y6k).\n\nThe theoretical process is that the customer would go to order a drink, and since they're\na new customer, they'd have to be entered into the system by the person running the machine\n(bartender, or waiting staff). They would have their name and credit card information taken,\nand would then be assigned a drinking vessel based on the first drink they were wanting to\norder. Multiple vessels could also be assigned to the same person. Once the customer is\nsetup and is ready to purchase their drink, they set the fluid vessel on the marked reader\narea on the dispenser. The system then recognizes the vessel, who it belongs to, asks the\ncustomer for the last four digits of their credit card, and then asks the customer which\ndrink they'd like to order. The customer then chooses what drink they'd like to have, the\nsystem double-checks that the vessel is the right size, and pours it.\n\nSecurity and privacy was one of the major goals of the project. The only information stored\nabout the user is their name, a secure hash of their credit card number, the last four digits\nof ther card, and their drink order history.\n\nThe project itself can pretty much be split into two major components: hardware and software.\nI would probably say the hardware is more interesting and posed more challenges for us. The\nfirst thing is how the heck do you pour the fluid? If you take into consideration that we only\nhad a $300 budget for the whole shebang, it's not an easy task. The way that the professionals\ndo it is with Carbon Dioxide-powered pumps, which are controlled by electronic valves and supplied\nby a tank and pressure regulator. Three pumps, valves, and the feed system would cost us well\nover $300. Our original idea was to use 24 VDC sprinkler valves, but that idea failed because the\nsprinkler valves by their nature require back-pressure to operate. We came up with the idea of using\nwindshield washer pumps made for cars. Since this was supposed to be a prototype, we didn't have to\nworry about our components being food-grade. That, coupled with the fact that the pumps operate on\n12V DC and are relatively inexpensive ($15-25 a pop), that's what we went with for our design.\n\nThe rest of the hardware design was fairly straightfoward. We used an 8051 microcontroller to control\neverything, an FTDI UM232 to handle the PC communications and a Parallax RFID reader to read the\ntags that are on the bottom of the drinking vessels. The serial communication is pretty interesting\nsince the USB-to-serial device has only one serial port but two devices to talk to (the RFID reader,\nand the PC). Our solution was to have the receive line go to the RFID reader (to the PC), and have\nthe transmit line go to the 8051 (from the PC). This meant that our 8051 couldn't talk back, so we\nhad to hope that things were working right. Additionally, Richard developed a simple serial language\nfor the 8051. If the 8051 received an ASCII 0 through 7, it would turn on that pin on the port we\nwere using. This could easily be modified to operate with all the ports on the 8051 to control 24\npumps, or even with some addressing logic to control a huge number of pumps.\n\nBelow is our hardware schematic, which should give you some idea of how it's all connected.\n\n\n\nIn my next post, I'll be talking about the software design. Stay tuned!", "title": "Intelligent Drink Dispenser Details"}, {"date": "2009-05-11", "blurb": "So, I've been pretty quiet about my Intelligent Drink Dispenser project so far,\nmostly because there was going to be a competition between myself and\n[Clint Rutkas](http://betterthaneveryone.com/archive/2009/04/11/856.aspx) and\nI didn't want to give the enemy any details.", "tags": ["idd"], "body": "So, I've been pretty quiet about my Intelligent Drink Dispenser project so far,\nmostly because there was going to be a competition between myself and\n[Clint Rutkas](http://betterthaneveryone.com/archive/2009/04/11/856.aspx) and\nI didn't want to give the enemy any details.\n\nWell, the cat's out of the bag: [http://news.mst.edu/2009/05/students_create_smart_way_to_m.html](http://news.mst.edu/2009/05/students_create_smart_way_to_m.html)\n\nThe communications department of my university, Missouri S&T (formerly UMR), gets\nalerts from Google News whenever someone mentions the university's name and since\nClint did just that, his post showed up in their email. After talking with the\ndirector of communications, he decided to run the story. I gotta say, it's a\npretty great way for my Senior Design class to wind down.\n\nFor those interested in the details of the Intelligent Drink Dispenser, stay\ntuned! I'll be posting more information about it soon.\n\nSide note: since the story got posted, my server's been chugging along to serve\nup my website, almost maxing out the upload on my poor cable internet connection.\nHere's the traffic graph from my router:\n\n", "title": "Intelligent Drink Dispenser in the news!"}, {"date": "2009-04-18", "blurb": "After spending all afternoon fighting with my new server and my DD-WRT router,\nI finally figured out how to get my server to PXE boot and fire up an Ubuntu\ninstall. All it really involved was setting up TFTP on another box (my desktop,\nto be specific), adding a line to DD-WRT's DNSMasq options, and configuring the\ndamn server to boot from PXE, which was the hardest part. Luckily, for those of\nyou who are struggling with it, here's how I did it.", "tags": ["servers", "linux"], "body": "After spending all afternoon fighting with my new server and my DD-WRT router,\nI finally figured out how to get my server to PXE boot and fire up an Ubuntu\ninstall. All it really involved was setting up TFTP on another box (my desktop,\nto be specific), adding a line to DD-WRT's DNSMasq options, and configuring the\ndamn server to boot from PXE, which was the hardest part. Luckily, for those of\nyou who are struggling with it, here's how I did it.\n\n### Setting up the PXE client\n\nI had to get my server to boot PXE in the first place. For most people, this just\nmeans poking around in the BIOS. Not for me though.\n\nAfter poking around the HP site, I've found out that my server is a first\ngeneration Proliant DL360. Since it's an older machine, this means that it doesn't\nhave a built-in BIOS config, but I had to actually download the old Compaq SmartStart\n5.5 CD. I had to hunt around the HP website, but to save you the trouble, you can snag it here:\n\n[http://ftp.hp.com/pub/products/servers/supportsoftware/ZIP/smartstart-5.50-0.zip](http://ftp.hp.com/pub/products/servers/supportsoftware/ZIP/smartstart-5.50-0.zip)\n\nOnce you boot from the CD, you'll want to go into the System Configuration\nUtility when prompted. From there, it's just like a giant BIOS. Just turn PXE\non for whatever ethernet port you're using and it's rarin' to go.\n\n### Setting up the TFTP server\n\nOnce my server was setup for PXE booting, I had to set up a tftp server for it\nto grab the boot image from. Since I was using my desktop, which runs Ubuntu, as\na host, setup was pretty easy. I just used tftpd-hpa per the Ubuntu wiki's recommendation.\n\n # sudo aptitude install tftpd-hpa\n\nI had to also edit the configuration file at /etc/default/tftpd-hpa. Mine looks like this:\n\n #Defaults for tftpd-hpa\n RUN_DAEMON=\"yes\"\n OPTIONS=\"-l -s /var/lib/tftpboot\"\n\nSince I was wanting to PXE boot into an Ubuntu install, I had to extract the\ninstall files into /var/lib/tftpboot as I put in the config file. For example, the\nnetboot image files for Ubuntu 9.04 can be found here:\n\n[http://archive.ubuntu.com/ubuntu/dists/jaunty/main/installer-i386/current/images/netboot/netboot.tar.gz](http://archive.ubuntu.com/ubuntu/dists/jaunty/main/installer-i386/current/images/netboot/netboot.tar.gz)\n\n### Setting up the the DHCP server\n\nDD-WRT uses dnsmasq for DHCP, so if you have a system which uses it too it shouldn't\nbe too much different to setup. Watch out, though! I initially screwed up my configuration\nwhich really messed with my router.\n\nAll you have to do is add a line to the Additional DNSMasq Options found under the Services\ntab. If you're running plain dnsmasq, just add the line to your dnsmasq.conf file. The line\ngoes a little something like this:\n\n dhcp-boot=pxelinux.0,mybox,10.0.0.100\n\nwhere pxelinux.0 is the file to boot, mybox is the hostname of the tftp server, and 10.0.0.100\nis the IP address of the tftp server. You could probably get away with only specifying the\nhostname or just leaving it blank and supplying the IP address. You can also get more fancy\nand send certain boot images to certain machines, etc. This way works just fine on a home\nnetwork like mine.\n\nOnce you get this all setup, any machines that try to PXE boot will receive the image and\nboot to it. If you used the Ubuntu install image like I did, you'll be able to install Ubuntu\non any PXE-capable machine or even boot into a rescue shell! Just remember that if you can't\nsetup a boot order (like my Proliant) make sure to disable the PXE boot in dnsmasq before rebooting.", "title": "PXE boot with DD-WRT and Ubuntu"}, {"date": "2009-04-17", "blurb": "Thanks to a generous donation from [Richard Allen](http://rsaxvc.net/), I now have a new server.", "tags": ["servers"], "body": "Thanks to a generous donation from [Richard Allen](http://rsaxvc.net/), I now have a new server.\n\n\n\nIt's a Compaq Proliant DL360. From what I can tell of it's past, a place where another\nfriend of mine was working was getting rid of their old hardware and he snagged a bunch.\nRichard got some of the servers, had no use for this one, and then gave it to me a couple\nof days ago.\n\nIt's probably a first generation DL360, but that doesn't mean it sucks. It's got dual\nPentium IIIs running at 1.266 GHz each, 512 MB of RAM, and two 18.3 GB SCSI drives running\nin RAID1. It's quite an upgrade from my current server, which is dual P3 450 MHz with a\nlittle less than 512 MB of RAM. The best part of the whole thing, though, is the Remote\nInsight Lights-Out Edition II card that came with it. It's a PCI-X card that redirects\nvideo, keyboard, and mouse from the system and supplies it to a web interface. This means\nthat no matter where I am, I can get a physical terminal to my server. Plus, if I plug an\nexternal power supply to it, I can even turn on my server remotely!\n\nI'll probably be moving everything from my current server over to the new one. Since I'm\nmirroring and then cutting over, there shouldn't be any problems with any of the services\nthat my box supplies.", "title": "New Server"}, {"date": "2009-04-15", "blurb": "So, I've decided to redo my website again. My old one was pretty bland and\nupdating stuff was a relatively a pain. Plus, I seem to be doing more interesting\nthings and having more interesting thoughts (hopefully) than I have in the past\ncouple of years. Of course, I am a Computer Engineer (aka nerd), so don't expect\nto see anything like me pondering the wonders of the cosmos here. I'll probably\nmostly post updates on projects I'm fiddling with, my struggles with technology,\nand what I've been up to.", "tags": [], "body": "So, I've decided to redo my website again. My old one was pretty bland and\nupdating stuff was a relatively a pain. Plus, I seem to be doing more interesting\nthings and having more interesting thoughts (hopefully) than I have in the past\ncouple of years. Of course, I am a Computer Engineer (aka nerd), so don't expect\nto see anything like me pondering the wonders of the cosmos here. I'll probably\nmostly post updates on projects I'm fiddling with, my struggles with technology,\nand what I've been up to.\n\nAs you can see, I decided to go with WordPress. I used it a long time ago, but\nafter seeing my roommate [Ben Murrell](http://benmurrell.com/) use it on the [Missouri S&T ACM site](http://acm.mst.edu/)\nand seeing what it was capable of, I went for it. Probably the most important\nthing for me was the ability to have static pages and link to them in a reasonable\nfashion (as you can see along the top and right sidebar). It just does everything\nI want to do without too much fuss, and it looks pretty while it does it.\n\nI'm still moving stuff from my old website and updating information, but feel\nfree to poke around in the meantime.", "title": "New Website"}], "tags": ["programming", "ipv6", "bike", "idd", "git", "games", "beer", "linux", "htpc", "cooking", "servers", "networking", "beertraq", "touring", "car"], "pages": [{"url": "/about/", "slug": "about", "parent": null, "body": "This about page was incredibly out-of-date, so I removed it. If you want to know who I am or what I'm up to, check out these links:\n\n* [Twitter](https://twitter.com/nickpegg)\n* [GitHub](https://github.com/nickpegg)", "title": "About me"}, {"url": "/projects/cpu-usage-meter/", "parent": "Projects", "body": "Back in the day, there was a little obscure operating system called BeOS. The\ncompany which made the OS was brave enough to put it on their own hardware, too.\nThis was dubbed the [BeBox](https://en.wikipedia.org/wiki/Bebox). Among all the\nneat doohickies on the computer were two CPU load meters (one for each processor).\nNow, how cool would it be to have a computer with those?\n\n__Very.__\n\n### Download\nNote: Linux code makes use of libserial and libstatgrab. Both must be installed for\nprogram to work/compile. The UM245R device uses the ftdi_sio driver. It's in the\n2.6 kernel tree, so it should (hopefully) be detected when you plug the device in.\n\nUSB controller program:\n\n* [Linux code and executable](/media/projects/cpu_meter.tar.gz)\n* Windows code removed due to buginess\n\n### Updates\n\n#### Status Update - Nov 27 2007\n\nWow, it's been almost a year since I've put work on this. I decided to finally write\ncode to make it work under Linux. I ended up throwing out the notion of trying to\nuse libusb. After 4 hours of research and code hacking, it worked!\n\n#### Status Update - Dec 08 2006\n\nThe hardware works and the software works (kinda). Once I get around to cleaning up\nsome of the code and adding some documentation, I'll start uploading stuff. Stay tuned!\n\n#### Status Update - Dec 02 2006\n\nGot the hardware working on a breadboard. Using DLP's test program, various patterns\nwere able to be sent. Video coming soon!\n\n### Statistics:\n* Cost: $27.69\n* Lines of code (Linux): 83\n* Lines of code (Windows): 1503\n* Sleep lost: Unknown\n\n### Hardware Design\nThe hardware is pretty simple. Using an UM245R, most of the work is done for you. The\n[UM245R](https://www.ftdichip.com/Products/EvaluationKits/UM245R.htm) takes in USB data\nand outputs it on the 8 data pins, and those 8 pins directly drive the LEDs. It's not\nquite as simple as that, since there's all sorts of protocol with Ready-to-Read and\nReady-to-Write and Read and Write pins that go high and low. I just cheated and used\nat 555 timer to generate a clock signal on the RD pin to give me the data. I just\nlucked out and the UM245R outputs the last data if there's no new data available.\n\n[Circuit Design](/media/img/cpu_meter/circuit.png)\n\n[Testing the circuit](/media/img/cpu_meter/testing.jpg)\n\n### Software\nAs with any hardware, there needs to be software which controls it. For the Windows\ncode, I decided to use [LibUSB](https://libusb.sf.net/) to help me with this project. Programming with LibUSB\nis fairly straightforward, which helps since the documentation is rather spotty. Along\nwith LibUSB, I also took the Queue class from [nicklib](/projects/) and wrote a UsbDevice class to\nhelp handle failures better. This stuff can be found in the source package above.\n\nAfter wrangling with libusb on the Windows side of things, I decided to throw out\nthat idea on the Linux client. It turns out that FTDI makes a driver for the UM245R\ncalled ftdi_sio which creates a virtual serial interface. I used this along with\nlibserial and libstatgrab to get it working.\n\nThe Linux code is rather simple and only does CPU usage. I'm planning on extending\nit to do things such as music visualization. This of course means writing some sort\nof user interface and probably using threads.\n\n### Pictures\nSome pictures of the final product:\n\n \n\n \n\n", "title": "CPU Usage Meter"}, {"url": "/projects/kegerator/", "parent": "Projects", "body": "I've been homebrewing for a couple of years now, and my least favorite part of\nthe whole process is definitely the bottling. Each 5 gallon batch has\napproximately 55 bottles that you have to clean, santize, fill, cap, clean\nagain, and put in boxes. I've gotten sick and tired of doing that for every\nbatch of beer, so I decided to make the jump and build myself a kegerator.\n\n![Kegerator mostly finished][0]\n\nBuilding a kegerator is fairly simple, only requiring some plumbing and\nwoodworking. The only hard part is the cost. Below is the cost for a\nthree-keg setup similar to my current two-keg setup.\n\n### Updates\n\n#### Feb 20, 2011\nGot the kegerator built yesterday minus a temperature controller. I got a\nlittle drill-happy and accidentally made three faucet holes instead of two.\nOops, I guess I'll have to put in that third faucet.\n\n### Links\n* [Flickr set](https://www.flickr.com/photos/nickpegg/sets/72157625971333921/)\n\n### Bill of Materials\n\n| Qty | \n\t\tCost Each | \n\t\tItem | \n\t
|---|---|---|
| 1\n\t\t | $198 | \n\t\tGE 7.0 cubic ft freezer | \n\t
| 1 | \n\t\t$90 | \n\t\t5 pound CO2 tank | \n\t
| 1 | \n\t\t$75 | \n\t\tDual gauge CO2 regulator | \n\t
| 1 | \n\t\t$47 | \n\t\t3-way CO2 distributor | \n\t
| 3 | \n\t\t$40 | \n\t\tUsed 5 gallon soda keg | \n\t
| 3 | \n\t\t$6.50 | \n\t\tBall lock gas disconnect - MFL | \n\t
| 3 | \n\t\t$6.50 | \n\t\tBall lock liquid disconnect - MFL | \n\t
| 7 | \n\t\t$1.30 | \n\t\t1/4\" barb-to-MFL connector | \n\t
| 7 | \n\t\t$0.25 | \n\t\tFlared nylon washers for MFL connections | \n\t
| 3 | \n\t\t$20 | \n\t\tStainless steel faucet shank | \n\t
| 3 | \n\t\t$2.25 | \n\t\t1/4\" barbed shank tail piece and hex nut | \n\t
| 3 | \n\t\t$0.10 | \n\t\tRubber shank washer | \n\t
| 3 | \n\t\t$31.50 | \n\t\tPerlick beer faucet | \n\t
| 3 | \n\t\t$2 | \n\t\tEconomy tap handle | \n\t
| 1 | \n\t\t$6.42 | \n\t\t12' 2x8 | \n\t
| 1 | \n\t\t$3.37 | \n\t\tRoll of weather stripping | \n\t
| 2 | \n\t\t$5.65 | \n\t\t25' roll of poly ice maker tubing | \n\t
| 14 | \n\t\t$0.65 | \n\t\t1/4\" to 1/2\" hose clamp | \n\t
| Total | \n\t\t$758.09 | \n\t\t\n\t |