Random Sequence - Articles Notes to Self, scripts & tips for geeks.
And other potentially useful information.
2013-05-24T09:47:35ZRandom Sequencefeedmaster@randomsequence.comhttp://www.randomsequence.com//articles/feed/UK Search Safari Extensionhttp://www.randomsequence.com/fa755791d0509bb06ae715a2072de724815ed84d2012-09-23T00:00:00Z<p>An extension for Safari which redirects searches from google.com to google.co.uk As of version 6.0, Safari still doesn’t have a setting to automatically use google.co.uk (or uk.yahoo.com) for searches. This extension redirects searches from Google.com to Google.co.uk, and from search.yahoo.com to uk.search.yahoo.com.</p>
<p>It doesn’t do anything else, there are no settings and it’s free (<a href="https://github.com/randomsequence/UK-Search-Safari-Extension">source available on GitHub</a>).</p>
<p><em>Update</em> Get the latest version from Github for Safari 6.0.1.</p>
<h2>Download</h2>
<p><a href="https://github.com/randomsequence/UK-Search-Safari-Extension/downloads">Get the latest version from Github</a></p>
Building OpenCV 2.2 for Snow Leopardhttp://www.randomsequence.com/e794a80eb109162d579df51db6d52e223bb0e9be2011-03-10T00:00:00Z<p>As I found, incorporating the OpenCV image processing library into your Cocoa app is more difficult that it sounds. The 2.2 release of <a href="http://opencv.willowgarage.com/wiki/">OpenCV</a> supports building on x86_64 systems. I spent longer than I expected to setting up a test Xcode Cocoa project where I could begin experimenting with the latest release, targeting i386 & x86_64. Here’s how I got there:</p>
<h3>Install CMake</h3>
<p>Building OpenCV 2.2 requires using CMake.</p>
<p><em>CMake is a unified, cross-platform, open-source build system that allows developers to build, test and package software by specifying build parameters in simple, portable text files.</em>
(<a href="http://en.wikipedia.org/wiki/CMake">Wikipedia</a>)</p>
<p>Being a clean-shaven developer, this is the first time I’ve needed to use this tool. It doesn’t come included with Snow Leopard, so you need to obtain this from somewhere else. I used <a href="http://www.macports.org/">MacPorts</a>. If you’ve previously installed MacPorts for something else, it’s worth doing an update before you install anything:</p>
<pre><code>sudo port selfupdate
</code></pre>
<p>This may take some time. When that’s done:</p>
<pre><code>sudo port clean cmake; sudo port install cmake;
</code></pre>
<p>The clean command may save you doing this twice if you’ve had a build which failed.</p>
<h3>Download & Configure OpenCV</h3>
<p>The latest version (2.2 at the time of writing) should be available here:
<a href="http://sourceforge.net/projects/opencvlibrary/files/opencv-unix/">http://sourceforge.net/projects/opencvlibrary/files/opencv-unix/</a></p>
<p>Once you’ve downloaded & extracted the source code, open a terminal window and head to that folder, then make yourself a build folder:</p>
<pre><code>cd OpenCV-2.2.0
mkdir build
cd build
</code></pre>
<p>Ask ccmake to make us an Xcode project:</p>
<pre><code>ccmake -G "Xcode" ../
</code></pre>
<p>In the ccmake interactive console, you should see a “EMPTY CACHE” at the top of the console window. Hit ‘c’ to create an initial configuration. Once that’s done, use the arrow keys to move down the list, enter to change a value. My configuration looked like this (I changed only BUILD_SHARED_LIBS & BUILD_TESTS, both to OFF):</p>
<pre><code>BUILD_EXAMPLES *OFF
BUILD_LATEX_DOCS *OFF
BUILD_NEW_PYTHON_SUPPORT *OFF
BUILD_PACKAGE *OFF
BUILD_SHARED_LIBS *OFF
BUILD_TESTS *OFF
BZIP2_LIBRARIES */usr/lib/libbz2.dylib
CMAKE_BACKWARDS_COMPATIBILITY *2.4
CMAKE_BUILD_TYPE *
CMAKE_CONFIGURATION_TYPES *Debug;Release;MinSizeRel;RelWithDebInfo
CMAKE_INSTALL_PREFIX */usr/local
CMAKE_OSX_ARCHITECTURES *
CMAKE_OSX_DEPLOYMENT_TARGET *
CMAKE_OSX_SYSROOT */Developer/SDKs/MacOSX10.6.sdk
CMAKE_VERBOSE *OFF
EIGEN2_INCLUDE_PATH *EIGEN2_INCLUDE_PATH-NOTFOUND
ENABLE_PROFILING *OFF
ENABLE_SSE *ON
ENABLE_SSE2 *ON
ENABLE_SSE3 *OFF
ENABLE_SSE41 *OFF
ENABLE_SSE42 *OFF
ENABLE_SSSE3 *OFF
EXECUTABLE_OUTPUT_PATH */Users/mrwalker/Downloads/OpenCV-2.2.0/build/bin
INSTALL_C_EXAMPLES *OFF
INSTALL_PYTHON_EXAMPLES *OFF
IPP_PATH *IPP_PATH-NOTFOUND
LIBRARY_OUTPUT_PATH */Users/mrwalker/Downloads/OpenCV-2.2.0/build/lib
OPENCV_BUILD_3RDPARTY_LIBS *ON
OPENCV_CONFIG_FILE_INCLUDE_DIR */Users/mrwalker/Downloads/OpenCV-2.2.0/build
OPENCV_EXTRA_C_FLAGS *
OPENCV_EXTRA_C_FLAGS_DEBUG *
OPENCV_EXTRA_C_FLAGS_RELEASE *
OPENCV_EXTRA_EXE_LINKER_FLAGS *
OPENCV_EXTRA_EXE_LINKER_FLAGS_ *
OPENCV_EXTRA_EXE_LINKER_FLAGS_ *
OPENCV_WARNINGS_ARE_ERRORS *OFF
OPENEXR_INCLUDE_PATH *OPENEXR_INCLUDE_PATH-NOTFOUND
PVAPI_INCLUDE_PATH *PVAPI_INCLUDE_PATH-NOTFOUND
USE_FAST_MATH *ON
USE_IPP *OFF
USE_O3
USE_OMIT_FRAME_POINTER *ON
WITH_1394 *ON
WITH_CARBON *OFF
WITH_CUDA *OFF
WITH_EIGEN2 *ON
WITH_FFMPEG *ON
WITH_JASPER *ON
WITH_JPEG *ON
WITH_OPENEXR *ON
WITH_PNG *ON
WITH_PVAPI *ON
WITH_QT *OFF
WITH_QT_OPENGL *OFF
WITH_QUICKTIME *OFF
WITH_TBB *OFF
WITH_TIFF *ON
</code></pre>
<p>Hit ‘c’ to reconfigure for the new settings, then ‘g’ to write out the configuration and exit. Open the build folder - it should now contain an XCode project:</p>
<pre><code>open OpenCV.xcodeproj
</code></pre>
<h3>Fat Binaries</h3>
<p>Building this Xcode project in Debug or Release configuration will make the static libraries for your current system architecture. If you’re going to link against these static libraries with a universal binary, you’re going to need multi-architecture libraries:</p>
<ul>
<li>Select OpenCV at the top of the project source tree, then choose File > Get Info from the menu (cmd-i). </li>
<li>Select the ‘build’ tab at the top of the window</li>
<li>Change the Configuration to Release</li>
<li>Under architectures, uncheck ‘Build Active Architecture Only’</li>
<li>If you’re targeting the Mac App Store, remove the PPC architectures from the Valid Architectures list</li>
<li>Close the project info panel. </li>
</ul>
<p>Now set the active configuration to Release, build your project. You’ve built yourself multi-architecture static libraries.</p>
<h3>Linking Against OpenCV</h3>
<p>Create a new Xcode project. I used a command line tool to test the first example project from <a href="http://www.amazon.com/Learning-OpenCV-Computer-Vision-Library/dp/0596516134">Learning OpenCV</a>:</p>
<ul>
<li>Choose File > New Project</li>
<li>Choose Mac OS X > Application from the source list</li>
<li>Choose Command Line Tool from the project templates</li>
<li>Choose Foundation under Type</li>
<li>Save the project. I named mine CVDemo and saved to the Desktop.</li>
</ul>
<p>Repeat the “fat binaries” process from above to make sure your test project has the same build architectures as the libraries you’re going to link against.</p>
<p>Add the static libraries from your OpenCV project.</p>
<ul>
<li>In your OpenCV project, Open the Products group in the source tree</li>
<li>Drag everything ending ‘.a’ from this project to the source tree in your new project. </li>
<li>Check “Copy items into destination group’s folder”</li>
<li>Check the add to target checkbox for your target (mine is called CVDemo)</li>
<li>Click Add</li>
</ul>
<h3>Frameworks & Build Settings</h3>
<p>OpenCV 2.2 itself links against the Cocoa, QuartzCore and QTKit frameworks.</p>
<ul>
<li>In your new project, select your target. Choose File > Get Info</li>
<li>Select the ‘General’ tab</li>
<li>Click the ‘+’ at the very bottom left of the Linked Libraries section</li>
<li>Select Cocoa, QuartzCore and QTKit from the list, click ‘Add’</li>
</ul>
<p>Xcode needs to know where it’s going to find your static libraries. Still looking at the Target Info window:</p>
<ul>
<li>Select the ‘Build’ tab</li>
<li>Scroll to ‘Linking’, double-click ‘Other Linker Flags’</li>
<li>Click ‘+’, Enter ‘-lstdc++’ (without quotes), click ‘OK’</li>
</ul>
<h3>Headers</h3>
<p>The headers for OpenCV 2.2 are split amongst various modules. I don’t know a sensible way to collect these together from the Xcode project (please let me know if you do), so I re-configured everything in a new build folder:</p>
<p>In the root folder of your downloaded source code, make a new folder:</p>
<pre><code>cd OpenCV-2.2.0
mkdir build_unix
cd build_unix
ccmake -G "Unix Makefiles" ../
</code></pre>
<ul>
<li>Generate the base configuration (‘c’)</li>
<li>change the settings as before with one change: set CMAKE_INSTALL_PREFIX to a path inside your build_unix folder. Mine was /Users/mrwalker/Downloads/OpenCV-2.2.0/build_unix/unix_install</li>
<li>configure again (‘c’)</li>
<li>generate the make files (‘g’)</li>
</ul>
<p>In the terminal, build & install the unix makefile:</p>
<pre><code> make; make install
</code></pre>
<p>This will collect the headers you need together into unix_install/include.</p>
<ul>
<li>Using the Finder, copy opencv & opencv2 from unix_install/include to new folder next to your new project (CVDemo). I named mine ‘headers’</li>
</ul>
<p>Xcode needs to know where to look for the OpenCV headers. Still looking at the Target Info window:</p>
<ul>
<li>Select the ‘Build’ tab</li>
<li>Scroll to ‘Search Paths’, double-click ‘Header Search Paths’</li>
<li>Click ‘+’, Enter ‘headers’ (without quotes), click ‘OK’</li>
</ul>
<h3>Sample Code</h3>
<p>In your test project (CVDemo), edit main.m with a test project. Mine looked like this:</p>
<pre><code>#import <Foundation/Foundation.h>
#import "opencv2/imgproc/imgproc_c.h"
#import "opencv2/highgui/highgui_c.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *filePath = nil;
if (argc > 1) {
filePath = [[NSString stringWithCString:argv[1] encoding:NSUTF8StringEncoding] stringByExpandingTildeInPath];
} else {
filePath = @"/Users/mrwalker/Desktop/test.jpg";
}
IplImage *img = cvLoadImage([filePath cStringUsingEncoding:NSUTF8StringEncoding], 1);
cvSmooth( img, img, CV_GAUSSIAN, 3, 3 , 0, 0);
cvNamedWindow("Test1", CV_WINDOW_AUTOSIZE);
cvShowImage("Test1", img);
cvWaitKey(0);
cvReleaseImage(&img);
cvDestroyWindow("Test1");
[pool drain];
return 0;
}
</code></pre>
<h3>Build & Run</h3>
<p>That’s it, you should now have an environment to play with OpenCV 2.2 on Snow Leopard.</p>
<p>If this article has saved you some time and you want to say thanks, you could buy my <a href="http://rndsq.com/albums">Albums app</a>, tell your friends about my <a href="http://rndsq.com/introquiz">Free Intro Quiz app</a>, or just say thanks <a href="http://twitter.com/mrwalker">via twitter</a>.</p>
Adding a Toolbar with Next & Previous above UITextField Keyboardhttp://www.randomsequence.com/a2e33d344f272e100d4a8efeabc7ae8a60a8ba7a2011-04-08T00:00:00Z<p>How to add a toolbar above the standard iPhone keyboard with next, previous & done buttons, as Mobile Safari does when filling in forms. Here’s how to add a custom toolbar above the standard iPhone keyboard which animates in and out as the keyboard shows / hides. Sample project included at the bottom.</p>
<p><strong>NOTE: From iOS 3.2, UITextView has an inputAccessoryView property which makes most of this redundant</strong></p>
<p>The important parts are:</p>
<p><strong>Subscribe to the UIWindow notifications <code>UIKeyboardWillShowNotification</code> and <code>UIKeyboardWillHideNotification</code></strong></p>
<p>These notify the observer of the keyboard’s appearance, size, position and animation details. With this information, we can animate our toolbar into the correct position in sync with the keyboard appearance animation.</p>
<p>The header file:</p>
<pre><code>//
// TFTestViewController.h
// TFTest
//
// Created by Johnnie Walker on 26/01/2010.
//
#import <UIKit/UIKit.h>
@interface TFTestViewController : UIViewController {
IBOutlet UIToolbar *keyboardToolbar;
UISegmentedControl *nextPreviousControl;
IBOutlet UITextField *textField1;
IBOutlet UITextField *textField2;
IBOutlet UITextField *textField3;
BOOL keyboardToolbarShouldHide;
}
@property (nonatomic, retain) UISegmentedControl *nextPreviousControl;
@property (nonatomic, retain) UIToolbar *keyboardToolbar;
- (IBAction)nextPrevious:(id)sender;
- (IBAction)dismissKeyboard:(id)sender;
- (IBAction)editingChanged:(id)sender;
@end
</code></pre>
<p>Creating & showing the toolbar when the keyboard appears:</p>
<pre><code>- (void)keyboardWillShow:(NSNotification *)notification
{
CGPoint beginCentre = [[[notification userInfo] valueForKey:UIKeyboardCenterBeginUserInfoKey] CGPointValue];
CGPoint endCentre = [[[notification userInfo] valueForKey:UIKeyboardCenterEndUserInfoKey] CGPointValue];
CGRect keyboardBounds = [[[notification userInfo] valueForKey:UIKeyboardBoundsUserInfoKey] CGRectValue];
UIViewAnimationCurve animationCurve = [[[notification userInfo] valueForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
NSTimeInterval animationDuration = [[[notification userInfo] valueForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
if (nil == keyboardToolbar) {
if(nil == keyboardToolbar) {
keyboardToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0,0,self.view.bounds.size.width,44)];
keyboardToolbar.barStyle = UIBarStyleBlackTranslucent;
keyboardToolbar.tintColor = [UIColor darkGrayColor];
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(dismissKeyboard:)];
UIBarButtonItem *flex = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UISegmentedControl *control = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:
NSLocalizedString(@"Previous",@"Previous form field"),
NSLocalizedString(@"Next",@"Next form field"),
nil]];
control.segmentedControlStyle = UISegmentedControlStyleBar;
control.tintColor = [UIColor darkGrayColor];
control.momentary = YES;
[control addTarget:self action:@selector(nextPrevious:) forControlEvents:UIControlEventValueChanged];
UIBarButtonItem *controlItem = [[UIBarButtonItem alloc] initWithCustomView:control];
self.nextPreviousControl = control;
NSArray *items = [[NSArray alloc] initWithObjects:controlItem, flex, barButtonItem, nil];
[keyboardToolbar setItems:items];
[control release];
[barButtonItem release];
[flex release];
[items release];
keyboardToolbar.frame = CGRectMake(beginCentre.x - (keyboardBounds.size.width/2),
beginCentre.y - (keyboardBounds.size.height/2) - keyboardToolbar.frame.size.height,
keyboardToolbar.frame.size.width,
keyboardToolbar.frame.size.height);
[self.view addSubview:keyboardToolbar];
}
}
[UIView beginAnimations:@"RS_showKeyboardAnimation" context:nil];
[UIView setAnimationCurve:animationCurve];
[UIView setAnimationDuration:animationDuration];
keyboardToolbar.alpha = 1.0;
keyboardToolbar.frame = CGRectMake(endCentre.x - (keyboardBounds.size.width/2),
endCentre.y - (keyboardBounds.size.height/2) - keyboardToolbar.frame.size.height - self.view.frame.origin.y,
keyboardToolbar.frame.size.width,
keyboardToolbar.frame.size.height);
[UIView commitAnimations];
keyboardToolbarShouldHide = YES;
}
</code></pre>
<p>Hiding the toolbar when the keyboard disappears, again in sync with the keyboard animation:</p>
<pre><code>- (void)keyboardWillHide:(NSNotification *)notification
{
if (nil == keyboardToolbar || !keyboardToolbarShouldHide) {
return;
}
CGPoint endCentre = [[[notification userInfo] valueForKey:UIKeyboardCenterEndUserInfoKey] CGPointValue];
CGRect keyboardBounds = [[[notification userInfo] valueForKey:UIKeyboardBoundsUserInfoKey] CGRectValue];
UIViewAnimationCurve animationCurve = [[[notification userInfo] valueForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
NSTimeInterval animationDuration = [[[notification userInfo] valueForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView beginAnimations:@"RS_hideKeyboardAnimation" context:nil];
[UIView setAnimationCurve:animationCurve];
[UIView setAnimationDuration:animationDuration];
keyboardToolbar.alpha = 0.0;
keyboardToolbar.frame = CGRectMake(endCentre.x - (keyboardBounds.size.width/2),
endCentre.y - (keyboardBounds.size.height/2) - keyboardToolbar.frame.size.height,
keyboardToolbar.frame.size.width,
keyboardToolbar.frame.size.height);
[UIView commitAnimations];
}
</code></pre>
<p><strong>Switch between fields using [(UITextField *) becomeFirstResponder:]</strong></p>
<p>Note that this is different to the way Mac OS X works, and not obvious from the documentation. Also note findFirstResponder: is not a standard UIView method. The sample project includes the code for the category on UIView.</p>
<pre><code>- (void)nextPrevious:(id)sender
{
UIView *responder = [self.view findFirstResponder];
if (nil == responder || ![responder isKindOfClass:[GroupTextField class]]) {
return;
}
switch([(UISegmentedControl *)sender selectedSegmentIndex]) {
case 0:
// previous
if (nil != ((GroupTextField *)responder).previousControl) {
[((GroupTextField *)responder).previousControl becomeFirstResponder];
DebugLog(@"currentControl: %i previousControl: %i",((GroupTextField *)responder).tag,((GroupTextField *)responder).previousControl.tag);
}
break;
case 1:
// next
if (nil != ((GroupTextField *)responder).nextControl) {
[((GroupTextField *)responder).nextControl becomeFirstResponder];
DebugLog(@"currentControl: %i nextControl: %i",((GroupTextField *)responder).tag,((GroupTextField *)responder).nextControl.tag);
}
break;
}
}
</code></pre>
<p><strong>Listen for UITextView’s <code>textFieldShouldBeginEditing:</code> and <code>textFieldShouldEndEditing:</code> delegate methods.</strong></p>
<p>When switching between fields either programatically or by tapping on them, the observer still recieves the keyboard hide / show notifications. Here we keep track when we’re moving to another field to cancel the animation.</p>
<pre><code>- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
keyboardToolbarShouldHide = NO;
DebugLog(@"textFieldShouldBeginEditing: %@",textField);
return YES;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
DebugLog(@"textFieldShouldEndEditing: %@",textField);
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
if (textField == textField1) {
[textField2 becomeFirstResponder];
} else if (textField == textField2) {
[textField3 becomeFirstResponder];
} else if (textField == textField3) {
[textField1 becomeFirstResponder];
}
return NO;
}
</code></pre>
<p>Use these to avoid animating the toolbar when the keyboard stays on screen.</p>
<p>Download the test project: %file_link:0%</p>
Django Admin Google Maps Location Picker with JQueryhttp://www.randomsequence.com/12f0de3dc76e067d21ed85125716e02e9f1e69f02009-10-22T00:00:00Z<p>An admin widget for Django which uses Google Maps + JQuery to pick a map location settings.py</p>
<pre><code>MAPS_API_KEY = 'XXYYZZ'
</code></pre>
<p>YOUR_APP/models.py</p>
<pre><code>from django.db import models
from YOUR_APP.widgets import *
class Place(models.Model):
"""(Place description)"""
location = LocationField(blank=True, max_length=255)
</code></pre>
<p>YOUR_APP/widgets.py</p>
<pre><code>from django import forms
from django.db import models
from django.conf import settings
class LocationPickerWidget(forms.TextInput):
class Media:
css = {
'all': (
settings.MEDIA_URL + 'css/location_picker.css',
)
}
js = (
'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js',
'http://www.google.com/jsapi?key=' + settings.MAPS_API_KEY,
settings.MEDIA_URL + 'js/jquery.location_picker.js',
)
def __init__(self, language=None, attrs=None):
self.language = language or settings.LANGUAGE_CODE[:2]
super(LocationPickerWidget, self).__init__(attrs=attrs)
def render(self, name, value, attrs=None):
if None == attrs:
attrs = {}
attrs['class'] = 'location_picker'
return super(LocationPickerWidget, self).render(name, value, attrs)
class LocationField(models.CharField):
def formfield(self, **kwargs):
kwargs['widget'] = LocationPickerWidget
return super(LocationField, self).formfield(**kwargs)
</code></pre>
<p>location_picker.css</p>
<pre><code>.location_picker_map {
width: 300px;
height: 200px;
border: 1px solid black;
padding: 2px;
display: inline-block;
}
</code></pre>
<p>jquery.location_picker.js</p>
<pre><code>google.load("maps", "2");
$(document).unload(function(){
GUnload();
});
$(document).ready(function(){
$("input.location_picker").each(function (i) {
var map = document.createElement('div');
map.className = "location_picker_map";
this.parentNode.insertBefore(map, this);
$(this).css('display','none');
var lat = 55.950161;
var lng = -3.187408;
if (this.value.split(',').length == 2) {
values = this.value.split(',');
lat = values[0];
lng = values[1];
}
var center = new GLatLng(lat,lng);
var map = new google.maps.Map2(map);
map.addControl(new GSmallMapControl());
map.setCenter(center, 13);
this.onMapClick = function(overlay, point) {
this.value = point.lat()+','+point.lng();
if (this.marker == null) {
this.marker = new GMarker(point);
this.map.addOverlay(this.marker);
} else {
this.marker.setPoint(point);
}
}
this.marker = new GMarker(center);
map.addOverlay(this.marker);
GEvent.bind(map, "click", this, this.onMapClick);
});
});
</code></pre>
Mercurial avgtag Extensionhttp://www.randomsequence.com/efa6e44dfa0145249be273ecd84a97f534b049202009-08-07T00:00:00Z<p>A <a href="http://mercurial.selenic.com/">Mercurial</a> extension for use with XCode. Updates CFBundleVersionString when adding a tag to the repository.</p>
<p>[Mercurial]: http://mercurial.selenic.com/ ##What Is This?</p>
<p>It’s a replacement command for <code>hg tag</code>. This version updates the short bundle string in your Info.Plist, commits the change, then adds the tag.</p>
<p>Tested with Mercurial 1.3 on Mac OS X 10.5.7</p>
<h2>Source</h2>
<p><code>avgtag.py</code></p>
<pre><code>#!/usr/bin/env python
from mercurial import (hg, repo, commands)
from subprocess import call
import os
def agvtag_cmd(ui, repo, tag, **opts):
path = ui.config('agvtag', 'path', default=".", untrusted=False)
os.chdir(path)
call(['agvtool', 'new-marketing-version', tag]);
node = repo.commit(text="Updates Bundle Version String (CFBundleVersionString) for tag "+tag)
commands.tag(ui, repo, tag)
cmdtable = {
# "command-name": (function-call, options-list, help-string)
"agvtag": (agvtag_cmd, [], "hg agvtag tag")
}
</code></pre>
<h2>Installation</h2>
<ol>
<li>Copy avgtag.py to your hgext directory. If you installed Mercurial on OS X 10.5 from a <a href="http://mercurial.berkwood.com/">binary package</a>, this is probably <code>/Library/Python/2.5/site-packages/hgext/</code></li>
<li>Add agvtag= to the extensions section of your ~/hgrc</li>
</ol>
<p><pre><code>
[extensions]
agvtag =<br />
</code></pre></p>
<h1>Usage</h1>
<pre><code>hg agvtag "1.0b1"
</code></pre>
<h2>Download</h2>
<p>%file_link:0%</p>
Updating Info.Plist Bundle Version from Mercurial Changeset ID at Build Timehttp://www.randomsequence.com/ecb7937db58ec9dea0c47db88463d85e811430322009-08-07T00:00:00Z<p>Automatically use the latest mercurial changeset id as CFBundleVersion ##How To</p>
<p>Create a new ‘Run Script’ Build Phase in your target. Set the Shell field to <code>/usr/bin/python</code></p>
<pre><code>#!/usr/env/python
from AppKit import NSMutableDictionary
import subprocess
import os
def increaseVersion():
# reading hg version
# use the line below instead if you want the full 40 character node id
# p1 = subprocess.Popen(["/usr/local/bin/hg","--debug","id", "-i"], stdout=subprocess.PIPE)
p1 = subprocess.Popen(["/usr/local/bin/hg","id", "-i"], stdout=subprocess.PIPE)
version = p1.communicate()[0].strip()
print('version: '+repr(version))
# reading info.plist file
projectPlist = NSMutableDictionary.dictionaryWithContentsOfFile_('Info.plist')
# setting the svn version for CFBundleVersion key
projectPlist['CFBundleVersion'] = version
projectPlist.writeToFile_atomically_('Info.plist', True)
os.utime('Info.plist', None)
if __name__ == '__main__':
increaseVersion()
</code></pre>
<h2>References</h2>
<p><a href="http://www.shinyfrog.net/en/sync-svn-version-and-cfbundleversion-in-xcode">Sync Svn version and CFBundleVersion in Xcode</a></p>
Using agvtool with Mercurial Hooks to Update XCode Bundle Versions for New Tagshttp://www.randomsequence.com/e993215bfdaa515f6ea00fafc1918f549119f9932009-08-07T00:00:00Z<p>A simple hook for [Mercurial][] which updates the “Bundle versions string, short” (CFBundleShortVersionString) in your XCode project Info.plist each time you add a new tag.</p>
<p>[Mercurial]: http://mercurial.selenic.com/ ##Set Up <a href="http://www.cocoadev.com/index.pl?AGVTool">Apple Generic Versioning</a></p>
<ol>
<li>In XCode, select your top level project</li>
<li>Get Info</li>
<li>Ensure the configuration dropdown is set to ‘All Configurations’</li>
<li>Set the “Versioning System” definition to <code>apple-generic</code></li>
</ol>
<h2>Add the Hook to your Repository</h2>
<p>Add the following to your projects’ hgrc (<code>.hg/hgrc</code>)</p>
<pre><code>[hooks]
pretag = cd <path/containing/xcode-project>; agvtool new-marketing-version $HG_TAG; hg commit -m "Updates Short Bundle Version for tag $HG_TAG"
</code></pre>
<p><strong>Replace <path/containing/xcode-project> with the path containing your .xcodeproj</strong></p>
<h2>Testing</h2>
<pre><code>hg tag "1.0b1"
</code></pre>
<p>You should see similar output to this:</p>
<pre><code>mbp% hg tag "1.0b1"
Setting CFBundleShortVersionString of project HookTest to:
1.0b1.
Updating CFBundleShortVersionString in Info.plist(s)...
Updated CFBundleShortVersionString in "HookTest.xcodeproj/../Info.plist" to 1.0b1
</code></pre>
<h2>Help & Supprt</h2>
<p>There is no help or support available, sorry!</p>
Applescript to Toggle iTunes Equalizer Presetshttp://www.randomsequence.com/601ca99d55f00a2e8e736676b606a4d31d374fdd2009-06-30T00:00:00Z<p>Use this to toggle between settings for desktop speakers and the MacBook Pro’s less capable small speakers. ###Applescript###</p>
<pre><code>set theEqPresetName to ""
tell application "iTunes"
if the current EQ preset is EQ preset "Flat" then
set the current EQ preset to EQ preset "Small Speakers"
else
set the current EQ preset to EQ preset "Flat"
end if
set theEqPresetName to name of the current EQ preset
end tell
</code></pre>
<p>I saved this script to ~/Library/Scripts/iTunes/Toggle Equalizer Preset.scpt, (you may need to create this folder yourself) then added that folder to <a href="http://www.obdev.at/products/launchbar/index.html">Lauchbar</a>’s configuration, so that I can toggle this using the keyboard.</p>
<p><strong>Note</strong> the equalizer’s On checkbox needs to be checked for this to have any effect on audio. I couldn’t find an easy & reliable way to switch that on using Applescript.</p>
<h3>Bonus Feature - Growl Notifications</h3>
<p>Add this to the bottom of the same Applescript to receive a <a href="http://growl.info/">Growl</a> notification including the name of the new preset:</p>
<pre><code>tell application "GrowlHelperApp"
-- Make a list of all the notification types
-- that this script will ever send:
set the allNotificationsList to ¬
{"EQ Preset Changed"}
-- Make a list of the notifications
-- that will be enabled by default.
-- Those not enabled by default can be enabled later
-- in the 'Applications' tab of the growl prefpane.
set the enabledNotificationsList to ¬
{item 1 of allNotificationsList}
-- Register our script with growl.
-- You can optionally (as here) set a default icon
-- for this script's notifications.
register as application ¬
"Toggle Equalizer Preset" all notifications allNotificationsList ¬
default notifications enabledNotificationsList ¬
icon of application "Script Editor"
-- Send a Notification...
notify with name ¬
"EQ Preset Changed" title ¬
"EQ Preset Changed" description ¬
theEqPresetName application name "Toggle Equalizer Preset"
end tell
</code></pre>
<h3>Download</h3>
<p>%file_link:0%<br />
%file_link:1% (With Growl Notification)</p>
NSIndexPath + NSArrayhttp://www.randomsequence.com/310b86e0b62b828562fc91c7be5380a992b2786a2008-11-25T00:00:00Z<p>A category on NSIndexPath which provides serialisation to and initialisation from an NSArray. ##How to Use:</p>
<pre><code> NSIndexPath *indexPath = [[[NSIndexPath indexPathWithIndex:1] indexPathByAddingIndex:2] indexPathByAddingIndex:3];
NSArray *indexes = [indexPath allIndexes];
NSIndexPath *anotherIndexPath = [NSIndexPath indexPathWithIndexes:indexes];
</code></pre>
<h2>NSIndexPath+NSArray.h:</h2>
<pre><code>//
// NSIndexPath+NSArray.h
//
// Created by Johnnie Walker on 29/10/2008.
//
// Public Domain
#import <Foundation/Foundation.h>
/*
NSIndexPath *idp = [[[NSIndexPath indexPathWithIndex:1] indexPathByAddingIndex:2] indexPathByAddingIndex:3];
NSLog(@"idp: %@",idp);
NSLog(@"[idp allIndexes]: %@",[idp allIndexes]);
NSLog(@"[NSIndexPath indexPathWithIndexes:[idp allIndexes]]: %@",[NSIndexPath indexPathWithIndexes:[idp allIndexes]]);
NSAssert([idp isEqual:[NSIndexPath indexPathWithIndexes:[idp allIndexes]]],@"Indexes don't match");
*/
@interface NSIndexPath (NSArray)
+ (NSIndexPath *)indexPathWithIndexes:(NSArray *)indexes;
- (NSIndexPath *)initWithIndexes:(NSArray *)indexes;
- (NSArray *)allIndexes;
@end
</code></pre>
<h2>NSIndexPath+NSArray.m</h2>
<pre><code>//
// NSIndexPath+NSArray.m
//
// Created by Johnnie Walker on 29/10/2008.
// Public Domain
//
#import "NSIndexPath+NSArray.h"
@implementation NSIndexPath (Array)
+ (NSIndexPath *)indexPathWithIndexes:(NSArray *)indexes
{
return [[[NSIndexPath alloc] initWithIndexes:indexes] autorelease];
}
- (NSIndexPath *)initWithIndexes:(NSArray *)indexes
{
NSUInteger idx[[indexes count]];
for (NSInteger i=0; i<[indexes count]; i++) {
idx[i] = [[indexes objectAtIndex:i] integerValue];
}
return [self initWithIndexes:idx length:[indexes count]];
}
- (NSArray *)allIndexes
{
NSMutableArray *indexes = [NSMutableArray arrayWithCapacity:[self length]];
for (NSInteger i=0; i<[self length]; i++) {
[indexes addObject:[NSNumber numberWithInteger:[self indexAtPosition:i]]];
}
return [[indexes copy] autorelease];
}
@end
</code></pre>
<h2>Download</h2>
<p>%file_link:0%</p>
iPhone Address Book & Google Maps Integrationhttp://www.randomsequence.com/812ed4562d3211363a7b813aa9cd2cf042b63bb22008-10-09T00:00:00Z<p>In iPhone OS, both Phone.app & Contacts.app are able to place special pins in Maps.app showing the location of a contact with a custom named pin & additional contact information in a detail view.</p>
<p>Below are my notes on replicating this functionality. ##Pins with Custom Titles
Google maps allows control of the title of a marker window by adding a title in parenthesise at the end of the URL, for example:<br />
<a href="http://maps.google.co.uk/maps?q=edinburgh(Capital%20of%20Scotland)">http://maps.google.co.uk/maps?q=edinburgh(Capital%20of%20Scotland)</a></p>
<p>As of iPhone OS 2.0.2, Maps.app disregards the custom title.</p>
<p>It is possible to place a pin with a title using co-ordinates rather than an address search, for example:<br />
<a href="http://maps.google.co.uk/maps?q=Capital%20of%20Scotland@55.927663,-3.166809">http://maps.google.co.uk/maps?q=Capital%20of%20Scotland@55.927663,-3.166809</a></p>
<p>As of iPhone OS 2.0.2, Maps.app shows ‘Capital of Scotland’ as the marker address, and again on the detail view.</p>
<h2>How do Phone.app & Contacts.app do it?</h2>
<p>Both use a specialised view provided by the <a href="http://developer.apple.com/iphone/library/documentation/AddressBookUI/Reference/AddressBookUI_Framework/index.html">Address Book UI Framework</a>. Address Book UI Framework is part of <a href="http://developer.apple.com/iphone/library/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/iPhoneOSTechnologies/chapter_3_section_4.html#//apple_ref/doc/uid/TP40007072-CH20-SW11">Core Services</a>.</p>
<p>Using the custom view, Address Book UI Framework opens the maps application using a special URL:</p>
<pre><code>maps:address=%@&abPersonID=%d&abAddressID=%d
</code></pre>
<p>Where abPersonID is the UID of the contact and abAddressID the address. The first parameter is used to populate Maps.app’s search box.</p>
<p><strong>To attach extra information to a maps.app pin you must create a record in address book, then display the detail view for that record</strong>.</p>