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.