autofont.py

It ain't pretty but it works. Interpolator function is from: Interpolated Lookup Tables in Python. The idea here is to generate tables like this so that text scales smoothly based on viewport width:
@media screen and (max-width: 480px) { body { font-size: 0.500000em; } }
@media screen and (min-width: 481px) and (max-width: 720px) { body { font-size: 0.750em; } }
@media screen and (min-width: 721px) and (max-width: 960px) { body { font-size: 1.000em; } }
@media screen and (min-width: 961px) and (max-width: 1200px) { body { font-size: 1.250em; } }
@media screen and (min-width: 1201px) and (max-width: 1440px) { body { font-size: 1.500em; } }
@media screen and (min-width: 1441px) and (max-width: 1680px) { body { font-size: 1.750em; } }
@media screen and (min-width: 1921px) { body { font-size: 2.000000em; } }
Here's the script:
import sys

if len(sys.argv) < 7:
    print 'usage: %s LOWEST_RESOLUTION HIGHEST_RESOLUTION SMALLEST_FONTSIZE LARGEST_FONTSIZE STEPS FONT_UNIT' % (sys.argv[0])
    sys.exit(1)

llowest_resolution = int(sys.argv[1])
highest_resolution = int(sys.argv[2])
smallest_fontsize = float(sys.argv[3])
largest_fontsize = float(sys.argv[4])
steps = int(sys.argv[5])-1
font_unit = str(sys.argv[6])

resolutions = InterpolatedArray(((1, lowest_resolution), (steps, highest_resolution)))
fontsizes = InterpolatedArray(((1, smallest_fontsize), (steps, largest_fontsize)))

print '@media screen and (max-width: %dpx) { body { font-size: %f%s; } }' % (lowest_resolution, smallest_fontsize, font_unit)

for i in range(2, steps+1):
    print '@media screen and (min-width: %dpx) and (max-width: %dpx) { body { font-size: %.3f%s; } }' % (resolutions[i-1], resolutions[i], fontsizes[i], font_unit)

print '@media screen and (min-width: %dpx) { body { font-size: %f%s; } }' % (highest_resolution, largest_fontsize, font_unit)

Note: to make this work in Internet Explorer versions < 9, include the css3-mediaqueries.js script by Wouter van der Graaf.

Tagged with:

Categorised as:


Reading EC2 tags with Boto

(Ouch! Looks like WordPress update to 3.1.3 wiped all the modifications I made to the default theme. Admittedly I should've seen that coming.) What I want to do is basically attach a key-value pair to an EC2 instance when launching it in AWS Management Console and read the value inside the instance when it's running. To be more specific, I use this to to set a key called environment that can have values like dev, stage and prod so that the Django config can decide which database to connect to etc. while starting up. I suspect that in Boto the current instance can somehow be referenced in a more direct fashion but this works as well. First, append the following to /etc/profile:
# See: http://stackoverflow.com/questions/625644/find-out-the-instance-id-from-within-an-ec2-machine
export EC2_INSTANCE_ID="`wget -q -O - http://169.254.169.254/latest/meta-data/instance-id || die \"wget instance-id has failed: $?\"`"
test -n "$EC2_INSTANCE_ID" || die 'cannot obtain instance-id'
export EC2_AVAIL_ZONE="`wget -q -O - http://169.254.169.254/latest/meta-data/placement/availability-zone || die \"wget availability-zone has failed: $?\"`"
test -n "$EC2_AVAIL_ZONE" || die 'cannot obtain availability-zone'
export EC2_REGION="`echo \"$EC2_AVAIL_ZONE\" | sed -e 's:\\([0-9][0-9]*\\)[a-z]*\\$:\\\\1:'`"
Now we know the region and instance ID. Next, install Boto by running the following commands:
wget "http://boto.googlecode.com/files/boto-2.0b4.tar.gz"
zcat boto-2.0b4.tar.gz | tar xfv -
cd boto-2.0b4
python ./setup.py install
Then, add these lines to ~/.profile:
export AWS_ACCESS_KEY_ID=<ACCESS_KEY>
export AWS_SECRET_ACCESS_KEY=<SECRET_KEY>
Or the equivalent in ~/.boto:
[Credentials]
aws_access_key_id = <ACCESS_KEY>
aws_secret_access_key = <SECRET_KEY>
Now, to read the tag we want in Python:
#!/usr/bin/env python                                                                                                                                           

import os
from boto import ec2

ec2_instance_id = os.environ.get('EC2_INSTANCE_ID')
ec2_region = os.environ.get('EC2_REGION')

conn = ec2.connect_to_region(ec2_region)

reservations = conn.get_all_instances()
instances = [i for r in reservations for i in r.instances]

for instance in instances:
    if instance.__dict__['id'] == ec2_instance_id:
        print instance.__dict__['tags']['environment']

Tagged with:

Categorised as:


Verifying Amazon SNS Messages with PHP

Messages sent by Amazon Simple Notification Service are signed, and checking that any received message is indeed from AWS and not from some douche trying to outsmart you is not very hard (nor should it be optional, for that matter): sns-verify.php The verify_sns() function expects the message in JSON format, plus region (e.g. "eu-west-1"), numerical account ID without dashes and an array containing the topics you're interested in. The code will verify both SubscriptionConfirmation and Notification messages. It loads the certificate from the address in SigningCertURL field to check against for each message separately because the certificate changes over time, as described here. It is also checked that the host where the certificate is loaded from is in the amazonaws.com domain. Example usage where subscriptions are automatically confirmed:
require_once('sns-verify.php');

if($_SERVER['REQUEST_METHOD'] != 'POST') {
    logger('Not POST request, quitting');
    exit();
}

$post = file_get_contents('php://input');

if(!verify_sns($post, 'REGION', 'ACCOUNT', array('TOPIC 1', 'TOPIC 2'))) {
    exit;
}

$msg = json_decode($post);


if($msg->Type == 'SubscriptionConfirmation') {
    logger('SNS SubscriptionConfirmation received);
    file_get_contents($msg->SubscribeURL);
} elseif($msg->Type == 'Notification') {
    logger('SNS Notification received);
    process_message($msg);
}

Tagged with:

Categorised as:


QUERY_STRING parsing in plain C

As far as I can tell (which, I'll be the first one to admit, doesn't count for that much) this code is so simple that there are no holes that could be exploited.

  char * query = getenv("QUERY_STRING");
  char * pair;
  char * key;
  double value;

  if(query &amp;&amp; strlen(query) > 0) {
    pair = strtok(query, "&amp;");
    while(pair) {
      key = (char *)malloc(strlen(pair)+1);
      sscanf(pair, "%[^=]=%lf", key, &amp;value;);
      if(!strcmp(key, "lat")) {
        lat = value;
      } else if(!strcmp(key, "lng")) {
        lng = value;
      }
      free(key);
      pair = strtok((char *)0, "&amp;");
    }
  }

Tagged with:

Categorised as:


Visitor Locator, Take Two

The new version that I hacked together stores number of visits per country and shows the totals when a user clicks a countrys' marker. Visits are stored in an SQLite database, which, as you may know, makes things very easy as there is no server to look after etc. I was thinking of using Berkeley DB, because in an app like this, all that SQL is simply unnecessary sugar, but was lazy in the end (as usual). Update: Added country flags in place of the same default icon for every country (see: Custom Icons section in Google Maps API). Update 2: Added tooltip-like functionality, which shows country details in a transient window (label) instead of the default info window. See GxMarker for additional info. Continuing here from where last nights' script ended. This is just the PHP side of things; Google Maps API examples can be found elsewhere. First we open an SQLite database and create a table for our visitor data if table does not exist:
try {
        $db = new PDO('sqlite:' . $_SERVER['DOCUMENT_ROOT'] . '/../db/visitor-locator.sqlite3');
} catch(PDOException $exception) {
        die($exception->getMessage());
}

$stmt = $db->query('SELECT name FROM sqlite_master WHERE type = 'table'');
$result = $stmt->fetchAll();
if(sizeof($result) == 0) {
        $db->beginTransaction();
        $db->exec('CREATE TABLE visits (country TEXT, visits INTEGER, lat TEXT, lng TEXT);');
        $db->commit();
}
Next, check if the country is already in the table and if it is, increment the 'visits' field:
$stmt = $db->query('SELECT country, visits FROM visits WHERE country = '' . $countryname . ''');
$result = $stmt->fetch();

if($result['country']) {
        $db->beginTransaction();
        $stmt = $db->prepare('UPDATE visits SET visits=:visits, lat=:lat, lng=:lng WHERE country=:country');
        $stmt->bindParam(':country', $countryname, PDO::PARAM_STR);
        $visits = $result['visits'] + 1;
        $stmt->bindParam(':visits', $visits, PDO::PARAM_INT);
        $stmt->bindParam(':lat', $lat, PDO::PARAM_STR);
        $stmt->bindParam(':lng', $lng, PDO::PARAM_STR);
        $stmt->execute();
        $db->commit();
}
If country was not in the table, create a row for it:
else {
        $db->beginTransaction();
        $stmt = $db->prepare('INSERT INTO visits (country, visits, lat, lng) VALUES (:country, :visits, :lat, :lng)');
        $stmt->bindParam(':country', $countryname, PDO::PARAM_STR);
        $visits = 1;
        $stmt->bindParam(':visits', $visits, PDO::PARAM_INT);
        $stmt->bindParam(':lat', $lat, PDO::PARAM_STR);
        $stmt->bindParam(':lng', $lng, PDO::PARAM_STR);
        $stmt->execute();
        $db->commit();
}
And lastly, fetch all rows and form a Javascript array for our client-side script to use:
$result = $db->query('SELECT country, visits, lat, lng FROM visits');

echo "<script type=\"text/javascript\">\n";
echo "//<![CDATA[\n";
echo "var tbl_country = []; var tbl_visits = []; var tbl_lat = []; var tbl_lng = []; var count = 0;\n";
foreach($result->fetchAll() as $row) {
        echo 'tbl_country[count] = \'' . $row['country'] . '\'; ';
        echo 'tbl_visits[count] = \'' . $row['visits'] . '\'; ';
        echo 'tbl_lat[count] = \'' . $row['lat'] . '\'; ';
        echo 'tbl_lng[count] = \'' . $row['lng'] . '\';';
        echo " count++;\n";
}
echo "//]]>\n";
echo "</script>\n";

Tagged with:

Categorised as: