Blog.jh

Notes from my mind

Github Cant Make Up for Bad Parenting

In what seems like an eternity ago at my old agency job, I forked a plugin for redmine called redmine_git_hosting. See, I had a grand idea that maybe we could move to git, just so long as we could meet some basic requirements. Redmine git hosting, should you follow its family tree, is a child of redmine-gitosis. Gitosis was close, but Gitolite was closer. Essentially we needed to lock down source control due to third party access, and lets face it, perhaps some not so stellar users.

So I forked this repo and figured, what the hey, all I need to do is change how it manages the config and add in some basic UI, right? right? Well yes, thats more or less it. But the support for the project faltered in the company, I had no time for it and I moved on to greener freelance pastures not long after. No harm no foul?

As it turns out, I had started to scratch an itch many people felt. I had quite a few contacts asking if it worked, it was forked fairly well (5 or 6 times). I had abandoned it, but GitHub had allowed it to live on. Other forks quickly got it to working prototype, and as far as I understand, its now been pulled back in to some sort of potential officiality. All I really did was click a button and change some lines, but it was enough.

So I was a bad parent, I started a public project and then almost immediately walked away. But it didnt matter, just starting it was all that was needed. I think this is the sort of thing that emphasises how important GitHub is. I dont think this would ever happen at, say, Sourceforge.

Programmers often talk about how every little piece of code you put out there can follow you around for a long time, long past your own interest. People will ask for support years after you wrote something small and then walked away. GitHub doesn’t negate that, but it makes it easier when someone does or you need to. It lets project live beyond the grip of their parents.

CSS Data URI’s and an Errant Pinky

I was messing around with using Data URi’s with CSS background images, when I ran into an odd error: Resource interpreted as Other but transferred with MIME type undefined. Here was my code (more or less):

1
2
3
4
5
6
7
8
<style>
div.example {
  width: 100px;
  height: 100px;
  border: 1px solid black;
  background: url(data:image/png:base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAABkCAYAAAEwK2r2AAAAXElEQVQYlbWQOwqAQAxEZ15MLmBl5/0vqc2KCKssCzavSTKfaN/WA0nqIiJEVYkls7uiVwHbIjNFVglg/PYbgIAQEbSQRDTLQZVZ80nYvn5gC4yw7zLXwE/8keUEV+cGka551C0AAAAASUVORK5CYII=);
}
</style>

See that pesky colon that should be semi? It should be this:

1
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAABkCAYAAAEwK2r2AAAAXElEQVQYlbWQOwqAQAxEZ15MLmBl5/0vqc2KCKssCzavSTKfaN/WA0nqIiJEVYkls7uiVwHbIjNFVglg/PYbgIAQEbSQRDTLQZVZ80nYvn5gC4yw7zLXwE/8keUEV+cGka551C0AAAAASUVORK5CYII=);

Problem solved!. Tsk tsk pesky typo’s.

Retrieving Network (Server) Passwords From Linkinus

I quite like Linkinus as an irc client. Its a bit bulky and not hugely well optimised, but theres something about it I enjoy. It does have some annoying habits however. One of those is that it doesn’t utilise the Mac OS X Keychain for server passwords. Super annoying when you’re like me and you forget what they are.

These passwords are retrievable however, they’re stored in ~/Library/Application Support/Linkinus 2/Networks.lnkData, and if you use a Hex Editor and search for your network name in ASCII mode, you’ll see the passwords in plaintext a few blocks later.

Not exactly a point in security for Linkinus, but I’m glad I have my passwords back :) I’ll probably file this as a bug and hope they choose to start using the keychain.

Integrating Beyond Compare Into WinSCP

This was originally posted on my now defunct posterous blog, but it’s useful info so reposting here:

Go to commands in winscp, add a new command. use:

"C:\Program Files\Beyond Compare 3\bcomp.exe" "!" "!^!" as the command, and select local files. If you use synchronise now, Beyond Compare will be available in the Commands menu.

Zend File Transfer Throwing fileUploadErrorIniSize

Just for your reference and mine, since its not obvious why this gets thrown (given the error name and message)

Your form needs to be enctype="multipart/form-data" otherwise the $_FILES array is empty and it all goes pear shaped. Kind of obvious, but thats a long garden path to walk down to find you’ve forgotten something so fundamental :/

Hiding Files From Finder

It’s super useful to hide files and folders from the finder. I find it’s a good way to deal with badly behaved applications that put folders in your Documents folder instead of in Library/Application Support like they should. If you have SetFile from the developer tools, you can also symlink these bad directories into their proper location and hide the symlink.

This method wont affect anything that needs to write to the folders since the paths remain the same.

If you dont have developer tools installed, use this: (Note: this doesn’t work on symlinks)

1
chflags -R hidden  chflags -R nohidden

If you do have developer tools installed, you can use SetFile

1
SetFile -a V  SetFile -a v

To make it work on symlinks, use -P on SetFile

1
SetFile -a V -P  SetFile -a v -P

PHP Paths, Getting It Right.

Paths in PHP, theres a way to do them properly. Lately I’ve seen this issue poke it’s head up amazingly frequently and I dont think it gets as much discussion as it should. I thought it was a solved problem, apparently not so.

Lets get started

Most PHP applications litter their code with include '../../library/someclass.php.class'. This isn’t much good to anyone, because its very easy to break, and no-one likes doing path janitor work when you should be coding. Want to move a file? Now you have to change 20 other files? bummer. So ok, maybe we could just create a constant, and use the full path?

1
2
3
<?php
define('PATH', '/home/me/webroot/Application'); include(PATH .
'/Library/someclass.php.class');

Well thats a damn sight better. Now we have a concrete place to look for our files. It’s good, but erm, what if we deploy on windows? Also, are we going to define path on every script entrance point? Not very DRY if you ask me. Plus, moving deployments is going to be a huge pain if the folder structure is different, and let’s just face it, it will be. Clearly, while we’re closer it’s not much of an improvement.

Luckily, PHP provides a few magic bullet functions that can help us out immediately.

So lets just say you have a single entrance point for your application, or at the very least a shared header file. We can grab our deployment root pretty quickly if we know where our header file is related the the code root. IE, in /home/me/webroot/Application/Init/set_paths.php

1
2
<?php
define('PATH_SITE', realpath(dirname(__FILE__) . '/../../'));

Awesome, thats our document root. It’s OS independant and its pretty easy to adapt if you change where set_paths.php lives. Now we can talk about some other locations in our application, just because constants are handy:

1
2
3
4
5
<?php
define('PATH_APPLICATION', realpath(PATH_SITE . "/Application"));
define('PATH_LIBRARY', realpath(PATH_SITE . "/Application/Library"));
define('PATH_CONFIG', realpath(PATH_SITE . "/Config")); define('PATH_WRITE',
realpath(PATH_SITE . "/Volatile"));

This is all very well and good, but its not really much better than our previous solution. We still have to specify a constant with our path to get includes to work. Enter in the PHP include path. By adding the relevant constants to our path, we wont need to reference them every time we include a file. Order of paths in the include path is actually pretty important for speed, so we make every effort to get them in order of usage.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
// There are some paths here by default, obviously. 
// We want to pull the current directory out of the stack so we can move it later.

$paths['inc'] = array_flip(explode(PATH_SEPARATOR, get_include_path()));
unset($paths['inc']['.']);
$paths['inc'] = array_flip($paths['inc']);

// The first item on the path the external libs that get used all the time,  
// then the application path, then the site path, and any php configured items.
// The current directory should be last. Why is the current directory on the path?
// Well if it wasn't, you couldn't have relative includes.

$paths = array_merge(
    array(
        PATH_LIBRARY,
        PATH_APPLICATION,
        PATH_SITE
    ),
    $paths['inc'],
    array(".")
);

// PATH_SEPARATOR is a PHP defined constant, and its better to use a constant
// than a 'magic' string.
set_include_path(implode(PATH_SEPARATOR, $paths));

Now all the critical locations in our application are on the path, and you can include to your hearts content, regardless of where you decide to store your libraries, settings etc.

1
2
<?php
include('someclass.php.class');

A step further

If you’re working with a fairly well designed OOP Application, we can go a bit further. If you subscribe to one file, one class (You do don’t you?), then the PEAR naming convention makes life very simple. It also makes a lot more sense as a naming convention than .php.class or .inc or whatever other silly pointless conventions exist.

The PEAR naming conventions dictate a 1:1 relation between the filesystem and the class. As an example, the class Foo_Bar_Baz would be found in the file “Foo/Bar/Baz.php” on your include_path.

Once you have a predictable mapping of files to classes, you can then implement spl_autoload_register And you can replace

1
2
<?php
include('someclass.php.class'); new SomeClass();

With simply

1
2
<?php
new SomeClass();

And have PHP deal with it for you. No more includes, what a wonderful world!

Redmine Plugins, Death by Gravatar

1
uninitialized constant ApplicationHelper::GravatarHelper

Seen that before? It’s really only reference in a few places, and neither are very helpful if you’re running into the issue.

The fix is pretty simple once you figure it out. Ready?

Rename your faulty plugin to something lower in the alphabet, so the gravatar plugin loads before yours.

Easy when you know how I spose. Still, it took a little while for us to figure that little gremlin out.

Vim: Buffers, Splits, Windows, Oh My!

I was looking for a way to get better control over my buffers in vim. Theres a fantastic blog post that explains how splits and windows work. Since I dont use the number pad, I’ve bound a heap of shortcuts to it for navigation around my vim instance.

The idea is the arrows on the numpad move around my buffers, and hitting 5 allows creation of a new split in that direction. So 58 gives me a split above my current one. Double tapping the direction gives a window, so 588. Its very intuitive, give it a try :)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
" Manipulate our buffers
nmap <kPlus> <C-W>+
nmap <kMinus> <C-W>-
nmap <kDivide> <C-W><
nmap <kMultiply> <C-W>>
nmap <kPoint> <C-W>=
nmap <kEnter> <C-W>_<C-W><Bar>

" window
" vertical
nmap <k5><k4><k4>  :topleft  vnew<CR>
nmap <k5><k6><k6>  :botright vnew<CR>
" horizontal
nmap <k5><k8><k8>  :topleft  new<CR>
nmap <k5><k2><k2>  :botright new<CR>

" buffer
" vertical
nmap <k5><k4>   :leftabove  vnew<CR>
nmap <k5><k6>   :rightbelow vnew<CR>
" horizontal
nmap <k5><k8>   :leftabove  new<CR>
nmap <k5><k2>   :rightbelow new<CR>

Group by Ranges in MySQL

Something that doesn’t seem to be covered very well, at least in my cursory googling, is an easy way to manipulate ranges of data in sql. MySQL provides a tool called Range Partitioning, which is great if your ranges are used regularly. However, most of the time ranges are needed temporarily when pulling statistical data.

After a bit of fiddling about, I think I’ve found a fairly acceptable way to get around the issue, by creating a temporary table to specify your ranges against your data set, and then performing your final result query against that.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
DROP TEMPORARY TABLE IF EXISTS ranges;

CREATE TEMPORARY TABLE ranges
    SELECT
        pkData AS fkData,
        CASE
            WHEN d.dob >= '1986-01-01' && d.dob <= '1991-12-31' THEN '20-24'
            WHEN d.dob >= '1981-01-01' && d.dob <= '1985-12-31' THEN '25-29'
            WHEN d.dob >= '1976-01-01' && d.dob <= '1980-12-31' THEN '30-34'
            WHEN d.dob >= '1971-01-01' && d.dob <= '1975-12-31' THEN '35-39'
            WHEN d.dob >= '1966-01-01' && d.dob <= '1970-12-31' THEN '40-44'
            WHEN d.dob >= '1961-01-01' && d.dob <= '1964-12-31' THEN '45-49'
            WHEN d.dob >= '1956-01-01' && d.dob <= '1960-12-31' THEN '50-54'
            WHEN d.dob >= '1951-01-01' && d.dob <= '1954-12-31' THEN '55-59'
            WHEN d.dob >= '1946-01-01' && d.dob <= '1941-12-31' THEN '60-64'
            ELSE '65+'
        END
            AS `range`
    FROM     DATABASE.DATA AS d;

You can then pull counts of each range:

1
2
3
4
SELECT COUNT(r.`range`) AS `count`,
             r.`range`
FROM     ranges AS r
GROUP   BY r.`range`;

Or just pull it as part of your result set:

1
2
3
4
SELECT *
FROM    DATA AS d
    LEFT JOIN ranges AS r
        ON d.pkData = r.fkData;