Good Things pt 2: YAML
I got acquinted with YAML during my short run-in with Ruby on Rails (more on this some other day, hopefully). Their official description is:

YAML(tm) (rhymes with "camel") is a straightforward machine parsable data serialization format designed for human readability and interaction with scripting languages such as Perl and Python.


Absolutely brilliant stuff. What it gives you, is a simple (no joke!) portable data format that's truly human-readable (indentation, baby!) and can easily be parsed into virtually any programming language's native data structure.

For example, in PHP (via the excellent Spyc library), this is how my webapp's DB settings would look like:
database:
host: localhost
name: collective_development
username: name
password: passwd
type: mysql
charset: utf-8

Then you just do
include 'lib/spyc.php5';
$c = Spyc::YAMLLoad( 'lib/collective.yml' );

And your whole configuration is accessible in a PHP array:
$link = mysql_connect( $c['database']['host'], $c['database']['username'], $c['database']['password'] );

|
AppleScripting Keynote 3
And in particular the add chart command. At first it seems like a really cool thing - easily create beautiful charts out of virtually any source. I was excited to try this with some Webalizer output. Looks like you have two options - the Automator Action or Script Editor

The action produces a chart right off the bat, but the input is weird:

Input: (Anything) Two dimensional array of chart labels and data.


What is that? After trying every possible permutation of what I thought an AS 2D array would look like (some of which even compiled!) with different kinds of input sources (AS, text) I finally gave up the Automator Action option.

Using script editor seemed promising at first, but a simple add chart with all the properties produced nothing. Finally managed to find this really nice example, but it only worked with Pages. Digging in the action's bundle revealed that you're supposed to tell the slide to add the chart. OK, time to put this new-found knowledge to work:
tell application "Keynote"
set theData to {{1, 2, 3}, {4, 5, 6}}
set theSlide to (slide 1) of first slideshow
tell theSlide
add chart row names {"Dec", "Jan"} column names {"Machines", "Visits", "Hits"} ¬
data theData type "vertical_bar_3d" group by "column"
end tell
end tell

Pasted Graphic 2

Tadaa! Sweet. Now all that remains is to add the webalizer parsing code...

|
Building universal binaries
So far I've had the best success with defining the following before configure:
> export LDFLAGS="-Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk -arch ppc -arch i386"
> export CFLAGS="-isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc"

Sometimes this lead to:
gcc: -E, -S, -save-temps and -M options are not allowed with multiple -arch flags

in which case passing --disable-dependency-tracking to configure seemed to help.
|
Remembering the QTVR Pan Angle
This only works with Safari:
QT_WriteOBJECT_XHTML (
'myVRmovie.mov', 800, 600, '',
'controller', 'true',
'id', 'myvrmovie',
'cache', 'true',
'pan', getAngle ());

... where getAngle() just uses a cookie:
function getAngle ()
{
return document.cookie.split ('=')[1];
}

... which is set with setAngle () like thus:
function setAngle ()
{
document.cookie = 'angle=' + Math.floor (document.myvrmovie.GetPanAngle ());
}

Finally, the hotspots are wired to go through this function:
function openPage (url)
{
setAngle ();
window.location (url);
}

|
Google search to RW (for lazy bums)
A really lazy way to add search to your RW page:
<div id="gsearch">
<form action="http://www.google.com/search">
<input type="text" name="q"/>
<input type="hidden" name="hl" value="en"/>
<input type="hidden" name="sitesearch" value="http://homepage.mac.com/filipp"/>
<input type="submit" value="Search with Google"/>
</form>
</div>


I think you could actually cook up something nice with a Google developer account and XMLHttpRequest...
|
Using script.aculo.us with XSLT
When using script.aculo.us with XSLT (XML to XHTML), don't include like this:
<script src="javascripts/scriptaculous.js" type="text/javascript">

This is because scriptaculous.js uses document.write () to include the components and that' apparently verboten when using XSL. The symptoms are weird too:
* Safari will acts as if all was OK, except Ajax.Request won't work
* Firefox/Gecko-based browsers will just hang on loading the document (an invinite "Reading") and you'll notice some class name related errors in the JS log.
In other words, the correct way to include, is by all the files separately and in the right order:
<script src="javascripts/effects.js" type="text/javascript"></script>
<script src="javascripts/builder.js" type="text/javascript"></script>
<script src="javascripts/dragdrop.js" type="text/javascript"></script>
...

|
Happy Holidays
The past few days have been weird. Got a really great idea for writing a hwmond replacement called servermond that would allow you to use at least some of the functionality of Server Monitor on any hardware. So far so not good. Getting the SSL decryption to work to reverse-engineer the Server Monitor protocol has been unsuccessful due to, quite frankly, lack of tools. ssldump won't compile straight, tried the macports version but that won't run. Finally managed to install ettercap (which seems like an awesome piece of engineering) but it hasn't helped me yet... This made me think why there's still no Mac native front end to any of these powerful free programs.

Plus, the cigarette addiction's kicking in again. I've been off it for about a year now but the past 5 days I've felt like I quit last weekend or something... Weird.

But to not feel totally unproductive, I've decided to roll out the first public version of Itch - my little Python script for XChat Aqua. Named thus not only because there were a few itches that I wanted to scratch in XChat, but also because it's my first ever Python script (and itchi means "one" in Japanese). Itch features:

  • Simple iTunes and QuickTime Player announcement. /np send nick will try and dcc the current tune to nick.

  • /away management (hitting /way toggles you away with a timer) with logging

  • Hardware (ioreg) and software (system_profiler) monitoring and specs. Just try /hw and /sp for the possible switches. These are not echoed to the channel.

  • iTalk. This was actually pea's brilliant idea. /isay will convert anything you say into "i-talk". iFor iExample iLike iThis.

  • Finally, /day will show you what's happened today in history (data from /usr/share/calendar/calendar.*)


There's a few other features that I want to add in there, but the existing ones were "stable" enough to release it into the general public. I consider it my little Christmas present to the Mac IRC population. ;-)
|
Modulo
This one is easy, but so important but used so rarely that you have time to forget it. How to build a table programmatically with a certain number of columns, with only one while - loop:
<table style="border: 1px solid black">
$i = 0;
$col = 4;
$val = 20;
$table = null;

while ($i < $val)
{
$i++;
$table .= '<tr>' + ($i % $col == 0) ? "<td>$i</td></tr>" : "<td>$i</td>";
}
print ($table);
?>
</table>

|
Variable Scopes
value = 0
def setValue():
value = 1
setValue ()
print value

What's that gonna print? That's right - 0. Must use global instead:
value = 0
def setValue():
global value
value = 1
setValue ()
print value

It's actually the exact same with PHP:
$value = 0;
function setValue () { $value = 1; }
setValue ();
print ("value: " . $value);

My brain tells me that if something's been defined previously, then we should be referencing that thing instead. It's not like I'm explicitly using different namespaces in - and outside my function. Like with JavaScript.
|
Two New Scripts
useradd.sh and freplace.sh. The first is a simple CLI utility for creating users and the second finds and replaces files.
> ./useradd.sh 
Usage: sudo useradd.sh [-u uid] [-g group] [-a] [-c] [-d home] [-s shell] [-rn realname] name

-a makes new user an administrator.
> ./freplace.sh
Usage: freplace.sh [-sb] [-o owner:group] -d indir target replacement

Replaces target in directory indir with replacement. Has a few extra features as well. Both are still pretty basic, but serve a purpose and I'll probably keep updating them. Handle with care.
|
Universal Hello World
I've been struggling with building universal (fat) binaries on OS X for quite a while now. Finally decided to sit down and figure this out. In a situation with many variables, it's often good to stop and try to "crystallise" the problem at hand. What better way to do this than with a Hello World - if that won't compile and link, then why should anything else, right?

#include <stdio.h>

int main (void)
{
printf ("Hello, world!\n");
return 0;
}

Then we compile:
> gcc hellow.c -o hellow
> ./hellow
Hello, world!
> file hellow
hellow: Mach-O executable ppc


So far so good. Now let's see if we can make a fat binary out of this sucker:
> gcc -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch ppc -arch i386 -arch ppc64 hellow.c -o hellow-fat
> ./hellow-fat
Hello, world!

> file hellow-fat
hellow-fat: Mach-O fat file with 3 architectures
hellow-fat (for architecture ppc): Mach-O executable ppc
hellow-fat (for architecture i386): Mach-O executable i386
hellow-fat (for architecture ppc64): Mach-O 64-bit executable ppc64

Hmm, that wasn't so bad. I guess here is where the "fat" in "fat binary" comes from:
> ls -lhS hellow*
-rwxr-xr-x 1 filipp filipp 44K Dec 12 13:45 hellow-fat
-rwxr-xr-x 1 filipp filipp 13K Dec 12 13:46 hellow
-rw-r--r-- 1 filipp filipp 80B Dec 12 13:21 hellow.c

Well, that turned out to be a useless experiment. At least I know that my cross-compiling support works now...
|
BBEdit Session Restore
BBEdit's probably my most important tool. Even though an editor is such a basic thing that it's almost kind of silly to be attached to one, you just get used to it over time and it's nice to constantly be finding new features and ways to use a tool.

I can easily have upwards of 20 documents open simultaneously - sometimes part of the same project, mostly not. This makes you weary of actually closing the app because what if you want to pick up exactly where you left off? Well, luckily, like so many things in life, this problem too can be solved with a little bit of AppleScript:
property theDocuments : {}

tell application "BBEdit"
if (count of document) is greater than 1 then
set theDocuments to file of every document as list
else
open theDocuments
end if
end tell

Just run that after and before every session you want to restore. If you have documents open, it'll save them, if not, open the ones you had open the last time. It's very crude but gets the job done for now. Naturally they don't work with Trasmit links etc because those are just temporarily open.

Properties are wonderful in AS because they are reinitialised only when the script is compiled. That makes them perfect for any kind of "temporary" persistent storage.
|
PHP's file_get_contents () and cookies
Sending cookies - you can do it with file_get_contents () - just look at the stream functions' constants (the context parameter). But I found out it's much easier using the curl plugin (which isn't always available, btw, but neither is file_get_contents ()):
$c = curl_init ($url);
curl_setopt ($c, CURLOPT_VERBOSE, 1); // For testing
curl_setopt ($c, CURLOPT_COOKIE, "variable=value");
curl_exec ($c);


It's that simple. An awesome tool for creating all kinds of site parsers.

|
Something New Every Day...
JavaScript - Associative Arrays Considered Harmful

The reason I stumbled across this was that Apple's QuickTime Embedding JS has this problem. The symptoms look crazy - you'll have other JS code inside your embed tag. This happened to me when using Prototype. The fix is easy - just replace "new Array ();" on line 165 with "new Object ();"

|
AppleScript Tidbits
AppleScript URL protocol support

Getting the home directory:
set theHomeDir to the POSIX path of home directory of (system info)

Getting and setting the clipboard:
set whatever to the clipboard
set the clipboard to "whatever"


Encoding URLs
Personally, I think you're best off just piping it through PHP:

do shell script "echo myurl | /usr/bin/php -r \"urlencode(fgets(STDIN));\""

Bu there's also some info on Apple's website.

How does ScriptEditor know which app is scriptable?
By looking for the NSAppleScriptEnabled key in an application bundle's Info.plist

|
Automate Out-of-Office Reply Toggling
This one actually made it to the site:

If there's one thing that computers are better at than humans, it's remembering things. Take for example the typical Out Of Office email reply - you go on vacation and set a rule in Mail.app to automatically respond of your absence to any email with a certain criteria. Then you come back and a day or two later remember to turn the notification back off again.

Well if You use iCal, your Mac most likely already knows when you're leaving and coming back so let's simply tie that information with Mail.app. Here's how:

Open Automator and from the Automator library add a "Run AppleScript" step.
Replace the code with the following, putting in the name of your Out of Office rule:

set myRule to "Name of my Out of Office rule"

tell application "Mail"

set enabled of rule myRule to not enabled of rule myRule

end tell

3) File > Save As Plug-In, give it a name (like "Toggle Out-Of-Office"), Plug-in for: iCal Alarm. Save.

iCal will open with a new event which you can simply delete. Then just create events on the start and end dates of your vacation (if you haven't already) and set our newly created script as the alarm (which you'll find in the alarm "Open file" dropdown menu).

The reply will now activate when yo leave and deactivate when you return. Just make sure your rule is Inactive before you go. :)
|
Flannel 1.0
This isn't much of a release announcement since it's not even available for download yet, but Flannel's demo page is finally up now.
This is all part of a not-so-elaborate scheme to get Flannel out there in the hands of the users. Not knowing the current state of true WYSIWYG publishers out there, I still think it could be very useful for people who just want their stuff online quickly and easily.

There's still alot of work to be done and the version that's running the demo's not the one I had in mind for the 1.0 release, but still...

|
Search & Replace with nano!
This is the coolest thing:
Ctrl - R - string to search, enter, to replace, + a
boom.

|
A Random Quote For Site Slogan

window.onload = function() {
var quotes = [
"I wanna be a racecar passenger.",
"Alright, you're a cook - can you farm?"];

var i = Math.floor(Math.random()*quotes.length);
document.getElementsByTagName('h2')[0].innerHTML = '"' + quotes[i] + '"';
}

Don't forget to add blank lines before and after the JS!

|
A Teacher's Pet
Punk made it to the Staff Favorites list. It will also be included on the cover CD of Univers Mac, a French Mac Magazine! Thanks!


tp

|
sortUsingSelector
After spending 4 days with the problem of sorting an array of NSDictionaries (!!) using every kind of method imaginable, I finally found the solution:

You can't use sortUsingSelector because that operates on the object in the array (in this case an NSDictionary). That explains the countless ("[CFDictionary compareScores] selector not recognized etc...") I was getting. Phew

So use sortUsingFunction instead. And as the guys at cocoadev so eloquently showed:
int someSort (id obj1, id obj2, void *context)
{
return [[(NSDictionary *)obj1 objectForKey:(NSString *)context] compare:[(NSDictionary *)obj2 objectForKey:(NSString *)context]];
}


Where "context" is the NSDictionary key you want to sort by.

|
Getting Stuff Into MySQL
Forget clumsy scripts to load SQL files into MySQL. Here's how it worked for me:

check your php.ini "upload_max_filesize"

$newFile = move_uploaded file ($FILES['yourfile']['tmp_name'], '/var/tmp/yourfile');
$sql = "LOAD DATA INFILE '$newFile'
INTO TABLE db.table
FIELDS TERMINATED BY ',' ENCLOSED BY '\"' ESCAPED BY '\"' LINES TERMINATED BY '\r'";


Strangely, MySQL 4.x doesn't like the "ENCLOSED BY" statement (it works, but will only import the first row)

|
PHP weirdness
This doesn't work as expected:
echo "foo:bar" | php -r "print str_replace(':','-','php://stdin');"


Must investigate. Maybe try with another machine...

UPDATE:
echo "foo:bar" | php -r "print str_replace(':','-',trim(fgets(STDIN)));"
|
Symbian madness
http://discussion.forum.nokia.com/forum/archive/index.php/t-66906.html
http://www.symbian-toys.com/
http://cms.planeetta.fi/symbian/labs

|
More On Spelling
http://www.cocoabuilder.com/archive/message/cocoa/2005/2/4/127543

|
phpBB privmsgs to PunBB

DELETE FROM punmessages;
INSERT INTO punmessages (subject,sender_id, sender, owner, posted, message, sender_ip,smileys,showed)
(SELECT privmsgs_subject, privmsgs_from_userid,
(SELECT username FROM phpbb_users WHERE phpbb_users.user_id = privmsgs_from_userid),
privmsgs_to_userid, privmsgs_date, privmsgs_text, INET_NTOA(CONV(privmsgs_ip,16,10)), privmsgs_enable_smilies,
(SELECT user_new_privmsg FROM phpbb_users WHERE phpbb_users.user_id = privmsgs_from_userid)
FROM phpbb_privmsgs, phpbb_privmsgs_text
WHERE privmsgs_id = privmsgs_text_id);