27 Jul 2017 code

I ❤ Weechat. It's my IRC client of choice. But I also use it for gtalk and Slack. All my conversations in one convenient interface. Even better, I run it in a remote tmux session so I can pick up wherever I left off from anywhere.

The only annoying thing about this setup was the lack of real notifications for private messages or mentions. So I wrote Weelisten.


Weelisten is a small python script that leverages Weechat's relay protocol, python 3 asyncio and libnotify so I can get awesome native notifications on my desktop.

Sounds useful? Get it on Github

26 Jul 2017 other

There's a lot of talk on the web about the dangers of always on technology and addictive social media. I'm here to give you a life pro tip.

Turn off mobile data.

You'll have wireless in most places anyway, but not being connected outside of wifi means less distractions on walks, at dinner, or in the movies. You can still turn on data if you really need it, but the barrier is high enough that you're unlikely to use it to get a quick hit of reddit.

I started doing this when AT&T made me give up my trusty nokia dumb phone and I got a smart phone. Seems to work great.

29 May 2017 Backpacking

'Manzana Trail'

Labor day weekend, the official start of summer. Time to bust out that barbecue, unfurl that tent! While many people in America are celebrating the beginning of the outdoor season, some of us are squeezing in our last few adventures before the end of it. While not technically closed during the summer the Los Padres National Forest back country it not a place you generally want to be in the middle of July. Water is scarce to non-existent, temperatures hang around the triple digits and as someone once said: "the ground itself becomes a furnace".

So when the forecast for the weekend showed mid 70s temperatures and even some cloud cover, Andrea and I took the opportunity to head out to the San Rafael Wilderness to give a few nights backpacking and a walk on the infamous Hurricane Deck a shot.

'Sandstone Formations'

After a 1 1/2 hour drive from Goleta we arrived at Nira Campground around 4:30 on Friday. From herethe trail crosses the Manzana and within the first 100 feet we behold a beautiful site: water! And lots of it. Not just a stagnant trickle that you are happy to be able to filter to drink, but an actual decent flowing water; enough to swim in.

The trail meanders along and occasionally across the Manzana, through some choice campsites and up and down a few cliffs. The surrounding terrain was riparian/chaparral with the occasional pine tree standing proudly above the oaks. The smell of sage was strong in the clear air adrift with the sounds of Canyon Wrens and the excited chattering of the creek itself. The trail at this point is very well trodden and clear and at the time of this writing had recently undergone some maintenance.

'Water Pools'

Shortly after passing Ray Camp the trail turns gently north and begins to climb a narrow valley. Here the creek makes the best use of elevation and treats you to waterfalls, pools, and fairy ponds. If you like to swim, this is your jam.

We reached our destination, Manzana Narrows just as dark was settling in. Here we unloaded our 5 pound burritos and engulfed them immediately. Our bellies content and our minds excited for the next day, we made our rest.

The next morning we awoke somewhat (but welcomely) late (thank you high canyon walls!) After some coffee and oatmeal we were off up the trail once again.

'Crazy Formations'

Almost immediately we were hit by a series of steep switchbacks out of the river canyon that made us grateful that the sun was not yet too strong at this time of day. At this point terrain changes rapidly: the riparian surroundings are completely replaced by foxtail meadows punctuated by the occasional oak tree. The sky here is is big, blue and wide: very few trees remain due to the Zaca fire which leveled the area in 2007. We crossed tiny tributaries lush with wildflowers and tadpoles and discovered a (secret) campsite complete with a running spring and a bedrock mortar.

The area's most stunning feature however has to be the massive sandstone outcroppings and cliffs which ripple, bugle and pierce the landscape. They are pockmarked with holes and harbor caves large enough to sleep in. The textures of the rock vary between smooth gold sandstone to geometric reptilian patterns. One particular boulder looked like a stack of pancakes.

Eventually we made it to White Ledge Camp where we took a refreshing swim in one of the sandstone pools and refilled our water. We took a left and headed up Hurricane Deck. Here is where the second half of our journey began.

'My Back'

I've heard all the mythos surrounding Hurricane Deck: how it is overgrown, steep, exposed and full of rattlesnakes. So we were OK with the fact that we might not have the greatest time. The trail started out pretty faint and right away we lost it twice and had to backtrack. Not a confidence inspiring start. However, once you reach the edge of the deck (sort of like a ridge) it becomes nearly impossible to get lost. That doesn't mean the trail is any easier, though. The chaparral get so thick in places we had to crouch down and push through with our arms and legs, un-snagging our packs and protecting our eyes from swinging twigs.

When the Deck opened up however, it was truly worth it. The 360° views of the San Rafael Wilderness were fantastic. A cool breeze drifted along the top gently buffeting wildflowers and butterflies. Most surprisingly: no rattlesnakes!

After five miles of pushing through Hurricane Deck we came to Lost Canyon trail which also shared the name of our camp for the night. At this point we had already hiked about 11 miles and were beginning to feel it. With just 4 miles to camp we began down the Lost Canyon trail, which is actually an old roadbed so quite wide in places, though severely overgrown so you wouldn't notice. We made one stop at Vulture Springs, most likely aptly named due to the fact that it is barely a trickle.

'Some Water'

Lost Canyon Trail is can be quite discouraging. Because it is an old roadbed the grade is maddeningly flat. This coupled with the fact that it has several quarter to half mile long switchbacks mean that oftentimes during the descent I could see just twenty to thirty feet below me the trail which I wouldn't reach for another twenty to thirty minutes. If the trail had been constructed for hikers instead of cars, it would probably be a quarter of the length.

Eventually we did make it to the bottom of the long Lost Canyon Road to Lost Canyon Camp. What we found was a dry overgrown camp with a single spot. Not exactly what we were hoping for after a 15 mile epic day! But probably what we should have expected.

Andrea made the executive decision that since we had hiked so much already anyway, we may as well make the last 4 miles back to Manzana Creek. My feet hurting, I followed. From here the trail follows Lost Canyon creek, which was dry until about a mile below-stream from camp. We talked about ice cream, fantasy novels, and whatever we could to keep our minds off our feet and legs going into our 19th mile of the day.

Eventually we made it back to Manzana Creek just as dark was settling. Luckily there was an open space at the other Lost Canyon Camp, the one at the bottom of the trail. Exhausted, we collapsed on to the bench.

'Some Water'

The irony is were only a mile from the car at Nira camp at this point. But since we had carried our packs all day, we were going to spend the night, dammit!

The next day we woke up late and lounged around camp for a few hours, then made the short trip back to Nira.

This loop is fantastic in a lot of ways. Hurricane Deck is unforgettable, Manzana Creek is unbeatable. Lost Canyon Trail not so much. But you could do this same loop in a smarter way we did, in more days and it would probably be one of the best backpacking routes around. I would recommend skipping the 19 mile day.

We'll be back next spring!

19 May 2017 code

If you are using rate limiting with Django Rest Framework you probably already know that it provides some pretty simple methods for setting global rate limits using DEFAULT_THROTTLE_RATES. You can also set rate limits for specific views using the throttle_classes property on class-based views or the @throttle_classes decorator for function based views.

What if you are using ViewSets but want different throttling rules to apply to different actions? Unfortunately DRF provides no official method of doing this. Luckily we can accomplish this functionality without too much fuss.

The solution comes from combining the ScopedRateThrottle throttle class with the get_throttles() method of APIView.

In our ViewSet let's override the get_throttles() method:

    class FooViewSet(viewsets.ModelViewSet):
        queryset = Foo.objects.all()
        serializer_class = FooSerializer

        def get_throttles(self):
            if self.action in ['delete', 'validate']:
                self.throttle_scope = 'foo.' + self.action
            return super().get_throttles()

        def validate(self, request):
            return Response('Validation!')

What we are doing here is pretty simple: checking to see if the action being performed is one we want to throttle , and if so, setting the throttle_scope property on the ViewSet.

This alone won't do anything (in fact it will error) so let's add the necessary config to settings.py to make it work:

            'user': '5000/day',
            'foo.delete': '100/day',
            'foo.validate': '10000/day'

The magic is contained within the ScopedRateThrottle. This class will look for the throttle_scope property on the view, and if found, look up a corresponding key in the DEFAULT_THROTTLE_RATES dictionary.

Notice that the keys are namespaced with .foo. This isn't necessary, but if you're using more than one ViewSet and you don't want the rules to apply to all of them, you should namespace them.

There you have it, throttling for ViewSets.

27 Feb 2017 code


I host quite a few sideprojects on my VPS. They range from static Jekyll sites (like this one) to large web applications. There's even some wordpress hiding in a corner, disgraced and neglected.

Despite the fact that none of these sites are actually useful for anything, they still need some poor bastard to keep then running. Over the years I've collected quite the assortment of nginx, uwsgi, php, apache, supervisor, and other configs. All of them written at various levels of understanding, none of them tracked anywhere, all of them confusing and terrible.

Docker to the rescue

One of the most under-spoken benefits of using docker is that a Dockerfile is literally a document describing how to get your garbage apps up and running. Ever forget a system dependency for some niche third part library? Have junky code that only runs with old versions of programming languages? It is nearly impossible to remember the myriad of caveats that come with deploying software.

If you're like me, and you don't write a ton of documentation, these are the kinds of things that can really bite you in the ass in the future when you have to modify or redeploy something.

Dockerizing your stuff is an excellent way of documenting what it actually takes to get something running. Plus you get all the other benefits of containerizing your apps, but there is nothing I can say here that hasn't been said before about that.

I've gone all in. I'm even using a jekyll docker image to generate this site now. As the only ruby application I ever actually use, I always forget the gems and other dependencies I need in order to run it - no longer.

It's all just a container away.

18 Nov 2016 code

This one got me for a bit. If you are using django-bootstrap3 and also want to use it's handy bootstrap_pagination template tag for generating pagination links, you may be in for an unplesant surprise if your view uses any GET parameters. While the django-bootstrap-pagination project handles this by default, django-bootstrap3 will not persist GET paramters between pages.

The key to using the bootstrap_pagination tag is the extra argument, which takes a string and appends it to each page. If you have the request_context context processor installed, you can pass in this string using the QueryDict urlencode() method. For example:

{% bootstrap_pagination page_obj extra=request.GET.urlencode %}

Voila. Pagination in django with bootstrap working as it should.

11 May 2016 astronomy, cycling

LCOGT has participated in this year's Cyclemaynia event in the best way we know how: by geeking out over both cycling and astronomy at the same time.

I thought it would be neat to do a scale model of the solar system that people could ride in order to experience in order to gain a deeper appreciation of how vast the solar system really is.


I was inspired by a model at Anza Borrego State Park which had 3-dimensional models of the planets along a dirt path in the desert. To do it our way we settled on using chalk to draw the planets along the Obern Trail. This is a popular carless path that helps link Santa Barbara to Goleta and sees pretty heavy traffic during rush hour.

We decided to place the Sun at the start of the path at Modoc rd and Neptune about 8 miles away at LCOGT's headquarters in Goleta, CA. Using this as the scale, we ended up with a ratio of about 0.245mi/AU


We decided to use a different scale for the size of the planets (otherwise they would be very, very tiny) and gave Jupiter a radius of 3 feet, or about 13x10-9 it's actual size. At this scale Mercury's radius was only 1.2 inches.

Trader Joes generously volunteered 2 chalk artists and on Monday the planets were drawn.

Thanks to everyone's support, this project was a success. See you on the trail!


09 May 2016 other

The first thing I noticed when I moved to Santa Barbara and started going outdoors was that everything just seemed a little more hostile than what I was used to. There are the ever present threats of overwhelming heat, lack of water, exposure and poison oak. By now, I've come to know some of the more subtle actors as well.

One of them I met today: Pitchfork Weed aka Bidens frondosa or, the Devil's Beggarticks, Devil's Pitchfork, Tickseed Sunflower... Would you believe it is closely related to the lovely sunflower? Neither would I, the family resemblance is illusive. Trust me, you don't want to run through a field of these, and their seeds are not pleasant.

Pitchfork Weed

I was walking down from the top of Tangerine Falls feeling pretty good about the stupid scramble I had just survived (despite a sprained wrist) when I felt a peculiar sensation on my legs. When I looked down and saw that they were covered, absolutely trashed, by tons of tiny pitchfork looking things. And they did not want to let go.

Pitchfork Pants

That's what pants are for I guess, so no harm no foul. I was still in a better situation than the dudes trying to scale the right side of the falls. I could hear their nervous laughter from a mile away. And then they stopped laughing, started yelling. Eventually they did make it out of sight - hope they made it!


13 Nov 2015 code

So I really like code linters. My coworkers know this. Actually, I got called a syntax Nazi today by a fellow developer. I'm OK with that. I believe in readability and consistency.

In my projects I make it impossible to make a git commit before the source code passes a flake8 check. How to perform this minor miracle you ask? With a simple git pre-commit hook:


flake8 .

When I commit, the hook executes. Since git knows a return of anything besides 0 means abort, it stops the commit from happening. Awesome.

Here is a terminal recording of it in action:

Don't forget to make your pre-commit hook file executable!

09 Oct 2015 code

Recently I started a new Django project, and this time I decided to go all in on Docker. No virtualenvs, no local databases - containers all the way.

There are about a million and ten articles about how to dockerize webapps by now. However, none of them seem to address one simple fact: we don't simply want to dockerize our applications, we want to develop them too!

sane-django-docker contains a sample django project webapp as well as the necessary config files to run both a development and production server.

Continue Reading...