Showing posts with label software. Show all posts
Showing posts with label software. Show all posts

August 23, 2011

Manchester encoding/decoding in LibHiJack


The hijack iPhone library implements Manchester encoding for digital communication.  Manchester encoding maps 0 to high-low transition, and 1 to low-high transition.

The iPhone library generates the transitions using full or half period of a sine wave, using a full period when a bit run is detected. An example of this is shown below.

Manchester encoding of 0110011101 by libHiJack


Detection of Manchester encoding is relatively simple: first the signal is regenerated into a square wave by setting all values above 0 to 1 and 0 otherwise. The number of samples between transitions (0 to 1 or 1 to 0) is then measured. When this interval is within an acceptable range (as determined by the baud rate) the bit is read simply by taking the value of the regenerated square wave immediately after the transition. This works out nicely because 1 maps to a low-high transition, and the value immediately after transition is 1, while 0 maps to high-low transition, and the value immediately after transition is 0.

The important thing to note is that detection of a bit occurs at the transition from one bit to the next, and the code ignores transitions during a bit period. Specifically a transition must occur between 3/4 and 3/2 bit periods from last bit detection, otherwise it is ignored.

For example the transition between sample 64 and 96 is ignored because it occurs 1/2 a bit period since the last bit detection at sample 64.

Finally, the UART frame used consists of a start bit, eight data bits, one parity bits and one stop bit. Note my example doesn't include the parity bit since I reimplemented the encoding algorithm in python to produce the graph.

Cheers,
Steve

June 06, 2011

MYOB Not Printing Chinese Characters in Invoices

Simply set the language for non-unicode programs to Chinese (PRC) and it will magically work.



Cheers,
Steve

May 29, 2011

git with multiple svn-remotes

Use git init to create an empty git repository, then edit .git/config to add the svn remotes:

[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
[svn-remote "svn"]
url = file:///home/steve/code/svn-repos/foo
fetch = trunk:refs/remotes/trunk
branches = branches/*:refs/remotes/*
tags = tags/*:refs/remotes/tags/*
[svn-remote "svn-other"]
url = file:///home/steve/tmp/foo-svn-other
fetch = trunk:refs/remotes/svn-other/trunk
branches = branches/*:refs/remotes/svn-other/*
tags = tags/*:refs/remotes/svn-other/tags/*

It is assumed at this point svn-other is simply a copy of svn. They are allowed to diverge later.

Do a git svn fetch -R svn to initialise git svn. To manage commits between the two svn remotes, create local tracking branches of remote branches:

$ git checkout -b trunk-other remotes/svn-other/trunk

I ended up with something like :

  master
  trunk
* trunk-other
  remotes/svn-other/trunk
  remotes/trunk

You can pull changes from one svn repository then push it to another:

$ git svn fetch -R svn
r1 = 049fed636e283096986e0eefa261be0525d8d7b3 (refs/remotes/trunk)
Checked out HEAD:
$ git svn dcommit
Committing to file:///home/steve/tmp/foo-svn-other/trunk ...
A test
Committed r2
A test
r2 = 10613af6701eca4b30a3ff89ab408e38ca157fa0 (refs/remotes/svn-other/trunk)
No changes between current HEAD and refs/remotes/svn-other/trunk
Resetting to the latest refs/remotes/svn-other/trunk

Cheers,
Steve

May 18, 2011

Find and svn add all untracked files

svn st | grep '^?' | sed 's/^[? ]*/"/' | sed 's/$/"/' | xargs svn add

Cheers,
Steve

May 08, 2011

Firehol and mDNS


Here is my firehol.conf that allows multicast mDNS packets through:


# define mdns so we will accept it
server_mdns_ports="udp/5353"
client_mdns_ports="5353"


interface eth+ multi
   policy return
   server mdns accept
   server multicast accept                                                                                                        


interface eth+ home src "${home_ips}"
    server  all         accept
    client  all         accept


Initially I had the server mdns accept and server multicast accept inside the home interface, but this didn't work. Firehol's developer, Mr Costa Tsaousis, pointed out that src "${home_ips}" on home would exclude broadcast packets sent from MAC addresses, thus the second interface definition (multi).

Cheers,
Steve

April 18, 2011

TIL: const, NSError, NSApplicationsupportDirectory


  • const char *foo; is not the same as char * const foo; The former declares a pointer to constant char, while the latter declares a constant pointer to char.
  • - [NSError localizedDescription] returns the object for key NSLocalizedDescriptionKey in the error's userInfo dictionary. I always wondered how to set it since there is no setLocalizedDescription:.
  • On iOS the application's Application Support directory doesn't seem to exist by default, unlike the Documents directory. This has to be created programmatically.

Cheers,
Steve

April 15, 2011

ICBM: iOS OTA Distribution Webapp

Finding myself in the position of needing to distribute several apps OTA and unable to use the more well known OTA services like testflightapp.com due to client concerns, I made my own, ICBM.

ICBM is a small python webapp built using my favourite webapp framework,  bottle. You just put your application along with icons and the Info.plist (not the binary one) into a directory, and ICBM will generate the required HTML page and manifest plist.

e.g.

  • icbm.py
    • AwesomeApp/
      • AwesomeApp.ipa
      • Icon.png
      • Icon_512.png
      • AwesomeApp-Info.plist


More detail over at its github page: https://github.com/freespace/icbm.

Cheers,
Steve

February 25, 2011

Tabbing in Vim With Tab Autocompletion

I use vim with a tab autocompletion macro, and sometimes I really do want to insert a tab character and autocompletion gets in the way.

Today I found out that if I hold down shift and hit tab, a tab is inserted and tab autocompletion doesn't get triggered. Prior to this I have been adding a space then hitting tab, which leaves ugly little space-tab sequences in my files.

Hope this helps some one out there.

Cheers,
Steve

February 21, 2011

Broken OS X Installers and How to Fix Them

The installers Ralink provides for some of their chipsets, like the RT2770 does something retarded: they attempt to unload a kext in a pre-install script, and when it fails the script fails and the entire install fails.

This means on a new machine, or one that never had the kext installed, you can't install their driver.

Fail.

It used to be that pkg installers were just directories, and fixing something like this is easy: find the offending line and comment it out. But OS X 10.5 onwards introduced flat pkgs. These don't give up their secrets so easily.

An article on cnet tipped me off to pkgutil, a program that is installed by default. It lets you expand a flat pkg into a directory, and more importantly, allows to repackage it as a flat pkg after you have excised the cause of your troubles. This last step is important because a flat pkg when unpacked has a different directory structure to a "normal" pkg and thus can not simply be open'd.

Here is what I did to fix Ralink's installer:

  1. pkgutil --expand installer.pkg ~/Desktop/installer-expanded.pkg
  2. cd ~/Desktop/installer-expanded.pkg/installroot.pkg/Scripts/
  3. vim preinstall #alternatively, for ppl unfamilar with vim:
    1. open .
    2. right click on preinstall, open in TextEdit.app
  4. comment out the offending line which is trying to remove the kext
  5. save and exit your editor
  6. cd ~/Desktop
  7. pkgutil --flatten installer-expanded.pkg installer.pkg
  8. open ./installer.pkg

Cheers,
Steve

January 27, 2011

iPhone 4 layer export script for Gimp

I often mockup iPhone interfaces on the Gimp, then exporting each layer for use as backgrounds. For iOS 4 each image needs to be exported twice: one at full resolution with @2x in its filename, and once at half-resolution without the @2x. e.g. nav_bg@2x.png and nav_bg.png.

Exporting layers by hand gets old real quick. Thankfully the Gimp supports scripting in my favourite language: python. Even better, Chris Mohler had already written a script to do something very similar, so all I needed to do was make some simple adjustments:
#!/usr/bin/env python
# -*- coding: <utf-8> -*-
# Author: Chris Mohler <cr33dog@gmail.com>
# Copyright 2009 Chris Mohler
# "Only Visible" and filename formatting introduced by mh
# License: GPL v3+
# Version 0.4
# GIMP plugin to export layers as PNGs
# modified by Shuning Bian 2011

from gimpfu import *
import os, re

gettext.install("gimp20-python", gimp.locale_directory, unicode=True)

def format_filename(layer):
    layername = layer.name.decode('utf-8')
    filename1 = layername + "@2x.png"
    filename2 = layername + ".png"
    return filename1,filename2

def get_layers_to_export(img):
    layers = []
    for layer in img.layers:
        if layer.visible:
            layers.append(layer)
    return layers

def export_layers(img, path):
    dupe = img.duplicate()
    savelayers = get_layers_to_export(dupe)
    for layer in dupe.layers:
        layer.visible = 0 
    for layer in dupe.layers:
        if layer in savelayers:
            layer.visible = 1

            if layer.mask:
                pdb.gimp_layer_remove_mask(layer, 0)

            filename1,filename2 = format_filename(layer)
            fullpath = os.path.join(path, filename1);
            tmp = dupe.duplicate()
            pdb.file_png_save(tmp, tmp.layers[0], fullpath, filename1, 0, 9, 1, 1, 1, 1, 1)

            imgwidth = pdb.gimp_image_width(img)
            imgheight = pdb.gimp_image_height(img)
            pdb.gimp_image_scale_full(tmp, imgwidth/2, imgheight/2, 2)

            fullpath = os.path.join(path, filename2)
            pdb.file_png_save(tmp, tmp.layers[0], fullpath, filename2, 0, 9, 1, 1, 1, 1, 1)

        dupe.remove_layer(layer)

            
register(
    proc_name=("python-fu-export-layers-iphone4"),
    blurb=("Export visible layers as PNG"),
    help=("Export all visible layers as individual PNG files."),
    author=("Chris Mohler <cr33dog@gmail.com> + sbian"),
    copyright=("Chris Mohler"),
    date=("2009"),
    label=("as _PNG"),
    imagetypes=("*"),
    params=[
        (PF_IMAGE, "img", "Image", None),
        (PF_DIRNAME, "path", "Save PNGs here", os.getcwd()),
           ],
    results=[],
    function=(export_layers), 
    menu=("<Image>/File/E_xport Layers"), 
    domain=("gimp20-python", gimp.locale_directory)
    )

main()

Cheers,
Steve

January 23, 2011

Socket.IO Framing Protocol

Socket.IO is a great library and framework that doesn't seem to have a good description of the protocol available. In interest of helping others when they google "socket.io framing protocol", this post was born.

The description of the framing protocol used by Socket.IO below is taken from ajaxorg's Socket.IO-node fork on github. I have made some changes with regards to the annotations, specifically that they must be terminated by with newline. This description is current for v0.6+.

Socket.IO Framing Protocol

Socket.IO 's framing protocol is on top of the underlying transport. Messages have the following format:
(message type)":"(content length)":"(data)","
Where message type is one of:

  • 0 for forced disconnect - no data is sent, always sent as 0:0:,
  • 1 for messages - see below
  • 2 for heartbeats - data is an integer, e.g. 2:1:0, 
  • 3 for session ID handshake - data is a session ID, e.g. 3:3:253,


Messages

If you were familiar with the Socket.IO protocol you will notice there appears to be no way now to specify a message contains JSON data as the new protocol has no counter part to the JSON Frame indicator ~j~. Fear not - the new Socket.IO protocol provides a means for this and many other possible extensions via annotations which maybe attachd to messages in a manner reminiscent of HTTP headers. 

A Socket.IO message now has the following format:
[key[:value]["\n"key[:value]]["\n"key[:value]..."\n"]":"[message]
In words: annotations are key-value pairs where the value may be omitted. Individual annotations are delimited by newlines, and annotations are separated from the message by another newline.

From examining the Socket.IO source, if no annotation is present then there should be no newline, but the colon is still required.

A JSON message is sent with a single annotation with key of j and no value. Below is an example taken from a debugging session:
1:128:j
:{"method":"create_user","params":[{"password":"jhhgffufuhgv","email":"h@h.com"}],"id":"83BCA0A8-7F9D-428A-A546-2EFCBDC20AB3"},
Note there is a newline after the j. The official Socket.IO client uses an additional annotation: r for realm. e.g.
1:18:r:chat
:Hello world,
Note the newline after chat.

Cheers,
Steve

January 16, 2011

UIGraphicsBeginImageContext on iPhone 4

I generate UIImages in some of my iOS applications, and prior to the iPhone 4 they all worked fine. With the introduction of the iPhone 4 and Retina Display, I realised my generated images were blurry even though I am rendering them at twice the resolution.

It turns out this is due to the scale property of my generated UIImages being set to 1. This is mainly due to my use of UIGraphicsBeginImageContext(), which creates a bitmap context that is a) non-opaque and b) scale=1. The fix is quite simple - use UIGraphicsBeginImageContextWithOptions() and specify the scale appropriately.

For images derived from an existing image, e.g. rotating an existing image, it is sufficient to use the scale property of UIImage. For images created "from scratch", I use the following bit of code:
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)])
{
  UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
}
else UIGraphicsBeginImageContext(size);

Cheers,
Steve

December 16, 2010

Pulse-o-matic now on App Store

It took a month and a bit, but Pulse-o-matic is finally on the App Store. For my loyal followers (all 3 of you), email me for a promotion code :)

Cheers,
Steve

September 21, 2010

Thoughts on HTML, computer programs, and programming languages

I would like to start this post off by saying that emotionally I agree with the sentiment that HTML is not a programming language. Intellectually, however, my position is that HTML is a programming language.

My argument for HTML as a programming language is very abstract, and to put it simply: programming languages are used to express instructions to the computer on what to do. HTML instructs the computer on how to display content, therefore HTML is a programming language. Against this argument are the following, which can be encountered on any number of programming websites.

The most common argument against HTML being a programming language is that it describes itself as a markup language, as evident by the M in HTML. I find this argument wanting on 2 fronts: a) it implicitly assumes that a markup language can not be a programming language. TEX is a good example of a language which 99% of the time is used for markup, and the other 1% for programming; b) this argument is superficial. It implies if I was to simply rename HTML to HTPL, hypertext programming language, then *poof* now it is a programming language without having changed any of its characteristics. A rose by any other name...

A better argument is that HTML doesn't have control structures, whereas programming languages do. Suppose we accept this argument, which implicitly requires programming languages to support control structures. Consider a strict subset of LOGO, called miniLOGO that contains only the turtle graphics part of LOGO and nothing else - no loops, no conditionals, no control structures. By the definition we have assumed here, miniLOGO isn't a programming language. Now suppose you write a program in miniLOGO to draw "hello world"  on the screen, what have you written? I (and most people) say it is a program. This then presents a problem: you should not be able to write a program with a not-programming-language. At least it is a problem for me.

Suppose now you say no, the miniLOGO hello world isn't a program, and you give one of two reasons - that it doesn't contain control structures or that it wasn't written in a programming language. The first reason implicitly defines all programs as those containing control structures. I can not accept this reason because you can make a non-program a program by injecting a control structure with no side effect, and it is no less absurd and no more useful than the accepting HTML as a programming language. Not to mention the millions of introductory programming texts that will need to be rewritten so "hello world" contains an unecessary control structure. (There are those who will then say: there ARE control structures, they are just a few levels of abstractions down. Well there are similar control structures in a browser. We do not worry about the rest of the abstraction stack, only the top of it).

For the second reason, consider what happens if I write the same program in full is-a-programming-language LOGO. Now it is a program by the virtue of having been written in a programming language, which brings us to an uncomfortable place: now we two things which are absolutely identical, but one is a program and one isn't by virtue of their parentage. Accepting this position is no more absurd than accepting that HTML is a programming language.

The final argument I will discuss is that my definition is such a generic definition just about anything is a programming language, therefore that definition is next to useless. This I agree with. However as I have (hopefully) demonstrated, it isn't easy to come up with a definition of what is a programming language (or in fact what is a program) that isn't contradictory or would invalidate millions of simple programs around the world.

I am still giving this issue thought, but until I am a more learned person in CS and possibly philosophy, my choice is between a definition of programming languages with low discriminatory powers, or ones which are fickle and contradictory.

HTML-is-a-programming-language, I choose you!

Cheers,
Steve

June 09, 2010

Script to make IPAs for ad-hoc distribution.

This script produces an IPA, then verifies to make sure the IPA is actually valid.
PRODUCT_NAME=""
IPA="${PRODUCT_NAME}.ipa"
APP="${PRODUCT_NAME}.app"

if [ -z "${PRODUCT_NAME}" ]; then
        echo "PRODUCT_NAME not set";
        exit 1;
fi

rm -rf ipa
mkdir -p ipa/Payload &&
cp -R build/Debug-iphoneos/${APP} ipa/Payload/ &&
pushd ipa &&
zip -q --symlinks -r ${IPA} Payload/ &&
mkdir test/ &&
cp ${IPA} test &&
cd test &&
unzip -q ${IPA} &&
cd Payload/ &&
codesign --verify --verbose ${APP} &&
popd
open ipa/
Designed to be ran from the command line, but it should be easily made into a build phase.

Cheers,
Steve

January 05, 2010

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

December 31, 2009

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

October 11, 2009

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.

August 05, 2009

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

June 07, 2009

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