Cookie Notice

As far as I know, and as far as I remember, nothing in this page does anything with Cookies.

2010/08/30

My Facebook Status Solution

You might remember me posting how to post status updates to Buzz, albeit via Perl. I mentioned how I wanted to do the same or similar with Facebook. I got nice suggestions of how to handle it via WWW::Facebook::API, and I tried to wrestle with Facebook's OAuth or similar implementation to get the access I need to do what I want. And then I figured out another way.

#!/usr/bin/perl

# usage: echo big long string of text | facebook.pl

# returns "big long string of text"

use 5.010 ;
use strict ;
use warnings ;
use Carp ;
use Data::Dumper ;
use Net::SMTP::TLS ;
use Getopt::Long ;
use IO::Interactive qw{ interactive } ;
use subs qw{ send_mail get_credentials } ;

my $status = join ' ', @ARGV ;
if ( length $status < 1 ) {
    while (  ) {
        $status .= $_ ;
        }
    chomp $status ;
    }

my $identity = 'MY_IDENTITY_STRING' ;
my @to ;
push @to, 'GETYOUROWNSPECIALEMAILFROM@m.facebook.com' ;
my $body = $status ;

my %msg ;
$msg{ body }    = $body ;
$msg{ to }      = \@to ;
$msg{ cc }      = \@cc ;

say send_mail %msg ;

exit ;

sub get_credentials {

    #this is the point where my setup sucks
    my %creds ;
    my $config = '/home/jacoby/.smtp_identities' ;
    if ( open my $fh, '<', $config ) {
        while ( <$fh> ) {
            my $line = $_ ;
            chomp $line ;
            $line = ( split m{\#}mx )[ 0 ] ;
            next if length $line < 1 ;
            $line =~ s{\s}{}gmx ;
            my @line = split m{,}mx, $line ;
            next if $line[ 0 ] ne $identity ;
            $creds{ from }     = $line[ 1 ] ;
            $creds{ server }   = $line[ 2 ] ;
            $creds{ username } = $line[ 3 ] ;
            $creds{ password } = $line[ 4 ] ;
            }
        close $fh ;
        }
    if ( defined $creds{ username } ) {
        return %creds ;
        }
    say 'No identity chosen' ;
    exit 1 ;

    }

sub send_mail {
    my %msg     = @_ ;
    my %creds   = get_credentials ;
    my $body    = $msg{ body } ;
    my $to      = $msg{ to } ;
    my @to      = @$to ;
    my $mailer = new Net::SMTP::TLS( $creds{ server },
                                     Hello    => $creds{ server },
                                     Port     => 587,
                                     User     => $creds{ username },
                                     Password => $creds{ password }, ) or croak $!;
    $mailer->mail( $creds{ from } ) ;
    $mailer->to( @to ) ;
    $mailer->data ;
    $mailer->datasend( 'Subject: ' . $body . "\n" ) ;
    $mailer->datasend( 'From: ' . $creds{ from } . "\n" ) ;
    $mailer->datasend( 'To: ' . ( join ',', @to ) . "\n" ) ;
    $mailer->datasend( "\n" ) ;
    $mailer->datasend( '' ) ;
    $mailer->dataend ;
    $mailer->quit ;
    return $msg{ body } ;
    }

I already had it, so I just had to modify it slightly, but it came to me. You can set status and upload images via email. I just hand to double-check the right way — statuses in subject, not body — and came right up.

get_credentials is my method for not hard-coding information into the code, and here I do exactly that for the $to email and the $identity string.

I could see using the big and scary Facebook API if I wanted to code up the next Farmville. I know my wife wants me to do that. But for this small purpose, there's little need to go through all that.

2010/08/27

I Have Brilliant Friends

Take overclocking. You have a processor, and if you tell it to run at 1.5x the given clock speed, you get 1.5 the performance. And a gob of heat. Which you then get a better heat sink to take care of.

Let's consider the opposite. You're there, you're doing work, but your workspace is too frakin' hot! What's your alternative? Underclocking. But don't you have to poke at the BIOS for that? Maybe mobo jumpers? Certainly reboot?

Maybe not.

PC World has an article on a software tool to handle just that situation, turning down the CPU speed when the server room heat becomes too much. (Yeah, it's a server thing. It isn't something that makes too much sense unless you have huge rooms full of servers, each full of long-running jobs.)

And I was in a Linux User Group with both guys in the article. So cool.

A Squeeze of Python to give me a Buzz

I've been learning Python.

I know, I know....

It starts with Google Buzz. I accept web pages and window apps as the only choices to see social media output from places like Identica, Twitter, Facebook, etc. But my preference is to type things on the command line for most of my content-generating needs. If I wanted to send the same thought to most of my microblogging sites, I just pipe it together.

echo My oh-so-crucial thought | twitter.pl | identi.pl | wiki.pl

So far, two things have been standing in my way. Facebook and Google Buzz. I have yet to find ways to use my beloved Perl to write to either. But I poked around and found some sample code on the Google Buzz API page. Specifically, I found make_post.py, which does write to Buzz, but it will not easily integrate to my preferred way. Specifically, it takes in your key and secret as command-line flags and accepts your Buzz update via STDIN. If that's how you roll, that's fine, but for me, the message is join ' ' , @ARGV . So, I recoded it, taking more out than I put in, and using some of my very slight knowledge of Python, to make this. I have the key and secret hard-coded, which is kinda acceptable for personal use but still not to be accepted. You should use the make_post.py that comes with buzz-python-client to set up your OAuth if you use this, because anything that would do that has been brutally ripped from the original code.

Expect Perl code based on this to come around eventually. For now, enjoy buzz-python-client and my addition.

# Copyright 2010 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import sys
import traceback
import getopt

#
# Load Buzz library (if available...)
#

try:
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import buzz
except ImportError:
print 'Error importing Buzz library!!!'

token = verification_code = buzz_client = ''

#
# Function to obtain login data
#

def GetLoginData():
'Obtains login information from either the command line or by querying the user'

global token, verification_code, buzz_client
key = 'KEYKEYKEYKEYKEYKEYKEYKEYKEYKEYKEYKEYKEY'
secret = 'SECRETSECRETSECRETSECRETSECRETSECRET'
buzz_client.build_oauth_access_token(key, secret)

#
# Main program starts here
#

try:
buzz_client = buzz.Client()
buzz_client.oauth_scopes=[buzz.FULL_ACCESS_SCOPE]
buzz_client.use_anonymous_oauth_consumer()
GetLoginData()
args = sys.argv
del args[0]
message = ' '.join(args)
message = message.strip()
post = buzz.Post(content=message)
buzz_client.create_post(post)
print message
except:
print '\nBzzzz! Something broke!!!'
print '-' * 50
traceback.print_exc()
print '-' * 50

2010/08/26

Quick Google Bookmarks Tutorial/Reminder

This is a question that came up on one of the new StackExchange betas, WebApps.
There appears to be two distinct sets of bookmarks maintained by Google. If you visit Google Notebook or Google Bookmarks you get one set. And if you sync Chrome accounts you get another. My question is: how can I get one set of bookmarks maintained on Google's web apps and through Chrome? I want to be able to access the bookmarks I have synced with Chrome from a web app when I'm using a public computer.
I answered it, but I'll hit the topic here, because I can.


This is Google Bookmarks. It seemed to be a response to Delicious, which turns the need for persistent and distributed bookmarks into a social media application. It wasn't imagined to be part of the browser. This was before Chrome was started, or at least before it was far along.

It was also before Google Docs was far along, because rather than working with Google Bookmarks, Google Chrome decided to work with Google Docs for bookmark storage. There's a folder under My Folders marked Google Chrome, which is where it stores your bookmarks.


So, guy on StackExchange, you CAN use a web app to access your bookmarks. It's just which one that's the question. And, for all the things you can say about Chrome, this feature, the easy integration of bookmarks syncing across platforms, is the one that sold me on Chrome. If all your bookmarks are in Google Bookmarks, it's dead easy to export them and import them into via your Bookmarks Manager.

Now, how do I sync bookmarks with a mobile Opera browser?

2010/08/24

Overdue Book Review: Higher Order Perl

Ever promise to do something and not remember it?

That's kinda how it is here. I thought I was being given a copy of Higher Order Perl, while not understanding or promptly forgetting that I had incurred the responsibility of writing a review. Which is now way late, after far better reviews have already been writtten, and now that you can freely download it from the author's website.

I'll start by giving you the takeaway: Right now, there are two books that a Perl programmer should have and should read and should integrate into their coding style. The first is Perl Best Practices by Damian Conway, and this is there to raise the minimum level of your programs. If you want your code to be readable and reusable, read this book and get it to this level. The other is Higher Order Perl. This is because, while you may be leveraging the Awesome Power of Perl, you don't know the half of it. Mark Jason Dominus knows, and this book tells you.

I first learned about MJD when years ago I was going to defend Perl to my Linux User Group. One of my defense points was from MJD, who said of Norvig's seven features that make Lisp different, Perl shares six. Not that I really used it like that. I saw the bit about fibonacci sequences that shows up here in page 33, coded my own iterative and recursive implementations, became convinced that yes, I see the problem here, and wrote my version that used a hash or array to fix it. I didn't hit the Memoize part, which is where the awesome power comes in.

I knew there was awesome power there for a long time. I just failed to learn about it, because it was beyond what I needed at the time. Until, of course, it became part of what I needed. I needed it because I was creating a stack of horrible copy-and-paste code that really needed a dispatch table. I needed it because I needed a better and more adaptable filesystem spider than I had.

I am, for the first time, going chapter-by-chapter through Higher Order Perl and I like to think that my code will be better for it. I know two programs that's better for it.

Douglas Crockford talking about Javascript: The Good parts


Javascript - The Good parts on O'Reilly.

2010/08/23

Think Globally, Play With Hashes Locally

Reading a bit from Effective Perl Programming, I found out that Perl 5.12 supports deleting an element in a hash in a local scope. I was looking up from Higher Order Perl for a moment, so you might guess that my thoughts went to manipulating dispatch tables.



my %subs = ( do => sub { return 'c' },
rey => sub { return 'd' },
mi => sub { return 'e' },
fa => sub { return 'f' },
so => sub { return 'g' },
la => sub { return 'a' },
ti => sub { return 'b' }, ) ;

my @notes = qw( do rey mi fa so la ti do rum fmep agog ) ;

{
delete local $subs{ ti } ;
say '=' x 20 ;
for my $note ( @notes ) {
if ( $subs{ $note } ) {
my $sub = $subs{ $note } ;
say join "\t", '', $note, &$sub ;
}
}
}

say '-' x 20 ;
for my $note ( @notes ) {
if ( $subs{ $note } ) {
my $sub = $subs{ $note } ;
say join "\t", '', $note, &$sub ;
}
}

====================
do c
rey d
mi e
fa f
so g
la a
do c
--------------------
do c
rey d
mi e
fa f
so g
la a
do c

Yeah, I'm still on 5.10. But that made me think.
Can you add to a hash only in the local scope?

my %subs = ( do => sub { return 'c' },
rey => sub { return 'd' },
mi => sub { return 'e' },
fa => sub { return 'f' },
so => sub { return 'g' },
la => sub { return 'a' },
ti => sub { return 'b' }, ) ;

my @notes = qw( do rey mi fa so la ti do rum fmep agog ) ;

{
local $subs{ rum } = sub { return 'one' } ;
say '=' x 20 ;
for my $note ( @notes ) {
if ( $subs{ $note } ) {
my $sub = $subs{ $note } ;
say join "\t", '', $note, &$sub ;
}
}
}

say '-' x 20 ;
for my $note ( @notes ) {
if ( $subs{ $note } ) {
my $sub = $subs{ $note } ;
say join "\t", '', $note, &$sub ;
}
}

====================
do c
rey d
mi e
fa f
so g
la a
ti b
do c
rum one
--------------------
do c
rey d
mi e
fa f
so g
la a
ti b
do c


Yeah, I'm still on 5.10. But that made me think.
And you might guess that it's a foregone conclusion that you can modify a hash element locally.



my %subs = ( do => sub { return 'c' },
rey => sub { return 'd' },
mi => sub { return 'e' },
fa => sub { return 'f' },
so => sub { return 'g' },
la => sub { return 'a' },
ti => sub { return 'b' }, ) ;

my @notes = qw( do rey mi fa so la ti do rum fmep agog ) ;

{
#delete local $subs{ ti } ;
#local $subs{ rum } = sub { return 'one' } ;
local $subs{ ti } = sub { return 'FMEP' } ;
say '=' x 20 ;
for my $note ( @notes ) {
if ( $subs{ $note } ) {
my $sub = $subs{ $note } ;
say join "\t", '', $note, &$sub ;
}
}
}

say '-' x 20 ;
for my $note ( @notes ) {
if ( $subs{ $note } ) {
my $sub = $subs{ $note } ;
say join "\t", '', $note, &$sub ;
}
}

====================
do c
rey d
mi e
fa f
so g
la a
ti FMEP
do c
--------------------
do c
rey d
mi e
fa f
so g
la a
ti b
do c

The more I play with dispatch tables, the more I imagine practical uses of this. I love cool stuff!

The Community is Solving My Problems!

The Stack Exchange Crew is pushing a few domain-specific Stack sites for beta-testing. The one I've been most involved in is the Ubuntu one. I had two specific problems which I think I have complained about there. The first is how, for no reason I could identify, I would lose the ability to view the contents of my ~ folder. The other is that I used to be able to connect my netbook's LINE OUT to my desktop's LINE IN and get both audio streams in one set of headphones.

The second one was the easiest. Simply using gst-launch to bridge the in and out of my desktop. I'm running media on my netbook right now, with my headphones plugged into my desktop. It was one simple apt-get install to implement.

The second one took a little more talking, but the top contender is that unstable symbolic links bringing down /usr/bin/ls but not /bin/ls, and my 12 sshfs mount points which I keep in /sshmounts to keep them where du won't search them, that's where the instability is. I'm waiting for the next time problems on my home box or one of the other mount points causes the problem again before I mark it answered, but I think it is.

I have logged into a few others, dealing with computer science and user interfaces, but Ubuntu is the one where I have had the most questions and found the most answers.

2010/08/19

Copy/Paste: The First Step Is To Admit You Have A Problem

Thanks to Juster, I have come up with a better way to handle it.


my %functions = ( 'status' => \&create_new_request_status,
'barcode' => \&update_request_barcode,
'lab_director' => \&update_request_lab_director,
'library_type' => \&update_request_library_type,
'request_name' => \&update_request_name,
'source' => \&update_request_source,
'species' => \&update_request_species, ) ;

my $out_url = 'request_info.cgi' ;
$out_url .= '?test=1' if defined $cgi->param( 'test' ) ;
$output .= $cgi->h2( $cgi->a( { href => $out_url }, 'Request Table' ) ) ;

## show specific run info
if ( 0 ) { } # BLANK to make adding and changing elsifs easier
elsif ( defined $cgi->param( 'request_id' ) ) {
for my $key ( $cgi->param() ) {
if ( $functions{ $key } ) {
my $data ;
$data->{ request_id } = $cgi->param( 'request_id' ) ;
if ( $key eq 'status' ) { # status is different
for my $word ( qw{ status program notes } ) {
$data->{ $word } = $cgi->param( $word ) ;
}
$functions{ $key }->( $data ) ;
}
else {
$data->{ val } = $cgi->param( $key ) ;
$functions{ $key }->( $data ) ;
}
}
}
my $request_id = $cgi->param( 'request_id' ) ;
$output .= $cgi->h2( 'Request #' . $request_id ) ;
$output .= $cgi->div( show_request( $request_id ) ) ;
}
else {
$output .= $cgi->div( show_list() ) ; # show full table
}
Of course, if I had another table showing what fields I need to put into each input hash, that would make the code even simpler.

Maybe quite obvious: using CGI to make a Javascript test page

I've been reading Javascript:The Good Parts on Safari, and looking through the code examples. When doing the same for Perl, I toss test.pl into an editor and add to it over and over. I suppose I could have a web page with an ever-growing SCRIPT section, but I had a more clever idea.

I made a CGI where the body is just a FORM with a TEXTAREA and a submit button, and I set it up so that when you clicked submit, the code is sent via POST (so you can be verbose) and put into the TEXTAREA and the SCRIPT block. I have a code sample, but it's as close to a textbook use of CGI.pm that I don't think there's much use to posting it.

And I could've put in a test.js and run spidermonkey, but it seems like you can't apt-get install it anymore. I've tried rhino, and just installed it again, but I didn't like it as much as spidermonkey. But if you're writing Javascript, you're likely coding for the web.

2010/08/18

The Heartbreak of Copy/Paste Code

This is actual CGI code that I'm working on.

    if ( 0 ) { }    # BLANK to make adding and changing elsifs easier
    elsif (    defined $cgi->param( 'request_id' )
            && defined $cgi->param( 'status' ) ) {
        my @keys ;
        my @vals ;
        my $data ;
        $data->{ request_id } = $cgi->param( 'request_id' ) ;
        $data->{ status }     = $cgi->param( 'status' ) ;
        $data->{ program }    = $cgi->param( 'program' ) ;
        $data->{ notes }      = $cgi->param( 'notes' ) ;
        create_new_request_status $data ;

        my $request_id = $cgi->param( 'request_id' ) ;
        $output .= $cgi->h2( 'Request #' . $request_id ) ;
        $output .= $cgi->div( show_request( $request_id ) ) ;
        }
    elsif (    defined $cgi->param( 'request_id' )
            && defined $cgi->param( 'barcode' ) ) {
        my $data ;
        $data->{ request_id } = $cgi->param( 'request_id' ) ;
        $data->{ val }        = $cgi->param( 'barcode' ) ;
        my $err        = update_request_barcode( $data ) ;
        my $request_id = $cgi->param( 'request_id' ) ;
        $output .= $cgi->h2( 'Request #' . $request_id ) ;
        $output .= $cgi->div( show_request( $request_id ) ) ;
        }
    elsif (    defined $cgi->param( 'request_id' )
            && defined $cgi->param( 'request_name' ) ) {
        my $data ;
        $data->{ request_id } = $cgi->param( 'request_id' ) ;
        $data->{ val }        = $cgi->param( 'request_name' ) ;
        my $err        = update_request_name( $data ) ;
        my $request_id = $cgi->param( 'request_id' ) ;
        $output .= $cgi->h2( 'Request #' . $request_id ) ;
        $output .= $cgi->div( show_request( $request_id ) ) ;
        }
    elsif (    defined $cgi->param( 'request_id' )
            && defined $cgi->param( 'species' ) ) {
        my $data ;
        $data->{ request_id } = $cgi->param( 'request_id' ) ;
        $data->{ val }        = $cgi->param( 'species' ) ;
        my $err        = update_request_species( $data ) ;
        my $request_id = $cgi->param( 'request_id' ) ;
        $output .= $cgi->h2( 'Request #' . $request_id ) ;
        $output .= $cgi->div( show_request( $request_id ) ) ;
        }
    elsif (    defined $cgi->param( 'request_id' )
            && defined $cgi->param( 'source' ) ) {
        my $data ;
        $data->{ request_id } = $cgi->param( 'request_id' ) ;
        $data->{ val }        = $cgi->param( 'source' ) ;
        my $err        = update_request_source( $data ) ;
        my $request_id = $cgi->param( 'request_id' ) ;
        $output .= $cgi->h2( 'Request #' . $request_id ) ;
        $output .= $cgi->div( show_request( $request_id ) ) ;
        }
    elsif (    defined $cgi->param( 'request_id' )
            && defined $cgi->param( 'library_type' ) ) {
        my $data ;
        $data->{ request_id } = $cgi->param( 'request_id' ) ;
        $data->{ val }        = $cgi->param( 'library_type' ) ;
        my $err        = update_request_library_type( $data ) ;
        my $request_id = $cgi->param( 'request_id' ) ;
        $output .= $cgi->h2( 'Request #' . $request_id ) ;
        $output .= $cgi->div( show_request( $request_id ) ) ;
        }
    elsif (    defined $cgi->param( 'request_id' )
            && defined $cgi->param( 'lab_director' ) ) {
        my $data ;
        $data->{ request_id } = $cgi->param( 'request_id' ) ;
        $data->{ val }        = $cgi->param( 'lab_director' ) ;
        my $err        = update_request_lab_director( $data ) ;
        my $request_id = $cgi->param( 'request_id' ) ;
        $output .= $cgi->h2( 'Request #' . $request_id ) ;
        $output .= $cgi->div( show_request( $request_id ) ) ;
        }
    elsif ( defined $cgi->param( 'request_id' ) ) {
        my $request_id = $cgi->param( 'request_id' ) ;
        $output .= $cgi->h2( 'Request #' . $request_id ) ;
        $output .= $cgi->div( show_request( $request_id ) ) ;
        }
There's value-scrubbing on the other side of all the update_request_* stuff. At one point, there were four cases here, and now there's nine. The if (0) {} bit at front was there to make it easy for me to juggle order if I want, but the rest ....

I'm Dave, and I'm a Copy/Paste Coder.

If I was tossing to the same function at the end, it would be one thing. I can imagine having something like the following function to fix things, but the big elsif chunk in the center seems only marginally better.
sub un_copy-paste {
    my $output ;
    my ( $request_id , $key , $val ) = @_ ;
    $data->{ request_id } = $cgi->param( 'request_id' ) ;
    $data->{ val }        = $cgi->param( 'source' ) ;
    my $err ;
    if ( 0 ) {}
    elsif ( $key eq 'source' ) { update_request_source( $data ) ; }
    elsif ( $key eq 'species' ) { update_request_species( $data ) ; }
    # and more like this
    $output .= $cgi->h2( 'Request #' . $request_id ) ;
    $output .= $cgi->div( show_request( $request_id ) ) ;
    return $output ;
    }
I think reading more Higher Order Perl could help me come up with something non-stupid.

2010/08/17

Every Now And Then, I Turn It On Again....


Slashdot reports that broadcasters and the RIAA are considering getting Congress to order FM radio into cellphones. On a tech level, I'm surprisingly OK with it. Cellphones already have GPS, cameras, MP3 players, keyboards, Wi-Fi, texting and email, plus a billion apps. I wonder if I can get an iPhone cover that makes it look like a Swiss Army knife.

And there was a time, once, long ago, where I would've loved to been able to have a programmable recording interface to radio. Something like this in my crontab.
0 17 * * 0 /usr/bin/radio-record -freq 98.9 -band fm -duration 60 # Blues hour of 98.9FM
But that was years ago. Honestly, the ONLY time I listen to radio these days is when my wife is driving, she only listens to talk radio and mostly listens to AM stations on the fuzzy edge of reception so that the experience is indistinguishable from white noise. And, notice, they want to have FM on phones. Not AM. There may be a technical reason. I kinda doubt it.

I have two issues with radio. First, there's variety. Within the classes of music I am interested in, radio gives me few choices. I have a greater chance of hearing a cool song I've never heard before in my MP3 directory than on the radio. And for many whole classes of music I like, there's no chance I can find it in my dial.

Then there's the advertising. I don't object categorically to advertising. I once did, but I don't anymore. I was taking an advanced editing course in J-school and was told that advertising was as much newspaper content as the news stories. I balked. Afterward, I had some downtime, opened up a copy of Maximum Rock'n'Roll and saw a Dischord Records ad showing that Fugazi had a new album coming out, and I was enlightened.

Taking it into a more computer-related forum, I can see on the back cover of the August issue of Maximum PC that you can get an Antec case that would allow you to hot-swap laptop-sized SATA drives out the front. We've hit drive sizes and data sizes where any personal backup choice besides putting it on a hard drive is too slow and too small to be practical, and here's a solution. This is Antec trying to sell me something. This is also news.

Radio is filled with ads trying to sell someone something, but it stopped selling stuff to me a long time ago.

The Slashdot audience dragged out the buggy-whip analogy, but I don't think that radio has no place in the 21st century. I think that cellphones would already have radios if there was a market for them. I think that Pandora on a smartphone will always sound better than an FM radio on a smartphone. It is the forcing of the issue that most bugs me, but I'm not

The thing I'd put into a cellphone if I had a choice is an LED flashlight. I've used the screens of my Palms and phones as a field-expedient light through many power outages before but would like more candlepower.

2010/08/11

Something Now Sucks Like A Vax


vax11 is a friend of mine. Well, acquaintance. I'm not sure that we shared words in the last three years. We used to be part of the local Linux Users Group together. I used to call his apartment the Museum for Retro-Computation. He thought the room we used for install-fests looked like NASA Mission Control circa Apollo, especially with all the monitors up, so he wore white short-sleeve shirts and skinny ties so he looked he belonged in NASA Mission Control circa Apollo. You can tell he's old-school by the fact his handle is vax11.

That's an image of his VT125 terminal, connecting to the VAX emulator on his HTC EVO phone, hanging from his VT125. Now, I'm a big geek — 6'4", 250lbs+, Plus all the coder, reads O'Reilly books for fun, read LoTR, saw Star Wars for his eighth birthday, owns a 20ft scarf stuff, has the Daredevil comic where Bullseye kills Elektra, blogs about frustration with electronic esoterica, etc — but this is way next level. Isn't it so cool?

2010/08/06

Rhythmbox Problems

That sure tells me what the problem is, doesn't it?

Poor Planning Prevents Proper Performance: An SQL Tale

I'm making an application that handles workflow for a gene sequencer. What's on my plate right now is creating a record online that we can then feed into the machine. The process starts with a request, and the names of all the tables related to the request match /^request/. Each request has one or more accessions (you can think of them as samples), and the name of each table related to accession matches match /^accession/. Not everything involved with this is perfect but not bad for a project that I wrote everything for.

But we don't handle requests. We don't load requests into the sequencer. We put samples on a chip and run the process on that. A chip can have 1-n regions with 1-n samples in each region, using barcoding, which I'll have to explain sometime.

What's the term for this? What did I use? "Chip"? "Run"?

Sequence.

And for a unique sample used in the run?

Barcode.

Let me metaphor for a moment to explain why this is so hateful. Imagine you're an official for Imaginary Elementary School, about to take the 2nd grade class to the Zoo for a field trip. Problem is, the 2nd grade class of Theoretical Elementary is going to. As is the 2nd grade of Potential Elementary, etc. So, you get a bunch of bright yellow shirts in 2nd-grader sizes that say "Imaginary Elementary Class Trip 2010". Then Theoretical gets a bunch of bright blue shirts saying "Theoretical Elem", etc., and now you know if that group of eight-year-olds running around is Imaginary or Theoretical.

Now, instead of 2nd graders, we're talking DNA samples, and instead of t-shirts, we have chemicals. When I think "barcoding", I think of putting barcodes on products so I know what price they are. I think "tagging" (like they do with wild animals to track their movements) is a more fitting metaphor and I like my extended T-shirt thing. And, right now, I'm wanting to make a table where I can say that, on August 6, the Imaginary Elementary kids wore red, and the obvious table name would be sequence_barcodes and the functions I need to write should be get_sequence_barcode() and set_sequence_barcode(), but because I'm using "barcode" as the generic term for the 2nd-grader and not the shirt the child wears, that table name and those function names are already used.

So I can't use the right names now because the wrong names were used in the past. I might just call the table keaton.

2010/08/05

More on Passwords

In the comments of a previous post on creating passwords, xenoterracide mentioned his method of creating more secure passwords.

I say "more secure" rather than secure because, as mentioned in an exchange in xeno's comments section that got so heated xeno locked the comments, the entropy could be better, plus if the desire for the passworded information gets big enough, they'll just use legal or extralegal methods rather than crack your password. Basically, we're trying to make it easier to have passwords that are better than average.

The Xeno method is as follows.

echo -n SOME_STRING_YOU_WILL_REMEMBER | sum | base64 

or

echo -n SOME_STRING_YOU_WILL_REMEMBER | sha1sum | base64 

I wrote code to automate it somewhat. I display the hexdigest and base64 digest of the string.

#!/usr/bin/perl

# turns the input into a string and puts out SHA1 digests in both hex and base64

use 5.010 ;
use strict ;
use warnings ;
use Digest::SHA1 ;

my $sha = Digest::SHA1->new;
$sha->add( lc join ' ' , @ARGV ) ;
say $sha->hexdigest;
say $sha->b64digest; 

But I have realized a problem with this. Let me give you the use case.

You have otherwise had your account hacked. You do this on a machine where someone else has root, or you have an ancient version of sendmail or you use .authorized_keys and someone came in free from another machine. They don't need to be root, they just need to be you.

grep password .bash_history
grep sha1sum .bash_history

So, writing it up as a tool that takes the string from STDIN while running, not from the command line so it ends up in the .history, that's how it should be.

I haven't written it up like that yet, but it should be easy. I mean, the above example is only 4 lines of real code, right?

My Wireless Networking, Plus


In the foreground is my netbook, connected to the campus wireless network with barely one bar of connectivity.

In the background is the antenna for the access point for the campus wireless network.

Yes, I can physically touch my netbook to the antenna and not get better than low connectivity. Elsewhere it's OK.

I have sent a help ticket on. I haven't sent this picture. Yet.


This one's just a bit silly. I realized that the foliage (which I think is for sale) is covering the hours. If it wasn't open 24 hours, covering up when you're open could be a problem. Still, it's kinda FAIL, don't you think?

2010/08/04

I Was Born A REPL

I have seen the Perl module Devel::REPL a few times. I haven't seen much use for it, thinking I can write a quick Perl program if I need to and a one-liner if necessary. Who needs a Perl shell?

Then I had reason to learn Python, or actually Jython, or a tool that used Jython for scripting. I went to the O'Reilly, and it started with using Python as a shell. (Or, Jython. Or ... whatever.) Then the oddest thing happened.

I used the Python shell as a calculator.

More than once.

That wasn't the push that made me consider re.pl. It was this helpful .rc file from recent blog commenter xenoterracide.

I don't use it often yet. I keep test.pl with the current test code at the top and most everything but the module declarations commented out, just for this purpose. And, as a purely aesthetic issue, I want to munge the way the prompt looks. But I'm sure I will use it.

2010/08/02

More Fun with Ubuntu upgraded to Lucid

I have a Linux box. I installed a 500GB drive and put on Ubuntu Jaunty. I left it at Jaunty through Karmic, thinking that I didn't want or need any of the diffs. But I got to Lucid and I thought I should move up.

I used the built-in upgrade method, rather than pulling out a live CD and reinstalling. I've come up with two problems. First, it comes up without a mouse pointer. I can mouse, but I just don't know where I'm mousing. I can fix that short-term — open the Appearance module, change the pointer, lock screen, unlock — but the short term fix is all I can do, because not long after, I lock up with the screen blinking Checking Battery Status. I remind you that this is on a desktop machine. No battery to check. All powered from the hole in the wall.

But that's not the annoying part.

The annoying part is that none of these issues come up when I log into another account I never used before. I logged in on Saturday. It's running fine still.

I don't want to have to rename and move lots of crap. I also don't want to reinstall from liveCD or live thumbdrive. But I don't want to keep it as-is, and it's hard to know which I want less.