• Network shares and XBMC on Apple TV 2

    The Apple TV 2 is a great piece of hardware, but by itself it isn't particularly useful unless your life revolves only around the Apple universe. Luckily, once jailbroken and loaded with XBMC (thanks to the instructions here), it makes one of the best media centre devices, and also one of the cheapest (compared to devices like the Boxee Box or Popcorn Hour).

    It isn't perfect (720p max, can't hold and scroll on the remote, occasionally crashes...), and I wish I had Boxee's awesome remote, but its ability to play pretty much any format at that price outweighs all its flaws. Plus as a bonus, it still works fine as an Apple TV, including AirPlay (one of the few useful out-of-the-box features), even while inside XBMC.

    The XBMC port is still a bit green though, but is generally fairly stable and usable. I had issues connecting it to my Linux-based NAS via SAMBA though - XBMC/Apple TV 2's SMB (network/Windows shares) implementation doesn't seem to be able to do authentication properly, at least the secure kind. It just sits there, and eventually comes up with an 'operation not permitted' error.

    After picking through the XBMC logs on the Apple TV 2 and SAMBA logs on my NAS, I had a hunch it was authentication encryption causing the issue, so I disabled it with the following parameters in smb.conf -

    encrypt passwords = no
    null passwords = yes

    Everything worked.. except Windows. Windows 7 (and possibly Vista as well) refuses to authenticate with a network share via unencrypted means, for good reason.

    There isn't a solution yet, but there is a workaround - by setting authentication to occur on a per-share basis on the NAS, instead of a per-user basis, XBMC can access shares with guest permissions as SAMBA does not require authentication and defaults to guest on those shares. (You can still choose to authenticate to those shares, and Windows will automatically try to do so with your current credentials.)

    To do this, simply add or change the following line in your smb.conf -

    security = share

    On the shares that you want to be able to access from XBMC, add the following option -

    guest ok = yes

    Restart SAMBA, and you should be able to connect from XBMC.

    (As an aside, I believe that's how Windows works as well, because I could access the guest-allowed shares on Windows from XBMC fine, but not the secured ones.)

  • Changing fonts on boxee box

    Out of the box (pun not intended), the boxee box works does most of what it promises fairly well. It needs a bit of spit and polish, but it's a decent attempt - plus if it was done perfectly, there wouldn't be a way to get around the update screen on startup :)

    Unfortunately, boxee, and therefore the boxee box, isn't very multilingual. In particular, the default skin font, Museo Sans, doesn't contain the glyphs needed to display non-Latin alphabet languages, e.g. Chinese, Japanese or Hebrew. It is a well known problem, but fortunately, there is a workaround - replace the skin font with another font that does contain those glyphs.

    This is easy to do on a standard PC because you have full access to everything. Not quite the same on the boxee box - the main system runs off a read-only ISO (that isn't really an ISO, but close enough). Fortunately, there are some writable areas, including the area that stores user settings and metadata, as well as skins (boxee supports custom skins, but there's no UI to support this).

    To change the fonts, you need to be running firmware version 0.9. On later firmware releases (version 1.0 or later), the box has been locked down a lot more and the hack used to gain command line access no longer works. There are various ways to downgrade back to version 0.9 though. This process is relatively fiddly; you should have some experience with the Linux commands if you're trying this.

    Bypassing the initial update and future updates

    1. When you first turn on your boxee box, it should be running v0.9, but it will automatically try to download the latest update. To circumvent this, either connect to wifi, or disconnect the ethernet cable. If you're connecting via a cable, plug the cable back in once you get to the wireless configuration screen. If you get stuck at the update screen, power off the box and try again.
    2. Complete the rest of the configuration.
    3. Go to Settings -> Appearance -> Screensaver, and change Screensaver mode to Off. Note that Black is not the same as Off, and doing this may lead to potential burn-in on your display. If you leave the screensaver on though, boxee will pop up a dialog at some random point and you'll have to update or power off to get rid of it.

    Getting access to the terminal

    1. Go to Apps -> Repositories (under Extras) .
    2. Click Add Repository, enter the following URL and click Done -
    3. Select Erik's App Repository, then UnBoxed. Click Start to start the app.
    4. Click the Enable telnet button, and take note of your boxee box's IP address.
    5. Using telnet (if you're using Windows, try executing telnet in the command prompt; if it doesn't work, download and use PuTTY) connect to your boxee box at the default telnet port. No credentials are needed to connect.

    Changing the font

    To change the font, you first need to make a copy of boxee's default skin into the userdata area, before changing the skin fonts and finally the config to point to this new skin.

    Make a copy of the default skin

    Simply execute the commands below in order in the telnet session. The trailing dots are very important.

    1. cd /.boxee/UserData/skin
    2. mkdir boxee-customfont
    3. cd boxee-customfont
    4. ln -s /opt/boxee/skin/boxee/720p .
    5. ln -s /opt/boxee/skin/boxee/colors .
    6. ln -s /opt/boxee/skin/boxee/media .
    7. ln -s /opt/boxee/skin/boxee/sounds .
    8. cp -r /opt/boxee/skin/boxee/Fonts .
    9. cp /opt/boxee/skin/boxee/skin.xml .

    Replace the font

    The most complete free font I've found so far is the Droid Sans set of fonts, designed for the Android operating system. You could also use Arial Unicode MS (installed with Windows, located in C:\Windows\Fonts), but that doesn't look very nice in my opinion, especially on the big screen. The Droid Sans set of fonts are freely available here, or directly downloadable here in .tar.gz format. I've re-hosted a recent snapshot of the font though, so you won't need to download it manually.

    Execute the following commands to replace with the Droid Sans font; adjust steps 2, 5, 6, 7 accordingly for other fonts. These steps pick up from the previous steps. You can get fonts on to the device either via the web with wget, a network share, or by plugging in an USB drive.

    1. cd Fonts
    2. wget .
    3. rm MuseoSans_500.ttf
    4. rm MuseoSans_700.ttf
    5. cp DroidSansFallback.ttf MuseoSans_500.ttf
    6. cp DroidSansFallback.ttf MuseoSans_700.ttf
    7. rm DroidSansFallback.ttf

    Changing the active skin

    This last set of steps activates the derived skin on your boxee box. Because of the limited space on the device, the only interactive text editor available is vi, which can be intimidating to some people. An alternative would be to set up a network share or use a USB stick to transfer the file to a computer, modify it, and transfer it back.

    Either way, to activate this alternative skin, you need to modify /.boxee/UserData/guisettings.xml. Once loaded, locate the following segment -


    Now chance the value of the skin element to boxee-customfont, like this,


    Save, transfer the file back to the boxee box if needed, then restart the boxee box. The default font should now have changed to whatever you changed it to, enabling you to see some CJK glyphs, instead of boxes.

    To revert these changes, simply revert the changes under Changing the active skin, then delete the /.boxee/UserData/skin/boxee-customfont directory.

    I haven't worked out a way to suppress the update notifications, so they'll be a bit annoying but bearable. If you upgrade, this hack may break and you won't be able to get terminal access to the box again without downgrading.

    Thumbs up to the info over at for the info on how to do this.

  • Rendering variable-sized SVGs

    As I tweeted earlier, I've been playing with SVG recently. But not in the way most people use SVG - I've been working on a website that generates SVGs on the fly with variable sets of data. This means coding the SVG manually, as opposed to drawing it visually in something like Inkscape. 

    As the set of data is variable, the dimensions of the resultant SVG is also variable. This means it is easier to just leave off the height and width attributes on the head SVG element, because it can't really be determined until it is rendered (and even then, there could be differences in the renderer or settings that may affect it). You would expect it to be determined implicitly, and it does kind of happen, but not as well as you'd expect.

    The 4 major browsers all offer differing behaviour. Here's an SVG that demonstrates the problems. Try opening it in different SVG-supporting browsers, Opera, Safari, Chrome or IE 9.

    To start off with, for some silly reason, no browser has the ability to pan or zoom SVG out of the box, not even if you are opening the raw SVG in the browser. And SVG without explicit dimensions don't get scrollbars, so anything that doesn't fit on the screen might as well not exist, even though there is obviously an implicit size for it to work with. Who knows why.

    Anyway, everything looks good when you open it. In that SVG, there is a script that scales the image when you scroll your mouse wheel. Try it. Alternatively, you can adjust the zoom level in your browser using the menus or CTRL and - or +.

    Personally, the expected behaviour is that the entire image is scaled and the browser window should be filled with the image. Scrollbars should appear if the image is larger than the window. This means that the default SVG viewport should be the size of the image, and if the dimensions are not explicitly specified, they should be implied based on the rendering's bounding box. The SVG specs aren't very explicit about what should happen in this situation as far as I can see.

    Here's what happens in the browsers I have installed:

    Opera 10.63 - this one isn't bad. The scaling works as expected. And performance is pretty good. The only issue are the grey vertical lines at hourly intervals. Those lines should stretch the height of the viewport (x1=100 y1=0 x2=100 y2=100%), i.e. the image. In this case Opera seems to have decided the viewport size is the browser window size due to the absence of explicit image dimensions. Ok, and looks good at the default zoom level, but as soon as you zoom out, you can see that they end at the original zoom level's edge, instead of extending to the new viewport edge as expected. To be fair, I can't find anything in the SVG specs that explicitly say what should happen, but this behaviour doesn't seem useful.

    Safari 5.0.3 / Chrome 8.0.552.210 beta - the WebKit family of browsers don't cope with this very well. As you zoom, it scales the image's dimensions as well as the SVG elements. This means that when you zoom out, the image appears clipped, making zooming out pointless. You can see the same behaviour when zooming in, as the scrollbars appear. Looking around at the SVG DOM, it seems that the root SVG element is given a value of 100% for both the width and height if they are not specified. On load, this is calculated from the implicit viewport, the window. When scaling though, these values are recalculated using the new scale factor instead, causing the problem.

    Firefox 4 Beta 7 - first off, the performance is horrible compared to every other browser. Stutters and lags, and it isn't even particularly complex, though it is large. When scaling, it exhibits the same issues as Opera. Hope they fix it before 4 goes gold.

    Internet Explorer 9 Beta - surprisingly, this is the only browser that rendered the SVG as expected (although it didn't have scrollbars either). The image scaled as expected, and the grey vertical lines worked as well. Performance was impressive too. Maybe they had the advantage of hindsight.

    The solution

    There are two. The first one is obvious - explicitly specify dimensions on the SVG image. All these problems go away if you do this.

    The second is a bit of a hack - if your SVG is going to be viewed in something that can execute JavaScript, you can use the following snippet to add the missing width and height attributes based on the bounding box of the rendered content, i.e. the width and height as rendered. The problem with this is that it doesn't cause scrollbars to appear in Opera. In Firefox 4 Beta 7, the scrollbars only appear as you start scaling. It works fine in Firefox 3.6.10 though.

    <script type="text/javascript">
            function fixDimensions() {
                // fix bug with Opera, Firefox and Chrome when scaling. Surprisingly,
                // only IE9 works as expected.
                var svgEl = document.documentElement;
                var bBox = svgEl.getBBox();
                if (svgEl.width.baseVal.valueAsString == "100%")
                        svgEl.width.baseVal.valueAsString = bBox.width + "px";
                if (svgEl.height.baseVal.valueAsString == "100%")
                        svgEl.height.baseVal.valueAsString = bBox.height + "px";

    You then need to add the following attribute to your root SVG element -


    That is needed as it doesn't seem to reliably work in all browsers if you add that handler using addEventListener, presumably because it isn't added before the load event fires.

    Here is the same SVG, but with the above script, and without the scaling script. Use the browser menus or keyboard shortcuts to test.

  • Downloading large files with VBScript

    Downloading (well doing anything really) is a pain with VBScript, but recently, while writing a script to download, install and update apps from the net, I discovered that the MSXML2.XMLHTTP COM object can't download large files. Well, it isn't necessarily large files that break it, but files that take a while to download. There seems to be an in-built timeout, and once that has been exceeded, it will cut the connection.

    The only evidence of this is the status code - it will return 0.

    Turns out you need to use MSXML2.ServerXMLHTTP in order to set timeouts to a longer period. The relevant sub-routine is setTimeouts. Note this doesn't seem to be a timeout in the traditional sense - this timeout value specifies how long the entire response can take, not how long to wait if there is no response from the server.

    Below is some code that wraps all this in a neat function.

    Function Download ( ByVal strUrl, ByVal strDestPath, ByVal overwrite )
        Dim intStatusCode, objXMLHTTP, objADOStream, objFSO
        Set objFSO = CreateObject("Scripting.FileSystemObject")
        ' if the file exists already, and we're not overwriting, quit now
        If Not overwrite And objFSO.FileExists(strDestPath) Then
            WScript.Echo "Already exists - " & strDestPath
            Download = True
            Exit Function
        End If
        WScript.Echo "Downloading " & strUrl & " to " & strDestPath
        ' Fetch the file
        ' need to use ServerXMLHTTP so can set timeouts for downloading large files
        Set objXMLHTTP = CreateObject("MSXML2.ServerXMLHTTP") "GET", strUrl, false
        objXMLHTTP.setTimeouts 1000 * 60 * 1, 1000 * 60 * 1, 1000 * 60 * 1, 1000 * 60 * 7
        intStatusCode = objXMLHTTP.Status
        If intStatusCode = 200 Then
            Set objADOStream = CreateObject("ADODB.Stream")
            objADOStream.Type = 1 'adTypeBinary
            objADOStream.Write objXMLHTTP.ResponseBody
            objADOStream.Position = 0    'Set the stream position to the start
            'If the file already exists, delete it.
            'Otherwise, place the file in the specified location
            If objFSO.FileExists(strDestPath) Then objFSO.DeleteFile strDestPath
            objADOStream.SaveToFile strDestPath
            Set objADOStream = Nothing
        End If
        Set objXMLHTTP = Nothing
        Set objFSO = Nothing
        WScript.Echo "Status code: " & intStatusCode & VBNewLine 
        If intStatusCode = 200 Then
            Download = True
            Download = False
        End If
    End Function
  • Run SuSE Studio images without persistence

    UPDATE (20/07/2013): A new workaround has been found that works with OpenSuSE 12.x.

    UPDATE (10/03/2012): This trick no longer works as of OpenSuSE 12.1 because the code that checks for USB boot devices during boot has been removed; only CD/DVD devices are checked on boot. (The code commit that changed this can be seen here.) The functions to perform the check are still there though, so if you modify linuxrc or the include file inside the initrd to call them, everything should just work. Unfortunately, SuSE Studio doesn't offer a way for you to hook into Kiwi so you can perform these changes before initrd is built (even though Kiwi itself has these hooks). Therefore as far as I know, this trick will only work with v11.4 or earlier.

    I've been playing with SuSE Studio recently - it allows you to build custom Linux images (on top of the OpenSuSE/SLED base) via a nifty web interface, test drive them before downloading them in a range of formats, including LiveCD, disk image or as a Xen/VMware image. 

    The beauty of it is it allows you to make easily reproducible Linux images, without having to keep the build configuration somewhere local. The downside however is that you need to download the entire image again every time you make a change, no matter how minor. (It'd be great if you could download binary diffs from previous versions, or better yet, be able to make limited local modifications without the build system.)

    I wanted to make a bootable USB stick, but without persistence so I can play around all I want without having to worry about breaking it. I'm using it as a replacement for Slax, which is unfortunately no longer being actively developed.

    Getting the custom Linux image to boot was easy - SuSE has a useful Image Writer tool for Windows users, and Linux people can simply use dd. However, it requires you to use the disk image format, which means changes are persisted on to whatever you put it on; the USB stick in this case.

    The only format without persistence is the Live CD format, but it isn't just a case of writing that image to the USB stick, because it uses ISOLINUX to boot, i.e. expects to be booted from a CDROM, or something emulating a CDROM. (At least from my experience anyway. The OpenSuSE instructions here seem to suggest otherwise. So give that a shot first, and come back here if it doesn't work.)

    What was needed was to use SYSLINUX instead, which is designed to boot off standard hard/flash drives, as well as some tricks to make the OpenSuSE startup code think it is a CDROM. Because of this though, this trick will not work if the system you're booting on actually has a CDROM (or some other optical drive) installed/attached.

    The following instructions are for a 32-bit image and to be performed on Windows, but should be easily adjustable for 64-bit and/or Linux.

    Prep the drive

    You'll need a USB that is at least the size of the ISO image. It will most likely need to be completely toasted, so make sure you have a backup of whatever is on there already. Don't expect to be able to use the remaining space for other purposes (more on this later).

    1. Plug the drive into your computer.
    2. Go to My Computer, right-click on the aforementioned USB drive (make sure this is the right drive!) and click Format.
    3. For the File System option, select FAT32 (this will most likely not be the default option). Then type in a volume label if you want, and click Start.

    Load the image on to the drive

    Now that the drive is ready, you will need to build and download your SuSE Studio machine in Live CD/DVD format if you haven't already. You will also need to download a tool to crack open the ISO image file if you don't have one already. Some recommendations are:

    • Virtual Clone Drive lets you 'mount' the ISO file as a CD drive, so you interact with it as if you had burnt that ISO image on to a disc. This is probably the easiest option; and it is a useful tool anyway.
    • WinImage or PeaZip lets you open ISO files as if they were ZIP files so you can extract files from them, but it doesn't let the image pretend to be an actual disc inserted into the system.

    If you're using Linux, you can simply mount the ISO file using the mount command.

    Once you have one of those tools (or something else), copy everything in the ISO image file on to the USB drive. There should be a boot directory, and two other files, config.isoclient and one named after your machine name and version.

    Let the trickery begin

    1. Download SYSLINUX 3.86. Don't download the 4.x versions, because the graphical boot menu that OpenSuSE doesn't work with it.
    2. Once downloaded, open the ZIP file and copy win32\syslinux.exe to the root of your USB drive (linux\syslinux for Linux users).
    3. On your USB drive, go to boot\i386\loader. (Amend accordingly if using 64-bit).
    4. Rename isolinux.cfg to syslinux.cfg.
    5. Open up syslinux.cfg in a decent text editor (i.e. one that understands Unix files - if it is all one big mess, try Notepad++).
    6. The file is split into a number of sections - the header (all the lines before the first 'label' line, then each line starting with 'label' denotes a new section. Find the 'append' lines for each section except the header and the Failsafe section, and add the following parameter to the end -
      For example,
      append initrd=initrd ramdisk_size=512000 ramdisk_blocksize=4096 splash=silent showopts cdinst=1
    7. Save the file.
    8. Go back to the root of your USB drive. Create a directory named 'etc' (without quotes).
    9. Inside the etc directory, create a file named 'ImageVersion' (without quotes). Make sure it is named exactly that (it is case-sensitive), and has no file extension. It should not contain anything. This is simply a marker file so the OpenSuSE scripts think this is a live image and will boot accordingly.
    10. Finally, you need to make this drive bootable by initializing SYSLINUX. Go to Start -> All Programs -> Accessories -> Command Prompt. Right-click on this, and select 'Run as administrator'. (Just click on it if you're using Windows XP.)
    11. Change the current drive to the USB drive, so if the USB drive was H drive, type -
      and press ENTER.
    12. Now type the following and press ENTER to initialize SYSLINUX on the USB drive.
      syslinux.exe -fma -d /boot/i386/loader H:
      Amended /boot/i386/loader if you're using 64-bit, and change H: to whatever your USB drive letter is. It won't say anything, but it needs a few seconds to do its work. When the light on your USB drive stops flashing, it should be done.

    Cross your fingers and reboot

    That should be it - reboot your computer, making sure that you tell your BIOS to boot from the USB drive first (usually F12 on Lenovo computers, F9 on HP computers).

    If it works, congratulations - you're done.

    If it doesn't, read on.

    'Boot error' message appears

    This usually occurs because you changed things on the USB drive after you initialized SYSLINUX. It may also occur seemingly randomly, as Windows sometimes does what it thinks are harmless operations on the drive, which end up breaking SYSLINUX. This why it isn't recommended to use this drive to store other files. To fix this situation, simply re-run steps 7-9 from the Let the trickery begin section above.

    'No DEFAULT or UI configuration directive found!' message appears

    This message seems to be referring to an error in the configuration file syslinux.cfg, but in fact can appear when SYSLINUX can't find the file for whatever reason.

    In our case, it seems to happen because it can't find the configuration file located in boot\i386\loader even though this is officially supported. SYSLINUX 4.0 seems to be more resilient and reliable (maybe because the file system code was re-written), but unfortunately we can't use it with OpenSuSE's graphical boot. So the other option is to copy the contents of boot\i386\loader to the root of the USB drive, then reinitialize SYSLINUX. It makes things a bit messier, but SYSLINUX 3.86 seems to be happier. 

    You can still use steps 10-12 above to initialize SYSLINUX even though the location has moved - when SYSLINUX is told /boot/i386/loader, it actually tries /boot/i386/loader/syslinux.cfg, /boot/i386/syslinux.cfg, /boot/syslinux.cfg, and finally /syslinux.cfg, in that order.

    'No devices matches MBR identifier: 0x01fe4d2 !' message appears (or some other hex code)

    This message means the cdinst=1 boot parameter is missing from the boot line. Check steps 5-7 in the instructions above.

    I need to update my image

    When updating your image (i.e. you re-built the image on SuSE Studio for whatever reason), you don't need to format the USB drive again. Just delete everything on it, then start at the Load the image on to the drive section.

    Final notes

    This should also work for the official OpenSuSE Live CD/DVD images because they presumably use the same booting process; I haven't tested this though. 

    The procedure here should also work for memory cards - that's what I used, and because the SD card sits flush in my ThinkPad, I have access to a full-featured Linux machine without having to install anything on to the hard drive or have anything sticking out of some port.

    Sidenote - my wireless or ethernet is connected but doesn't seem to be able to send anything

    I encountered an issue where my wireless connection had an IP address and the DNS and gateway settings were all set up properly, but nothing was going in or out - no pings, no DNS lookups, no direct IP address connections, nothing. This turned out to be IPv6 interfering and also probably because it isn't configured properly (actually not at all) on my network. OpenSuSE now enables IPv6 support in the kernel by default, therefore to switch it off, it is necessary to use the following boot parameter -

  • Developing with Django on Windows

    There have been numerous posts lately on the django-users mailing list from people having issues with running Django on Windows; usually due to lack of file associations or Django not being installed properly. Here's my take on the easiest way to install Django on Windows for both development and production.

    I've used these steps on Windows 7, so it should work fine on Vista and Server 2008 and 2008 R2. They'll probably also work on XP or Server 2003 / R2.

    Set up Python

    1. Download and install ActivePython 2.x. Do not download ActivePython 3.x because Django isn't compatible with Python 3.x yet. ActivePython is a Python distribution by ActiveState that includes some extra 'batteries' and settings to make Python easy to use out-of-the-box on Windows. You do not need to download Python as well - this is Python plus a few more things.

    While that's downloading and installing, brush up on some Python basics.

    Install Django

    1. Open up the command prompt (Start -> Accessories -> Command Prompt). Note - Windows PowerShell is not the same as the Command Prompt; similar, but not the same.
    2. Type the following and press ENTER. 
      pip install Django

    This will automatically download and install the latest release version of Django into the default Python package location (<location where ActivePython is installed, e.g. C:\Python27>\Lib\site-packages). This is a good location, and should be acceptable for nearly all cases.

    If you're curious, learn more about pip, a package installation tool for Python, while it is installing.

    Tutorial time!

    Now you're ready to work through the Django tutorial. You should be able to complete the tutorial now, just like a hardcore *nix hacker.

    Grrrr, Notepad.

    If using Notepad to edit Django code is driving you up the wall, try using the Eclipse-based pydev or Netbeans' experimental Python support. PyCharm is another option. My personal favourite is ActiveState's Komodo Edit - based on the Mozilla Firefox platform, it's not bloated like Eclipse and Netbeans, yet powerful enough to be productive. 

    And as a bonus, because ActivePython sets up your paths properly, Komodo Edit's auto-complete will just work with Django (and everything else you install into the standard Python package locations).

    Other things

    At some point you'll probably want to do something serious and outgrow SQLite (that comes in-built with Python). PostgreSQL and mySQL both work fine on Windows, alternatively there's a third-party Microsoft SQL Server connector for Django available, django-mssql

    For production, it is often easiest just to run Django under Linux, even inside a VM. But if that's not possible, here are some posts worth looking at for running Django under Windows and IIS (not much point doing it with Apache on Windows):

    The two most popular options seem to be,

    And lastly, Django ticket #2039 might also be of interest.