Posts explaining how to do something, fix something, etc. This is where you’ll find my useful posts.

Unfortunately, given how software evolves over time, I should probably say “once useful”. If you’re digging through the archives, check the dates.

Write a file as root from a non-root vim.

Caveat lector: I wrote this post in high school; it’s likely outdated and poorly written.

Problem

I often edit config files in vim, try to save them, and then realize that I ran vim as a normal user and the config file is in /etc. In the past I would close vim and redo all of my changes as root (using sudo). This is a real pain especially if I had made a lot of changes.

Solution

Add the following to your ~/.vimrc:

cmap w!! w !sudo tee % >/dev/null<CR>:e!<CR><CR>

A while ago I came across this post that describes how to save a file as root from a non-root vim by adding cmap w!! w !sudo tee % >/dev/null to my .vimrc.

The problem is that, after running this command, vim will notice that the file has changed on disk and ask the user if he or she wants to reload it. After a while this got annoying, therefore the multiple CRs (enters) and the :e! (reloads the file).

Navigate text with vi(m) keys on linux

Caveat lector: I wrote this post in high school; it’s likely outdated and poorly written.

Intro

Lifehacker recently posted a AutoHotkey script for windows that allows text navigation using letters instead of the arrow keys. In response to @wersdaluv’s post, I wrote a very simple script that allows users to navigate text using the standard vim keys (hjkl) when the caps-lock key is toggled. Feel free and add to my very basic script.

Steps

I stored the script referenced in this post in a paste-bin and now it’s gone. Live and learn…

  1. Download my script (via copy and paste) from here. Lost (email if found).
  2. Save the script somewhere where you will not delete it and mark it as executable (chmod u+x /path/to/script.sh)
  3. Add the script to the startup programs with the argument init (i.e. /path/to/script.sh init). If you don’t know how to add startup programs in your Desktop Environment, Google it.
  4. Assign F13 (the now remapped capslock key), as a hotkey in your window manager. Set the command to '/path/to/script.sh toggle'. Again, if you don’t know how to add a hotkey, Google it.
  5. Now either log out and then in or run ’/path/to/script.sh init' in order to remap the capslock key.
  6. Pressing the capslock key should now toggle navigation mode.

Bash completion with aptitude aliases

Caveat lector: I wrote this post in high school; it’s likely outdated and poorly written.

Problem

  1. If I used my alias for installing an application (inst application), I would have to know the full application name because I would not have bash completion. This was very annoying when installing libraries because they often have weird version strings tacked on to their ends.
  2. If I used the full command (sudo aptitude install application), I would have bash completion and would therefore not have to know the whole application name. I could simply type libxul and get libxul0d.

On one hand, I would type a short command plus a complected application name, on the other I would type a long command and a simple application name. I wanted to be able to type a short command with a simple application name.

Solution

I wrote my own bash completion rules. They are based on the default aptitude bash completion rules but customized for aliases.

# Install Completion
#
_aptitude_all()
{
        local cur dashoptions

        COMPREPLY=()
        cur=`_get_cword`

        dashoptions='-S -u -i -h --help --version -s --simulate -d \
                     --download-only -P --prompt -y --assume-yes -F \
                     --display-format -O --sort -w --width -f -r -g \
                     --with-recommends --with-suggests -R -G \
                     --without-recommends --without-suggests -t \
                     --target-release -V --show-versions -D --show-deps\
                     -Z -v --verbose --purge-unused'

        if [[ "$cur" == -* ]]; then
            COMPREPLY=( $( compgen -W "$dashoptions" -- $cur ) )
        else
                COMPREPLY=( $( apt-cache pkgnames $cur 2> /dev/null ) )
        fi
        return 0
}
_aptitude_installed()
{
        local cur dashoptions

        COMPREPLY=()
        cur=`_get_cword`

        dashoptions='-S -u -i -h --help --version -s --simulate -d \
                     --download-only -P --prompt -y --assume-yes -F \
                     --display-format -O --sort -w --width -f -r -g \
                     --with-recommends --with-suggests -R -G \
                     --without-recommends --without-suggests -t \
                     --target-release -V --show-versions -D --show-deps\
                     -Z -v --verbose --purge-unused'

        if [[ "$cur" == -* ]]; then
            COMPREPLY=( $( compgen -W "$dashoptions" -- $cur ) )
        else
                COMPREPLY=( $( _comp_dpkg_installed_packages $cur ) )
        fi
        return 0
}
complete -F _aptitude_all $default inst
complete -F _aptitude_all $default upgrade
complete -F _aptitude_all $default apt-info
complete -F _aptitude_all $default apt-changes
complete -F _aptitude_all $default apt-download
complete -F _aptitude_installed $default uninst
complete -F _aptitude_installed $default reinst
complete -F _aptitude_installed $default purge

Just copy it into a file such as ~/.bash_completion and source the file in your ~/.bashrc by adding “. ~/.bash_completion”.

Change/Add/Remove the aliases at the end of the file. The lines that start with complete -F _aptitude_all complete any available or installed package and lines that start with complete -F _aptitude_installed complete only installed packages.

inst, upgrade, apt-info, apt-changes…. are my aliases. You must use YOUR ALIASES for this to work. To add aliases, read this.

How to invite someone to Ubuntu One

Caveat lector: I wrote this post in high school; it’s likely outdated and poorly written.

For anyone with an Ubuntu One account, the following are instructions for sending invites:

  1. Go to My Files in the web interface.
  2. Create a new folder (to be shared) with the person that you will be inviting
  3. Go to the sharing tab (on the right).
  4. Share the folder with the person that you want to invite (The trick is that someone does not have to have an Ubuntu One account to accept a share).

http://ubuntuone.com

For anyone looking for an invite, just ask @bugabundo at Identi.ca.

How to record one's linux computer with pulseaudio

Caveat lector: I wrote this post in high school; it’s likely outdated and poorly written.

I posted a simple tip to an Identi.ca user (mxc) explaining how to record a skype conversation and felt that others might find the information useful. Here is an elaborated explanation of how to record the sound from a linux computer.

  1. Install pavucontrol and the gnome-sound-recorder (in the gnome-media package).
  2. Open the gnome-sound-recorder and start recording
  3. Open the pulseaudio volume control and switch to the recording tab
  4. Click on the down arrow of the “gnome-sound-recorder” Record Stream, Select “Move Stream” and move the stream to the “Monitor” stream for your sound card.

This should record all sound from your computer if you are using pulseaudio. I have not tested this with skype but it should work.

Change the notification icon in Mumbles without creating a plugin.

Caveat lector: I wrote this post in high school; it’s likely outdated and poorly written.

I have noticed that several people have asked how to change the notification icon on mumbles without creating a new plugin.This is actually very simple: use the generic DBus plugin with dbus-send. I believe that this tutorial requires the SVN version but I may be mistaken. First add a new section to your DBus plugin configuration file. If you do not have this configuration file, copy the sample one from the mumbles source tarball (found on the project’s homepage). The file is called dbus.conf.sample. Copy this file to ~/.mumbles/dbus.conf. The new section is as follows:

[program-or-script-name]
enabled = true
interface = org.program-or-script-name.DBus
path = /org/program-or-script-name/DBus
signal = your-signal
icon = your-icon.png

Put your-icon.png in the ~/.mumbles/plugins/icons/ folder.your-signal is your name for the alert. None of these variables are important but they must be consistent.

After doing the previous and restarting mumbles, run this command:

dbus-send /org/program-or-script-name/DBus org.`*program-or-script-name*`.DBus.your-signal string:"Title" string:"Message"

Make sure that you replace all necessary variables. This will display a mumbles popup with your custom icon, title, and message. You can also specify a click action using launch = action.

Mumbles with gmail

Caveat lector: I wrote this post in high school; it’s likely outdated and poorly written.

I have been playing around with mumbles lately and have written a gmail plugin for anyone interested. Mumbles is a notification system that works very much like growl for the mac. The latest SVN version can even replace the gnome notification daemon (but not very well). While still in its infancy, this project shows a lot of promise. I based the plugin on the evolution tutorial on project’s homepage. I based the script on this script (with many modifications). When you click on the notification popup, evolution will launch (you can edit the source to change the program). The script requires python-feedparser.

Plugin, Source, and Script package: gmail-plugin_mumbles.tar.gz

Installing the precompiled plugin:

Do step 2 from the next section. Now copy the plugin to ~/.mumbles/plugins/.

Installing the plugin from source (adapted from dot_j’s tutorial (gone)):

1. Download the source

Download the package and extract. Then open a terminal window inside the plugin-source folder.

2. Create the directory structure and choose an icon

Run the following command:

mkdir -p ~/.mumbles/plugins/icons

Then either run this to use the default evolution icon…

cp /usr/share/icons/hicolor/22×22/apps/evolution.png ~/.mumbles/plugins/icons

Or just copy your desired icon into the plugins/icons folder and rename it to evolution.png. This is unnecessary if you already have the evolution plugin.

Build and install the plugin

cd ~/gmail_plugin
python setup.py bdist_egg

This will use our setup.py file to create our plugin. After it runs, you should see a file named GmailMumbles-0.1-py2.5.egg in the dist directory that was created by the build process. Here the -py2.5 part of the filename refers to what version of python you are using (it may vary, but if you are able to start mumbles, should not matter).

The .egg file is our plugin, so the only thing left to do is copy that to the mumbles plugin directory.

cp dist/GmailMumbles-0.1-py2.5.egg ~/.mumbles/plugins

Installing the script:

Find the script in the package and edit the username and password variables. Run this script with python /path/to/gmail.py (replace /path/to with the path to the script). By default, this script will check for new email every 2 minutes and alert the user of new mail.

BTW: This script does not safely store the username and password. I may, in the distant future, make this script work with gnome-keyring but this is not likely. I hope that mumbles will soon get better notification-daemon support so that I can go back to using mail-notification.

Running the "Ubunu System Panel" on a 64 bit machine.

Caveat lector: I wrote this post in high school; it’s likely outdated and poorly written.

After installing the 64 bit version of Ubuntu on my Dell Inspiron 1420n I found that the USP (Ubuntu System Panel) keybindings do not work. This is because the /usr/lib/python2.4/site-packages/usp/plugins/_keybinder.so is compiled for a 32 bit system. After a little searching I found out that Glipper includes a _keybinder.so file. After replacing USP’s _keybinder.so with Glipper’s version, the keybindings worked fine.

  1. Download glipper aptitude download glipper.
  2. Extract the glipper deb with dpkg-deb -x glipper_1.0-1ubuntu1_amd64.deb glipper (change glipper_1.0-1ubuntu1_amd64.deb to the name of your file).
  3. Copy in the new _keybinder.so with sudo cp ./glipper/usr/lib/python-support/glipper/python2.5/glipper/keybinder/_keybinder.so /usr/lib/python2.4/site-packages/usp/plugins/_keybinder.so.
  4. Restart USP with killall gnome-panel and your USP shortcut keys should now work.

Edit: This is no longer necessary.

Conky: The simple system monitor

Caveat lector: I wrote this post in high school; it’s likely outdated and poorly written.

Conky is a simple system monitor that uses very little ram.

I have 2 conky-rc files: a system monitor and a weather display.

I wrote my system monitor from scratch and my weather display is based on this tutorial.

System Monitor conkyrc

system monitor

# System Monitor
# Stebalien.com
# set to yes if you want Conky to be forked in the background
background no

# Use Xft?
use_xft yes

# Xft font when Xft is enabled
xftfont Bitstream Vera Sans Mono:size=8

# Text alpha when using Xft
xftalpha 0.8

# Update interval in seconds
update_interval 5.0

# This is the number of times Conky will update before quitting.
# Set to zero to run forever.
total_run_times 0

# Create own window instead of using desktop (required in nautilus)
own_window yes

# If own_window is yes, you may use type normal, desktop or override
own_window_type override

# Use pseudo transparency with own_window?
own_window_transparent yes

# If own_window_transparent is set to no, you can set the background colour here
own_window_colour black

# If own_window is yes, these window manager hints may be used
#own_window_hints undecorated,below,sticky,skip_taskbar,skip_pager

# Use double buffering (reduces flicker, may not work for everyone)
double_buffer yes

# Minimum size of text area
minimum_size 280 5

# Draw shades?
draw_shades yes

# Draw outlines?
draw_outline no

# Draw borders around text
draw_borders no

# Draw borders around graphs
draw_graph_borders yes

# Stippled borders?
stippled_borders 8

# border margins
border_margin 4

# border width
border_width 1

# Default colors and also border colors
default_color white
default_shade_color black
default_outline_color black

# Text alignment, other possible values are commented
#alignment top_left
#alignment top_right
alignment bottom_left
#alignment bottom_right
#alignment none

# Gap between borders of screen and text
# same thing as passing -x at command line
gap_x 12
gap_y 12

# Subtract file system buffers from used memory?
no_buffers yes

# set to yes if you want all text to be in uppercase
uppercase no

# number of cpu samples to average
# set to 1 to disable averaging
cpu_avg_samples 2

# number of net samples to average
# set to 1 to disable averaging
net_avg_samples 2

# Force UTF8? note that UTF8 support required XFT
override_utf8_locale no

# Add spaces to keep things from moving about?  This only affects certain objects.
use_spacer no

color1 SteelBlue4
TEXT
${color1}${tcp_portmon 50005 50005 lservice 0}          ${color green}${tcp_portmon 50005 50005 rip 0}
${color1}Drives:      ${color lightgrey}Lin:${color}${fs_used_perc /}% | ${color lightgrey}Home:${color}${fs_used_perc /home}% | ${color lightgrey}Ext:${color}${fs_used_perc /media/ext}%
${color1}Network:     ${color lightgrey}Down:$color${downspeed ath0} k/s | ${color lightgrey}Up:$color${upspeed ath0} k/s
${color1}System:      ${color lightgrey}CPU:$color$cpu% | ${color lightgrey}RAM:$color$memperc% | ${color lightgrey}SWAP:$color$swapperc%

Replace ath0 with the name of your network interface.

Weather Display conkyrc

weather panel

# Weather display
# Stebalien.com
# set to yes if you want Conky to be forked in the background
background no

# Use Xft?
use_xft yes

# Xft font when Xft is enabled
#xftfont Bitstream Vera Sans Mono:size=8
#xftfont Terminus:size=8
xftfont Liberation Sans:size=8

# Text alpha when using Xft
xftalpha 0.8

# Print everything to console?
# out_to_console no

# mail spool
#mail_spool $MAIL

# Update interval in seconds
update_interval 5.0

# This is the number of times Conky will update before quitting.
# Set to zero to run forever.
total_run_times 0

# Create own window instead of using desktop (required in nautilus)
own_window no

# Use double buffering (reduces flicker, may not work for everyone)
double_buffer yes

# Minimum size of text area
minimum_size 100 5
maximum_width 600

# Draw shades?
draw_shades no

# Draw outlines?
draw_outline no

# Draw borders around text
draw_borders no
draw_graph_borders yes

# Stippled borders?
stippled_borders 8

# border margins
border_margin 4

# border width
border_width 1

# Default colors and also border colors
default_color white
default_shade_color black
default_outline_color white

# own window options
own_window  yes
own_window_transparent yes
own_window_type  override
own_window_hints undecorated,below,sticky,skip_taskbar,skip_pager

# Text alignment, other possible values are commented
#alignment top_left
#alignment top_right
#alignment bottom_left
alignment bottom_right

# Gap between borders of screen and text
# same thing as passing -x at command line
gap_x 10
gap_y -10

# Subtract file system buffers from used memory?
no_buffers yes

# set to yes if you want all text to be in uppercase
uppercase no

# number of cpu samples to average
# set to 1 to disable averaging
cpu_avg_samples 2

# number of net samples to average
# set to 1 to disable averaging
net_avg_samples 2

# Force UTF8? note that UTF8 support required XFT
override_utf8_locale yes

# Add spaces to keep things from moving about?  This only affects certain objects.
use_spacer yes

# colors
color1 white
# light blue
color2 6892C6
# orange
color3 E77320
# green
color4 78BF39
# red
color5 CC0000
# Steel blue
color6 SteelBlue4

# variable is given either in format $variable or in ${variable}. Latter
# allows characters right after the variable and must be used in network
# stuff because of an argument

# stuff after 'TEXT' will be formatted on screen

TEXT
$color6${hr 1}
 ${voffset -2}Now:
${voffset -6}${hr 1}
   ${voffset -8}$color${font weather:size=64}${execi 3600 python ~/.conky/conkyForecast.py --location=USCA0638 --datatype=WF}${font}
                     ${voffset -66}Conditions: ${execi 3600 python ~/.conky/conkyForecast.py --location=USCA0638 --datatype=CC}
                     Temp: ${execi 3600 python ~/.conky/conkyForecast.py -i --location=USCA0638 --datatype=HT}
                     Wind: ${execi 3600 python ~/.conky/conkyForecast.py -i --location=USCA0638 --datatype=WS} ${execi 3600 python ~/.conky/conkyForecast.py --location=USCA0638 --datatype=WD}
                     Humidity: ${execi 3600 python ~/.conky/conkyForecast.py --location=USCA0638 --datatype=HM}
${voffset -4}$color6${hr 1}
  ${voffset -2}${execi 3600 python ~/.conky/conkyForecast.py --location=USCA0638 --datatype=DW --shortweekday --startday=0 --spaces=9 --endday=4}
${voffset -6}${hr 1}
$color${voffset 4}${font weather:size=24}${execi 3600 python ~/.conky/conkyForecast.py --location=USCA0638 --datatype=WF --startday=0 --endday=4 --spaces=1}${font}
          ${font Liberation Sans:size=6}${voffset -36}${execi 3600 python ~/.conky/conkyForecast.py -i --location=USCA0638 --datatype=HT --startday=0 --endday=4 --spaces=18}
               ${execi 3600 python ~/.conky/conkyForecast.py -i --location=USCA0638 --datatype=LT --startday=0 --endday=4 --spaces=17}
               ${execi 3600 python ~/.conky/conkyForecast.py --location=USCA0638 --datatype=PC --startday=0 --endday=4 --spaces=19}

Replace ~/.conky/conkyForecast.py with the location of your weather script. Replace USCA0638 with your city code (see the tutorial link at the beginning of this post).

Conky weather script

#!/usr/bin/python
# -*- coding: utf-8 -*-
###############################################################################
# conkyForecast.py is a (not so) simple (anymore) python script to gather
# details of the current weather for use in conky.
#
#  Author: Kaivalagi
# Created: 13/04/2008
# Modifications:
# 14/04/2008 Allow day ranges for forecast data
# 14/04/2008 Check for connectivity to xoap service
# 18/04/2008 Allow the setting of spaces for ranged output
# 18/04/2008 Allow Night and Day forecast output
# 18/04/2008 Support locale for condition code text "CC" option, awaiting spanish language translation
# 18/04/2008 Use pickling for class data rather than opening xml, this bypasses the need to interrogate cached data
# 19/04/2008 Added spanish condition text - Thanks Bruce M
# 19/04/2008 Added isnumeric check on all numeric output with units suffix
# 19/04/2008 Altered pickle file naming to include location code
# 19/04/2008 Added spanish week days conversion via locale
# 20/04/2008 Added decent command argument parser
# 20/04/2008 Added --shortweekday option, if given the day of week data type is shortened to 3 characters
# 21/04/2008 Fixed locale options for forecast output
# 21/04/2008 Added --template option to allow custom output using a single exec call :)
# 21/04/2008 Added --hideunits option to remove, for example, mph and C from output
# 23/04/2008 Removed --imperial option from template, this MUST be set as a standard option on the script call and not used in the template file.
# 23/04/2008 Readded --imperial option to template, enabling metric or imperial values per datatype. Note when using templates command line option will not work.
# 23/04/2008 Added output notifying user if the location given is bad
# 24/04/2008 Added handling for no connectivity, will revert to cached data now (erroring if no cache exists). Tests by trying to open xoap.weather.com
# 24/04/2008 Fixed Celsius to fahrenheit conversion
# 06/05/2008 Updated url used after webservice was updated
# 09/05/2008 Consolidated current condition and forecast data fetch into one call
# 09/05/2008 Added Sunrise and sunset to datatypes, these are specific to both current conditions and forecast data
# 09/05/2008 Added moon phase, barometer reading and barometer description to datatypes, these are only specific to current conditions and so are N/A in forecasted output
# 09/05/2008 Added unit conversions for barometer from mb to inches (imperial)
#   09/05/2008  Updated spanish condition text - Thanks Bruce M
#   10/05/2008  Added french locale data - Thanks benpaka
#   12/05/2008  Added new BF (bearing font) datatype to provide an arrow character (use with Arrow.ttf font) instead of NSEW output from WD (wind direction)
#   12/05/2008  Updated WD output to be locale specific, currently supports default english and spanish - Thanks Bruce M
# 18/05/2008 Added new MF (moon font) datatype to provide a moon font character (characters incorrect and no dedicated font yet).
# 21/05/2008 For current conditions the --datatype=LT option now displays "feels like" temperature rather than the current temperature
#
# TODO:
# Consolidate pkl files into one file/class
# Add a weather font based moon phase output based on moon icon data
# ??? Any more requirements out there?

import sys, os, socket, urllib2, datetime, time
from xml.dom import minidom
from stat import *
from optparse import OptionParser
import locale
import gettext
import pickle
from math import *

APP="conkyForecast.py"
DIR=os.path.dirname (__file__) + '/locale'
gettext.bindtextdomain(APP, DIR)
gettext.textdomain(APP)
_ = gettext.gettext

class CommandLineParser:

    parser = None

    def __init__(self):

        self.parser = OptionParser()
        self.parser.add_option("-l","--location", dest="location", default="UKXX0103", type="string", metavar="CODE", help=u"location code for weather data [default: %default],Use the following url to determine your location code by city name: http://xoap.weather.com/search/search?where=Norwich")
        self.parser.add_option("-d","--datatype",dest="datatype", default="HT", type="string", metavar="DATATYPE", help=u"[default: %default] The data type options are: DW (Day Of Week), WF (Weather Font Output), LT (Forecast:Low Temp,Current:Feels Like Temp), HT (Forecast:High Temp,Current:Current Temp), CC (Current Conditions), CT (Conditions Text), PC (Precipitation Chance), HM (Humidity), WD (Wind Direction), WS (Wind Speed), WG (Wind Gusts), CN (City Name), SR (sunrise), SS (sunset), MP (moon phase), MF (moon font), BR (barometer reading), BD (barometer description). Not applicable at command line when using templates.")
        self.parser.add_option("-s","--startday",dest="startday", type="int", metavar="NUMBER", help=u"define the starting day number, if omitted current conditions are output. Not applicable at command line when using templates.")
        self.parser.add_option("-e","--endday",dest="endday", type="int", metavar="NUMBER", help=u"define the ending day number, if omitted only starting day data is output. Not applicable at command line when using templates.")
        self.parser.add_option("-S","--spaces",dest="spaces", type="int", default=1, metavar="NUMBER", help=u"[default: %default] Define the number of spaces between ranged output. Not applicable at command line when using templates.")
        self.parser.add_option("-t","--template",dest="template", type="string", metavar="FILE", help=u"define a template file to generate output in one call. A displayable item in the file is in the form {--datatype=HT --startday=1}. The following are possible options within each item: --datatype,--startday,--endday,--night,--shortweekday,--imperial,--hideunits,--spaces . Note that the short forms of the options are not currently supported! None of these options are applicable at command line when using templates.")
        self.parser.add_option("-L","--locale",dest="locale", type="string", help=u"override the system locale for language output (en=english, es=spanish, fr=french, more to come)")
        self.parser.add_option("-i","--imperial",dest="imperial", default=False, action="store_true", help=u"request imperial units, if omitted output is in metric. Not applicable at command line when using templates.")
        self.parser.add_option("-n","--night",dest="night", default=False, action="store_true", help=u"switch output to night data, if omitted day output will be output. Not applicable at command line when using templates.")
        self.parser.add_option("-w","--shortweekday",dest="shortweekday", default=False, action="store_true", help=u"Shorten the day of week data type to 3 characters. Not applicable at command line when using templates.")
        self.parser.add_option("-u","--hideunits",dest="hideunits", default=False, action="store_true", help=u"Hide units such as mph or C, degree symbols (°) are still shown. Not applicable at command line when using templates.")
        self.parser.add_option("-v","--verbose",dest="verbose", default=False, action="store_true", help=u"request verbose output, no a good idea when running through conky!")
        self.parser.add_option("-r","--refetch",dest="refetch", default=False, action="store_true", help=u"fetch data regardless of data expiry")

    def parse_args(self):
        (options, args) = self.parser.parse_args()
        return (options, args)

    def print_help(self):
        return self.parser.print_help()

class WeatherData:
    def __init__(self, day_of_week, low, high, condition_code, condition_text, precip, humidity, wind_dir, wind_speed, wind_gusts, city, sunrise, sunset, moon_phase, moon_icon, bar_read, bar_desc):
        self.day_of_week = u""+day_of_week
        self.low = u""+low
        self.high = u""+high
        self.condition_code = u""+condition_code
        self.condition_text = u""+condition_text
        self.precip = u""+precip
        self.humidity = u""+humidity
        self.wind_dir = u""+wind_dir
        self.wind_speed = u""+wind_speed
        self.wind_gusts = u""+wind_gusts
        self.city = u""+city
        self.sunrise = u""+sunrise
        self.sunset = u""+sunset
        self.moon_phase = u""+moon_phase
        self.moon_icon = u""+moon_icon
        self.bar_read = u""+bar_read
        self.bar_desc = u""+bar_desc


class WeatherText:

    conditions_text = {
        "0": _(u"Tornado"),
        "1": _(u"Tropical Storm"),
        "2": _(u"Hurricane"),
        "3": _(u"Severe Thunderstorms"),
        "4": _(u"Thunderstorms"),
        "5": _(u"Mixed Rain and Snow"),
        "6": _(u"Mixed Rain and Sleet"),
        "7": _(u"Mixed Precipitation"),
        "8": _(u"Freezing Drizzle"),
        "9": _(u"Drizzle"),
        "10": _(u"Freezing Rain"),
        "11": _(u"Showers"),
        "12": _(u"Showers"),
        "13": _(u"Snow Flurries"),
        "14": _(u"Light Snow Showers"),
        "15": _(u"Blowing Snow"),
        "16": _(u"Snow"),
        "17": _(u"Hail"),
        "18": _(u"Sleet"),
        "19": _(u"Dust"),
        "20": _(u"Fog"),
        "21": _(u"Haze"),
        "22": _(u"Smoke"),
        "23": _(u"Blustery"),
        "24": _(u"Windy"),
        "25": _(u"Cold"),
        "26": _(u"Cloudy"),
        "27": _(u"Mostly Cloudy"),
        "28": _(u"Mostly Cloudy"),
        "29": _(u"Partly Cloudy"),
        "30": _(u"Partly Cloudy"),
        "31": _(u"Clear"),
        "32": _(u"Clear"),
        "33": _(u"Fair"),
        "34": _(u"Fair"),
        "35": _(u"Mixed Rain and Hail"),
        "36": _(u"Hot"),
        "37": _(u"Isolated Thunderstorms"),
        "38": _(u"Scattered Thunderstorms"),
        "39": _(u"Scattered Thunderstorms"),
        "40": _(u"Scattered Showers"),
        "41": _(u"Heavy Snow"),
        "42": _(u"Scattered Snow Showers"),
        "43": _(u"Heavy Snow"),
        "44": _(u"Partly Cloudy"),
        "45": _(u"Thunder Showers"),
        "46": _(u"Snow Showers"),
        "47": _(u"Isolated Thunderstorms"),
        "na": _(u"N/A"),
        "-": _(u"N/A")
    }

    conditions_text_es = {
        "0": _(u"Tornado"),
        "1": _(u"Tormenta Tropical"),
        "2": _(u"Huracá¡n"),
        "3": _(u"Tormentas Fuertes"),
        "4": _(u"Tormentas"),
        "5": _(u"Lluvia y Nieve Mezclada"),
        "6": _(u"Lluvia y Aguanieve Mezclada"),
        "7": _(u"Aguanieve"),
        "8": _(u"Llovizna Helada"),
        "9": _(u"Llovizna"),
        "10": _(u"Lluvia Engelante"), # o lluvia helada
        "11": _(u"Chaparrones"),
        "12": _(u"Chaparrones"),
        "13": _(u"Nieve Ligera"),
        "14": _(u"Nieve Ligera"),
        "15": _(u"Ventisca de Nieve"),
        "16": _(u"Nieve"),
        "17": _(u"Granizo"),
        "18": _(u"Aguanieve"),
        "19": _(u"Polvo"),
        "20": _(u"Niebla"),
        "21": _(u"Bruma"),
        "22": _(u"Humo"),
        "23": _(u"Tempestad"),
        "24": _(u"Ventoso"),
        "25": _(u"Fráo"),
        "26": _(u"Muy Nublado"),
        "27": _(u"Principalmente Nublado"),
        "28": _(u"Principalmente Nublado"),
        "29": _(u"Parcialmente Nublado"),
        "30": _(u"Parcialmente Nublado"),
        "31": _(u"Despejado"),
        "32": _(u"Despejado"),
        "33": _(u"Algo Nublado"),
        "34": _(u"Algo Nublado"),
        "35": _(u"Lluvia con Granizo"),
        "36": _(u"Calor"),
        "37": _(u"Tormentas Aisladas"),
        "38": _(u"Tormentas Dispersas"),
        "39": _(u"Tormentas Dispersas"),
        "40": _(u"Chubascos Dispersos"),
        "41": _(u"Nieve Pesada"),
        "42": _(u"Nevadas Débiles y Dispersas"),
        "43": _(u"Nevada Intensa"),
        "44": _(u"Nubes Dispersas"),
        "45": _(u"Tormentas"),
        "46": _(u"Nevadas Dispersas"),
        "47": _(u"Tormentas Aisladas"),
        "na": _(u"N/A"),
        "-": _(u"N/A")
    }

    conditions_text_fr = {
        "0": _(u"Tornade"),
        "1": _(u"Tempête Tropicale"),
        "2": _(u"Ouragan"),
        "3": _(u"Orages Violents"),
        "4": _(u"Orageux"),
        "5": _(u"Pluie et Neige"),
        "6": _(u"Pluie et Neige Mouillée"),
        "7": _(u"Variable avec averses"),
        "8": _(u"Bruine Givrante"),
        "9": _(u"Bruine"),
        "10": _(u"Pluie Glacante"),
        "11": _(u"Averses"),
        "12": _(u"Averses"),
        "13": _(u"Légère Neige"),
        "14": _(u"Forte Neige"),
        "15": _(u"Tempête de Neige"),
        "16": _(u"Neige"),
        "17": _(u"Grêle"),
        "18": _(u"Pluie/Neige"),
        "19": _(u"Nuage de poussière"),
        "20": _(u"Brouillard"),
        "21": _(u"Brume"),
        "22": _(u"Fumée"),
        "23": _(u"Tres Venteux"),
        "24": _(u"Venteux"),
        "25": _(u"Froid"),
        "26": _(u"Nuageux"),
        "27": _(u"Tres Nuageux"),
        "28": _(u"Tres Nuageux"),
        "29": _(u"Nuages Disséminés"),
        "30": _(u"Nuages Disséminés"),
        "31": _(u"Beau"),
        "32": _(u"Beau"),
        "33": _(u"Belles Éclaircies"),
        "34": _(u"Belles Éclaircies"),
        "35": _(u"Pluie avec Grêle"),
        "36": _(u"Chaleur"),
        "37": _(u"Orages Isolés"),
        "38": _(u"Orages Localisés"),
        "39": _(u"Orages Localisés"),
        "40": _(u"Averses Localisées"),
        "41": _(u"Neige Lourde"),
        "42": _(u"Tempête de Neige Localisées"),
        "43": _(u"Neige Lourde"),
        "44": _(u"Nuages Disséminés"),
        "45": _(u"Orages"),
        "46": _(u"Tempête de Neige"),
        "47": _(u"Orages Isolés"),
        "na": _(u"N/A"),
        "-": _(u"N/A")
    }

    conditions_weather_font = {
        "0": _(u"W"),
        "1": _(u"V"),
        "2": _(u"W"),
        "3": _(u"s"),
        "4": _(u"p"),
        "5": _(u"k"),
        "6": _(u"k"),
        "7": _(u"g"),
        "8": _(u"g"),
        "9": _(u"g"),
        "10": _(u"h"),
        "11": _(u"g"),
        "12": _(u"g"),
        "13": _(u"k"),
        "14": _(u"k"),
        "15": _(u"k"),
        "16": _(u"k"),
        "17": _(u"k"),
        "18": _(u"k"),
        "19": _(u"e"),
        "20": _(u"e"),
        "21": _(u"a"),
        "22": _(u"d"),
        "23": _(u"d"),
        "24": _(u"d"),
        "25": _(u"d"),
        "26": _(u"e"),
        "27": _(u"e"),
        "28": _(u"e"),
        "29": _(u"c"),
        "30": _(u"c"),
        "31": _(u"a"),
        "32": _(u"a"),
        "33": _(u"b"),
        "34": _(u"b"),
        "35": _(u"k"),
        "36": _(u"a"),
        "37": _(u"f"),
        "38": _(u"f"),
        "39": _(u"f"),
        "40": _(u"g"),
        "41": _(u"k"),
        "42": _(u"k"),
        "43": _(u"k"),
        "44": _(u"b"),
        "45": _(u"g"),
        "46": _(u"k"),
        "47": _(u"f"),
        "na": _(u""),
        "-": _(u"")
    }

    conditions_moon_font = {
        "0": _(u"0"),
        "1": _(u"1"),
        "2": _(u"2"),
        "3": _(u"3"),
        "4": _(u"4"),
        "5": _(u"5"),
        "6": _(u"6"),
        "7": _(u"7"),
        "8": _(u"8"),
        "9": _(u"9"),
        "10": _(u"10"),
        "11": _(u"11"),
        "12": _(u"12"),
        "13": _(u"13"),
        "14": _(u"14"),
        "15": _(u"15"),
        "16": _(u"16"),
        "17": _(u"17"),
        "18": _(u"18"),
        "19": _(u"19"),
        "20": _(u"20"),
        "21": _(u"21"),
        "22": _(u"22"),
        "23": _(u"23"),
        "24": _(u"24"),
        "25": _(u"25"),
        "na": _(u""),
        "-": _(u"")
    }

    day_of_week = {
        "Today": _(u"Today"),
        "Monday": _(u"Monday"),
        "Tuesday": _(u"Tuesday"),
        "Wednesday": _(u"Wednesday"),
        "Thursday": _(u"Thursday"),
        "Friday": _(u"Friday"),
        "Saturday": _(u"Saturday"),
        "Sunday": _(u"Sunday")
    }

    day_of_week_short = {
        "Today": _(u"Now"),
        "Monday": _(u"Mon"),
        "Tuesday": _(u"Tue"),
        "Wednesday": _(u"Wed"),
        "Thursday": _(u"Thu"),
        "Friday": _(u"Fri"),
        "Saturday": _(u"Sat"),
        "Sunday": _(u"Sun")
    }

    day_of_week_es = {
        "Today": _(u"hoy"),
        "Monday": _(u"lunes"),
        "Tuesday": _(u"martes"),
        "Wednesday": _(u"miércoles"),
        "Thursday": _(u"jueves"),
        "Friday": _(u"viernes"),
        "Saturday": _(u"sábado"),
        "Sunday": _(u"domingo")
    }

    day_of_week_short_es = {
        "Today": _(u"hoy"),
        "Monday": _(u"lun"),
        "Tuesday": _(u"mar"),
        "Wednesday": _(u"mié"),
        "Thursday": _(u"jue"),
        "Friday": _(u"vie"),
        "Saturday": _(u"sáb"),
        "Sunday": _(u"dom")
    }

    day_of_week_fr = {
        "Today": _(u"Aujourd'hui"),
        "Monday": _(u"Lundi"),
        "Tuesday": _(u"Mardi"),
        "Wednesday": _(u"Mercredi"),
        "Thursday": _(u"Jeudi"),
        "Friday": _(u"Vendredi"),
        "Saturday": _(u"Samedi"),
        "Sunday": _(u"Dimanche")
    }

    day_of_week_short_fr = {
        "Today": _(u"Auj"),
        "Monday": _(u"Lun"),
        "Tuesday": _(u"Mar"),
        "Wednesday": _(u"Mer"),
        "Thursday": _(u"Jeu"),
        "Friday": _(u"Ven"),
        "Saturday": _(u"Sam"),
        "Sunday": _(u"Dim")
    }

    bearing_arrow_font = {
        "N": _(u"i"),
        "NNE": _(u"j"),
        "NE": _(u"k"),
        "ENE": _(u"l"),
        "E": _(u"m"),
        "ESE": _(u"n"),
        "SE": _(u"o"),
        "SSE": _(u"p"),
        "S": _(u"a"),
        "SSW": _(u"b"),
        "SW": _(u"c"),
        "WSW": _(u"d"),
        "W": _(u"e"),
        "WNW": _(u"f"),
        "NW": _(u"g"),
        "NNW": _(u"h"),
        "N/A": _(u" ")
    }

    bearing_text_es = {
        "N": _(u"N"),
        "NNE": _(u"NNE"),
        "NE": _(u"NE"),
        "ENE": _(u"ENE"),
        "E": _(u"E"),
        "ESE": _(u"ESE"),
        "SE": _(u"SE"),
        "SSE": _(u"SSE"),
        "S": _(u"S"),
        "SSW": _(u"SSO"),
        "SW": _(u"SO"),
        "WSW": _(u"WOW"),
        "W": _(u"O"),
        "WNW": _(u"ONO"),
        "NW": _(u"NO"),
        "NNW": _(u"NNO"),
        "N/A": _(u"N\A")
    }

    bearing_text_fr = {
        "N": _(u"N"),
        "NNE": _(u"NNE"),
        "NE": _(u"NE"),
        "ENE": _(u"ENE"),
        "E": _(u"E"),
        "ESE": _(u"ESE"),
        "SE": _(u"SE"),
        "SSE": _(u"SSE"),
        "S": _(u"S"),
        "SSW": _(u"SSO"),
        "SW": _(u"SO"),
        "WSW": _(u"WOW"),
        "W": _(u"O"),
        "WNW": _(u"ONO"),
        "NW": _(u"NO"),
        "NNW": _(u"NNO"),
        "N/A": _(u"N\A")
    }

class GlobalWeather:

    current_conditions = []
    day_forecast = []
    night_forecast = []

    locale = "en"

    options = None
    weatherxmldoc = ""

        TEMP_FILEPATH_CURRENT = "/tmp/conkyForecast-c-LOCATION.pkl"
    TEMP_FILEPATH_DAYFORECAST = "/tmp/conkyForecast-df-LOCATION.pkl"
    TEMP_FILEPATH_NIGHTFORECAST = "/tmp/conkyForecast-nf-LOCATION.pkl"
        EXPIRY_MINUTES = 30
    DEFAULT_SPACING = u" "


    def __init__(self,options):

        self.options = options

        if self.options.locale == None:
            try:
                self.locale = locale.getdefaultlocale()[0][0:2]
                #self.locale = "es" #uncomment this line to force Spanish locale
                #self.locale = "fr" #uncomment this line to force French locale
            except:
                print "locale not set"
        else:
            self.locale = self.options.locale
            #self.locale = "es" #uncomment this line to force Spanish locale
            #self.locale = "fr" #uncomment this line to force French locale

        if self.options.verbose == True:
            print >> sys.stdout, "locale set to ",self.locale

    def getText(self,nodelist):
        rc = ""
        for node in nodelist:
            if node.nodeType == node.TEXT_NODE:
                rc = rc + node.data
        return rc


    def getSpaces(self,spaces):
        string = u""
        if spaces == None:
            string = self.DEFAULT_SPACING
        else:
            for i in range(0, spaces+1):
                string = string + u" "
        return string


    def isNumeric(self,string):
        try:
            dummy = float(string)
            return True
        except:
            return False

    def isConnectionAvailable(self):
        # ensure we can access weather.com's server by opening the url
        try:
            usock = urllib2.urlopen('http://xoap.weather.com')
            usock.close()
            return True
        except:
            return False

    def getBearingText(self,bearing):
        bearing = float(bearing)
        if bearing  11.25:
            return u"N"
        elif bearing  33.75:
            return u"NNE"
        elif bearing  56.25:
            return u"NE"
        elif bearing  78.75:
            return u"ENE"
        elif bearing  101.25:
            return u"E"
        elif bearing  123.75:
            return u"ESE"
        elif bearing  146.25:
            return u"SE"
        elif bearing  168.75:
            return u"SSE"
        elif bearing  191.25:
            return u"S"
        elif bearing  213.75:
            return u"SSW"
        elif bearing  236.25:
            return u"SW"
        elif bearing  258.75:
            return u"WSW"
        elif bearing  281.25:
            return u"W"
        elif bearing  303.75:
            return u"WNW"
        elif bearing  326.25:
            return u"NW"
        elif bearing  348.75:
            return u"NNW"
        else:
            return "N/A"

    def convertCelsiusToFahrenheit(self,temp):
        return str(int(floor(((float(temp)*9.0)/5.0)+32)))

    def convertKilometresToMiles(self,dist):
        return str(int(floor(float(dist)*0.621371192)))

    def convertMillibarsToInches(self,mb):
        return str(int(floor(float(mb)/33.8582)))

    def getTemplateList(self,template):

    templatelist = []

    for template_part in template.split("{"):
            if template_part != "":
                for template_part in template_part.split("}"):
                    if template_part != "":
                        templatelist.append(u""+template_part)

        return templatelist


    def getOutputText(self,datatype,startday,endday,night,shortweekday,imperial,hideunits,spaces):
        #try:
            output = u""

            # define current units for output
            if hideunits == False:
                if imperial == False:
                    tempunit = u"°C"
                    speedunit = u"kph"
                    pressureunit = u"mb"
                else:
                    tempunit = u"°F"
                    speedunit = u"mph"
                    pressureunit = u"in"
            else:
                tempunit = u"°"
                speedunit = u""
                pressureunit = u""

            if startday == None: # current conditions

                if datatype == "DW":
                    if self.locale == "es":
                        if shortweekday == True:
                            output = WeatherText.day_of_week_short_es[self.current_conditions[0].day_of_week]
                        else:
                            output = WeatherText.day_of_week_es[self.current_conditions[0].day_of_week]
                    elif self.locale == "fr":
                        if shortweekday == True:
                            output = WeatherText.day_of_week_short_fr[self.current_conditions[0].day_of_week]
                        else:
                            output = WeatherText.day_of_week_fr[self.current_conditions[0].day_of_week]
                    else:
                        if shortweekday == True:
                            output = WeatherText.day_of_week_short[self.current_conditions[0].day_of_week]
                        else:
                            output = WeatherText.day_of_week[self.current_conditions[0].day_of_week]
                elif datatype == "WF": # weather font
                    output = WeatherText.conditions_weather_font[self.current_conditions[0].condition_code]
                elif datatype == "LT":
                    string = self.current_conditions[0].low
                    if self.isNumeric(string) == True:
                        if imperial == True:
                            string = self.convertCelsiusToFahrenheit(string)
                        string = string + tempunit
                    output = string
                elif datatype == "HT":
                    string = self.current_conditions[0].high
                    if self.isNumeric(string) == True:
                        if imperial == True:
                            string = self.convertCelsiusToFahrenheit(string)
                        string = string + tempunit
                    output = string
                elif datatype == "CC":
                    if self.locale == "es":
                        output = WeatherText.conditions_text_es[self.current_conditions[0].condition_code]
                    elif self.locale == "fr":
                        output = WeatherText.conditions_text_fr[self.current_conditions[0].condition_code]
                    else:
                        output = WeatherText.conditions_text[self.current_conditions[0].condition_code]
                elif datatype == "CT":
                    output = self.current_conditions[0].condition_text
                elif datatype == "PC":
                    string = self.current_conditions[0].precip
                    if self.isNumeric(string) == True:
                        string = string + u"%"
                    output = string
                elif datatype == "HM":
                    string = self.current_conditions[0].humidity
                    if self.isNumeric(string) == True:
                        string = string + u"%"
                    output = string
                elif datatype == "WD":
                    string = self.current_conditions[0].wind_dir
                    if self.isNumeric(string) == True:
                        string = self.getBearingText(string)

                    if self.locale == "es":
                        output = WeatherText.bearing_text_es[string]
                    elif self.locale == "fr":
                        output = WeatherText.bearing_text_fr[string]
                    else:
                        output = string

                elif datatype == "BF":
                    string = self.current_conditions[0].wind_dir
                    if self.isNumeric(string) == True:
                        string = WeatherText.bearing_arrow_font[self.getBearingText(string)]
                    output = string
                elif datatype == "WS":
                    string = self.current_conditions[0].wind_speed
                    if self.isNumeric(string) == True:
                        if imperial == True:
                            string = self.convertKilometresToMiles(string)
                        string = string + speedunit
                    output = string
                elif datatype == "WG":
                    string = self.current_conditions[0].wind_gusts
                    if self.isNumeric(string) == True:
                        if imperial == True:
                            string = self.convertKilometresToMiles(string)
                        string = string + speedunit
                    output = string
                elif datatype == "CN":
                    output = self.current_conditions[0].city
                elif datatype == "SR":
                    output = self.current_conditions[0].sunrise
                elif datatype == "SS":
                    output = self.current_conditions[0].sunset
                elif datatype == "MP":
                    output = self.current_conditions[0].moon_phase
                elif datatype == "MF":
                    output = WeatherText.conditions_moon_font[self.current_conditions[0].moon_icon]
                elif datatype == "BR":
                    string = self.current_conditions[0].bar_read
                    if self.isNumeric(string) == True:
                        if imperial == True:
                            string = self.convertMillibarsToInches(string)
                        string = string + pressureunit
                    output = string
                elif datatype == "BD":
                    output = self.current_conditions[0].bar_desc
                else:
                    output = "\nERROR:Unknown data type requested"

            else: # forecast data

                if endday == None: # if no endday was set use startday
                    endday = startday

                if night == True: # night forecast required

                    for day_number in range(startday, endday+1):

                        if datatype == "DW":
                            if self.locale == "es":
                                if shortweekday == True:
                                    output = output + self.getSpaces(spaces) + WeatherText.day_of_week_short_es[self.night_forecast[day_number].day_of_week]
                                else:
                                    output = output + self.getSpaces(spaces) + WeatherText.day_of_week_es[self.night_forecast[day_number].day_of_week]
                            elif self.locale == "fr":
                                if shortweekday == True:
                                    output = output + self.getSpaces(spaces) + WeatherText.day_of_week_short_fr[self.night_forecast[day_number].day_of_week]
                                else:
                                    output = output + self.getSpaces(spaces) + WeatherText.day_of_week_fr[self.night_forecast[day_number].day_of_week]
                            else:
                                if shortweekday == True:
                                    output = output + self.getSpaces(spaces) + WeatherText.day_of_week_short[self.night_forecast[day_number].day_of_week]
                                else:
                                    output = output + self.getSpaces(spaces) + WeatherText.day_of_week[self.night_forecast[day_number].day_of_week]
                        elif datatype == "WF": # weather font
                            output = output + self.getSpaces(spaces) + WeatherText.conditions_weather_font[self.night_forecast[day_number].condition_code]
                        elif datatype == "LT":
                            string = self.night_forecast[day_number].low
                            if self.isNumeric(string) == True:
                                if imperial == True:
                                    string = self.convertCelsiusToFahrenheit(string)
                                string = string + tempunit
                            output = output + self.getSpaces(spaces) + string

                        elif datatype == "HT":
                            string = self.night_forecast[day_number].high
                            if self.isNumeric(string) == True:
                                if imperial == True:
                                    string = self.convertCelsiusToFahrenheit(string)
                                string = string + tempunit
                            output = output + self.getSpaces(spaces) + string
                        elif datatype == "CC":
                            if self.locale == "es":
                                output = output + self.getSpaces(spaces) + WeatherText.conditions_text_es[self.night_forecast[day_number].condition_code]
                            elif self.locale == "fr":
                                output = output + self.getSpaces(spaces) + WeatherText.conditions_text_fr[self.night_forecast[day_number].condition_code]
                            else:
                                output = output + self.getSpaces(spaces) + WeatherText.conditions_text[self.night_forecast[day_number].condition_code]
                        elif datatype == "CT":
                            output = output + self.getSpaces(spaces) + self.night_forecast[day_number].condition_text
                        elif datatype == "PC":
                            string = self.night_forecast[day_number].precip
                            if self.isNumeric(string) == True:
                                string = string + u"%"
                            output = output + self.getSpaces(spaces) + string
                        elif datatype == "HM":
                            string = self.night_forecast[day_number].humidity
                            if self.isNumeric(string) == True:
                                string = string + u"%"
                            output = output + self.getSpaces(spaces) + string
                        elif datatype == "WD":
                            string = self.night_forecast[day_number].wind_dir
                            if self.locale == "es":
                                output = output + self.getSpaces(spaces) + WeatherText.bearing_text_es[string]
                            elif self.locale == "fr":
                                output = output + self.getSpaces(spaces) + WeatherText.bearing_text_fr[string]
                            else:
                                output = output + self.getSpaces(spaces) + string

                        elif datatype == "BF":
                            output = output + self.getSpaces(spaces) + WeatherText.bearing_arrow_font[self.night_forecast[day_number].wind_dir]
                        elif datatype == "WS":
                            string = self.night_forecast[day_number].wind_speed
                            if self.isNumeric(string) == True:
                                if imperial == True:
                                    string = self.convertKilometresToMiles(string)
                                string = string + speedunit
                            output = output + self.getSpaces(spaces) + string
                        elif datatype == "WG":
                            string = self.night_forecast[day_number].wind_gusts
                            if self.isNumeric(string) == True:
                                if imperial == True:
                                    string = self.convertKilometresToMiles(string)
                                string = string + speedunit
                            output = output + self.getSpaces(spaces) + string
                        elif datatype == "CN":
                            output = output + self.getSpaces(spaces) + self.night_forecast[day_number].city
                        elif datatype == "SR":
                            output = output + self.getSpaces(spaces) + self.night_forecast[day_number].sunrise
                        elif datatype == "SS":
                            output = output + self.getSpaces(spaces) + self.night_forecast[day_number].sunset
                        elif datatype == "MP":
                            output = output + self.getSpaces(spaces) + self.night_forecast[day_number].moon_phase
                        elif datatype == "MF":
                            output = output + self.getSpaces(spaces) + WeatherText.conditions_moon_font[self.night_forecast[day_number].moon_icon]
                        elif datatype == "BR":
                            output = output + self.getSpaces(spaces) + self.night_forecast[day_number].bar_read
                        elif datatype == "BD":
                            output = output + self.getSpaces(spaces) + self.night_forecast[day_number].bar_desc
                        else:
                            output = "\nERROR:Unknown data type requested"
                            break

                else: # day forecast wanted

                    for day_number in range(startday, endday+1):

                        if datatype == "DW":
                            if self.locale == "es":
                                if shortweekday == True:
                                    output = output + self.getSpaces(spaces) + WeatherText.day_of_week_short_es[self.day_forecast[day_number].day_of_week]
                                else:
                                    output = output + self.getSpaces(spaces) + WeatherText.day_of_week_es[self.day_forecast[day_number].day_of_week]
                            elif self.locale == "fr":
                                if shortweekday == True:
                                    output = output + self.getSpaces(spaces) + WeatherText.day_of_week_short_fr[self.day_forecast[day_number].day_of_week]
                                else:
                                    output = output + self.getSpaces(spaces) + WeatherText.day_of_week_fr[self.day_forecast[day_number].day_of_week]
                            else:
                                if shortweekday == True:
                                    output = output + self.getSpaces(spaces) + WeatherText.day_of_week_short[self.day_forecast[day_number].day_of_week]
                                else:
                                    output = output + self.getSpaces(spaces) + WeatherText.day_of_week[self.day_forecast[day_number].day_of_week]
                        elif datatype == "WF": # weather font
                            output = output + self.getSpaces(spaces) + WeatherText.conditions_weather_font[self.day_forecast[day_number].condition_code]
                        elif datatype == "LT":
                            string = self.day_forecast[day_number].low
                            if self.isNumeric(string) == True:
                                if imperial == True:
                                    string = self.convertCelsiusToFahrenheit(string)
                                string = string + tempunit
                            output = output + self.getSpaces(spaces) + string
                        elif datatype == "HT":
                            string = self.day_forecast[day_number].high
                            if self.isNumeric(string) == True:
                                if imperial == True:
                                    string = self.convertCelsiusToFahrenheit(string)
                                string = string + tempunit
                            output = output + self.getSpaces(spaces) + string
                        elif datatype == "CC":
                            if self.locale == "es":
                                output = output + self.getSpaces(spaces) + WeatherText.conditions_text_es[self.day_forecast[day_number].condition_code]
                            elif self.locale == "fr":
                                output = output + self.getSpaces(spaces) + WeatherText.conditions_text_fr[self.day_forecast[day_number].condition_code]
                            else:
                                output = output + self.getSpaces(spaces) + WeatherText.conditions_text[self.day_forecast[day_number].condition_code]
                        elif datatype == "CT":
                            output = output + self.getSpaces(spaces) + self.day_forecast[day_number].condition_text
                        elif datatype == "PC":
                            string = self.day_forecast[day_number].precip
                            if self.isNumeric(string) == True:
                                string = string + u"%"
                            output = output + self.getSpaces(spaces) + string
                        elif datatype == "HM":
                            string = self.day_forecast[day_number].humidity
                            if self.isNumeric(string) == True:
                                string = string + u"%"
                            output = output + self.getSpaces(spaces) + string
                        elif datatype == "WD":
                            string = self.day_forecast[day_number].wind_dir

                            if self.locale == "es":
                                output = output + self.getSpaces(spaces) + WeatherText.bearing_text_es[string]
                            elif self.locale == "fr":
                                output = output + self.getSpaces(spaces) + WeatherText.bearing_text_fr[string]
                            else:
                                output = output + self.getSpaces(spaces) + string

                        elif datatype == "BF":
                            output = output + self.getSpaces(spaces) + WeatherText.bearing_arrow_font[self.day_forecast[day_number].wind_dir]
                        elif datatype == "WS":
                            string = self.day_forecast[day_number].wind_speed
                            if self.isNumeric(string) == True:
                                if imperial == True:
                                    string = self.convertKilometresToMiles(string)
                                string = string + speedunit
                            output = output + self.getSpaces(spaces) + string
                        elif datatype == "WG":
                            string = self.day_forecast[day_number].wind_gusts
                            if self.isNumeric(string) == True:
                                if imperial == True:
                                    string = self.convertKilometresToMiles(string)
                                string = string + speedunit
                            output = output + self.getSpaces(spaces) + string
                        elif datatype == "CN":
                            output = output + self.getSpaces(spaces) + self.day_forecast[day_number].city
                        elif datatype == "SR":
                            output = output + self.getSpaces(spaces) + self.day_forecast[day_number].sunrise
                        elif datatype == "SS":
                            output = output + self.getSpaces(spaces) + self.day_forecast[day_number].sunset
                        elif datatype == "MP":
                            output = output + self.getSpaces(spaces) + self.day_forecast[day_number].moon_phase
                        elif datatype == "MF":
                            output = output + self.getSpaces(spaces) + WeatherText.conditions_moon_font[self.day_forecast[day_number].moon_icon]
                        elif datatype == "BR":
                            output = output + self.getSpaces(spaces) + self.day_forecast[day_number].bar_read
                        elif datatype == "BD":
                            output = output + self.getSpaces(spaces) + self.day_forecast[day_number].bar_desc
                        else:
                            output = u"\nERROR:Unknown data type requested"
                            break

            output = u""+output.strip(u" ") # lose leading/trailing spaces
            return output

        #except:
            #print "getOutputText:Unexpected error: ", sys.exc_info()[0]


    def getOutputTextFromTemplate(self,template):
        #try:

            # keys to template data
            DATATYPE_KEY = "--datatype="
            STARTDAY_KEY = "--startday="
            ENDDAY_KEY = "--endday="
            NIGHT_KEY = "--night"
            SHORTWEEKDAY_KEY = "--shortweekday"
            IMPERIAL_KEY = "--imperial"
            HIDEUNITS_KEY = "--hideunits"
            SPACES_KEY = "--spaces="

            output = u""

            optionfound = False

            #load the file
            try:
                fileinput = open(self.options.template)
                template = fileinput.read()
                fileinput.close()
            except:
                output = u"Template file no found!"

            templatelist = self.getTemplateList(template)

            # lets walk through the template list and determine the output for each item found
            for i in range(0,len(templatelist)-1):

                pos = templatelist[i].find(DATATYPE_KEY)
                if pos != -1:
                    optionfound = True
                    pos = pos + len(DATATYPE_KEY)
                    datatype = templatelist[i][pos:pos+4].strip("}").strip("{").strip("-").strip(" ")
                else:
                    datatype = None

                pos = templatelist[i].find(STARTDAY_KEY)
                if pos != -1:
                    optionfound = True
                    pos = pos + len(STARTDAY_KEY)
                    startday = int(templatelist[i][pos:pos+4].strip("}").strip("{").strip("-").strip(" "))
                else:
                    startday = None

                pos = templatelist[i].find(ENDDAY_KEY)
                if pos != -1:
                    optionfound = True
                    pos = pos + len(ENDDAY_KEY)
                    endday = int(templatelist[i][pos:pos+4].strip("}").strip("{").strip("-").strip(" "))
                else:
                    endday = None

                pos = templatelist[i].find(NIGHT_KEY)
                if pos != -1:
                    optionfound = True
                    night = True
                else:
                    night = False

                pos = templatelist[i].find(SHORTWEEKDAY_KEY)
                if pos != -1:
                    optionfound = True
                    shortweekday = True
                else:
                    shortweekday = False

                pos = templatelist[i].find(IMPERIAL_KEY)
                if pos != -1:
                    optionfound = True
                    imperial = True
                else:
                    imperial = False

                pos = templatelist[i].find(HIDEUNITS_KEY)
                if pos != -1:
                    optionfound = True
                    hideunits = True
                else:
                    hideunits = False

                pos = templatelist[i].find(SPACES_KEY)
                if pos != -1:
                    optionfound = True
                    pos = pos + len(SPACES_KEY)
                    spaces = int(templatelist[i][pos:pos+4].strip("}").strip("{").strip("-").strip(" "))
                else:
                    spaces = 1

                if optionfound == True:
                    templatelist[i] = self.getOutputText(datatype,startday,endday,night,shortweekday,imperial,hideunits,spaces)
                    optionfound = False

            # go through the list concatenating the output now that it's been populated
            for item in templatelist:
                output = output + item

            return output

        #except:
            #print "getOutputTextFromTemplate:Unexpected error: ", sys.exc_info()[0]


    def fetchData(self):

        # always fetch metric data, use conversation functions on this data
        file_path_current = self.TEMP_FILEPATH_CURRENT.replace("LOCATION",self.options.location)
        file_path_dayforecast = self.TEMP_FILEPATH_DAYFORECAST.replace("LOCATION",self.options.location)
        file_path_nightforecast = self.TEMP_FILEPATH_NIGHTFORECAST.replace("LOCATION",self.options.location)

        if self.isConnectionAvailable() == False:
            if os.path.exists(file_path_current):
                RefetchData = False
            else: # no connection, no cache, bang!
                print "No internet connection is available and no cached weather data exists."
        elif self.options.refetch == True:
            RefetchData = True
        else:
                # does the data need retrieving again?
                if os.path.exists(file_path_current):
                    lastmodDate = time.localtime(os.stat(file_path_current)[ST_MTIME])
                expiryDate = (datetime.datetime.today() - datetime.timedelta(minutes=self.EXPIRY_MINUTES)).timetuple()

                if expiryDate > lastmodDate:
                    RefetchData = True
                else:
                    RefetchData = False
            else:
                RefetchData = True


                                                                # fetch the current conditions data, either from the website or by 'unpickling'
            if RefetchData == True:

            # obtain current conditions data from xoap service
            try:

                # http://xoap.weather.com/weather/local/UKXX0103?cc=*=5=xoap=xoap=1061785028=e374effbfd74930b

                url = 'http://xoap.weather.com/weather/local/' + self.options.location + '?cc=*=8=xoap=xoap=1061785028=e374effbfd74930b=m'
                if self.options.verbose == True:
                    print >> sys.stdout, "fetching weather data from ",url

                usock = urllib2.urlopen(url)
                xml = usock.read()
                usock.close()
                self.weatherxmldoc = minidom.parseString(xml)
            except:
                print "fetchData:Unexpected error: ", sys.exc_info()[0]
                print "Unable to contact weather source for current conditions"

            # tell the user if the location is bad...
            found = xml.find("Invalid location provided")
            if found != -1:
                print "Invalid location provided"

            # interrogate weather data, load into class structure and pickle it
            try:

                # prepare weather data lists
                self.current_conditions = []
                self.day_forecast = []
                self.night_forecast = []

                # collect general data
                weather_n = self.weatherxmldoc.documentElement
                location_n = weather_n.getElementsByTagName('loc')[0]
                city_n = location_n.getElementsByTagName('dnam')[0]
                city = self.getText(city_n.childNodes)

                # collect current conditions data
                day_of_week = u"Today"
                precip = u"N/A"
                sunrise_n = location_n.getElementsByTagName('sunr')[0]
                sunrise = self.getText(sunrise_n.childNodes)
                sunset_n = location_n.getElementsByTagName('suns')[0]
                sunset = self.getText(sunset_n.childNodes)
                current_condition_n = weather_n.getElementsByTagName('cc')[0]
                current_desc_n = current_condition_n.getElementsByTagName('t')[0]
                current_desc = self.getText(current_desc_n.childNodes)
                current_code_n = current_condition_n.getElementsByTagName('icon')[0]
                current_code = self.getText(current_code_n.childNodes)
                current_temp_n = current_condition_n.getElementsByTagName('tmp')[0]
                current_temp = self.getText(current_temp_n.childNodes)
                current_temp_feels_n = current_condition_n.getElementsByTagName('flik')[0]
                current_temp_feels = self.getText(current_temp_feels_n.childNodes)
                bar_n = current_condition_n.getElementsByTagName('bar')[0]
                bar_read_n = bar_n.getElementsByTagName('r')[0]
                bar_read = self.getText(bar_read_n.childNodes)
                bar_desc_n = bar_n.getElementsByTagName('d')[0]
                bar_desc = self.getText(bar_desc_n.childNodes)
                wind_n = current_condition_n.getElementsByTagName('wind')[0]
                wind_speed_n = wind_n.getElementsByTagName('s')[0]
                wind_speed = self.getText(wind_speed_n.childNodes)
                wind_gust_n = wind_n.getElementsByTagName('gust')[0]
                wind_gusts = self.getText(wind_gust_n.childNodes)
                wind_dir_n = wind_n.getElementsByTagName('d')[0]
                wind_direction = self.getText(wind_dir_n.childNodes)
                humidity_n = current_condition_n.getElementsByTagName('hmid')[0]
                humidity = self.getText(humidity_n.childNodes)
                moon_n = current_condition_n.getElementsByTagName('moon')[0]
                moon_icon_n = moon_n.getElementsByTagName('icon')[0]
                moon_icon = self.getText(moon_icon_n.childNodes)
                moon_phase_n = moon_n.getElementsByTagName('t')[0]
                moon_phase = self.getText(moon_phase_n.childNodes)
                current_conditions_data = WeatherData(day_of_week, current_temp_feels, current_temp, current_code, current_desc, precip, humidity, wind_direction, wind_speed, wind_gusts, city, sunrise, sunset, moon_phase, moon_icon, bar_read, bar_desc)
                self.current_conditions.append(current_conditions_data)

                # collect forecast data
                bar_read = u"N/A"
                bar_desc = u"N/A"
                moon_phase = u"N/A"
                moon_icon = u"na"
                forecast_n = weather_n.getElementsByTagName('dayf')[0]
                day_nodes = forecast_n.getElementsByTagName('day')

                for day in day_nodes:
                    day_of_week = day.getAttribute('t')
                    day_of_year = day.getAttribute('dt')
                    high_temp_n = day.getElementsByTagName('hi')[0]
                    high_temp = self.getText(high_temp_n.childNodes)
                    low_temp_n = day.getElementsByTagName('low')[0]
                    low_temp = self.getText(low_temp_n.childNodes)

                    sunrise_n = day.getElementsByTagName('sunr')[0]
                    sunrise = self.getText(sunrise_n.childNodes)
                    sunset_n = day.getElementsByTagName('suns')[0]
                    sunset = self.getText(sunset_n.childNodes)

                    # day forecast specific data
                    daytime_n = day.getElementsByTagName('part')[0] # day
                    condition_code_n = daytime_n.getElementsByTagName('icon')[0]
                    condition_code = self.getText(condition_code_n.childNodes)
                    condition_n = daytime_n.getElementsByTagName('t')[0]
                    condition = self.getText(condition_n.childNodes)
                    precip_n = daytime_n.getElementsByTagName('ppcp')[0]
                    precip = self.getText(precip_n.childNodes)
                    humidity_n = daytime_n.getElementsByTagName('hmid')[0]
                    humidity = self.getText(humidity_n.childNodes)
                    wind_n = daytime_n.getElementsByTagName('wind')[0]
                    wind_speed_n = wind_n.getElementsByTagName('s')[0]
                    wind_speed = self.getText(wind_speed_n.childNodes)
                    wind_direction_n = wind_n.getElementsByTagName('t')[0]
                    wind_direction = self.getText(wind_direction_n.childNodes)
                    wind_gusts_n = wind_n.getElementsByTagName('gust')[0]
                    wind_gusts = self.getText(wind_gusts_n.childNodes)
                    day_forecast_data = WeatherData(day_of_week, low_temp, high_temp, condition_code, condition, precip, humidity, wind_direction, wind_speed, wind_gusts, city, sunrise, sunset, moon_phase, moon_icon, bar_read, bar_desc)
                    self.day_forecast.append(day_forecast_data)

                    # night forecast specific data
                    daytime_n = day.getElementsByTagName('part')[1] # night
                    condition_code_n = daytime_n.getElementsByTagName('icon')[0]
                    condition_code = self.getText(condition_code_n.childNodes)
                    condition_n = daytime_n.getElementsByTagName('t')[0]
                    condition = self.getText(condition_n.childNodes)
                    precip_n = daytime_n.getElementsByTagName('ppcp')[0]
                    precip = self.getText(precip_n.childNodes)
                    humidity_n = daytime_n.getElementsByTagName('hmid')[0]
                    humidity = self.getText(humidity_n.childNodes)
                    wind_n = daytime_n.getElementsByTagName('wind')[0]
                    wind_speed_n = wind_n.getElementsByTagName('s')[0]
                    wind_speed = self.getText(wind_speed_n.childNodes)
                    wind_direction_n = wind_n.getElementsByTagName('t')[0]
                    wind_direction = self.getText(wind_direction_n.childNodes)
                    wind_gusts_n = wind_n.getElementsByTagName('gust')[0]
                    wind_gusts = self.getText(wind_gusts_n.childNodes)
                    night_forecast_data = WeatherData(day_of_week, low_temp, high_temp, condition_code, condition, precip, humidity, wind_direction, wind_speed, wind_gusts, city, sunrise, sunset, moon_phase, moon_icon, bar_read, bar_desc)
                    self.night_forecast.append(night_forecast_data)


                # pickle the data for next time!
                fileoutput = open(file_path_current, 'w')
                    pickle.dump(self.current_conditions,fileoutput)
                    fileoutput.close()

                fileoutput = open(file_path_dayforecast, 'w')
                    pickle.dump(self.day_forecast,fileoutput)
                    fileoutput.close()

                fileoutput = open(file_path_nightforecast, 'w')
                    pickle.dump(self.night_forecast,fileoutput)
                    fileoutput.close()

            except:
                print "fetchData:Unexpected error: ", sys.exc_info()[0]
                print "Unable to interrogate the weather data"

        else: # fetch weather data from pickled class files
            if self.options.verbose == True:
                print >> sys.stdout, "fetching weather data from file: ",file_path_current

                fileinput = open(file_path_current, 'r')
            self.current_conditions = pickle.load(fileinput)
            fileinput.close()

            if self.options.verbose == True:
                print >> sys.stdout, "fetching day forecast data from files: ",file_path_dayforecast, file_path_nightforecast

                fileinput = open(file_path_dayforecast, 'r')
            self.day_forecast = pickle.load(fileinput)
            fileinput.close()

            if self.options.verbose == True:
                print >> sys.stdout, "fetching day forecast data from files: ",file_path_nightforecast, file_path_nightforecast

                fileinput = open(file_path_nightforecast, 'r')
            self.night_forecast = pickle.load(fileinput)
            fileinput.close()

    def outputData(self):
        #try:

            if self.options.template != None:

                output = self.getOutputTextFromTemplate(self.options.template)

            else:

                output = self.getOutputText(self.options.datatype,self.options.startday,self.options.endday,self.options.night,self.options.shortweekday,self.options.imperial,self.options.hideunits,self.options.spaces)


            print output.encode("utf-8")

        #except:
            #print "outputData:Unexpected error: ", sys.exc_info()[0]

if __name__ == "__main__":

    parser = CommandLineParser()
    (options, args) = parser.parse_args()

    if options.verbose == True:
        print >> sys.stdout, "location:",options.location
        print >> sys.stdout, "imperial:",options.imperial
        print >> sys.stdout, "datatype:",options.datatype
        print >> sys.stdout, "night:",options.night
        print >> sys.stdout, "start day:",options.startday
        print >> sys.stdout, "end day:",options.endday
        print >> sys.stdout, "spaces:",options.spaces
        print >> sys.stdout, "verbose:",options.verbose
        print >> sys.stdout, "refetch:",options.refetch

    # create new global weather object
    weather = GlobalWeather(options)
    weather.fetchData()
    weather.outputData()

Save this script as conkyForecast.py and make it executable.

Install fonts using nautilus-actions

Caveat lector: I wrote this post in high school; it’s likely outdated and poorly written.

Nautilus-Actions installs custom entries in the context menu in nautilus. I needed a simple way to install fonts so I wrote a command for nautilus-actions.

Set “Path:” to bash

Set Parameters to -c "if zenity --question --text=\"Would you like to install the font system wide?\" --title=\"Install to System\"; then gksudo cp %M /usr/share/fonts/truetype/local/%m; else cp %M ~/.fonts/%m; fi; exit 0;".

If you do not want to install nautilus actions you can simply create a Nautilus script.

The contents of the script should be:

#!/bin/bash
if zenity --question --text="Would you like to install the font system wide?" --title="Install to System"; then
     for $i in $NAUTILUS_SCRIPT_SELECTED_FILE_PATHS; do
          gksudo cp $i /usr/share/fonts/truetype/local/$(basename $i)
     done
else
     for $i in $NAUTILUS_SCRIPT_SELECTED_FILE_PATHS; do
          cp $i ~/.fonts/$(basename $i)
     done
fi
exit 0

Save this script in ‘~/.gnome2/nautilus-scripts’ and make it executable (chmod u+x).