failing like never before

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
27Aug/090

Maximum Cow Capacity

This sign (a sort of precursor to modern speed limits and bridge maximum carrying capacity signs) hanging over a foot bridge, located next to Greenback Lane and spanning the American River in Folsom, California (Google Maps link), has always amused me. Based upon my scant knowledge of Folsom and Sacramento, I would estimate that the sign and the bridge are about 100 years old. During those days, $25 dollars would have been considered a fairly substantial sum.

Although I have always tried to obey the speed limit (walking speed)  while crossing the bridge, I have noticed that most other cyclists pay no attention to the sign and that no one seems to be enforcing the speed limit across the bridge. Housing developments have sprung up in the area surronding the foot bridge during the past hundred years and I doubt that anyone has driven cattle across it in at least four decades. Nevertheless the sign still stands to amuse all those who happen to look up as they walk across the bridge.

And for those who can't be bothered to click on the picture and experience the slightly tacky yet cool lightbox effects, here is what it reads:

$5 FINE FOR DRIVING OVER
THIS BRIDGE FASTER THEN A WALK
$25 FOR DRIVING MORE THAN
20 HEAD OF HORSES, 50 HEAD OF CATTLE
OR 200 SHEEP, HOGS OR GOATS
OVER THIS BRIDGE AT ONE TIME

16Aug/091

Everyman Attempt 1

My first crack at the everyman schedule lasted a pitiful four days.  My failure is due mostly to my not adhering to the sleep schedule, and a terrible inability to fall asleep during the daytime. So of course, my attempt at polyphasic sleep was a total failure. Thoughout my four day experimenation period, I remained tired and rather out of sorts. I am hoping to start another attempt at polyphasic sleep starting tomorrow.

12Aug/090

Day 3 of the Everyman

3am   – 6am - (Monday, August 10)
11am – 11:20am
4pm   – 4:20pm
10pm – 10:20pm

Last night I overslept my 10pm nap until 2am. I fell asleep at 3am and then woke up to my alarm at 6am.

11Aug/090

Day 2 of the Everyman

3am   – 6am - (Monday, August 10)

Again, as mentioned in the previous day's post, I missed naps yesterday and overslept my 10pm nap and didn't wake up until 5am. However, I'll still be trying to continue the everyman. Right now, I'm still feeling a little bit tired, but all in all not bad.

Net speed: 77 WPM
Accuracy: 93%
Gross Speed: 83 WPM

11am – 11:20am

I laid in bed for about an hour but was completely unable to fall asleep. Like I said previously, I have always had difficulty falling asleep during the daytime even when I'm extremely exhausted.

I'm going to stop taking the typing tests because I'm pretty sure they reflect nothing about my reflexes and wakefulness.

4pm   – 4:20pm

Tried to fall asleep in a chair at the library but was again, entirely unsuccessful despite being very tired.

10pm – 10:20pm

I laid down before 10 and told my dad to wake me up at 10:30, which he did. Unfortunately I was unable to fall asleep in that thirty minute time span. Amusingly enough, after my dad left my room I laid in bed for a few more minutes and fell asleep, slept through my alarm (again) and didn't wake up until 2am.