With a little side of applesauce...

Friday, September 26, 2008

Thunderbird - Preparing a csv file for importing into Gmail

I was sorely mistaken about Gmail now taking a slightly modified csv import from Thunderbird :( Apparently, it just throws everything into "notes", which works visually in the web GUI, but is not searched when auto-completing email addresses. So.... I modified my meeting maker import scripts to import thunderbird contacts as well.

Here is the awk statement to prepare a csv file (don't forget to remove the header line):
cat tbird_export.txt  | sed 's/,/|/g' |  tr -d '\015' | sed 's/"//g' | awk -F\| '{print $1,$2"|"$5"|"$12,$14,$15,$16,$17"|"$8"|"$7"|"$9"|"$3,$4,$6,$10,$11,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36 }' > tbird_import.txt


Here is the csv field breakdown:

   1-2           5      12-17         8            7            9         3-6,10-11,18-36
contact name | email | address | phone home | phone work | phone mobile | Notes


1 - First Name
2 - Last Name
3 - Display Name
4 - Nickname
5 - Primary Email
6 - Secondary Email
7 - Work Phone
8 - Home Phone
9 - Fax Number
10 - Pager Number
11 - Mobile Number
12 - Home Address
13 - Home Address 2
14 - Home City
15 - Home State
16 - Home ZipCode
17 - Home Country
18 - Work Address
19 - Work Address 2
20 - Work City
21 - Work State
22 - Work ZipCode
23 - Work Country
24 - Job Title
25 - Department
26 - Organization
27 - Web Page 1
28 - Web Page 2
29 - Birth Year
30 - Birth Month
31 - Birth Day
32 - Custom 1
33 - Custom 2
34 - Custom 3
35 - Custom 4
36 - Notes


Here is the run.sh:
#!/bin/sh
####################
#
# Copyright 200 Shannon Eric Peevey <speeves@stolaf.edu>
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
#####################
#
# Contacts Import/Export script
# - exports contacts from the existing systems, and re-imports from the gmail systems.
#
####################

# load our common library
. ./common.sh

### Initialize variables
TMP="/tmp/"
IMPORT_FILE_PATH=""
DOMAIN="mydomain.edu"
MAX_RESULTS="10000"


usage="
---------------------------
Usage: ${0} [-hadbupo]

Help Options
-h This message

Actions
-a Action to perform
(
i|contactstogoogle - import contacts into gmail
ix|xmltogoogle - import contacts into gmail from gdata api export
e|contactsfromgoogle - export contacts from gmail

)

Variables
-u user account email address
-p user account password
-o import/export file (used to import contacts into gmail - see README.txt for more information)"
-d path to import file directory


while getopts "a:d:b:u:p:o:h" OPT
do
case $OPT in
a )
ACTION=$OPTARG
;;
u )
USERNAMETMP=$OPTARG
USERNAME=$(echo $USERNAMETMP | cut -d\@ -f1)
;;
p )
PASSWORD=$OPTARG
;;
o )
IMPORT_FILE=$OPTARG
;;
d )
IMPORT_FILE_PATH="${OPTARG}/"
;;
h )
echo "$usage"
exit 1
;;
\?)
echo "$usage"
exit 1;;
esac
done
# remove the flags from $@
shift $((${OPTIND} - 1))

# grab the action that we need to perform
case $ACTION in
i|contactstogoogle )
contactstogoogle
;;
ix|xmltogoogle )
xmltogoogle
;;
e|contactsfromgoogle )
contactsfromgoogle
;;
esac



And, the library file, common.sh:
#!/bin/sh
####################
#
# Copyright 2009 Shannon Eric Peevey <speeves@stolaf.edu>
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
#####################
#
# Contacts Import/Export Library
# - exports contacts from the existing systems, and re-imports from the gmail systems.
#
####################

contactstogoogle()
{
# set tmpfolder
CONTACTFILE="${TMP}${USERNAME}.xml"
LOG_DATE=$(date +%d/%b/%Y:%X\ %z)

# let's wrap our migration steps here to simplify the function above
authtoken=$(getauthtoken)

### now we handle the import file
IMPORT_FILE_LOCATION="${IMPORT_FILE_PATH}${IMPORT_FILE}"
while read abook_line
do
contact_name=$(echo $abook_line | cut -d\| -f1)
contact_email=$(echo $abook_line | cut -d\| -f2)
contact_address=$(echo $abook_line | cut -d\| -f3)
contact_phone_home=$(echo $abook_line | cut -d\| -f4)
contact_phone_work=$(echo $abook_line | cut -d\| -f5)
contact_phone_mobile=$(echo $abook_line | cut -d\| -f6)
notes="$(echo $abook_line | awk -F\| '{print $7 }')"

if [ "$contact_name" != "" ]; then
usertitle="${contact_name}"
else
usertitle="Unnamed Contact"
fi

if [ "${contact_email}" != "" ]; then
xmlcreateimport
postentryimport
fi
done < ${IMPORT_FILE_LOCATION}

}

xmltogoogle()
{
# set tmpfolder
#CONTACTFILE="${TMP}${USERNAME}.xml"
LOG_DATE=$(date +%d/%b/%Y:%X\ %z)

# let's wrap our migration steps here to simplify the function above
authtoken=$(getauthtoken)

### now we handle the import file
for f in $(ls ${IMPORT_FILE_PATH})
do
CONTACTFILE="${IMPORT_FILE_PATH}${f}"
postentryimportbatch
done
}


contactsfromgoogle()
{
# set tmpfolder
LOG_DATE=$(date +%d/%b/%Y:%X\ %z)

# let's wrap our migration steps here to simplify the function above
authtoken=$(getauthtoken)

### now we handle the import file
EXPORT_FILE_LOCATION="${IMPORT_FILE_PATH}${IMPORT_FILE}"

totalcontacts=$(postentryexportgettotal)
echo ${totalcontacts}
INDEX=1
MAX_RESULTS=99
iter=1
while [ ${INDEX} -lt $(( $totalcontacts + 99 )) ];
do
#xmlcreateexport
postentryexport > ${EXPORT_FILE_LOCATION}.${iter}
iter=$(( $iter + 1 ))
INDEX=$(( $INDEX + 99 ))
done

}

getauthtoken()
{
# use curl to get auth token
if [ "$USERNAME" = "" ] || [ "$PASSWORD" = "" ]; then
echo "$usage"
exit 1
else
curl -s https://www.google.com/accounts/ClientLogin -d Email=${USERNAME}@${DOMAIN} -d Passwd=${PASSWORD} -d accountType=HOSTED -d source=Google-cURL-Example-${USERNAME} -d service=cp | grep Auth
fi
}

postentryimport()
{
# use curl to post the xml batch feed that was created
# http://www.google.com/m8/feeds/contacts/liz%40gmail.com/full
curl -v -s --url http://www.google.com/m8/feeds/contacts/${USERNAME}@${DOMAIN}/full --header "Authorization: GoogleLogin ${authtoken}" --header "Content-Type: application/atom+xml" --data "@${CONTACTFILE}"
}

postentryimportbatch()
{
# use curl to post the xml batch feed that was created
# http://www.google.com/m8/feeds/contacts/liz%40gmail.com/full
curl -v -s --url http://www.google.com/m8/feeds/contacts/${USERNAME}@${DOMAIN}/full/batch --header "Authorization: GoogleLogin ${authtoken}" --header "Content-Type: application/atom+xml" --data "@${CONTACTFILE}" | tidy -xml -indent -quiet

}

postentryexport()
{
# use curl to post the xml batch feed that was created
# http://www.google.com/m8/feeds/contacts/liz%40gmail.com/full
curl -v -s --url http://www.google.com/m8/feeds/contacts/${USERNAME}@${DOMAIN}/full?start-index=${INDEX}\&max-results=${MAX_RESULTS} --header "Authorization: GoogleLogin ${authtoken}" --header "Content-Type: application/atom+xml"
}

postentryexportgettotal()
{
# use curl to post the xml batch feed that was created
# http://www.google.com/m8/feeds/contacts/liz%40gmail.com/full
curl -v -s --url http://www.google.com/m8/feeds/contacts/${USERNAME}@${DOMAIN}/full?max-results=${MAX_RESULTS} --header "Authorization: GoogleLogin ${authtoken}" --header "Content-Type: application/atom+xml" | tidy -xml -indent -quiet | grep '<openSearch:totalResults>' | cut -d\> -f2 | cut -d\< -f1
}


xmlcreateimport()
{
echo "<atom:entry xmlns:atom='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005'>" > ${CONTACTFILE}
echo " <atom:category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/contact/2008#contact' />" >> ${CONTACTFILE}
echo " <atom:title type='text'>${usertitle}</atom:title>" >> ${CONTACTFILE}
echo " <atom:content type='text'>${notes: -Notes}</atom:content>" >> ${CONTACTFILE}
echo " <gd:email rel='http://schemas.google.com/g/2005#work' address=\"${contact_email}\" />" >> ${CONTACTFILE}
echo " <gd:email rel='http://schemas.google.com/g/2005#home' address=\"${contact_email}\" />" >> ${CONTACTFILE}
if [ "${contact_phone_home}" != "" ]; then
echo " <gd:phoneNumber rel='http://schemas.google.com/g/2005#home' primary='true'>${contact_phone_home}</gd:phoneNumber>" >> ${CONTACTFILE}
fi
if [ "${contact_phone_work}" != "" ]; then
echo " <gd:phoneNumber rel='http://schemas.google.com/g/2005#work' >${contact_phone_work}</gd:phoneNumber>" >> ${CONTACTFILE}
fi
if [ "${contact_phone_mobile}" != "" ]; then
echo " <gd:phoneNumber rel='http://schemas.google.com/g/2005#mobile' >${contact_phone_mobile}</gd:phoneNumber>" >> ${CONTACTFILE}
fi
if [ "${contact_address}" != "" -a "${contact_address}" != " " ]; then
echo " <gd:postalAddress rel='http://schemas.google.com/g/2005#other' primary='true'>${contact_address}</gd:postalAddress>" >> ${CONTACTFILE}
fi
echo "</atom:entry>" >> ${CONTACTFILE}
}

Tuesday, September 23, 2008

Coldfusion - cfoutput is cfloop

It makes sense, but I didn't "really" connect this until:

coldfusion.tagext.InvalidTagAttributeException: Attribute validation error for tag cfoutput.
at coldfusion.tagext.QueryLoop.setQuery(QueryLoop.java:76)

Monday, September 22, 2008

Google Search - in Pirate

Ok, I saw this Google Blog entry, and just had to post it. Click here to go directly to the Google Search in Pirate.

Do you be feelin' lucky?!

Friday, September 19, 2008

Coldfusion - where is the source code for mod_jrun?

Coldfusion connectors continue to confound... Where is the source code for mod_jrun? Contained in wsconfig.jar, of course!

Who would think to look in wsconfig.jar for the connector source code? I wouldn't have, though it is documented here, and this great posting really walks you through compiling the module.

Thursday, September 18, 2008

Google Apps for Education - Gmail - gets full directory searching in the address field

Another friend, Dan, pointed out that GAE now gets full domain searching for email addresses while typing in the To: or any address field, (Compose Mail). This is similar to the auto-complete functionality in other email clients, and is a major coup for GAE. Previously, the address completion drop-down only listed My and Suggested Contacts, and most of our users were grumbling a bit about having to search for everyone. (I expected this feature to appear sooner or later, it has already been implemented in Google Docs and Calendar for the past month or two).

In addition to this change, he pointed out that there are some more Google Lab tools, "Right-side labels", and "Right-side chat", by Emily C. These work best for wide-screen monitors, but is still pretty cool :)

Thanks for pointing these out!!

Google Docs - Problems opening attachments

My friend, Michael, showed me the work-around for import issues when opening document attachments in Gmail. Here is the error:

"We're sorry, but Google Docs has encountered an unexpected error."

Here is the fix:

Hit the Back button once.

Gmail Contact Import upgrade

It appears that Google did a major release, and the contact import has received a major upgrade. In the past, you could only import "Name, Email, Notes", but now, (I saw this yesterday), you can:

1. Do a full import of an Outlook CSV.
2. Do a full import of Thunderbird CSV, but change the "Display Name" header to "Name".

Sorry Thunderbird folks!! You get short-changed again, BUT, I imagine this is a bug, and will be fixed shortly.

BTW, you will know if you forgot to change "Display Name" to "Name", as all of your contacts will be listed as "(Unnamed Contact)", (even though "Display Name" is correctly imported, and viewed when clicking on the contact). If this happens, delete all of your problem contacts, change the column header, and everything will import correctly.

Wednesday, September 17, 2008

Google - defensive response to Facebook?

Is this a defensive response against the popularity of Facebook, et al, and the fact that email is losing footing as a social medium?

http://googleblog.blogspot.com/2008/09/social-web-all-about-small-stuff.html

Tuesday, September 16, 2008

Google Calendar - How can I add a document attachment to my calendar event?

You can "add" an email attachment by entering the unique email URL into the description of your event. The URLs will look similar to:

http://mail.google.com/a/domain.com/#all/11c5875f7ee200db
http://mail.google.com/a/domain.com/#inbox/11c6b363fa0d1907

The next time you open the event, you can click on the hyperlink, and it will take you to your email, where you can review your attachment.

(I wrote the St. Olaf FAQ entry, so am plagiarizing myself :) Or not, if there is a better way :)) )

Friday, September 12, 2008

Gmail contact import - using a delimited file

Here are shell scripts to import the contacts in the pipe-delimited file mentioned in my last post, "Meeting Maker - prepare export for pushing into gmail".

As is my style, I split them into two files.

1. run.sh - the "user interface", which handles the options, and calls the appropriate functions
2. common.sh - the library of functions which is included in run.sh

St. Olaf College has been great about giving me the opportunity to work on these gmail migrations, as well as letting me share these under the GPL.

run.sh:
#!/bin/sh
####################
#
# Copyright 2008 Shannon Eric Peevey <speeves@stolaf.edu>
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
#####################
#
# Contacts Import/Export script
# - exports contacts from the existing systems, and re-imports from the gmail systems.
#
####################

# load our common library
. ./common.sh

### Initialize variables
TMP="/tmp/"
IMPORT_FILE_PATH=""
DOMAIN="example.com"


usage="
---------------------------
Usage: ${0} [-hadbupo]

Help Options
-h This message

Actions
-a Action to perform
(
i|contactstogoogle - import contacts into gmail
)

Variables
-u user account email address
-p user account password
-o import file (used to import contacts into gmail - see README.txt for more information)"



while getopts "a:db:u:p:o:h" OPT
do
case $OPT in
a )
ACTION=$OPTARG
;;
u )
USERNAMETMP=$OPTARG
USERNAME=$(echo $USERNAMETMP | cut -d\@ -f1)
;;
p )
PASSWORD=$OPTARG
;;
o )
IMPORT_FILE=$OPTARG
;;
h )
echo "$usage"
exit 1
;;
\?)
echo "$usage"
exit 1;;
esac
done
# remove the flags from $@
shift $((${OPTIND} - 1))

# grab the action that we need to perform
case $ACTION in
i|contactstogoogle )
contactstogoogle
;;
esac



common.sh:
#!/bin/sh
####################
#
# Copyright 2008 Shannon Eric Peevey <speeves@stolaf.edu>
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
#####################
#
# Contacts Import/Export Library
# - exports contacts from the existing systems, and re-imports from the gmail systems.
#
####################

contactstogoogle()
{
# set tmpfolder
CONTACTFILE="${TMP}${USERNAME}.xml"
LOG_DATE=$(date +%d/%b/%Y:%X\ %z)

# let's wrap our migration steps here to simplify the function above
authtoken=$(getauthtoken)

### now we handle the import file
IMPORT_FILE_LOCATION="${IMPORT_FILE_PATH}${IMPORT_FILE}"
while read abook_line
do
contact_name=$(echo $abook_line | cut -d\| -f1)
contact_email=$(echo $abook_line | cut -d\| -f2)
contact_address=$(echo $abook_line | cut -d\| -f3)
contact_phone_home=$(echo $abook_line | cut -d\| -f4)
contact_phone_work=$(echo $abook_line | cut -d\| -f5)
contact_phone_mobile=$(echo $abook_line | cut -d\| -f6)
notes="$(echo $abook_line | awk -F\| '{print $7 }')"

if [ "$contact_name" != "" ]; then
usertitle="${contact_name}"
else
usertitle="Unnamed Contact"
fi

if [ "${contact_email}" != "" ]; then
xmlcreate
postentry
fi
done < ${IMPORT_FILE_LOCATION}

}


getauthtoken()
{
# use curl to get auth token
if [ "$USERNAME" = "" ] || [ "$PASSWORD" = "" ]; then
echo "$usage"
exit 1
else
curl -s https://www.google.com/accounts/ClientLogin -d Email=${USERNAME}@${DOMAIN} -d Passwd=${PASSWORD} -d accountType=HOSTED -d source=Google-cURL-Example-${USERNAME} -d service=cp | grep Auth
fi
}

postentry()
{
# use curl to post the xml batch feed that was created
# http://www.google.com/m8/feeds/contacts/liz%40gmail.com/full
curl -v -s --url http://www.google.com/m8/feeds/contacts/${USERNAME}@${DOMAIN}/full --header "Authorization: GoogleLogin ${authtoken}" --header "Content-Type: application/atom+xml" --data "@${CONTACTFILE}"
}


xmlcreate()
{
echo "<atom:entry xmlns:atom='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005'>" > ${CONTACTFILE}
echo " <atom:category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/contact/2008#contact' />" >> ${CONTACTFILE}
echo " <atom:title type='text'>${usertitle}</atom:title>" >> ${CONTACTFILE}
echo " <atom:content type='text'>${notes: -Notes}</atom:content>" >> ${CONTACTFILE}
echo " <gd:email rel='http://schemas.google.com/g/2005#work' address=\"${contact_email}\" />" >> ${CONTACTFILE}
echo " <gd:email rel='http://schemas.google.com/g/2005#home' address=\"${contact_email}\" />" >> ${CONTACTFILE}
if [ "${contact_phone_home}" != "" ]; then
echo " <gd:phoneNumber rel='http://schemas.google.com/g/2005#home' primary='true'>${contact_phone_home}</gd:phoneNumber>" >> ${CONTACTFILE}
fi
if [ "${contact_phone_work}" != "" ]; then
echo " <gd:phoneNumber rel='http://schemas.google.com/g/2005#work' >${contact_phone_work}</gd:phoneNumber>" >> ${CONTACTFILE}
fi
if [ "${contact_phone_mobile}" != "" ]; then
echo " <gd:phoneNumber rel='http://schemas.google.com/g/2005#mobile' >${contact_phone_mobile}</gd:phoneNumber>" >> ${CONTACTFILE}
fi
if [ "${contact_address}" != "" -a "${contact_address}" != " " ]; then
echo " <gd:postalAddress rel='http://schemas.google.com/g/2005#other' primary='true'>${contact_address}</gd:postalAddress>" >> ${CONTACTFILE}
fi
echo "</atom:entry>" >> ${CONTACTFILE}
}

Meeting Maker - prepare export for pushing into gmail

Here is the BASH one-liner to transform a meeting maker tab-delimited export into a pipe-delimited text file for us to parse and push up into Gmail:
cat meetingmaker_export.txt  | sed 's/\t/|/g' |  tr -d '\015' | sed 's/"//g' | awk -F\| '{print $1,$2"|"$13"|"$7,$8,$9,$10"|"$14"|"$15"|"$16"|"$4,$5,$6,$22,$23,$24,$25,$26 }' > mm_import.txt



Here is the schema for our pipe-delimited file (the numbers correspond to the columns in the meeting maker export, (which I included and numbered below)):
   1-2         13      7-10      14           15           16             4-6,22-26
contact name | email | address | phone home | phone work | phone mobile | Notes

1 - First Name
2 - Last Name
3 - Category
4 - Title
5 - Department
6 - Room
7 - Company
8 - Address
9 - City
10 - State
11 - ZIP
12 - Country
13 - Email
14 - Home Phone
15 - Work Phone
16 - Mobile Phone
17 - Pager
18 - Fax
19 - Other Phone 1
20 - Other Phone 2
21 - Other Phone 3
22 - Custom 1
23 - Custom 2
24 - Custom 3
25 - Custom 4
26 - Info

Meeting Maker - contact fields on export

Here are the columns from a Meeting Maker contact export:
First Name|Last Name|Category|Title|Department|Room

|Company|Address|City|State|ZIP|Country

|Email|Home Phone|Work Phone|Mobile Phone|Pager|Fax

|Other Phone 1|Other Phone 2|Other Phone 3

|Custom 1|Custom 2|Custom 3|Custom 4|Info|

Thursday, September 11, 2008

Facebook - feed your blog

Simplaris appears to be the simplest way to feed your blog into Facebook. Very simple :)

Facebook is buggy, and here is why

I am fairly new to facebook, but am surprised at how buggy such a popular site is. (Maybe I shouldn't be, since I have worked behind the scenes at one). Anyways, as I had additional UI issues tonight, I thought I would see if there was a bug list anywhere, and was pleasantly surprises to find that they have a public Bugzilla installation:
http://bugs.developers.facebook.com/

As well as a developers page to help people to harness the Facebook API:
http://developers.facebook.com/

And even more importantly:
http://developers.facebook.com/opensource.php

Where they are giving back to the Free Software community! Very, very, VERY cool :)

But, wait!! There's more...
http://developers.facebook.com/fbopen/contribute.pdf

Very sad... It appears that any contributions made back to Facebook become the property of Facebook, and Facebook may even use contributors work to obtain patents:

"Contributor agrees that this assignment may be submitted by Facebook to obtain patents, mask work
registrations, copyright registrations and otherwise to protect Facebook’s ownership in the Contribution and any and all
related inventions and works of authorship in any country."

How very corporate... I guess I probably won't be contributing to that project...

Coldfusion classpaths

I thought I had posted a link to this, but here is the best explanation for adding third-party jars into your application:
http://weblogs.macromedia.com/cantrell/archives/2004/07/the_definitive.html

Monday, September 8, 2008

Javascript - great video coverage of the language from Douglas Crockford

The JavaScript Programming Language:

http://video.yahoo.com/watch/111593/1710507
http://video.yahoo.com/watch/111586/1027832
http://video.yahoo.com/watch/111595/1710607
http://video.yahoo.com/watch/111596/1710658

Two hours worth of glorious learning :)

Screen - Linux Journal article

What!? My blog has no postings on Screen usage??? I have used screen for over two years now, and find it invaluable. It is great for those who are too lazy to open multiple tabs, or need multiple sessions open on a remote machine, _and_ for restarting those sessions after your VPN disconnects, (as they are want to do)... Here is a good overview from Linux Journal that keeps coming up when I try to remember how to do X:
http://www.linuxjournal.com/article/6340

Javascript - debugging

Here is the ever popular Firebug add-on, (of which I only recently became aware):
https://addons.mozilla.org/en-US/firefox/addon/1843