Brittle Stars @ Pop Mayhem, Thursday, May 8

6500 miles can’t stop the rock. Thursday, May 8th, a reunited Brittle Stars play Common Grounds as a part of Gainesville’s Pop Mayhem festival.

Hear songs such as, but not performed as well as, these:

Also that night: Ifwhen, the Buddy System, Giddy-Up Helicopter, and maybe one other band. Sorry to hear about Que Possum! :(

The show is $10 at the door/on tonevendor, or get the full pass to get in all the shows.

Still waiting on Opera

A whole six months after beta 1’s release, 9.5 beta 2 is finally out. At work I installed it over beta 1 and it works like a charm; the issues I was waiting on seem to have been fixed.

At home it’s a different story. I installed over beta 1 and the result was unusable. I got strange errors on HTTPS pages, and more cripplingly, Javascript files either don’t load completely (random bytes chopped off the end of the file) or don’t load at all. The error console tells me “Script not loaded!” Yeah I noticed!

I tried everything to get beta 2 working:

  • deleted the main config file and restarted Opera (“resets” Opera, losing all my bookmarks and settings of course)
  • uninstalled and reinstalled
  • uninstalled, deleted all Opera stuff from Program Files, ~/Application Data, ~/Local Settings, and the registry before reinstalling
  • did the above using both installers available

Each time I had the same Javascript and HTTPs problems.

Minifying Javascript and CSS on mrclay.org

Update: Please read the new version of this article. It covers Minify 2.1, which is much easier to use.

Minify v2 is coming along, but it’s time to start getting some real-world testing, so last night I started serving this site’s Javascript and CSS (at least the 6 files in my WordPress templates) via a recent Minify snapshot.

As you can see below, I was serving 67K over 6 requests and was using some packed Javascript, which has a client-side decompression overhead.

fiddler1.png

Using Minify, this is down to 2 requests, 28K (58% reduction), and I’m no longer using any packed Javascript:

fiddler2.png

Getting it working

  1. Exported Minify from svn (only the /lib tree is really needed).
  2. Placed the contents of /lib in my PHP include path.
  3. Determined where I wanted to store cache files (server-side caching is a must.)
  4. Gathered a list of the JS/CSS files I wanted to serve.
  5. Created “min.php” in the doc root:
    // load Minify
    require_once 'Minify.php';
    
    // setup caching
    Minify::useServerCache(realpath("{$_SERVER['DOCUMENT_ROOT']}/../tmp"));
    
    // controller options
    $options = array(
    	'groups' => array(
    		'js' => array(
    			'//wp-content/chili/jquery-1.2.3.min.js'
    			,'//wp-content/chili/chili-1.8b.js'
    			,'//wp-content/chili/recipes.js'
    			,'//js/email.js'
    		)
    		,'css' => array(
    			'//wp-content/chili/recipes.css'
    			,'//wp-content/themes/orangesky/style.css'
    		)
    	)
    );
    
    // serve it!
    Minify::serve('Groups', $options);

    (note: The double solidi at the beginning of the filenames are shortcuts for $_SERVER['DOCUMENT_ROOT'].)

  6. In HTML, replaced the 4 script elements with one:
    <script type="text/javascript" src="/min/js"></script>

    (note: Why not “min.php/js”? Since I use MultiViews, I can request min.php by just “min”.)

  7. and replaced the 2 stylesheet links with one:
    <link rel="stylesheet" href="/min/css" type="text/css" media="screen" />

At this point Minify was doing its job, but there was a big problem: My theme’s CSS uses relative URIs to reference images. Thankfully Minify’s CSS minifier can rewrite these, but I needed to specify that option just for style.css.

I did that by giving a Minify_Source object in place of the filename:

// load Minify_Source
require_once 'Minify/Source.php';

// new controller options
$options = array(
	'groups' => array(
		'js' => array(
			'//wp-content/chili/jquery-1.2.3.min.js'
			,'//wp-content/chili/chili-1.8b.js'
			,'//wp-content/chili/recipes.js'
			,'//js/email.js'
		)
		,'css' => array(
			'//wp-content/chili/recipes.css'

			// style.css has some relative URIs we'll need to fix since
			// it will be served from a different URL
			,new Minify_Source(array(
				'filepath' => '//wp-content/themes/orangesky/style.css'
				,'minifyOptions' => array(
					'prependRelativePath' => '../wp-content/themes/orangesky/'
				)
			))
		)
	)
);

Now, during the minification of style.css, Minify prepends all relative URIs with ../wp-content/themes/orangesky/, which fixes all the image links.

What’s next

This is fine for now, but there’s one more step we can do: send far off Expires headers with our JS/CSS. This is tricky because whenever a change is made to a source file, the URL used to call it must change in order to force the browser to download the new version. As of this morning, Minify has an elegant way to handle this, but I’ll tackle this in a later post.

Update: Please read the new version of this article. It covers Minify 2.1, which is much easier to use.

Polyphonic pitch adjustment is born

Aside from the horrors of Auto-tune, the tool changed the state-of-the-art dealing with monophonic sound. Well, competitor product Melodyne will soon be able to apply pitch adjustment to polyphonic sound. This is huge. Huge. The amazing video shows this advance and a taste of the amazing power this will bring to recordists. About 2/3rds way through, it effortlessly changes the whole scale of a piece of music from minor to major, then to “Spanish”. It’s freaking amazing. [Thanks, shek-e]

Music is killing music

I’d never claim file sharing doesn’t hurt music sales, but there’s another simple reason why individual music releases will continue to sell more poorly over time: The continuous explosion of choice. Even if listeners spent as much on music as they did years ago, the chances of us buying the same releases drops constantly as “out-of-print” becomes meaningless.

Also it’s easier than ever to know about the “essential” albums and comps, and they’re reissued feverishly. Every indiepop band should make their music accessible as possible; you’re not just competing with Belle & Sebastian, but also Village Green, Odessey & Oracle, Field Mice reissues, awesome girl group comps, et al. Good luck!

Should I mention a Brittle Stars CD comp is in the works?

Opera intermission

I’m a long-time Opera fan and flagwaver, but the pain of bugs in 9.5 beta finally forced me to switch to Firefox last week. I’ve been using 9.5 beta1 since the end of October. When do we get a new one? I see the weekly builds, but they’re all alphas (no thanks). The biggest problems I’ve had were with the rich text editor and Flash (which everyone incorrectly assumes to be a cross-browser development panacea), but, as a webdev, I’m now spoiled having instant access to Firebug.

Firefox now has closed tab access (though I miss ctrl-z) and session restore, but within a few minutes I had mouse gestures and wand back. This is petty, but a big reason I loved Opera is that it let me put the address bar, tabs and everything at the bottom. I haven’t found an easy way to do that in FF. FF is also noticeably slower in a lot of actions, but having everything actually work (including Google Docs) is really a breathe of fresh air.

I’ll continue to test Opera and give each beta/full release a whirl, but winning me back will require these to work:

New Minify version in the works

Back in August I came across Ryan Grove‘s great Minify project, which is essentially a PHP client-optimizing file server for Javascript and CSS. I was in the design stage of a project with similar goals so I decided to try merging the two projects. Ryan thought the result had potential to be the base of the next major release, and since he hadn’t had much time lately to devote to Minify, he made me co-owner of the project.

Last week I finally got around to committing the code, and since then I’ve been fleshing it out, adding more features, docs, and tests, and updating the project pages a bit. The major difference is that the server is now built from separate utility classes, each lazy-loaded as needed. Some new features:

  • separate front controller makes it easy to change how HTTP requests are handled
  • file caching uses the very mature Cache_Lite
  • supports conditional GET and far-future Expires models of client caching
  • serve content from any source, not just files
  • new “minifiers” (content compressors) for CSS and HTML with unit tests

At this point to see the new Minify in action you’ll need a Subversion client, like the Windows shell extension TortoiseSVN or the Eclipse plugin Subclipse. You can checkout a read-only working copy at http://minify.googlecode.com/svn/trunk/ and the README has easy setup instructions.

Marriage Rock I

Yeah, we did it. I was in charge of the music and spent most hours from weeks before up until the morning of with my head stuck inside MediaMonkey. I can’t say enough good things about the “Gold” version, but these posts will shockingly not be about the boring machinations of software.

Look For Me As You Go By – The Innocence Mission
Our first dance. I was warned it seems like an eternity when 60 people are staring at you, so I chopped 19 seconds from the end chorus. Love this song.

Keep Sending Me Black Fireworks (wedding edit) – Of Montreal
Lately this is the closest Of Montreal’s come to a straight up pop love song, and it’s perfect. I did cut some weirdness to keep guests bouncing.

Uncontrollable Boasting
Three awesome tunes that pretty much glued themselves together. “Going Back to Miami” is courtesy of the ever-awesome Bubblegum Machine.

I forgot how uninviting makeshift reception dance floors can be, and how quick people file out once the cake is cut, but no matter; these songs became our soundtrack for weeks before and after the ceremony.

A lot more to come…

Distance and bearings between GPS coordinates in SQL

Another post from my sql abominations series. I’m running this on MySQL 5 particularly.

Assume you have a table of locations with Latitude and Longitude for each one. In my case the table is “station”, primary key being “LocID”. With help from this article, first we create a view to get 3D coordinates (6378 = Earth’s radius in km):

CREATE VIEW gpsGlb AS
    SELECT
        LocID
        ,6378 * COS(RADIANS(Latitude)) * COS(RADIANS(Longitude)) AS x
        ,6378 * COS(RADIANS(Latitude)) * SIN(RADIANS(Longitude)) AS y
        ,6378 * SIN(RADIANS(Latitude)) AS z
    FROM station;

Now we can query for great-circle distance (I want rounded miles) to all locations from, say, LocID 405:

SELECT
    LocID
    ,ROUND((2 * 6378 * ASIN(d / 2 / 6378)) * 0.621371192) AS dist_mi
FROM
    (SELECT
        SQRT(dx * dx + dy * dy + dz * dz) AS d
        ,LocID
     FROM
        (SELECT
            p1.x - p2.x AS dx
            ,p1.y - p2.y AS dy
            ,p1.z - p2.z AS dz
            ,p2.LocID
        FROM gpsGlb p1
        JOIN gpsGlb p2 ON (p1.LocID = 405 AND p2.LocID != 405)
       ) t1
    ) t2
ORDER BY dist_mi

With help from this article, we can query for the initial bearing to each location. The “boxed” calculation will come in handy later.

SELECT
    LocID
    ,(360 + DEGREES(ATAN2(y, x))) % 360 AS initBearing_deg
    ,ROUND(((360 + DEGREES(ATAN2(y, x))) % 360) / 22.5) * 22.5
     AS initBearingBoxed_deg
FROM
    (SELECT
        SIN(RADIANS(s2.Longitude - s1.Longitude)) * COS(RADIANS(s2.Latitude))
        AS y
        ,COS(RADIANS(s1.Latitude)) * SIN(RADIANS(s2.Latitude))
            - SIN(RADIANS(s1.Latitude)) * COS(RADIANS(s2.Latitude))
               * COS(RADIANS(s2.Longitude - s1.Longitude))
        AS x
        ,s2.LocID
    FROM station s1
    JOIN station s2 ON (s1.LocID = 405 AND s2.LocID != 405)
    ) q1

What you’ve all been waiting for! The combined query plus boxed compass directions (like ‘NNE’), etc. I’ve also added a limit for the distance in the qq1 subquery since I only want close locations.

SELECT
    qq2.LocID
    ,dist_mi
    ,CASE initBearingBoxed_deg
        WHEN 22.5 THEN 'NNE'   WHEN 45 THEN 'NE'
        WHEN 67.5 THEN 'ENE'   WHEN 90 THEN 'E'
        WHEN 112.5 THEN 'ESE'  WHEN 135 THEN 'SE'
        WHEN 157.5 THEN 'SSE'  WHEN 180 THEN 'S'
        WHEN 202.5 THEN 'SSW'  WHEN 225 THEN 'SW'
        WHEN 247.5 THEN 'WSW'  WHEN 270 THEN 'W'
        WHEN 292.5 THEN 'WNW'  WHEN 315 THEN 'NW'
        WHEN 337.5 THEN 'NNW'  ELSE 'N'
     END AS bearing
FROM (
    SELECT
        LocID
        ,ROUND((2 * 6378 * ASIN(d / 2 / 6378)) * 0.621371192) AS dist_mi
    FROM
        (SELECT
            SQRT(dx * dx + dy * dy + dz * dz) AS d
            ,LocID
         FROM
            (SELECT
                p1.x - p2.x AS dx
                ,p1.y - p2.y AS dy
                ,p1.z - p2.z AS dz
                ,p2.LocID
            FROM gpsGlb p1
            JOIN gpsGlb p2 ON (p1.LocID = 405 AND p2.LocID != 405)
           ) t1
        ) t2
    ) qq1
JOIN (
    SELECT
        LocID
        ,(360 + DEGREES(ATAN2(y, x))) % 360 AS initBearing_deg
        ,(360 + ROUND((DEGREES(ATAN2(y, x))) / 22.5) * 22.5) % 360
         AS initBearingBoxed_deg
    FROM
        (SELECT
            SIN(RADIANS(s2.Longitude - s1.Longitude)) * COS(RADIANS(s2.Latitude))
             AS y
            ,COS(RADIANS(s1.Latitude)) * SIN(RADIANS(s2.Latitude))
                - SIN(RADIANS(s1.Latitude)) * COS(RADIANS(s2.Latitude))
                   * COS(RADIANS(s2.Longitude - s1.Longitude))
             AS x
            ,s2.LocID
        FROM station s1
        JOIN station s2 ON (s1.LocID = 405 AND s2.LocID != 405)
        ) q1
    ) qq2 ON (qq1.LocID = qq2.LocID
              AND qq1.dist_mi <= 60)
ORDER BY dist_mi

Result set is something like:

LocID dist_mi bearing
250 25 E
260 30 NNE
240 42 ENE

Hope this is useful to someone.