MaxMind’s mod_geoip directly inserted into your webserver would be the easiest for external/programmable GeoIP support.

It’d make more sense to check the browser’s language(s) of choice, than force a user of a region into a language they don’t want. Let Apache handle the language, itself, then just display the runtime code (if that’s what you want to do) independently with mod_geoip.

First, setup your supported languages, and priority in Apache:

AddLanguage en .en
AddLanguage fr .fr
AddLanguage es .es
AddLanguage de .de

Then, set your defaults you want to support in order of priority:

LanguagePriority en fr es de

Create multiple pages with the different languages embedded. “index.html” would be removed, and you would have “index.html.en”, “index.html.fr”, “index.html.es”, and “index.html.de” (This also works for .php, .shtml, etc.)

Now, GeoIP’s database for the country name database part, which almost mimmics the above, but uses a different format, ISO3166.

Here’s some tiny little throwaway GeoIP code. It displays those tiny flags in my sig. It has very little overhead with mod_geoip, marginal with the runtime PHP library. This is an old version without eTags (caching) support. It’d be smarter to cache these into RAM than to continually read them from the disk, if you have the choice. You may use this code, if you want.

<?php
// Simple little example utlity to display a small flag based upon GeoIP data.
// by Shawn Holwegner <shawn/at/holwegner/dot/com>
// You may reuse this code, if you want.  I stake no claims to it.
//
// This example supports both mod_geoip, and the external PHP API.
// If mod_geoip is installed:
  $country = "";
  // Do we have apache_note()?
  if (function_exists('apache_note'))
    $country = strtolower(apache_note("GEOIP_COUNTRY_CODE"));
  if (empty($country)) {
    // external MaxMind PHP support
    @require_once("./geoip.inc");
    $gi = geoip_open("./GeoIP.dat", GEOIP_STANDARD);
    $country = strtolower(geoip_country_code_by_addr($gi, $_SERVER["REMOTE_ADDR"
]));
    geoip_close($gi);
    if ($country) {
      header ("Pragma: no-cache");
      header("Expires: Mon, 26 Jul 1999 04:20:00 GMT");
      header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
      header('Cache-Control: no-store, no-cache, must-revalidate');
      header('Cache-Control: pre-check=0, post-check=0, max-age=0');
      header("Content-type: image/gif");
      if (file_exists('./'.$country.'.gif')) {
         readfile('./'.$country.'.gif');
      } else {
         // Generic 'empty' country banner.
         readfile("./00.gif");
      }
    }
  }
?>

I hope this information has been helpful as to easily, and properly implement GeoIP support. Stop forcing me to read Spanish when I’m in Latin America; I get enough of that when I’m in the states!

Long after the death of the ‘demoscene’ of the 90s, I stumble upon Ronald Jenkees. If he’s not demoscene, nothing is. Check this out, it starts out very Skaven, has a touch of Vogue in it, and ends up with a twist of Purple Motion:

Here’s one of his more “Hip-Hop” tracks:

You want it? Sure you do. Click here to get it.

Postfix: Ronald replied to me about my proposed demoscene influence:

“I loved demoscene before I knew there was a name for it. … Then just recently some commenters (you included) educated me on that. Whatta cool thing.”

What a down to earth guy.

Post-Postfix: I bought his CD and it’s worth every cent. Can’t wait for the next one!

This was annoying me. The KPowersave module could control my LCD's backlight, but the ACPI controls would not. Obviously, there is full hardware support, but the ACPI system isn't quite up to the task.

The ACPI scripts merely fake the keys when called, with a hard coded value. This, obviously, was not working.

So, I decided on a rather convoluted method. First, I ended up finding my actual brightness control device (there are several listed on my machine), by running the following as root (it will NOT work via sudo):

  %for n in /proc/acpi/video/**/LCD/brightness; do \
   echo "Trying $n..."; for fade in `seq 1 100`; do sleep \
   0.01s; echo -n "$fade" > $n; done; done

This will print the devices it finds, and attempt to set the LCD levels from 1 (nearly off) to 100 (full brightness). As different LCDs have different specifications, you can't just randomly assume a single number will work. I was being lazy, and although it didn't accept them all, it was still a neat effect.

I found that my LCD device was actually: /proc/acpi/video/VID1/LCD/brightness

Then, I made the world's ugliest parser to see what the available levels were, and to shift up, or down, according to the script. Since there are separate 'up' and 'down' scripts, I decided to be lazy. Have I mentioned yet how incredibly ugly this whole thing is? I wish there was a more bourne-ish portable way to deal with quasi-arrays.

Here's my new /etc/acpi/video_brightnessdown.sh:

#!/bin/sh
#Yeah, I got kind of lazy.  Arrays in Bourne SUCK.
DEVICE=/proc/acpi/video/VID1/LCD/brightness
#. /usr/share/acpi-support/key-constants
#acpi_fakekey $KEY_BRIGHTNESSDOWN
CURRENTLEVEL=`grep 'current:' $DEVICE | awk '{print $2}'`
if [ "x"$CURRENTLEVEL = "x0" ]; then
  CURRENTLEVEL=100
fi
SORTEDLEVELS=`grep 'levels:' $DEVICE | sed -e \
   s,levels:,,g -e 's,\s,\n,g' | sort -n | uniq | \
   grep -v '^$' | sed s,\n,\ ,g | xargs echo`
for levels in `echo $SORTEDLEVELS | sed 's,\n,\ ,g'`
do
    if [ $CURRENTLEVEL = $levels ]; then
      echo -n $LASTLEVEL > $DEVICE
      break
    fi
    LASTLEVEL=$levels
done
... and /etc/acpi/video_brightnessup.sh:

#!/bin/sh
#. /usr/share/acpi-support/key-constants
#acpi_fakekey $KEY_BRIGHTNESSUP
DEVICE=/proc/acpi/video/VID1/LCD/brightness
CURRENTLEVEL=`grep 'current:' $DEVICE | awk '{print $2}'`
if [ "x"$CURRENTLEVEL = "x0" ]; then
  CURRENTLEVEL=100
fi
SORTEDLEVELS=`grep 'levels:' $DEVICE | sed -e s,levels:,,g \
  -e 's,\s,\n,g' | sort -n -r | uniq | grep -v '^$' \
  | sed s,\n,\ ,g | xargs echo`
for levels in `echo $SORTEDLEVELS | sed 's,\n,\ ,g'`
do
    if [ $CURRENTLEVEL = $levels ]; then
      echo -n $LASTLEVEL > $DEVICE
      break
    fi
    LASTLEVEL=$levels
done

Remember to chmod your files, and chown them!

chmod 755 /etc/acpi/video_brightnessup.sh
chmod 755 /etc/acpi/video_brightnessdown.sh
chown root.root /etc/acpi/video_brightnessup.sh
chown root.root /etc/acpi/video_brightnessdown.sh
I hope these scripts work for you, and save you some of the headache I was experiencing!

The following flowchart says quite a bit about software development on the whole, and why it’s so easy to fail; it’s almost 100% true for any system with more than one programmer – and that single programmer often resorts to adding hacks upon hacks upon hacks just to make something work, leaving an ill-maintained piece of code.