Monthly Archives: September 2010

Frustrations And Broken Electronics

Nearly all the electronics in my life seem to be suffering severe bouts of entropy: Piggybacker‘s hard drive has started to fail, I accidentally stepped on and snapped off the speaker jack plugged into the front of Limited Edition, and my cellphone’s battery has started to die frighteningly quickly.

The solution for Piggybacker may be as follows:

  1. Steal Frankenstein’s CF card.
  2. Put it into Piggybacker.
  3. Install something Debian-y  on Piggybacker.
  4. Install XP on a VirtualBox VM.

I wouldn’t be able to experiment freely with native hardware using Frankenstein, but it may make using XP on Piggybacker a more pleasant experience. And I do kinda owe my brother Frankenstein’s corpse, which I’m sure he would be psyched to play with.

As for Limited Edition, I think I just have to suck it up and buy new speakers 😦 . Worst of all, I actually damaged the jack as well, and I don’t know of any way to easily fix that one. I really liked my old speakers, too, but they did have this weird ability to pick up both local radio stations and cellphone activity that somewhat diminished their awesomeness.

Oh, and my cellphone? I may go back to my ancient RAZR (still kicking!) until I can afford a new battery.

UPDATE: Trying to remove Piggybacker’s hard drive from its enclosure was entirely too difficult — I needed a tiny Frearson and an even tinier Torx — and since I didn’t have a small enough Torx screwdriver, and pliers slid right off the screw head, and even force didn’t work, I just had to try to work around it. And then I realized that unfortunately, the CF-to-IDE interface card is made for 3.5″, not 2.5″ drives… which I should have remembered. So much for that.

UPDATE #2: I ordered a 2.5″ CF-to-IDE adapter… which should arrive in late October. I’m VBoxing Crunchbang to see if Openbox would work for me. I tried 9.04.01 on VirtualBox, and I am somewhat impressed, though rather baffled by the sparseness of it. I guess I need to read up on how best to use it first.

UPDATE #3: Went back to the ancient RAZR. 😦

A Short Hiatus

This coming week I will likely not be posting at all, or only posting non coding-related posts. My few hours carved out of the week to do writing and coding for this blog have been repossessed by the rest of my life. I do apologize for the break in coverage, but I will be back next week with both barrels blazing (as it were).

*Facepalm* (Sorry About The Meme)

Well, I came to a sudden realization shortly after my post on Saturday — because ROT13 is its own solver, I didn’t need any loops at all for encoding vs. decoding ROT13, just a single function 😳 . And even more horrifying was the next realization — I didn’t even need to have two separate ROT13 programs in the first place AT ALL! Wow. That makes me feel good about myself.

So… here is the “all I ever really needed to do” update, rot13er.v1-0-1.py:

ROT13er v1.0.1

ROT13er v1.0.1

#!/usr/bin/env python

# rot13er.py v1.0.1
# ROT13er
#
# Changelog:
# v1.0.1 (09/26/2010) + Cleaned up code
# v1.0.0 (09/25/2010) + Initial release
#                     * Combines ROT13 Encoder & ROT13 Decoder
#
# Copyright 2010 Benjamin Braithwaite
#
# 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 3 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.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# imports maketrans capability & generate ROT13 translation table

from string import maketrans

rot13table = maketrans("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",\
"NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm")

# user interface and encoding magics

print "ROT13er v1.0.1"
print "Copyright 2010 by Benjamin Braithwaite"
print
print "A simple ROT13 translator"
print
toberotted = ""
while not toberotted.strip():
    toberotted = raw_input("Enter your text (ROT13 or plaintext): ")
print
print toberotted.translate(rot13table)
print

# successful exit dialog

raw_input ("Press <enter> to exit.")

You can download rot13er.v1-0-1.py from my Dropbox.

It’s the simple things that get you.

~/random001

#1: Distros!

I’m really very interested in Linux Mint Debian Edition. It seems like it could be a viable replacement for Limited Edition if I could install KDE4 rather than Gnome as my DE of choice.

I am also very excited about the upcoming release of Kubuntu 10.10 Maverick Meerkat! Yeah, I said Kubuntu — I know all the focus is on Ubuntu, but I’m really psyched that it means that soon Linux Mint 10 KDE will be here!

#2: Text Editors and GUIs

I want to learn both Vim and Emacs, since they are both giants in the hacking culture, but they are radically different one from another, and I don’t want learning the editor to get in the way of my learning to code.

Then I stumbled upon Cream, a Vim-a-like that brings a GUI and other helpful features to Vim. This is something that I am excited about because my whole life I’ve gravitated towards the GUI for pretty much everything beyond really basic operations. I mean, using the mouse and key commands in concert can be really fast most of the time, and I usually do consumption, not creation, with my computer, so a GUI just makes more sense for that.

#3: Am I The Only One?

I hear over and over again how important it is to have a mentor, or at least a partner, when you code so there is always both pressure to do better and a check to make sure you’re considering all the open options. However, since I live in Hannibal, Missouri, the opportunities for doing so are… limited.

Okay, they’re as close to nonexistent as could be.

However, Breck Yunits’ post on how to get yourself a mentor mentioned a way I didn’t think of previously — Github. His other ideas, though good, are a bit impractical for me right now, but Github seems like it may be a promising avenue for me to pursue.

#4: Linux, MP3 Players, and Me

I’ve decided to search for a replacement for my many broken MP3 players (including a 30GB iPod Video 5.5G, a 512MB iPod Shuffle 1G, a 40GB iPod 4G, and two 8GB iPod Touch 2Gs). I always mean to get rid of them on eBay, but never manage to get around to it. However, time to change!

I’m looking for a good Linux-supported alternative to iPods in terms of functionality and cheapness, and I’m going to try to get them with the money from selling all my decrepit DAPs. I’ve dallied with Rockbox in the past, so the original firmware is not necessarily a roadblock, but a good firmware would be nice anyway. Current contenders are the Cowon D2 and Sansa Fuze, but most of the players on the Xiph Portable Players page or the Rockbox Current Builds page would be alright.

if And else Are My New Best Friends

I’ve been trying to figure out how to put my ROT13 Encoder and ROT13 Decoder into a single program since I first wrote them three weeks ago. (Really? It seems much longer than that…) Anyway, I figured out how to do it with if and else, so now ROT13 Encoder and ROT13 Decoder are no more — and ROT13er has taken both their places!

ROT13er can both decode and encode ROT13, but also has the same while magic that makes sure users enter an option when required. I also found out by accident what I should have known all along — I don’t need two different translation tables like I had for the originals because ROT13 is its own decoder and encoder (e.g., A -> O -> A), so I could remove an entire expression, even though the program now does more! …which also means that having two different programs was completely redundant in the first place 🙄 . I guess experience really is the best teacher.

Anyway, here for you to peruse is rot13er.v1-0-0.py:

ROT13er v1.0.0

ROT13er v1.0.0

#!/usr/bin/env python

# rot13er.py v1.0.0
# ROT13er
#
# Changelog:
# v1.0.0 (09/25/2010) + Initial release
#                     * Combines ROT13 Encoder & ROT13 Decoder
#
# Copyright 2010 Benjamin Braithwaite
#
# 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 3 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.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# imports maketrans capability

from string import maketrans

# generate ROT13 translation table

rot13table = maketrans("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",\
"NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm")

# user interface and encoding magics

print "ROT13er v1.0.0"
print "Copyright 2010 by Benjamin Braithwaite"
print
chooser = ""
while not chooser.strip():
    chooser = raw_input("Do you want to encode into (e) or decode ROT13 (d)? [Default is encode]: ")

# if user hits <d>, do decoding magic

if chooser == "d":
    print
    toberotted = ""
    while not toberotted.strip():
        toberotted = raw_input("Enter the text you wish to encode into ROT13: ")
    print
    print toberotted.translate(rot13table)
    print

# if user hits anything other than <d>, do encoding magic

else:
    print
    tobederotted = ""
    while not tobederotted.strip():
        tobederotted = raw_input("Enter the ROT13 text you wish to decode: ")
    print
    print tobederotted.translate(rot13table)
    print

# successful exit dialog

raw_input ("Press <enter> to exit.")

You can also download rot13er.v1-0-0.py from my Dropbox.

I also updated Phonebook, which now uses while loops to make sure the user enters something when asked (like pretty much all my other programs to date). I also used the same trick as in ROT13er to make the default request a phone number if the user enters an invalid option. I present to you, O Mighty Interwebs, phonebook.v1-0-1.py:

Phonebook v1.0.1

Phonebook v1.0.1

#!/usr/bin/env python

# phonebook.py v1.0.1
# Phonebook
#
# Changelog:
# v1.0.1 (09/25/2010) + Ensures user enters data
#                     + Returns phone number by default if wrong key pressed
# v1.0.0 (09/12/2010) + Initial release
#
# Copyright 2010 Benjamin Braithwaite
#
# 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 3 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.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# dictionary database of Alice, Bob, & Cecilia's phone/addr info

peopledb = {
	"Alice": {"phone": "(555) 241-0244", "addr": "123 Happy Street"},
	"Bob": {"phone": "(555) 241-3410", "addr": "456 Cherry Avenue"},
	"Cecilia": {"phone": "(555) 813-5801", "addr": "789 Neverending Circle"}
}

# user interface 😛

print "Phonebook v1.0.1"
print "Copyright 2010 by Benjamin Braithwaite"
print
print "Sample phonebook application"
print
name = ""
while not name.strip():
	name = raw_input("Name to look up (Alice, Bob, or Cecilia): ")
print
whatinfo = ""
while not whatinfo.strip():
	whatinfo = raw_input("Do you want %s\'s phone number (p) or address (a)? [Default is phone]: " % (name))
print

# choose output based on what info user requests, if bad request assume phone

if whatinfo == "p": key = "phone"
if whatinfo == "a": key = "addr"
else: key = "phone"

# format depending on info requested

whatformat = {"addr": "address", "phone": "phone number"}

# print output requested if available, else print error message

if name in peopledb: print "%s\'s %s is %s." % (name, whatformat[key], peopledb[name][key])
else: print name + "\'s name is not in the database."
print

# successful exit dialog

raw_input ("Press <enter> to exit.")

You can also download phonebook.v1-0-1.py from my Dropbox.

I’m still working on that Morse Code translator, but I’m not sure how to split a raw_input string into individual elements, look up each element in a dictionary, replace them, then turn all the individual elements back into a string. Perhaps there is a better/simpler way, but that’s all I can think of at the moment as a potential solution, and I don’t quite know how to translate it into working Python code. *sigh* I’ll get it eventually.

What I Learned In Python This Week #4-5: Dictionaries (Conditionals, Loops, and More Next Week)

Tools I Used:

  • Geany
    • Still my favorite mini-IDE!
  • Python shell / bash shell
    • I use the Python shell to learn functions interactively, and the bash shell to execute the scripts I write (though I now use Geany’s F5 shortcut more often).

Accomplishments:

  • No new code, but cleaned up much of my old code and added some new features

Functions/Concepts I Learned:

  • Dictionaries
    • Dictionaries are pretty much what they sound like — two linked items, one being a key and the other being a value. More specifically, they are a mapping, and the only mapping type built in to Python.
    • You can use dict() to make a new dictionary from other types (strings, tuples, other dictionaries), but to make a completely new dictionary just declare it with a foo = {} type of statement.
    • Dictionary operations are much like string operations, only adapted to key/value rather than slice/item — so I won’t be giving a horrendously long and detailed list of what they actually are. It should be rather intuitive, so just look it up in the official Python documentation if you need such a list.
    • Dictionaries are awesome for string formatting — just use %(dictionary_key) for your conversion specifiers, and then use % dictionary_name to read the dictionary’s values into your string. Magic!
    • .clear() clears your dictionary of all items and returns None.
    • .copy() makes a shallow copy of your dictionary. This means values are the same in both the original and the copy, so replacing an item in the copy leaves the original alone, but modifying an item in the copy will likewise modify the original — and vice versa.
    • .fromkeys() creates a dictionary from your supplied keys, and sets the values as None.
    • .get() lets you access a nonexistent key and return None rather than crashing your program. You can also set a return value other than None if you want.
    • .has_key() is equivalent to in.
    • .items() reads a dictionary and returns a list consisting of key/value tuples. .iteritems() returns an iterator instead of a list.
    • .keys() reads a dictionary and returns a list of the keys in the dictionary. .iterkeys() returns an iterator instead.
    • .pop() returns the value of a specified key, then removes the key and its value from the dictionary.
    • .popitem() returns a random (because dictionaries don’t have any ordering at all) key/value pair and removes it from the dictionary. According to Hetland, this is a way to process key/value pairs efficiently without first retrieving a keys list.
    • .setdefault() either returns a value or, if the key/value pair doesn’t exist, it creates the key/value pair with the value set to None. You can also specify a value other than None if you want.
    • .update() updates the values of one dictionary with the values of another (if the keys are identical) or it creates new key/value pairs (if there are no corresponding keys in the dictionary you are modifying).
    • .values() reads a dictionary and returns a list of values in it. .itervalues() returns a iterator instead.
  • print can print multiple types of expressions if you separate them with a comma.
  • import can be used with as to make “aliases” of multiple functions with the same name, either by renaming the module or the specific functions. (Probably not technically correct, but that’s my mental shorthand for how it works.)

I also learned about loops and conditionals, but that’s going to be a really huge post in and of itself, so I’m saving it for next week — I’m likely going to need a while to digest what I’m learning about them, and I’d like to do some new coding (I’m working on a Morse code translator) to explore these things practically.

Honestly, I really am getting these concepts, but it’s hard to keep practicing them over and over, even with eight hours of coding a week, because that time also goes toward writing for this blog, and sometimes coding activities are preempted by some other necessity of life (stupid life!). However, even though my learning is sometimes quite protracted, this blog has really helped to keep me going forward no matter what, because I really want to write in it — if that makes any sense. Yeah, there’s only ~10 pageviews a day so far, but it’s nice to know that maybe my bumblings will help someone else.

So have an awesome weekend, all you Python coders — and good luck 😉 .

CentOS As A SOHO File Server (With A CF Hard Drive)

The Situation:

At my work (Scripture Memory Fellowship), the need for a file server has become more… pressing. We are also working to implement a VPN, which would be totally awesome for both non-office employees and off-site conventions, and would make having an always-on file server even more helpful.

Now we don’t have a VPN yet (or a file server, for that matter), but I looked around for something that would serve our needs well, and I found CentOS, which is essentially RHEL (Red Hat Enterprise Linux) without the large service support contracts that RHEL requires. So I started thinking…

The Guinea Pig:

Frankenstein has been lingering for nearly a month without an OS because the BIOS doesn’t support USB booting, and I took the optical drive out of it back in September 2009 when I made Limited Edition. However, Frankenstein would be a perfect testbed for both configuring a SOHO file server and for seeing how well a CF card works as a hard drive!

[Note: The CF card in Frankenstein is from ~2007, and CF read/write speed has since progressed significantly, especially in high-capacity cards. There were higher-speed cards available then, but I wanted one as a replacement hard drive for my old 30GB iPod Video 5.5G, so speed was not at all my primary concern in choosing a card 😛 .]

The Install:

Whipping out my trusty screwdriver, I re-transplanted my DVD drive to Frankenstein and popped in the CentOS install DVD. CentOS booted up fine, and the Anaconda installer worked beautifully all the way through. I installed both the Server and Server GUI options, and in total the install took about two hours due to the super-slow write speeds of this particular CF card 🙄 .

It takes about two minutes to boot to the desktop, which is okay — better than what I was expecting, anyway.

CentOS 5.5 on Frankenstein

CentOS 5.5 on Frankenstein

The Configuration:

[Disclaimer: This is not a setup for optimal security! I focused on getting things to work as proof-of-concept, not on making a template for a real-world server setup.]

First, I ran updates, which took pretty much half a day. Undoubtedly this would be much, much faster on a conventional hard drive, but I have time to spare 😉 . Then I installed Firefox (which for some reason was left out of the install, but still listed as the default web browser).

I set SELinux on permissive during installation, and went to System > Administration > Server Settings > Samba to set up a Samba share for the Public folder on my home folder. Basically, you just hit “Add Share”, browse to the directory you want to share, and set the options you want. In the end, you should end up with something like this:

Samba Server Configuration on Frankenstein

Samba Server Configuration on Frankenstein

Next thing is to go to Preferences > Server Settings in the Samba Server Configuration program. In the “Basic” tab, change the workgroup name to whatever workgroup you want your Samba shares to be a part of. Then in the “Security” tab make authentication mode “Share”, so you don’t have to enter a password to access your Samba share in Windows.

Now when you do try to access a file on a /home-based Samba share (in my case, /home/bgbraithwaite/Public), SELinux will yell at you, so do some CLI magic to allow this behavior (not necessary for SELinux in permissive mode, but it keeps you from drowning in error messages):

setsebool -P samba_enable_home_dirs=1

And you should be ready to start sharing right away!

The Testing:

Well, you see the pictures? I uploaded them from the Samba share 😉 .

The Verdict:

CentOS certainly works well as a simple Samba file server. In the future, I hope to test CentOS’s capabilities in other areas (like using it as a web server for OpenAtrium, or possibly as a mail server), but getting a working Samba file server was the priority in this test.

The uber-slow installation, updates, program launching, etc. could have been greatly speeded up if I would have chosen ext2 as the filesystem with the noatime attribute set (why I didn’t do that the first time, I don’t know). I will probably use ext2 exclusively on Frankenstein now, because the constant disk access on a slow CF card is painful to behold. I’m not really worried about wear, I just don’t want to sit so long waiting for nothing to happen.

As for security, I doubtless need more stringent settings, but I’ll figure that out later. SELinux seems to be a powerful tool for configuring and maintaining a secure box, and I will no doubt learn the ins and outs of it when I set up the real thing.

So, is CentOS really the best distro for a SOHO file server? The answer is probably no, with qualifications. CentOS’s focus on enterprise use means that it could certainly scale with a business as it grows, but it also means a certain amount of technical know-how is necessary to set it up properly, and for many smaller businesses with no homegrown techies, CentOS may be too difficult to set up. This is not to say that CentOS is difficult to set up — because it certainly wasn’t — but most people seem to have an irrational fear of all things tech, and lose all higher cognitive function when they interact with it. An unfortunate fact of life, that.

For our purposes, though, CentOS seems very crisp and professional. The whole experience was quite pleasant and easy to understand (at least for me, a professional end-user), and no doubt the child of RHEL will be on our server… whenever we get around to building one 🙄 .

UPDATE: Name our new server!