20100105

Introducing GeoNote AR (2.0)

Some of you might know I have been working on a little iPhone app called GeoNote (iTunes link). Its basic goal is to allow you to annotate the real world by allowing you to leave little messages (notes) which are "pinned" to real world locations. These little messages are visible to anyone running GeoNote.

Initially GeoNote had a rather unflattering interface: just a List View of notes. However as the iPhone SDK and the iPhone itself evolved, GeoNote also evolved. First it gained Map view, which was much more intuitive and useful, then with the iPhone 3GS and a bit of time on my hands, GeoNote gained Augmented Reality view:


Cool isn't it :D It is available in GeoNote 2.0, but only for people with iPhone 3GS. GeoNote will run on iPod touch and iPhone 3G, but AR will not be available.

The Augmented Reality View is activated by holding the phone up like you would to take a landscape picture, with the home button on the right. The colour scheme is customisable, since I haven't found a nice set of colours. It looks rather retro'ish with the default green colour scheme:


There are a lot of things that cane be done better, like a nice way to select notes, and more customisation for things like limiting distance, etc. But as they say, release early, release often :-)

For more on the app, visit: http://gtd.pictorii.com. It is rather nasty right now, I will work on that :)

Cheers,
Steve

Labels:


20091231

Order Matters With XCode's Build Phrases

I use a custom script to insert the current git commit into GeoNote, so when I get bug reports I have a better idea of which version the user is running. The script is as below:

import os
from Foundation import NSMutableDictionary

version = os.popen4("/sw/bin/git rev-parse --short HEAD")[1].read()
info = os.environ['INFOPLIST_FILE']
print info
plist = NSMutableDictionary.dictionaryWithContentsOfFile_(info)
print plist
plist['revision'] = version[:-1]
plist.writeToFile_atomically_(info, 1)

This was added as a Run Script Build Phrase. The problem I noticed was that the commit short hash inserted into Info.plist was always one commit behind. After some head scratching, I realised this was because by default the new build phrase is inserted last, and the order matters! It isn't actually possible to reorder build phrases by drag and dropping the children nodes around. You have to do a head-insert by dragging a child to the parent, which inserts it at the top.


Voila, problem solved.

Cheers,
Steve

Labels: , ,


20091011

qrbackup

I generated a gpg keypair for myself today, and I was looking for a fairly safe way to back it up. I don't particularly trust DVD/CDs, and keeping it on flash is even more worrying. I wanted a means of backup I can see and touch.

Paperbak would be great if it was ported to something not windows. Since it wasn't, I settled on QR Code.

Thus qrbackup was born. It will base32 encode a file, then encode it into QR codes using google chart service.

I have tested it from backup to restoration, and it works. YMMV, more instructions available after the jump.

Cheers,
Steve

P.S. Pardon my python.

Labels: , ,


20090805

git-daemon on debian vserver

Annoyingly git-daemon-run requires runit on debian, but runit will fail to install properly in a debian vserver because it doesn't have init.

One solution is to reconfigure vserver to use plain init style.

However I didn't want to this because I don't want to take down my vserver just yet. So here is the required line for /etc/inetd.conf:

git     stream  tcp     nowait  nobody /usr/bin/git git daemon --inetd /var/git-repos

Cheers,
Steve

Labels: , ,


20090607

Dealing with rkhunter warnings

rkhunter often warns on file property changes after upgrade and such, and sometimes you just aren't sure whether it is due to recent upgrades, or because you really were compromised. The following script was written to compare the checksum of all files rkhunter warns about against the originals in a debian repository.

The latest version of this is available in my script.git respos.

#!/bin/bash
desc="
This script will verify whether files for which rkhunter has logged a 
warning for is still valid. It does this by finding which debian package
it came out of, and downloads them, unpacks them, then checks
the checksums.

Run it by supplying a rkhunter log file as first argument
"

HASHER="sha256sum"

IFS="
"
function find_suspect_files
{
 echo "parsing $1 for suspect files" 1>&2
 grep -1 Warning "$1"| grep File | sed 's|.*File: ||'
}

function find_packages
{
 echo "finding packages" 1>&2
 for suspect_file in $1
 do
  package=$(dpkg -S $suspect_file|awk '{print $1}'|sed 's/.$//')
  echo "suspect file $suspect_file found in $package" 1>&2
  echo $package
 done

}

function make_aptitude_args
{
 echo "generating aptitude arguments" 1>&2
 for package in $1
 do
  version=$(dpkg -p $package | grep Version | awk '{print $2}')
  echo $package=$version
 done
}

function cleanup
{
 echo "cleaning up"
 popd
 rm -rf tmp
 exit $1
}

function setup
{
 echo "setting up"
 rm -rf tmp
 mkdir tmp
 pushd tmp
}

if [ $# -ne 1 ];
then
 echo "$desc"
 exit 1
fi

suspect_files=$(find_suspect_files "$1")

packages=$(find_packages "$suspect_files" | sort | uniq)

if [ -z "$packages" ];
then
 echo "***WARNING****"
 echo "No packages contain any of the suspect files!"
 cleanup 1
fi

aptitude_args=$(make_aptitude_args "$packages")

setup

echo "downloading packages"
aptitude download $aptitude_args 1>/dev/null
if [ $? -ne 0 ];
then
 echo "aptitude download failed!"
 echo "args=$aptitude_args"
 cleanup 1
fi

echo "unpacking"
for deb_file in *.deb
do
 ar -x $deb_file
 tar zxf data.tar.gz 
 rm -rf data.tar.gz control.tar.gz
done

for suspect_file in $suspect_files
do
 if [ ! -f ".$suspect_file" ]
 then
  echo "***WARNING****"
  echo "For some reason .$suspect_file does not exis!"
  continue
 fi
 echo -n "verifying $suspect_file... "
 suspect_sum=$($HASHER $suspect_file | awk '{print $1}')
 clean_sum=$($HASHER ".$suspect_file" | awk '{print $1}')
 if [ $suspect_sum == $clean_sum ];
 then
  echo "OK"
 else
  echo
  echo "***WARNING****"
  echo "Checksum mistmatch for $suspect_file!!!"
  echo "Should be: $clean_sum"
  echo "Is: $suspect_sum"
 fi
done
cleanup

Cheers,
Steve

Labels: , ,


20090604

microbric viper review

The microbric viper is neat. Good quality parts and unique idea. Makes a decent robotics platform if you get the wheel add-on. However, you gotta have small fingers to get some of the parts in place. Despite this, the hardware is solid, I like it. The one thing I would ask for however is more short-nuts and a printed manual, not a CDROM with a PDF. Take a leaf from LEGO and their construction manuals.

While the hardware is decent, the microbric viper is sadly let down by the software.

The microbric viper uses the basicAtom (by basicmicro), a PIC 16F87{6,7} with a custom bootloader. Now there is nothing wrong with this - arduino uses a custom bootloader too. However the custom bootloader uses a proprietary programming protocol. This is pretty fail, but what really fails is the programming software only runs under windows (or wine under ubuntu, but only for now).

IMHO the basic-esque language used by basicAtom is no better than what picaxe offers. I am completely at a lost as to why companies would use the basicmicro's products and lock themselves to a single supplier. Think about it: if basicmicro goes bust, your products using the basicAtom will not longer have a supported development environment.

Robotics companies need to seriously consider how their selection of controller will affect their customers - specifically those customers who aren't going to be running windows and staying with in the limits of whatever custom language designed by the controller vendors.

Arduino would be the best choice IMHO. Open hardware, open software. You don't have to pay premiums for the bootloader, and the number of people who will consider your product increases to include people like me.

I bought the microbric viper because it was on sale: reduced to $29 from $199. If I had known I could only program it under windows or that it used such a closed platform, I won't have bought it, even for that price.

Cheers,
Steve

Labels: , , , ,


20090508

Facebook python authentication gateway

Edit: it occurred to me what I have below is the basics of a thin facebook api wrapper. I might make it into one at some point in the future.

If you don't know what this does, you don't need it. Hope this helps some one. Written because pyfacebook is broken, always returns error 100.

FB_API_HOST="api.facebook.com"
FB_API_PATH="/restserver.php"

def get_session(auth_token):
        params={
                "api_key":FB_API_KEY,
                "v":"1.0",
                "auth_token":auth_token,
                "generate_session_secret":1,
                "method":"auth.getSession",
        }

        sorted = params.items()
        sorted.sort(key=lambda x:x[0])

        str_to_hash = ''.join(["%s=%s"%(x[0], x[1]) for x in sorted])
        str_to_hash += FB_API_SECRET

        md5 = hashlib.md5()
        md5.update(str_to_hash)

        sig = md5.hexdigest()

        params["sig"] = sig

        encoded_params = urllib.urlencode(params)
        headers = {
                "Content-type":"application/x-www-form-urlencoded",
        }

        conn = httplib.HTTPConnection(FB_API_HOST)
        conn.request("POST", FB_API_PATH, encoded_params, headers)

        response = conn.getresponse()

        print response.status, response.reason
        return response.read()

This Works For Me when I use it with iphone facebook-connect client:

[FBSession sessionForApplication:myApiKey getSessionProxy:myURL delegate:self];

Cheers,
Steve

Labels: , ,


20090429

Stripping trailing whitespace from XCode

Firstly, my usual approach of s/\s+$//g doesn't work since it eats up the newline too. s/\s+$/\n/g doesn't work either because the Replace: field in the find dialogue doesn't escape the \n.

Final solution is as shown: s/[ \t]+$//g

Cheers,
Steve

Labels: , , , ,


20081226

DIY digital spirit level



DIY digital spirit level
Originally uploaded by sentientintelligence
A simply digital spirit level using a LIS302DL accelerometer from nkcelectronics coupled with a seeeduino for processing and a 2x16 character LCD display for output.

Sketch is available for your convenience. Note the Sketch includes an extra feature: PWM backlight on pin3.


Cheers,
Steve

Labels: , , ,


20080920

A relatively pain free Linux/OS X VNC setup

Ever since I got my 2nd monitor, I been using VNC to work on my laptop. Leopard's inbuilt VNC server isn't really VNC compliant, and has many issues when used with a normal VNC client. I have found Vine server to be an excellent replacement. The client side is a little interesting. RealVNC didn't work too well for me, in that often the screen would stop responding, or it would not receive key events. The best setup I have found is to use tightvnc with the following Vine server settings:

The client and server will happily share the clipboard if you enable it. Settings are accessed via F8 in the client, and via Preferences in the server. The client is smart enough to synchronise clipboards only when it loses focus - which would be you switching away to say, paste a url into firefox. All in all it is a fairly painless experience.

Cheers,
Steve

Labels: , , , , ,


20080731

iwconfig not setting essid?

If iwconfig wlan0 essid blah is seemingly not working when connecting to a open wireless network, then try

  1. iwconfig wlan0 essid blah
  2. iwconfig wlan0 key open
  3. iwconfig wlan0 enc off

The above seems to work for me by turning off encryption. It would appear with encryption enabled, iwconfig won't work for a open network because of some magic or other. If it still doesn't work, then try stick the above in your /etc/network/interfaces and prefix the commands with "wireless-", like so:

allow-hotplug wlan0
iface wlan0 inet dhcp
wireless-essid blah
wireless-key open
wireless-enc off

Hope this help some people, it drove me nuts!

Cheers,
Steve

Labels: , ,


20080724

grub, xfs, debian

Running grub-install with a XFS partition will likely fail - there is a reason lilo is used when XFS is root! The issue is grub-install creates the stage files in /boot/grub, which grub then expects to find when it accesses the disk directly using its own file system drivers. For most file systems sync is sufficient to force this to be true, but not with XFS - unless grubs's XFS drivers replays the journal, grub won't find the files. The detailed why of this is covered in this thread. To get around this, one needs to effectively replace sync with mount -r -o remount /; mount -w -o remount /. A quick a nasty way to get grub going with XFS partition is as follows:

  • init 1 # need single user mode to be able to remount root
  • cp /usr/sbin/grub-install /tmp # make a copy of grub-install to butcher
  • vim /tmp/grub-install
  • # now butcher grub-install as follows:
  • # 1. find the line that says "Sync to prevent GRUB from not finding stage files
  • # 2. deleted everything after sync
  • # 3. add exit 0 after sync for good measures
  • /tmp/grub-install # invoke our amputated grub-install to just produce the stage files
  • mount -r -o remount / # flush everything by mount as read only
  • mount -w -o remount / # remount since grub needs it to be rw
  • grub # invoke the grub shell
  • root (hdx,y) # manually specify the disk x partition y where /boot/grub/* is located
  • setup (hdx) # install grub into the disk x's MBR. DO NOT specify a partition number, XFS's sector 0 is NOT reserved for boot loaders!!
  • quit # exit grub
  • reboot # should work now

Cheers,
Steve

Labels: , , ,


20080716

unoffical libfg repository

I have set up an unofficial git respository for libfg patches and new swig generated python interface, as Gavin Baker (the author) appears to be busy with other things. This is a maintance only repository as far as libfg goes - I don't plan on adding any more features (since all the ones I need are there already). I will however work to produce a more pythonic interface to libfg, as the swig generated interface is a straight port of C api into Python.

Currently the repository contains the following fixes and enhancements:

If you have a patch against libfg, please post it at the libfg project's page first, and then to me if Gavin does not respond. I do not intend to take over development of libfg, and it is my hope Gavin will in the future make this obselete/redundant.

Cheers,
Steve

Labels: , , , , , ,


20080705

Another holiday, another webapp

Thats right, another webapp! This time using google's app engine, so feel free to abuse it, somewhat :P

Rank'em is its name, and it basically lets you create a collection of Things then allow other people to rank each Thing against each other, producing an overall ranking of Things.

Have fun and let me know what can be done better.

Cheers,
Steve

Labels: ,


20080505

Death by *nix

chown state: you
chmod o+x you
./you

Cheers,
Steve

Labels: , , ,


20080428

{} I <3 thee

Firstly, I am the kind of guy who likes tabs over spaces, because I don't like forcing my particular preferences on to other people. To wax poetic, I like to give other people the freedom of choosing how they want their code indented. This of course brings me into the firing line of python programmers, for whom the 4-spaces-per-indentation-level is equivalent to the Ten Commandments handed down from Mount Sinai. Officially, python doesn't care, but thats like saying officially the Church accepts evolution.

I was editing a working python file written by some one else today, and wanted to convert it to tabs (yes yes, I know all about leaving files as I found them etc. Silence). So I ran unexpand -t 4 on the file. This simply replaces 4 spaces with one tab. This should have given me a working and correct python file though now indented with tabs. Naturally (Moore's law and all) this is not happened. The newly tab-indented file was riddled with errors because the original file was not indented properly so the simple conversion did not work. And as I go about fixing the errors python threw at me, I realised to my horror that information about the structure of the code was corrupted. Because python interprets code structure based on indentation, if your indentation is incorrect, your code is incorrect.

In comparison, a brace using language like C would have made the corrections trivial, because the braces explicitly specify the code structure. Python's argument that everyone indents anyway and thus braces are redundant is flawed - braces are not redundant because braces represent the separation of content from presentation, something that has been hammered into developers. In ignoring this, python has allowed a new class of errors - changing the appearance of code will now change the function of the code. I really can't see how this is a good thing.

If nothing else, python's integration of presentation and content, and thus presentation and program correctness makes it a far less robust language than brace using languages. Less robust in that a mangled python file is unrecoverable unless you actually read the code to figure out its structure, and that incorrectly transcribed python will likely run anyway with no syntactic or runtime errors.

Consider for example, the following code:

for n in names:
    foo(n)
    bar(n)

If you were transcribing the code and accidentally did not indent bar(n), the code now does something complete different yet no syntax or runtime error will be thrown. Now if the above code used braces, then it would have no effect. And if you forgot the brace, a syntax error will be thrown.

To be fair, python is a lovely language, and I do love it and use it extensively. Whitespace-as-syntax stance appeared at first to be a great idea, and one which now appears to be short sighted and naive. If nothing else, at least an interpreter which disallows incorrect space-indent files, that way tab->space and space->tab conversions would work correctly all the time.

Let me now put on my flame retardant undies, and you can flame away

Cheers,
Steve

Labels: , , , ,


20080328

eeepc, likes and dislikes

Likes:

Dislikes:

Cheers,
Steve

Labels: , , , ,


20060318

Fourier fitting with gnuplot

gnuplot can be used to fit a fourier series to a series of data points. In my case it was an observation log for the star BE Lyncis from the Bossom Observatory, curtsey of Geir Klingenberg.

Firstly one needs to define a time function t(x) such that as x progresses from its minimum value to its maximum value t(x) ranges from 0 to 2PI. In my case minimum value of x was 2453416.20172 and maximum value was 2453416.42447. So my t(x) was constructed as follows:

t(x)=(x-2453416.20172)/0.22275*2*pi

We now need to define a fourier series, f(x). It takes the generic form of:

f(t)=c+a0*cos(t)+a1*sin(t)+a2*cos(2*t)+a3*sin(2*t)+ ...+{a#*cos((#+1)*t)+a(#+1)*sin((#+1)*t)}

Where #=0,1,2,3... infinity, and is the degree of the fourier series. Now we can use gnuplot's fit function to determine the values of all co-efficients and the constant c:

fit f(t(x)) 'be_lyn-2005.txt' using 1:2 via c,a0,a1,a2,...,a#,a(#+1)

A quick explanation: we are trying to fit f(t) where t=t(x) using data from the file be_lyn-2005.txt with data from the first and second column. The order of 1:2 is significant as it is in the form of x:y. Thus 2:1 means the first column is y value, second column is x value. (This is from experience, if any one knows better, tell me!)

Co-efficient values and the constant will be computed and shown, along with various statistic data. An plot of the fourier series and the observed data is shown below.

The plain text file be_lyn-2005.txt has 3 columns: JD, instrumental magnitude, and error estimate, the later of which was not used.

Cheers,
Steve

Labels: , , , , ,


This page is powered by Blogger. Isn't yours?