<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.0.2" -->
<rss version="2.0" 
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	>

<channel>
	<title>blackrat.org</title>
	<link>http://pqmf.com</link>
	<description>Paul McKibbin does not exist as either a human or a corporate entity</description>
	<pubDate>Wed, 26 Mar 2008 15:58:22 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.0.2</generator>
	<language>en</language>
			<item>
		<title>Enhancing Streamlined Enumerations</title>
		<link>http://pqmf.com/ruby/enhancing-streamlined-enumerations/</link>
		<comments>http://pqmf.com/ruby/enhancing-streamlined-enumerations/#comments</comments>
		<pubDate>Wed, 26 Mar 2008 15:55:18 +0000</pubDate>
		<dc:creator>blackrat</dc:creator>
		
	<dc:subject>ruby</dc:subject>
	<dc:subject>rails</dc:subject>
	<dc:subject>rubyonrails</dc:subject>
	<dc:subject>streamlined</dc:subject>
		<guid isPermaLink="false">http://pqmf.com/uncategorized/enhancing-streamlined-enumerations/</guid>
		<description><![CDATA[Recently, I&#8217;ve been looking at the Streamlined framework. For those of you who don&#8217;t know, Streamlined is an Ajaxified Scaffold currently under development. The edge version shows promise and is stable enough for my personal use as an administration tool.
One area which is particularly interesting is the way that they handle enumerations and the fact [...]]]></description>
			<content:encoded><![CDATA[<p>Recently, I&#8217;ve been looking at the <a href="http://streamlinedframework.org/">Streamlined framework</a>. For those of you who don&#8217;t know, Streamlined is an Ajaxified Scaffold currently under development. The edge version shows promise and is stable enough for my personal use as an administration tool.<br />
One area which is particularly interesting is the way that they handle enumerations and the fact that they are called late in the process rather than being instantiated once and then used. This may appear as an inefficiency at first glance, but in tracing through the call progress, I realized that you could make them more dynamic and allow for dynamic changes to the enumeration on a per item basis.<br />
This means that if you have an exclusive list, you can restrict the choices to only those items that haven&#8217;t yet been assigned to other rows in the database.<br />
For example, in one of my projects, you can assign a unique number to each row, and my desire was to restrict the view so that only the numbers that are available can be chosen.<br />
So if you have possible numbers of<br />
[1,2,3,4,5,6,7,8]</p>
<p>Assign 1 to the first row and for new items, [2,3,4,5,6,7,8] should be available, but [1,2,3,4,5,6,7,8] would be available for editing the first row.</p>
<p>Assign 5 to the second row and for new items, [2,3,4,6,7,8] should be available with [1,2,3,4,6,7,8] available for editing the first row and [2,3,4,5,6,7,8] available for editing the second row.</p>
<p>Coding this for the model is fairly straightforward:</p>
<pre><code>class DynamicTest < ActiveRecord::Base
  def available_nodes
    node_list=[1,2,3,4,5,6,7,8]
    nodes=DynamicTest.find(:all)
    nodes.each do |n|
      node_list-=[n.number] unless n.number==number
    end
    node_list
  end
end
</code></pre>
<p>The unfortunate thing is that Streamlined doesn&#8217;t support this call, you can perform a call to DynamicTest.available_nodes, but that wouldn&#8217;t let you know what the current item is and you wouldn&#8217;t be able to see it in the list or edit views. Not very useful. What is needed is a way to call this directly from the row rendering code when you have the item in scope.<br />
Since this is new functionality for Streamlined, the guys who maintain the codebase may adopt it, but for those of you who want to monkeypatch your own version or just see my take on it, you can download this <a href="http://dynamic_enumerations.tgz">sample project</a>.</p>
<p>The monkeypatch (in app/streamlined/dynamic_tests_ui.rb) overrides four of the streamlined functions and adds two more for handling dynamic enumerations. This means that in addition to the original</p>
<pre><code>Streamlined.ui_for(DynamicTest) do
  user_columns :number, {:enumeration => Numbers::TYPES}
end

class Numbers
  TYPES = [1,2,3,4,5,6,7,8]
end
</code></pre>
<p>and its Hash and 2d array counterparts, you can now have:</p>
<pre><code>Streamlined.ui_for(DynamicTest) do
  user_columns :number, {:enumeration => {:action=>:available_nodes}}
end
</code></pre>
<p>which will perform a late call to the DynamicTest#available_nodes scoped for the current row.</p>
<p>For those of you who just want to look at the code without downloading a full rails project, the relevant monkeypatched pieces are:</p>
<pre><code>
#Note: There is a bug in _enumeration.html that prevents non-Fixednum numeric
#indices. This should be updated in the template version
#<% value = item.send(relationship.name) -%>
#<% key_value_pair = relationship.enumeration_key_for(value) -%>
#<%= key_value_pair ? key_value_pair.first : relationship.unassigned_value %>

module Streamlined::Controller::EnumerationMethods
  def dynamic_enumeration
    dynamic_enumeration_method=nil
    @enumeration_name=params[:enumeration]
    rel_type=model_ui.scalars[@enumeration_name.to_sym]
    rel_type.enumeration.each { |k,v|
      dynamic_enumeration_method=v if k==:action
    }
    dynamic_enumeration_method.nil? ? rel_type.enumeration : instance.send(dynamic_enumeration_method).to_2d_array
  end

  # Shows the enumeration&#8217;s configured +Edit+ view, as defined in streamlined_ui
  # and Streamlined::Column.
  def edit_enumeration
    self.instance = model.find(params[:id])
    @enumeration_name = params[:enumeration]
    rel_type = model_ui.scalars[@enumeration_name.to_sym]
    @all_items=dynamic_enumeration
    @selected_item = instance.send(@enumeration_name)
    render(:partial => rel_type.edit_view.partial, :locals => {:item => instance, :relationship => rel_type})
  end

  # Show&#8217;s the enumeration&#8217;s configured +Show+ view,
  # as defined in streamlined_ui and Streamlined::Column.
  def show_enumeration
    self.instance = model.find(params[:id])
    rel_type = model_ui.scalars[params[:enumeration].to_sym]
    rel_type.enumeration=dynamic_enumeration
    render(:partial => rel_type.show_view.partial, :locals => {:item => instance, :relationship => rel_type})
  end
end

class Streamlined::Column::ActiveRecord < Streamlined::Column::Base
  def dynamic_enumeration(item)
    dynamic_enumeration_method=nil
    @enumeration.each { |k,v|
      dynamic_enumeration_method=v if k==:action
    }
    dynamic_enumeration_method.nil? ? @enumeration : item.send(dynamic_enumeration_method)
  end

  def render_td_show(view, item)
    if enumeration
      content = item.send(self.name)
      @enumeration=dynamic_enumeration(item)
      key_value_pair = enumeration_key_for(content) # call wraps enumeration to 2d array, so check unnecessary
      content = key_value_pair.first if key_value_pair
      content = content &#038;&#038; !content.blank? ? content : self.unassigned_value
      content = wrap_with_link(content, view, item)
    else
      render_content(view, item)
    end
  end

  def render_enumeration_select(view, item)
    id = relationship_div_id(name, item)
    @enumeration=dynamic_enumeration(item)
    choices = enumeration  #enumeration call wraps to 2d array so extra call is redundant
    choices.unshift(unassigned_option) if column_can_be_unassigned?(parent_model, name.to_sym)
    args = [model_underscore, name, choices]
    args << {} << html_options unless html_options.empty?
    view.select(*args)
  end
end
</code></pre>
]]></content:encoded>
			<wfw:commentRSS>http://pqmf.com/ruby/enhancing-streamlined-enumerations/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>Microsoft Surface Parody</title>
		<link>http://pqmf.com/cool/microsoft-surface-parody/</link>
		<comments>http://pqmf.com/cool/microsoft-surface-parody/#comments</comments>
		<pubDate>Mon, 17 Mar 2008 06:53:23 +0000</pubDate>
		<dc:creator>blackrat</dc:creator>
		
	<dc:subject>cool</dc:subject>
	<dc:subject>fun</dc:subject>
		<guid isPermaLink="false">http://pqmf.com/uncategorized/microsoft-surface-parody/</guid>
		<description><![CDATA[Hot on the heels of the Microsoft Surface announcement, and the statement by Tim Berners Lee that various devices and integrated software packages will be talking to each other seemlessly over the internet, and that everything (electronic) will be more tightly integrated in the future (Does anyone want to say Web 4.0 before they are [...]]]></description>
			<content:encoded><![CDATA[<p>Hot on the heels of the Microsoft Surface announcement, and the statement by Tim Berners Lee that various devices and integrated software packages will be talking to each other seemlessly over the internet, and that everything (electronic) will be more tightly integrated in the future (Does anyone want to say Web 4.0 before they are shot down for confusing the internet with the web?), came this spoof voiceover of the advertising that Microsoft has produced to try to show that they are still innovating in hardware.<br />
<object width="425" height="355"><br />
<param name="movie" value="http://www.youtube.com/v/CZrr7AZ9nCY"></param>
<param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/CZrr7AZ9nCY" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"></embed></object>
</p>
]]></content:encoded>
			<wfw:commentRSS>http://pqmf.com/cool/microsoft-surface-parody/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>The Woodcock in Beacon Hill</title>
		<link>http://pqmf.com/cool/the-woodcock-in-beacon-hill/</link>
		<comments>http://pqmf.com/cool/the-woodcock-in-beacon-hill/#comments</comments>
		<pubDate>Sat, 10 Nov 2007 21:57:46 +0000</pubDate>
		<dc:creator>blackrat</dc:creator>
		
	<dc:subject>cool</dc:subject>
	<dc:subject>fun</dc:subject>
	<dc:subject>websites</dc:subject>
		<guid isPermaLink="false">http://pqmf.com/uncategorized/the-woodcock-in-beacon-hill/</guid>
		<description><![CDATA[A favorite haunt of the blogging community, and now the home for all the meetings, is the Woodcock in Beacon Hill. Since we have met there on a number of occasions, and befriended the staff and landlord, this has become almost a home away from home for most of us.

Since the landlord is geek friendly, [...]]]></description>
			<content:encoded><![CDATA[<p>A favorite haunt of the blogging community, and now the home for all the meetings, is the Woodcock in Beacon Hill. Since we have met there on a number of occasions, and befriended the staff and landlord, this has become almost a home away from home for most of us.<br />
<img src="http://thewoodcock.com/images/woodcock_day.jpg" alt="The Woodcock by Night" /><br />
Since the landlord is geek friendly, and has a sofa that I occasionally live on two of us have collaborated and created him a website. <a href="http://thewoodcock.com">Check out our favorite haunt.</a>
</p>
]]></content:encoded>
			<wfw:commentRSS>http://pqmf.com/cool/the-woodcock-in-beacon-hill/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>Complete Floors</title>
		<link>http://pqmf.com/websites/complete-floors/</link>
		<comments>http://pqmf.com/websites/complete-floors/#comments</comments>
		<pubDate>Mon, 20 Aug 2007 16:27:41 +0000</pubDate>
		<dc:creator>blackrat</dc:creator>
		
	<dc:subject>websites</dc:subject>
		<guid isPermaLink="false">http://pqmf.com/uncategorized/complete-floors/</guid>
		<description><![CDATA[I have another website on my portfolio. You can check out their work (and mine) at http://completefloorsltd.co.uk

]]></description>
			<content:encoded><![CDATA[<p>I have another website on my portfolio. You can check out their work (and mine) at <a href="http://completefloorsltd.com">http://completefloorsltd.co.uk</a>
</p>
]]></content:encoded>
			<wfw:commentRSS>http://pqmf.com/websites/complete-floors/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>Tree Surgery</title>
		<link>http://pqmf.com/websites/tree-surgery/</link>
		<comments>http://pqmf.com/websites/tree-surgery/#comments</comments>
		<pubDate>Mon, 20 Aug 2007 16:26:03 +0000</pubDate>
		<dc:creator>blackrat</dc:creator>
		
	<dc:subject>websites</dc:subject>
		<guid isPermaLink="false">http://pqmf.com/uncategorized/tree-surgery/</guid>
		<description><![CDATA[New website development. Not in Ruby this time, but they are happy with the results. Check it out at http://butlerandbrown.com.

]]></description>
			<content:encoded><![CDATA[<p>New website development. Not in Ruby this time, but they are happy with the results. Check it out at <a href="http://butlerandbrown.com">http://butlerandbrown.com</a>.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://pqmf.com/websites/tree-surgery/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>Realplayer streaming BBC to mp3 files</title>
		<link>http://pqmf.com/pvr/realplayer-streaming-bbc-to-mp3-files/</link>
		<comments>http://pqmf.com/pvr/realplayer-streaming-bbc-to-mp3-files/#comments</comments>
		<pubDate>Thu, 02 Aug 2007 01:42:27 +0000</pubDate>
		<dc:creator>blackrat</dc:creator>
		
	<dc:subject>PVR</dc:subject>
	<dc:subject>PAR</dc:subject>
		<guid isPermaLink="false">http://pqmf.com/uncategorized/realplayer-steaming-bbc-to-mp3-files/</guid>
		<description><![CDATA[The BBC listen again facility allows you to play back audio broadcasts up to seven days after they originally air. That&#8217;s fine, unless you listen to most of your radio in the car, or away from your computer.
OK. So you can listen live, as long as you are in the UK, but sometimes I would [...]]]></description>
			<content:encoded><![CDATA[<p>The BBC listen again facility allows you to play back audio broadcasts up to seven days after they originally air. That&#8217;s fine, unless you listen to most of your radio in the car, or away from your computer.</p>
<p>OK. So you can listen live, as long as you are in the UK, but sometimes I would like to listen to the last 3 episodes of Perelandra, and possibly find out what&#8217;s going on in Lionel Nimrod&#8217;s Inexplicable World, while on a plane, or driving around Seattle.</p>
<p>This is where Mplayer, and the title of this blog entry come in.</p>
<p>The basic premise is to use mplayer to stream an entry to the harddrive in PCM format (wav), convert from wav to mp3 and drop in onto an mp3 file.</p>
<p>The following snippet from a larger script demonstrates the basic principle.</p>
<pre><code>
#Input:      $1 url
#               $2 name of file to record to (excluding extension)
#
mplayer -prefer-ipv4 -bandwidth 99999999 -vc null -vo null -ao pcm:fast -ao pcm:file=$2.wav $1
lame $2.wav $2.mp3
rm $2.wav
</code></pre>
<p>With a high bandwidth, it takes roughly a minute to download and encode a programme. Renaming or naming files are pretty tedious to do however, so I started to look at listing programmes, such as bleb and the BBC&#8217;s own backstage listings in order to automate the process. <a id="more-23"></a></p>
<p>OK. Confession time. I&#8217;ve been running this script for about three years. It&#8217;s a prototype which started off using bleb, and has since been converted to the TV_Anytime format handling that BBC Backstage uses. Since the BBC backstage feeds aren&#8217;t guaranteed, and in fact were down for most of last month, I&#8217;ve left the uncalled bleb information in. </p>
<p>I need to make an edit to it twice a year, since I haven&#8217;t gotten around to putting in handling for the switch between the UK summertime and GMT. (Current format is &#8220;Summer Time&#8221;, and searching for that string in the code should make it obvious where you need to change it.)</p>
<p>It&#8217;s a bash Version 3 script, which, since it works adequately and does just what I want it to, I haven&#8217;t converted it to Ruby. I will. It&#8217;s taken me until now to put it online, so don&#8217;t hold your breath.</p>
<p>Last warning. It&#8217;s big and you also need xmlstarlet, sed and optionally tv_grab_uk_bleb (from xmltv if you want to use bleb rather than TVAnytime).</p>
<p>For Ubuntu and Debian users,</p>
<p><DIV class="command_line"><br />
apt get install xmlstarlet xmltv sed
</div>
<p>should do the trick. Mind you, if you don&#8217;t already have sed installed, you might have other problems.</p>
<p>There are some other features, such as the prevention of downloading two copies of the same episode on the same day (by comparison of the description), Naming and layout of directories by name of the programme. Episode guide files which contain a programme description, etc. There is a slight modification to programmes downloaded at 18:30 from the guide, since they sometimes have the time 1832 in the streaming filename.</p>
<p>It will handle multiple days (for when you forget), and you can invoke it with</p>
<p><DIV class="command_line"><br />
bbccomedy.sh -7 -6 -5 -4 -3 -2 -1
</div>
<p>as a command line to stream seven days of recordings. It&#8217;s currently only set up for Radio4 and BBC7, and only those times I am interested in. I&#8217;ve had some success in making all of the streaming run in parallel, but this will put unnecessary load on the system and since I run it overnight, or when I know I&#8217;m going to be away, it doesn&#8217;t bother me if it takes 10 minutes or 80 to run through.</p>
<p>I also tried to run it as a cron job, but mplayer seems to stall indefinitely for an unknown reason, and I haven&#8217;t managed to correct this random occurrence.</p>
<p>Finally, before we get to the code, if it does stall, you need to delete the episodes/programme name/date_channel_episode (.wav and .mp3) and the check/date_channel_episode.chk before it will rerecord and the ~/audio/radio/bbccomedy.lck file before it will allow itself to rerun.</p>
<p>Apart from that, enjoy.</p>
<p>bbccomedy.sh</p>
<pre><code>#!/bin/bash
#Note: This script used the eval function to pass by reference. First parameter in most cases is the variable name. Use caution.

#GLOBAL VARIABLES - old style

#NO_ENC=echo
#DEBUG=echo

# Utility functions
#
# Date/Time manipulation, string manipulation
#

# Globals

SED=/bin/sed
GNU_DATE=/bin/date
MKDIR=/bin/mkdir

# Functions 

#Function:	set_init_value
#Description:	return the value or the default value of a parameter
#
#Requires:
#Externals:
#Input:		$1 variable to change
#		$2 value
#		$3 default value
#Returns	Value or default value if value not set

set_init_value ()
{
local rc=$2

	if [ -z $2 ] ; then rc=$3 ; fi
	eval "$1=${rc}"
}

#Function:	make_dir
#Description:	Create directory tree
#
#Requires:	set_init_value
#Externals:	mkdir
#Input:		$1	directory tree to create
#Returns:	none

make_dir ()
{
local makedir
set_init_value makedir ${MKDIR} "/bin/mkdir"

	if [ ! -d $1 ] ; then
		${makedir} -p $1 >> ${g_debug_log}
	fi
}

#Function:	get_datestamp
#Description:	Returned the date specified by a particular offset
#
#Requires:	set_init_value
#Externals:	GNU date
#Input:		$1 variable name for datestame
#		$2 offset

get_datestamp()
{
local datestamp=""
local date

set_init_value date ${GNU_DATE} "/bin/date"

	if [ -x ${date} ] ; then
		datestamp=`${date} --date="$2 days" +%Y%m%d`
	else
		echo FATAL: get_datestamp reports ${date} "(Gnu Date)" is missing or not executable.
		exit 1
	fi
	eval "$1=${datestamp}"
}

#Function:	get_tv_anytime_datestamp
#Description:	Returned the date specified by a particular offset in the format used
#		by TV_Anytime
#
#Requires:	set_init_value
#Externals:	GNU date
#Input:		$1 variable name for datestame
#		$2 offset

get_tv_anytime_datestamp()
{
local datestamp=""
local date

set_init_value date ${GNU_DATE} "/bin/date"

	if [ -x ${date} ] ; then
		datestamp=`${date} --date="$2 days" +%Y-%m-%dT`
	else
		echo FATAL: get_datestamp reports ${date} "(Gnu Date)" is missing or not executable.
		exit 1
	fi
	eval "$1=${datestamp}"
}

#Function:	get_tv_anytime_timestamp
#Description:	Returned the time specified in the format used
#		by TV-Anytime
#
#Requires:	set_init_value
#Externals:	GNU date
#Input:		$1 variable name for datestame
#		$2 time in hhmm format

get_tv_anytime_time()
{
local timestamp=""

	timestamp=${2:0:2}":"${2:2:2}"00Z"
	eval "$1=${timestamp}"
}

#Function:	get_dow
#Description:	Returns the name of the day of the week
#
#Requires:	set_init_value
#Externals:	GNU date
#Input:		$1 variable name
#		$2 offset from current day
#Returns:	Name of the day of the week

get_dow ()
{
local dow
local date

set_init_value date ${GNU_DATE} "/bin/date"

	if [ -x ${date} ] ; then
		dow=`"${date}" --date="$2 days" +%w`
	else
		echo FATAL: get_dow reports ${date} "(Gnu Date)" is missing or not executable.
		exit 1
	fi
	case ${dow} in
		1) dow="mon"
		;;
		2) dow="tue"
		;;
		3) dow="wed"
		;;
		4) dow="thu"
		;;
		5) dow="fri"
		;;
		6) dow="sat"
		;;
		0) dow="sun"
		;;
		*) echo "Unrecognised date:" ${dow} >> ${g_error_log}
	esac
	eval "$1=${dow}"
}

#Function:	normalize_name
#Description:	Returned the name in a "safe" format
#
#Requires:	set_init_value, normalize_description
#Externals:	sed
#Input:		$1 variable name for normalized name
#		$2 name

normalize_name ()
{
local name=$2
local sed
set_init_value sed ${SED} "/bin/sed"

	if [ -x ${sed} ] ; then
		name=`echo "$2" | ${sed} -e 's/ /_/g'`
		normalize_description p_name ${name}
		name=${p_name}
	else
		echo ERROR: normalize_name reports ${sed} "(sed)" is missing or not executable.
	fi
	eval "$1='${name}'"
}

#Function:	normalize_description
#Description:	Returned the description in a "safe" format
#
#Requires:	set_init_value
#Externals:	sed
#Input:		$1 variable name for normalized description
#		$2 description

normalize_description ()
{
local name=$2
local sed=""
set_init_value sed ${SED} "/bin/sed"

	if [ -x ${sed} ] ; then
		name=`echo "${name}" | ${sed} -e 's/.//g'`
		name=`echo "${name}" | ${sed} -e 's/,//g'`
		name=`echo "${name}" | ${sed} -e 's/://g'`
		name=`echo "${name}" | ${sed} -e 's/"//g'`
		name=`echo "${name}" | ${sed} -e "s/'//g"`
	else
		echo ERROR: normalize_description reports ${sed} "(sed)" is missing or not executable.
	fi
	eval "$1='${name}'"
}

#
# TV-Anytime Functions
#
# Functions for creating and manipulating the TV-Anytime grabber files
#

# Globals
TV_ANYTIME_DIR=~/.borg/TV_Anytime
WGET=/usr/bin/wget
TAR=/bin/tar

# Functions 

#Function: tv_anytime_setup
#Description:	Grabs programme listings to TV_ANYTIME directory tree for the specified day
#
#Requires:	set_init_value, make_dir
#Externals:	wget, tar
#Input:        	$1 offset
#Returns:  	None

tv_anytime_setup()
{
local dir
local grabber
local datestamp
local curdir
local newdatestamp
local offsetcount

set_init_value dir "${TV_ANYTIME_DIR}" "~/.borg/TV_Anytime"
set_init_value grabber "${WGET}" "/usr/bin/wget"
set_init_value tar "${TAR}" "/bin/tar"

	make_dir ${dir}
	get_datestamp p_datestamp $1
	datestamp=${p_datestamp}
	offsetcount=$(( $1 -6 ))
	while [ ${offsetcount} -le $1 ]; do
		get_datestamp p_datestamp ${offsetcount}
		if [ -d ${dir}/${p_datestamp} ] ; then
			echo ${dir}/${p_datestamp} exists. Delete to refetch.
			g_tv_anywhere_datestamp=${p_datestamp}
			return 0
		else
			offsetcount=$(( ${offsetcount} +1 ))
		fi
	done
	offsetcount=$(( $1 -6 ))
	found=0
	while [ ${offsetcount} -le $1 ]; do
		get_datestamp p_datestamp ${offsetcount}
		offsetcount=$(( ${offsetcount} +1 ))
		if [ -e ${dir}/${p_datestamp}.tar.gz ] ; then
			found=${p_datestamp}
			g_tv_anywhere_datestamp=${p_datestamp}
			echo ${dir}/${p_datestamp}.tar.gz exists. Delete to refetch
		fi
	done
	echo ${found}
	echo ${datestamp}
	if [ ${found} = 0 ]; then
		if [ -x ${grabber} ] ; then
			${grabber} http://backstage.bbc.co.uk/feeds/tvradio/${datestamp}.tar.gz --output-document=${dir}/${datestamp}.tar.gz
		else
			echo ${grabber} "(wget)" is not executable or does not exist
		fi
	else
		datestamp=${found}
	fi
	if [ -e ${dir}/${datestamp}.tar.gz ] ; then
		if [ -x ${tar} ] ; then
			curdir=`pwd`
			cd ${dir}
			${tar} -zxvf ${datestamp}.tar.gz
			if [ -d xml13 ] ; then
				mv xml13 ${datestamp}
			fi
			g_tv_anywhere_datestamp=${p_datestamp}
			cd ${curdir}
		else
			echo ${tar} "(tar)" is not executable or does not exist
		fi
	fi
}

#Function:	tv_anytime_get_details
#Description:	Get Program details from tv_anytime listings
#
#Requires:	set_init_value,  normalize_name, normalize_description
#Externals:	xmlstarlet
#Input:		$1 variable name for title
#		$2 variable name for description
#		$3 channel
#		$4 datestamp
#		$5 time

tv_anytime_get_details()
{
local dir
local xml_file
local tree
local title
local desc
local b_time
local z_time
local crid
local channel
local namespace
local xml

set_init_value dir "${TV_ANYTIME_DIR}" "~/.borg/TV_Anytime"
set_init_value xml "${XML_PARSER}" "/usr/bin/xmlstarlet"

	case $3 in
		"bbc7") channel="BBCSeven"
		;;
		"bbc_radio4") channel="BBCRFour"
		;;
		*) echo "Unrecognised channel $3" >> ${debug_log}
		;;
	esac
	z_time=$(( $5 - 100 )) # Use this short term for British Summer Time
#	z_time=$5
	b_time=${4:0:4}"-"${4:4:2}"-"${4:6:2}"T"${z_time:0:2}":"${5:2:2}":00Z"
	namespace=' -N t=urn:tva:metadata:2005 '
	xml_file=${g_tv_anywhere_datestamp}/$4${channel}_pl.xml
	tree="//t:ScheduleEvent[t:PublishedStartTime='$b_time']/t:Program"

	crid=`${xml} sel ${namespace} -T -t -m ${tree} -v "@crid" -n ${dir}/${xml_file}`
	xml_file=${g_tv_anywhere_datestamp}/$4${channel}_pi.xml
	tree="//t:ProgramInformation[@programId='${crid}']/t:BasicDescription"

	title=`${xml} sel ${namespace} -T -t -m ${tree} -v "t:Title" -n ${dir}/${xml_file}`
	desc=`${xml} sel ${namespace} -T -t -m ${tree} -v "t:Synopsis[@length='short']" -n ${dir}/${xml_file}`
	normalize_name $1 "${title}"
	normalize_description $2 "${desc}"
}

#
# Bleb Functions
#
# Functions for creating and manipulating the Bleb UK TV grabber files
#

# Globals

BLEB_DIR=~/.borg/bleb
BLEB_CONF="bleb.conf"
BLEB_GRABBER=/usr/bin/tv_grab_uk_bleb
BLEB_TREE=/tv/programme
XML_PARSER=/usr/bin/xmlstarlet

# Functions 

#Function: bleb_setup
#Description:	Grabs programme listings to bleb.xml for the specified day and channel
#
#Requires:	set_init_value, make_dir
#Externals:	tv_grab_uk_bleb
#Input:	   	$1 channel
#          	$2 offset
#Returns:  	None

bleb_setup ()
{
local dir
local conf_file
local grabber
local xml_file=""

set_init_value dir "${BLEB_DIR}" "~/.borg/bleb"
set_init_value conf_file "${BLEB_CONF}" "bleb.conf"
set_init_value grabber "${BLEB_GRABBER}" "/usr/bin/tv_grab_uk_bleb" 

	make_dir ${dir}
	conf_file=${dir}/${conf_file}
	xml_file=${dir}/${g_datestamp}_$1.xml

	if [ -e ${xml_file} ] ; then
		echo ${xml_file} already exists. Delete to download new file. >> ${g_debug_log}
	else
		echo $1 > ${conf_file}
		if [ -x ${grabber} ] ; then
			${grabber} --output ${xml_file} --days=1 --offset=$2 --config-file ${conf_file} 2>>${g_debug_log}
		else
			echo ERROR: bleb_setup reports ${grabber} "(tv_grab_uk_bleb)" is missing or not executable.
		fi
	fi
}

#Function:	bleb_get_details
#Description:	Get Program details from bleb listings
#
#Requires:	set_init_value, bleb_filename, normalize_name, normalize_description
#Externals:	xmlstarlet
#Input:		$1 variable name for title
#		$2 variable name for description
#		$3 channel
#		$4 datestamp
#		$5 time

bleb_get_details ()
{
local dir
local xml_file
local tree
local title
local desc
local b_time

set_init_value dir "${BLEB_DIR}" "~/.borg/bleb"
set_init_value tree "${BLEB_TREE}" "/tv/programme"
set_init_value xml "${XML_PARSER}" "/usr/bin/xmlstarlet"
xml_file=""
title=""
desc=""

	b_time=$4$5"00 +0100"
	xml_file=${dir}/$4_$3.xml

	title=`${xml} sel -T -t -m ${tree}[@start="'${b_time}'"] -v title -n ${xml_file}`
	desc=`${xml} sel -T -t -m ${tree}[@start="'${b_time}'"] -v desc -n ${xml_file}`

	normalize_name $1 "${title}"
	normalize_description $2 "${desc}"
}

#
# Radio Functions
#
# Functions for recording radio programmes
#

echo Define record_radio 

#Function:	record_radio
#Description:	Record radio programs from the given url to a filename detected from the programme listings. Skip if file exists or is a duplicate, or cannot be found
#
#Externals:	mplayer, lame, cat, rm
#Input:		$1 url
#		$2 datestamp
#		$3 time of recording
#		$4 channel

radio_record ()
{
check_file=""
local name
local desc
local long_name
local check_file

	echo $2 $3 $4 >> ${g_debug_log}
#	bleb_get_details p_name p_desc $4 $2 $3
	tv_anytime_get_details p_name p_desc $4 $2 $3
	if [ "${p_name}" = "" ] ; then
		if [ $3 = 1830 ] ; then
#			bleb_get_details p_name p_desc $4 $2 1832
			tv_anytime_get_details p_name p_desc $4 $2 1832
		fi
	fi
	if [ "${p_name}" = "" ] ; then
		name="unknown"
		desc="Unknown"
		check_file=$2_$3_$4_${name}.chk
	else
		name=${p_name}
		desc=${p_desc}
		check_file=$2_$4_${name}.chk
	fi
	echo Attempting to record ${name} >> ${g_debug_log}
	echo Description ${desc} >> ${g_debug_log}
	long_name=$2_$3_$4_${name}

	if [ -e ${g_chk}/$check_file ]; then
		desc2=`cat ${g_chk}/${check_file}`
		if [ "${desc:0:50}" = "${desc2:0:50}" ] ; then
			echo Won't record ${g_mp3}/${name}/${long_name}.mp3 while ${g_chk}/${check_file} exists
			echo Won't record ${g_mp3}/${name}/${long_name}.mp3 while ${g_chk}/${check_file} exists >> ${g_debug_log}
			return 1
		fi
	fi
	if [ -e ${g_mp3}/${name}/${long_name}.mp3 ] ; then
		echo ${g_mp3}/${name}/${long_name}.mp3 already exists. Delete to rerecord. >> ${g_debug_log}
		echo ${g_mp3}/${name}/${long_name}.mp3 already exists. Delete to rerecord.
	else
		if [ -e ${g_wav}/${name}/${long_name}.wav ] ; then
			echo ${g_wav}/${name}/${long_name}.wav exists. Delete to rerecord. Will continue with mp3 encoding >> ${g_debug_log}
			echo ${g_wav}/${name}/${long_name}.wav exists. Delete to rerecord. Will continue with mp3 encoding
		else
			make_dir ${g_wav}/${name}
			${DEBUG} mplayer -prefer-ipv4 -bandwidth 99999999 -vc null -vo null -ao pcm:fast -ao pcm:waveheader -ao pcm:file=${g_wav}/${name}/${long_name}.wav $1
			if [ -e ${g_wav}/${name}/${long_name}.wav ] ; then
				echo ${g_mp3}/${name}/${long_name}.wav recording successful. >> ${g_debug_log}
				echo ${g_mp3}/${name}/${long_name}.wav recording successful.
			else
				echo ${g_mp3}/${name}/${long_name}.wav recording failed. >> ${g_debug_log}
				echo ${g_mp3}/${name}/${long_name}.wav recording failed. >> ${g_error_log}
				echo ${g_mp3}/${name}/${long_name}.wav recording failed.
			fi
		fi
		if [ -e ${g_wav}/${name}/${long_name}.wav ] ; then
			make_dir ${g_mp3}/${name}
			${NO_ENC} ${DEBUG} lame ${g_wav}/${name}/${long_name}.wav ${g_mp3}/${name}/${long_name}.mp3
			${NO_ENC} ${DEBUG} rm ${g_wav}/${name}/${long_name}.wav
			echo ${desc} > ${g_chk}/${check_file}
		fi
	fi
	if [ -e ${g_mp3}/${name}/${long_name}.mp3 ] ; then
		if [ ! -e ${g_guide}/${long_name}.txt ] ; then
			make_dir ${g_guide}
			echo Adding missing guide details for ${name} to ${g_guide}/${long_name}.txt
			echo ${name} > ${g_guide}/${long_name}.txt
			echo ${desc} >> ${g_guide}/${long_name}.txt
		fi
	fi
}

echo Define main

#	Main function
#
#	Entry point for the Record Radio Function
#

main ()
{
# Create required directories
	make_dir ${g_root}
	make_dir ${g_wav}
	make_dir ${g_mp3}
	make_dir ${g_chk}
	make_dir ${g_guide}
	cd ${g_root}

# Get Datestamp and Day of Week
	get_datestamp g_datestamp ${g_offset}
	get_dow g_dow ${g_offset}

# Setup Bleb programme listings for required channels and dates
#	bleb_setup ${g_radio4} ${g_offset}
#	bleb_setup ${g_bbc7} ${g_offset}

# Setup TV-Anytime programme listings for required dates
	tv_anytime_setup ${g_offset}

	for g_time in 1830
	do
		for g_type in comedy factual science
		do
			g_url=rtsp://rmv8.bbc.net.uk/radio4/${g_type}/${g_dow}${g_time}.ra
			radio_record ${g_url} ${g_datestamp} ${g_time} ${g_radio4}
			g_url=rtsp://rmv8.bbc.net.uk/radio4/${g_type}/${g_time}_${g_dow}.ra
			radio_record ${g_url} ${g_datestamp} ${g_time} ${g_radio4}
		done
		g_url=rtsp://rmv8.bbc.net.uk/radio4/${g_dow}${g_time}.ra
		radio_record ${g_url} ${g_datestamp} ${g_time} ${g_radio4}
		g_url=rtsp://rmv8.bbc.net.uk/radio4/${g_time}_${g_dow}.ra
		radio_record ${g_url} ${g_datestamp} ${g_time} ${g_radio4}
	done

	for g_time in 1800 1830 2200 2230 2300 2330
	do
		g_url=rtsp://rmv8.bbc.net.uk/bbc7/${g_time}_${g_dow}.ra
		radio_record ${g_url} ${g_datestamp} ${g_time} ${g_bbc7}
	done
}

#
#	Real Main
#
#	Actual entry point for the shell script
#

#GLOBAL VARIABLES - new style

set_init_value g_root ${ROOT_DIR} "~/audio/radio"
set_init_value g_wav ${WAV_DIR} "~/audio/radio/episodes"
set_init_value g_mp3 ${MP3_DIR} "~/audio/radio/episodes"
set_init_value g_chk ${CHK_DIR} "~/audio/radio/check"
set_init_value g_guide ${GUIDE_DIR} "~/audio/radio/guide"
set_init_value g_radio4 ${RADIO4} "bbc_radio4"
set_init_value g_bbc7 ${BBC7} "bbc7"
set_init_value g_error_log ${ERROR_LOG} "~/audio/radio/error.log"
set_init_value g_debug_log ${DEBUG_LOG} "~/audio/radio/debug.log"
set_init_value g_lock_file ${LOCK} "~/audio/radio/bbccomedy.lck"

if [ ! -e "${g_lock_file}" ] ; then
	echo `date` >> ${g_error_log}
	echo `date` >> ${g_debug_log}
	echo `date` > ${g_lock_file}
	echo BBC Radio Recording Programme starting >> ${g_debug_log}
	echo BBC Radio Recording Programme starting
	while [ -n "$1" ]; do
	set_init_value g_offset $1 -1
		main $1
		shift
	done
	echo BBC Radio Recording Programme exiting >> ${g_debug_log}
	echo BBC Radio Recording Programme exiting
	rm ${g_lock_file}
fi

</code></pre>
]]></content:encoded>
			<wfw:commentRSS>http://pqmf.com/pvr/realplayer-streaming-bbc-to-mp3-files/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>It&#8217;s 1973, almost dinnertime. I&#8217;m having &#8216;oops</title>
		<link>http://pqmf.com/cool/its-1973-dinnertime-and-im-having-oops/</link>
		<comments>http://pqmf.com/cool/its-1973-dinnertime-and-im-having-oops/#comments</comments>
		<pubDate>Wed, 04 Jul 2007 16:21:27 +0000</pubDate>
		<dc:creator>blackrat</dc:creator>
		
	<dc:subject>cool</dc:subject>
	<dc:subject>fun</dc:subject>
		<guid isPermaLink="false">http://pqmf.com/uncategorized/its-1973-dinnertime-and-im-having-oops/</guid>
		<description><![CDATA[



]]></description>
			<content:encoded><![CDATA[<p><object width="425" height="350"><br />
<param name="movie" value="http://www.youtube.com/v/i5H1MNpiu5c"></param>
<param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/i5H1MNpiu5c" type="application/x-shockwave-flash" wmode="transparent" width="425" height="350"></embed></object>
</p>
]]></content:encoded>
			<wfw:commentRSS>http://pqmf.com/cool/its-1973-dinnertime-and-im-having-oops/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>Rails IDE - Komodo 4.1</title>
		<link>http://pqmf.com/ruby/rails-ide-komodo/</link>
		<comments>http://pqmf.com/ruby/rails-ide-komodo/#comments</comments>
		<pubDate>Wed, 23 May 2007 23:48:11 +0000</pubDate>
		<dc:creator>blackrat</dc:creator>
		
	<dc:subject>ruby</dc:subject>
	<dc:subject>rails</dc:subject>
	<dc:subject>rubyonrails</dc:subject><dc:subject>komodo</dc:subject><dc:subject>rails</dc:subject><dc:subject>ruby</dc:subject><dc:subject>rubyonrails</dc:subject>
		<guid isPermaLink="false">http://pqmf.com/uncategorized/rails-ide-komodo/</guid>
		<description><![CDATA[I&#8217;m a great believer in free software, most of my systems are run using Apache, MySQL, Linux, and Ruby, as I&#8217;m sure quite a lot of you are running also. I&#8217;m also a great believer in the right tool for the right job, even if that isn&#8217;t a free tool. After using several of the [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m a great believer in free software, most of my systems are run using Apache, MySQL, Linux, and Ruby, as I&#8217;m sure quite a lot of you are running also. I&#8217;m also a great believer in the right tool for the right job, even if that isn&#8217;t a free tool. After using several of the free offerings, I downloaded the 4.0 beta of Komodo IDE to see if it was the right tool for developing RubyOnRails apps.</p>
<p>It was a little clunky. The editor and syntax highlighting were fine, and the approach to extending language support was also great. (I use <a href="http://haml.hamptoncatlin.com">Haml and Sass</a>, rather than RHtml and CSS) The debugger took up to a minute to hit breakpoints, however, and although it was possible to use it , it was a little more difficult than I would have liked.</p>
<p>4.1 has changed all of that for me. Currently in beta, it is fast and shows the great strides that they have achieved. The Pro version is simply the best IDE I have used for Rails, bar none. I purchased mine and use Komodo now almost exclusively on all of my projects. Version 4.1 is available as a Trial from <a href="http://www.activestate.com/products/komodo_ide/?_x=1">here</a>.</p>
<p>Update: 4.1 has become the official release version, and is no longer in Beta. I feel an upgrade coming on.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://pqmf.com/ruby/rails-ide-komodo/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>Solid State Aircraft</title>
		<link>http://pqmf.com/cool/solid-state-aircraft/</link>
		<comments>http://pqmf.com/cool/solid-state-aircraft/#comments</comments>
		<pubDate>Wed, 23 May 2007 22:59:05 +0000</pubDate>
		<dc:creator>blackrat</dc:creator>
		
	<dc:subject>cool</dc:subject><dc:subject>aircraft</dc:subject><dc:subject>cool</dc:subject><dc:subject>solid state</dc:subject><dc:subject>video</dc:subject><dc:subject>YouTube</dc:subject>
		<guid isPermaLink="false">http://pqmf.com/uncategorized/solid-state-aircraft/</guid>
		<description><![CDATA[Even if the science is still not quite there yet, the CGI is great. This is just cool. I want one. I&#8217;m not responsible for the cruddy commentary from a geek who thinks he is funny, but I love it when people come up with new ways for using great ideas.


]]></description>
			<content:encoded><![CDATA[<p>Even if the science is still not quite there yet, the CGI is great. This is just cool. I want one. I&#8217;m not responsible for the cruddy commentary from a geek who thinks he is funny, but I love it when people come up with new ways for using great ideas.<br />
<br />
<embed src="http://www.youtube.com/v/m0eoeYSylCI" type="application/x-shockwave-flash" wmode="transparent" width="390" height="350"></embed></object></p>
]]></content:encoded>
			<wfw:commentRSS>http://pqmf.com/cool/solid-state-aircraft/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>Bloggers in Hindhead, Haslemere and Farnham</title>
		<link>http://pqmf.com/bloggers/bloggers-in-hindhead-haslemere-and-farnham/</link>
		<comments>http://pqmf.com/bloggers/bloggers-in-hindhead-haslemere-and-farnham/#comments</comments>
		<pubDate>Thu, 03 May 2007 08:50:41 +0000</pubDate>
		<dc:creator>blackrat</dc:creator>
		
	<dc:subject>bloggers</dc:subject><dc:subject>beer</dc:subject><dc:subject>bloggers</dc:subject><dc:subject>farnham</dc:subject><dc:subject>grayshott</dc:subject><dc:subject>hindhead</dc:subject><dc:subject>social</dc:subject>
		<guid isPermaLink="false">http://pqmf.com/bloggers/bloggers-in-hindhead-haslemere-and-farnham/</guid>
		<description><![CDATA[
Recently, I joined a small group of like minded individuals (social drinkers), under the guise of a blogger get together. I thought that this would be a one-off visit, or perhaps an occassional quarterly or monthly, a few blokes go down the pub and talk about computers. I couldn&#8217;t have been more wrong. You can [...]]]></description>
			<content:encoded><![CDATA[<p><img width=550 src="http://photos1.blogger.com/x/blogger2/2170/3177/300/z/810587/image-upload-2-786638.jpg" alt="Bloggers at the Farnham Beer Festival" /></p>
<p>Recently, I joined a small group of like minded individuals (social drinkers), under the guise of a blogger get together. I thought that this would be a one-off visit, or perhaps an occassional quarterly or monthly, a few blokes go down the pub and talk about computers. I couldn&#8217;t have been more wrong. You can read about our weekly (yes, <strong><em>weekly</em></strong>) exploits at <a href="http://more-than-just-us.blogspot.com/">More That Just Us</a>. If you are in the area on a Thursday night. drop one of us a line, and pop-along. We are an eclectic bunch who just seem to enjoy company despite our varied tastes in other things.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://pqmf.com/bloggers/bloggers-in-hindhead-haslemere-and-farnham/feed/</wfw:commentRSS>
		</item>
	</channel>
</rss>
