failing like never before

27Sep/090

Group Cycling

I went on my first group ride yesterday morning with the school cycling club. It was a bit depressing showing up at the meeting location with my toe clips, friction shifters, and 1989 Miyata, when everyone else present was sporting expensive carbon fiber and aluminum racing bikes with stiff racing shoes, but I ended up keeping up passably well, at least for the first half; I ended up falling behind the pack on the return trip since I wasn't really used to pumping out 20 MPH for three hours.

I had some trouble riding together in such a close pack. Its a little scary to ride a foot behind someone's wheel at 20 MPH, and my rather poor bike handling certainly didn't lend me any confidence. Towards the middle of the ride I started getting more comfortable with riding in a tight group, especially when I started to feel the burn in my thighs (drafting does make life a little easier).

My Miyata Alumicross was most definitely not made for racing, a fact which became very apparent on hills. On long descents when everyone ducked down into a tuck, the air resistance generated by my knobby cyclocross tires resulted in me slowly drifting more and more towards the back of the group, despite the fact that I practically had my nose on level with my headset. And on very small descents, when the group shifted into their smallest sprockets and started pedaling with speed, I was doing 120+ RPMs in my smallest sprocket, struggling to keep up.

Nevertheless, I found it to be a highly enjoyable ride, and I will definitely be going out for more group rides in the future.

Filed under: Out Doors No Comments
11Sep/094

Python Animated Progress Bar

I wanted to be able to have an animated progress bar to be displayed in a terminal for my current Python project. There are already various implementations on the Internet of something like what I wanted, but I couldn't find one that was animated. So for the sake of practice, I decided to write my own. In order to be able to have the bar animated, and still allow the program to get other work done, I had to create a seperate thread to manage the status bar.

Code for the bar, (and also sample code to create a demo) are below.

import time
import sys
import os
import threading

"""
Display an animated statusbar, with progress and percentage
( items-completed/items-total )
displayed below the statusbar. Seperate thread is used to
display the spinning "icon." In order to stop the statusbar thread
early, calling thread can use join() 

example output created by StatusBar thread:

[===============\--------------]
30/60  50%

Written by chi (aka chi42) from 42gems.com-- 11 Sept, 2009

Copyright (C) 2009 chi (from 42gems.com)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

Please see http://www.gnu.org/licenses/ for a copy of the license.
"""

class StatusBar(threading.Thread):

    # class variables:
    # max:  number of total items to be completed
    # pos:  number of completed items
    # inc:  amount of items to increment completed 'pos' by
    #           (shared resource)
    # comp: amount of '=' to display in the progress bar
    # running: whether or not the statusbar is running
    def __init__(self, pos=0, max=100):
        threading.Thread.__init__(self)
        self.pos = pos
        self.max = max
        self.busy_char = '|'
        self.running = 0
        self.inc =  0
        self.__getsize()
        self.comp = int(float(self.pos) / self.max * self.columns)
        self.inc_lock = threading.Lock() 

    # find number of columns in terminal
    def __getsize(self):
        rows, columns = os.popen('stty size', 'r').read().split()
        if int(columns) > 80:
            self.columns = 80 - 2
        else:
            self.columns = int(columns) - 2
        return

    # redraw progress bar and all numerial values
    def __print(self):
        self.__getsize()

        sys.stdout.write('\x1b[1G')
        sys.stdout.write('[' + '=' * self.comp + self.busy_char + \
            '-'*(self.columns - self.comp - 1) + ']'   )
        sys.stdout.write('\n\x1b[0K' + str(self.pos) + \
            '/' + str(self.max) + '\t' + \
            str( round(float(self.pos) / self.max * 100, 2)) + '%')
        sys.stdout.write('\x1b[1A\x1b[' + \
            str(self.comp + 2) + 'G')
        sys.stdout.flush()
        return

    # run the thread
    def run(self):
        global busy_chars, inteval
        busy_chars = ['|','/','-','\\']
        interval = 0.3

        self.running = 1 

        self.__print()
        while 1:
            # loop and display the busy spinning icon
            for c in busy_chars:
                self.busy_char = c
                sys.stdout.write(c + '\x1b[1D')
                sys.stdout.flush()
                time.sleep(interval)

                self.inc_lock.acquire()
                if self.inc:
                    if (self.pos + self.inc) >= self.max:
                        self.inc_lock.release()
                        self.pos = self.max
                        self.comp = self.columns
                        self.busy_char = ''
                        self.__print()
                        sys.stdout.write('\n\n')
                        self.running = 0
                        return 0
                    else:
                        self.pos += self.inc
                        self.inc = 0
                        self.inc_lock.release()
                        self.comp = int(float(self.pos) / self.max \
                            * self.columns)
                        self.__print()
                else:
                    self.inc_lock.release()
        return 1

    # increment number of completed items used by calling thread
    def increment(self):
        if self.running:
            self.inc_lock.acquire()
            self.inc += 1
            self.inc_lock.release()
            return 0
        else:
            return 1

Annnd the demo code:

#!/usr/bin/python

import statusbar
import time
import os

print '\n'

min, max = 0, 80
inc_sleep = 3 

bar = statusbar.StatusBar(min, max)

rows, columns = os.popen('stty size', 'r').read().split()
print 'columns in screen: ', columns 

bar.start()
while 1:
    time.sleep(inc_sleep)
    if bar.increment():
        break
print 'done!'
9Sep/0929

Miyata Alumicross

I got a 1989 Miyata Alumicross earlier this summer and have managed to put a few hundred miles on it so far. We bought it from the previous owner for $200 who apparently had the bike sitting in storage for almost the past two decades, so its in surprisngly good condition despite its age. Almost all of the components on the bike are original, except for the saddle, bar tape, and toe clips (all of which I replaced myself).

Here's a description of the bike:

  • 58cm, weighing approx. 24 lbs.
  • Aluminum main tubes, APA-bonded 3-lug construction
  • Suntour XCD-6000 deraileurs
  • Suntour Accushift Bar Con shifters (front shifter is friction, rear is index/friction)
  • Suntour cantilever brakes
  • Suntour XCD-6000 CW-XD00 cycloid triple crankset (48, 38, 28)
  • CrMo fork
  • Wolber GTx 700C rims
  • IRC cross-country 35mm tires
  • Suntour 6-speed freewheel (13, 15, 17, 20, 24, 28)
  • Sansin sealed hub
  • air-bottle basement (braze-on for CO2 cartridge)
  • Interior back-brake cable thru top tube
  • Steel pedals with strapless toe clips
  • SR Sakae custom Modolo patent (Anatomic bend) handlebars

The Alumicross was apparently Miyata's top "cross" bike at the time of its production. I'm not quite sure if Miyata designed the Alumicross with cyclocross specifically in mind, or if its just a hybrid type bike. Nevertheless, its a good ride, and is light and speedy despite its thicker tires and heavier then normal frame, while still being well suited for cyclocross rides. Its also a good bike for riding around town and doing some recreational riding, and I suspect that it would do quite well at loaded touring since it seems to have all the threaded holes for attaching additional racks and panniers. The low gear gearing and wide gear ratios makes the Alumicross great for long, steep hill climbs while carrying lots of additional weight, but they also mean that the Alumicross is ill suited for high-speed road races.

2Sep/090

Word of the Day…

I learned a new word today, and its possibly my most favorite word ever, beating out "doughty" (which I learned from reading The Lord of the Rings in middle school). And the word of the day is:

defenestration.

Defenestration is defined as being the act of throwing someone or something out of a window. I was not hitherto aware a word such such as defenestration existed, and am quite frankly astounded that a word was created to describe such an action.

I picked up the word today while watching an old episode of Dark Angel online.

Filed under: Random Stuff No Comments
1Sep/090

Gmail Down Time Again…

So Gmail is down again and has been for at least thiry minutes, attempts to access the webpage results in a 502 error. I disallowed IMAP and POP forwarding on my account so I have no way of knowing if IMAP and POP are still accessible, but I am inclined to assume that they're not. Gmail outages while rare, are not unheard of, and I have always ridden out the down times without too much complaining. But Google's mail software is now officially out of beta, and it is not acceptable for a production-ready product to be having these kinds of outages. I may just have to create a 42gems.com e-mail and use that instead of my gmail account as my primary e-mail address.

Filed under: Software No Comments