Wednesday, February 06, 2013

Darpa funds python development for big data

DARPA funds python development for big data

Friday, January 11, 2013

National Geographic Photo of the Day using Python

A small snippet of code to get the National Geographic Photo of the Day.
It uses mechanize and beautiful soup 4 to help with the scraping.

It also has a function to allow walking backwards to pickup previous photos.

# -*- coding: utf-8 -*-
import os
import re
import sys

import mechanize
from bs4 import BeautifulSoup

MASTER_URL = "http://photography.nationalgeographic.com/photography/photo-of-the-day/?source=NavPhoPOD"

class POD_Browser(mechanize.Browser):
    """
    A browser for pod, with our configuration settings.
    """
    def __init__(self, *args, **kwargs):
        mechanize.Browser.__init__(self, *args, **kwargs)
        self.set_handle_robots(False)
        self.set_debug_redirects(False)
        self.set_debug_http(False)
        self.set_handle_equiv(True)
        self.set_handle_gzip(True)
        self.set_handle_redirect(True)
        self.open(MASTER_URL)

class Session(object):
    """
    A Session.
    """
    def __init__(self):
        self.browser = POD_Browser()

    def downloadPhotoOfTheDay(self):
        """
        Search the page looking for a Wallpaper link. Not all pages have
        Wallpaper link, and we (politely) don't download the image in that
        case.
        """
        page = self.browser.response().read()
        soup = BeautifulSoup(page)

        tags = soup.find_all('a', text = re.compile ('Download Wallpaper'))
        for t in tags:
            filename = t['href'].split('/')[-1]
            # If we've already downloaded the file, don't download it again.
            if not os.path.exists(filename):
                filename, _headers = self.browser.retrieve(t['href'], filename )
                print filename
                sys.stdout.flush()

    def goPrevious(self):
        """
        Find the previous link and go back a day
        """
        link = self.browser.find_link(text_regex = re.compile('Previous'))
        self.browser.follow_link(link)
        
    def downloadPriorPhotos(self, start = 1, num = 10):
        """
        Download some prior photos.
        You can start 7 days back and get 14 days of photos with
        start = 7, num = 14

        :param start: How many days to go back before starting
        :param num: How many days to look at.
        
        """
        for x in xrange(start):
            self.goPrevious()

        for x in xrange(num):
            self.downloadPhotoOfTheDay()
            self.goPrevious()

if __name__ == '__main__':
    s = Session()
    s.downloadPhotoOfTheDay()
    # If you want to get the last week's worth uncomment this instead.
    #s.downloadPriorPhotos(num = 7)

Wednesday, April 11, 2012

pyWallpaper Updated

I have committed a much more comprehensive version of pyWallpaper to the subversion repository.

It is multi-threaded to speed up the wallpaper construction  (most of the threads end up being I/O bound, so this is a win in terms of elapsed time).

Also supports walking subfolders by prefixing paths with a +

The code is still available at http://code.google.com/p/pywallpaper/

Saturday, March 12, 2011

When .999 is actually 1

You remember at school (or maybe you're just learning now) when doing fractions, that dividing something by 9 would give you an "infinite" decimal that repeated? For example 4/9 = .444444 on to infinity.

This means that if you ever see a number that is that way you know it's something divided by 9, so .77777...  is 7/9.

But wait, what about .999999... ? That would be 9/9 which is 1, that can't be right!

In fact it is, and without any tricks, here's the algebra to show it.

I will use .999999r to indicate .9 repeater, normally it would be a .9 with a . above the 9, but, finding a font that everyone has that has that proved too tedious :-) I have also made all the steps explicit instead of doing multiple operations at once, just so algebra beginners can see there is no subterfuge going on.

Let a = .999999r

Multiply both sides by 10 gives
10a = 9.999999r

Subtract 9 from both sides gives
10a - 9 = .999999r

Replace .999999r with a from above
10a - 9 = a

Subtract a from both sides
10a - 9 - a = 0

Add 9 to both sides
10a - a = 9

Simplify
9a = 9

Divide both sides by 9
a = 1

Therefore .999999r = 1

Thursday, November 18, 2010

Process Explorer gets Tree CPU Usage feature

The feature I've missed most from Process Explorer has been implemented in version 14.
The ability to see the combined CPU usage for a parent and all its children, this is especially useful for things like Chrome, but, now I can roll up a lot of trees of stuff and still see what's making my CPU fans spin up all of a sudden.

Thanks guys d8)

http://blogs.technet.com/b/sysinternals/archive/2010/11/16/update-process-explorer-v14.aspx

Friday, October 08, 2010

5 Fridays, 5 Saturdays, 5 Sundays, 823 years, wrong..

The calendar repeats every 11 years, so the maximum this can be is 11 years...
so October in 2021 will be the same as October in 2010 (handy if you want to reuse those calendars), go ahead look on your computer or phone right now.

However, we have a few months that have 31 days, and we only need one of them to begin on a Friday.
In 2013, March starts on a Friday (and 2024, etc)...

In 2014, August starts on a Friday (and 2025, etc)...

There are other months in other years that have 3 days that occur 5 times too, so, it's not special.

Next time someone tells you something about some weird calendar event, think about the 11 year cycle, and go back/forward 11 years and see if it's true.

Tuesday, October 05, 2010

When...

When you "talk" like a LOL Cats caption, I wonder if your parents were too closely related to each other...

Thursday, September 09, 2010

Random code repo

I've created a google project (akm-code) into which I can dump random code projects.
Most of the code in there is finished, but, might be suffering from bit-rot (patches welcome d8)

You can browse the code here; http://code.google.com/p/akm-code/source/browse/

Wednesday, August 18, 2010

Serial terminals

Most people forget, that putty and its relations are usable as serial terminals under windows. Putty has built in terminal emulation and you can choose speed and COM port, AND save the profile.

This is useful for things like Bus Pirate or Arduino use since you can just pull up your profile from the putty interface.

Monday, July 26, 2010

Google Code Repo for windows wallpaper code

I've setup a google code repository for the pywallpaper code.
You can download it from there , and get any updates as I make them, or contribute patches.

pywallpaper project

Tuesday, July 20, 2010

Set windows wallpaper from python for multiple monitors

This code will allow you to set a different image per monitor for any combination of monitors. Monitors don't have to be the same size, or setup to be square on for it to work. You can have your third monitor straddling the other two, and the wallpaper will be built to accommodate it.

You can now specify per-monitor directory lists if you want.

There are blending and resizing options available too, see the comments.

I've added a setup.py to make a .exe so that the dos window doesn't pop-up.

#!C:/python25/python.exe

# Code to rotate or set wallpaper under windows
# Copyright (C) Andrew K. Milton 2007 - 2010
# Released under a 2-clause BSD License
# See: http://www.opensource.org/licenses/bsd-license.php

# Multi monitor detection based on http://code.activestate.com/recipes/460509/

# This will handle any configuration of an arbitrary number of monitors,
# including offset boundaries.


import os
import sys
import time
import random

from optparse import OptionParser
from ConfigParser import SafeConfigParser
import ctypes

from ctypes import windll

from win32con import *
import win32gui
import win32api
import win32con

from PIL import Image, ImageDraw, ImageChops, ImageOps, ImageFilter


# I recommend you create a pywallpaper.conf file that looks something
# like this to store the directories in rather than specifying -d
# multiple times on the command line.
#
# NB you can specify paths per monitor. Any monitor number without its
# own paths will get the global paths. Monitors start at 0 which is always
# the primary monitor.
#
# Some options don't play nicely together.

"""
[global]
Blending = True
BlendRatio = 0.40
Crop = False
Fill = True
Gradient = False
PreRotate = True

[directories]
paths = C:\Documents and Settings\akm\My Documents\My Pictures\gb
        C:\Documents and Settings\akm\My Documents\My Pictures\Ralph

[monitor_0]
paths = C:\Documents and Settings\akm\My Documents\My Pictures\Wide Screen
[monitor_1]
paths = C:\Documents and Settings\akm\My Documents\My Pictures\Landscapes
"""

# If you don't like the little dos window that pops you can use the
# following as setup.py to create a .exe that won't display the window,
# makes it a little easier to use as a startup item too.

"""
from distutils.core import setup
import py2exe

options = {
    "bundle_files": 2,
    "ascii": 1, # to make a smaller executable, don't include the encodings
    "compressed": 1, # compress the library archive
    "excludes": ['w9xpopen.exe',]
    }

setup( windows = ['pyWallpaper.py'],
       options = {'py2exe': options},
       )
"""


class RECT(ctypes.Structure):
    _fields_ = [
        ('left', ctypes.c_long),
        ('top', ctypes.c_long),
        ('right', ctypes.c_long),
        ('bottom', ctypes.c_long)
        ]
    def dump(self):
        f = (self.left, self.top, self.right, self.bottom)
        return [int(i) for i in f]

class MONITORINFO(ctypes.Structure):
    _fields_ = [
        ('cbSize', ctypes.c_ulong),
        ('rcMonitor', RECT),
        ('rcWork', RECT),
        ('dwFlags', ctypes.c_ulong)
        ]

class Monitor(object):
    def __init__(self, monitor, physical, working, flags):
        self.monitor = monitor
        self.physical = physical
        self.working = working
        self.size = self.getSize(*self.physical)
        self.width, self.height = self.size
        self.left, self.top, self.right, self.bottom = self.physical
        self._left, self._top, self._right, self._bottom = self.physical
        
        self.isPrimary = (flags != 0)

        self.cTop = self.top
        if self.cTop < 0:
            self.cTop = 20000  + self.cTop
        self.cLeft = self.left
        if self.cLeft < 0:
            self.cLeft  = 20000  + self.cLeft

        self.wLeft = int(self.left)
        self.wTop = int(self.top)

        self.needsSplit = ( (self.left < 0 and self.right > 0) or
                            (self.top < 0 and self.bottom > 0) )
        if self.needsSplit:
            self.needVSplit = self.top < 0 and self.bottom > 0
            self.needHSplit = self.left < 0 and self.right > 0

    def addWallpaper(self, bgImage, wallpaper):
        if not self.needsSplit:
            bgImage.paste(wallpaper, (self.wLeft, self.wTop))
            return

        if self.needVSplit:
            height = -self.top
            bottom = wallpaper.crop((0, 0, self.width, height))
            bottom.load()
            top = wallpaper.crop((0, height, self.width, self.height))
            top.load()
            bgImage.paste(top, (self.wLeft, 0))
            bgImage.paste(bottom, (self.wLeft, bgImage.size[1] - height))
        else:
            width = -self.left
            right = wallpaper.crop((0, 0, width, self.height))
            right.load()
            left = wallpaper.crop((width, 0, self.width, self.height))
            left.load()
            bgImage.paste(left, (0, self.wTop))
            bgImage.paste(right, (bgImage.size[0] - width, self.wTop))

            
    def getSize(self, left, top, right, bottom):
        return [abs(right - left), abs(bottom - top)]

    def __repr__(self):
        return 'extent: ' + str(self.physical) + ' :: size: ' + str(self.size) + ' :: primary: ' + str(self.isPrimary) + ' :: needsSplit ' + str(self.needsSplit) + ':: ' + hex(self.monitor)
    def __cmp__(self, other):
        if not cmp(self.cTop, other.cTop):
            return cmp(self.cLeft, other.cLeft)
        return cmp(self.top, other.top)

class Desktop(object):
    def __init__(self):
        self.setMonitorExtents()

        # Merge with the desktop background colour
        # Handy to tint your background to your theme.
        self.Blending = True

        # Amount of picture to bg colour ratio
        # This works well for black...
        self.BlendRatio = 0.40

        # Render a gradient under the image..
        # I'm not overly happy with the results.
        self.Gradient = False

        # Crop black/white borders before zooming
        # This doesn't work well with Fill..
        self.Crop = False

        # Don't just maxpect the image... blow it up so there's no bg colour
        # showing so this will crop parts.
        self.Fill = True

        # If the aspect ratio is "wrong" for the monitor, rotate it for a
        # better fit first. So portraits rotate for landscape monitors.
        # With per-monitor dirs you can sort your pictures based on aspect
        # ratio if you want.
        self.PreRotate = True
        
        self.createEmptyWallpaper()

    def createEmptyWallpaper(self):
        c = (0, 0, 0)

        if self.Blending:
            # Alpha blend the image with the current desktop colour
            # Or black if something goes wrong with getting the desktop colour
            try:
                dc = windll.user32.GetSysColor(1)
                c = ((dc & 0xFF  ),
                     (dc & 0xFF00) >> 8,
                     (dc & 0xFF0000) >> 16)
            except:
                pass

        self.bgColour = c

        bgImage = Image.new('RGB', self.wSize, c)
            
        if self.Gradient:
            r, g, b = c
            width, height = bgImage.size
            fh = float(height)

            if (r + g + b) / 3 < 64:
                r1, g1, b1 = (128, 128, 128)
            else:
                r1, g1, b1 = c
                r, g, b = (64, 64, 64)

            rd = r1 - r
            gd = g1 - g
            bd = b1 - b

            rs = float(rd) / fh
            gs = float(gd) / fh
            bs = float(bd) / fh

            draw = ImageDraw.Draw(bgImage)
            for h in range(0, height):
                draw.line((0, h, width, h),
                          fill = (int(r1), int(g1), int(b1)))
                r1 -= rs
                b1 -= bs
                g1 -= gs
                
        self.bgImage = bgImage

    def findMonitors(self):
        retval = []
        CBFUNC = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_ulong, ctypes.c_ulong, ctypes.POINTER(RECT), ctypes.c_double)
        def cb(hMonitor, hdcMonitor, lprcMonitor, dwData):
            r = lprcMonitor.contents
            data = [hMonitor]
            data.append(r.dump())
            retval.append(data)
            return 1
        cbfunc = CBFUNC(cb)
        temp = windll.user32.EnumDisplayMonitors(0, 0, cbfunc, 0)
        return retval

    def calcWallSize(self):
        # Also sets the relative offsets for building the wallpaper...
        
        ms = self.monitors

        primaryMonitor = [m for m in ms if m.isPrimary][0]

        leftMonitors = [m for m in ms if m.left < 0]
        rightMonitors = [m for m in ms if m.left >= primaryMonitor.right]
        topMonitors = [m for m in ms if m.top < 0]
        bottomMonitors = [m for m in ms if m.top >= primaryMonitor.bottom]

        leftMonitors.sort()
        rightMonitors.sort()
        topMonitors.sort()
        bottomMonitors.sort()

        hMonitors = [primaryMonitor,] + rightMonitors + leftMonitors
        vMonitors = [primaryMonitor,] + bottomMonitors + topMonitors

        width = max([m.right for m in ms])
        height = max([m.bottom for m in ms])

        extraWidth = -min([m.left for m in ms])
        extraHeight = -min([m.top for m in ms])

        width += extraWidth
        height += extraHeight

        hOff = width
        redo = []
        for m in leftMonitors:
            m.wLeft = width + m.left
            if m in bottomMonitors:
                continue
            m.right = width

        for m in topMonitors:
            m.wTop = height + m.top
            if m in rightMonitors:
                continue

            m.bottom = height

        return (width, height)    

    def getMonitors(self):
        retval = []
        for hMonitor, extents in self.findMonitors():
            # data = [hMonitor]
            mi = MONITORINFO()
            mi.cbSize = ctypes.sizeof(MONITORINFO)
            mi.rcMonitor = RECT()
            mi.rcWork = RECT()            
            res = windll.user32.GetMonitorInfoA(hMonitor, ctypes.byref(mi))
            data = Monitor(hMonitor, mi.rcMonitor.dump(), mi.rcWork.dump(), mi.dwFlags)
            retval.append(data)
        return retval
        
    def setMonitorExtents(self):
        self.monitors = self.getMonitors()
        self.wSize = self.calcWallSize()

    def getDefaultDirs(self):
        return [r'C:\Documents and Settings\All Users\Documents\My Pictures\Sample Pictures',]

    def setWallPaperFromBmp(self, pathToBmp):
        """ Given a path to a bmp, set it as the wallpaper """

        # Set it and make sure windows remembers the wallpaper we set.
        result = windll.user32.SystemParametersInfoA(
            SPI_SETDESKWALLPAPER, 0,
            pathToBmp,
            SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE)
        
        if not result:
            raise Exception("Unable to set wallpaper.")

    def autoCrop(self, im, bgcolor = (0, 0, 0)):
        if im.mode != "RGB":
            im = im.convert("RGB")

        im2 = ImageOps.autocontrast(im, 5)
        bg = Image.new("RGB", im.size, bgcolor)
        diff = ImageChops.difference(im2, bg)
        bbox = diff.getbbox()
        if bbox:
            return im.crop(bbox)
        return im # no contents

    def maxAspectWallPaper_fill(self, image, width, height):
        # Blow up the image making sure that the smallest image aspect
        # fills the monitor.
        
        rsFilter = Image.BICUBIC
        scale = 2.0

        imWidth, imHeight = image.size


        hScale = float(height) / float(imHeight)
        wScale = float(width) / float(imWidth)

        scale = max(hScale, wScale)
            
        if scale < 1:
            rsFilter = Image.ANTIALIAS

        newSize = (int(imWidth * scale), int(imHeight * scale))
        
        newImage = image.resize(newSize, rsFilter)

        if scale > 2:
            newImage = newImage.filter(ImageFilter.BLUR)

        imWidth, imHeight = newSize

        x = int((imWidth - width) / 2.0)
        y = int((imHeight - height) / 2.0)
        bbox = (x, 0, width + x, height + y)
        return newImage.crop(bbox)
    
    def maxAspectWallPaper(self, image, width, height):
        # Blow the image up as much as possible without exceeding the monitor
        # bounds.
        rsFilter = Image.BICUBIC
        scale = 2.0

        imWidth, imHeight = image.size

        hScale = float(height) / float(imHeight)
        wScale = float(width) / float(imWidth)

        if self.Fill:
            scale = max(hScale, wScale)
        else:
            scale = min(hScale, wScale)
            
        if scale < 1:
            rsFilter = Image.ANTIALIAS

        newSize = (int(imWidth * scale), int(imHeight * scale))
        newImage = image.resize(newSize, rsFilter)
        if self.Fill:
            imWidth, imHeight = newSize
            x = int((imWidth - width) / 2.0)
            y = int((imHeight - height) / 2.0)
            bbox = (x, 0, width + x, height + y)
            newImage = newImage.crop(bbox)
        return newImage

    def preRotateImage(self,image):
        # Rotate 90 degrees.
        im = image.rotate(-90, resample = True, expand = True)
        return im

    def createWallPaperFromFile(self, pathToImage, monitor):
        # Given a path to an image, convert it to bmp format and set it as
        # the wallpaper

        bmpImage = Image.open(pathToImage)

        if self.PreRotate:
            if bmpImage.size[0] < bmpImage.size[1]:
                bmpImage = self.preRotateImage(bmpImage)
        
        if self.Crop:
            bmpImage = self.autoCrop(bmpImage, (0,0,0))
            bmpImage = self.autoCrop(bmpImage, (255,255,255))
            
        bmpImage = self.maxAspectWallPaper(bmpImage, *monitor.size)

        bmpSize = bmpImage.size
        xOffset = int((monitor.size[0] - bmpImage.size[0]) / 2)
        yOffset = int((monitor.size[1] - bmpImage.size[1]) / 2)

        if bmpImage.size != monitor.size:
            img1 = Image.new("RGB", monitor.size, (0, 0, 0))
        img1.paste(bmpImage, (xOffset, yOffset))

        if self.Blending:
            img2 = Image.new("RGB", monitor.size, self.bgColour)
            return Image.blend(img2, img1, self.BlendRatio)
        return img1

    def setWallpaperStyleSingle(self):
        # 0x80000001 == HKEY_CURRENT_USER
        k = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER,"Control Panel\\Desktop",0,win32con.KEY_SET_VALUE)
        win32api.RegSetValueEx(k, "WallpaperStyle", 0, win32con.REG_SZ, "0")
        win32api.RegSetValueEx(k, "TileWallpaper", 0, win32con.REG_SZ, "0")

    def setWallpaperStyleMulti(self):
        # To set a multi-monitor wallpaper, we need to tile it...
        # 0x80000001 == HKEY_CURRENT_USER
        k = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER,"Control Panel\\Desktop",0,win32con.KEY_SET_VALUE)
        win32api.RegSetValueEx(k, "WallpaperStyle", 0, win32con.REG_SZ, "0")
        win32api.RegSetValueEx(k, "TileWallpaper", 0, win32con.REG_SZ, "1")

    def setWallpaperStyle(self):
        if len(self.monitors) > 1:
            self.setWallpaperStyleMulti()
        else:
            self.setWallpaperStyleSingle()

    def setWallpaper(self):
        self.setWallpaperStyle()

        # Save the new wallpaper in our current directory.
        newPath = os.getcwd()
        newPath = os.path.join(newPath, 'pywallpaper.bmp')
        self.bgImage.save(newPath, "BMP")
        self.setWallPaperFromBmp(newPath)

    def setWallpaperFromFile(self, pathToImage):
        for monitor in self.monitors:
            img = self.createWallPaperFromFile(filename, monitor)
            monitor.addWallpaper(self.bgImage, img)

        self.setWallpaper()

    def setWallPaperFromFileList(self, pathToDir, monitor):
        """ Given a directory choose an image from it and set it as a wallpaper """
        # Image directories often contain Thumbs.db or other non-image
        # files or directories, try a few times to set a wallpaper, and then just give up.

        tries = 0
        done = False
        filenames = []
        files = os.listdir(pathToDir)

        try:
            # Priorwalls.txt is used so that we don't repeat an image
            # until every other image in that directory has been seen
            # The file is rewritten when necessary.
            prevList = open('priorWalls.txt', 'rb')
            filenames = [l.strip() for l in prevList.readlines()]
            prevList.close()
        except:
            pass

        files = [os.path.join(pathToDir, f) for f in files if not f.endswith('.db')]
        availChoices = [f for f in files if not f in filenames and not f.endswith('.db')]

        if not availChoices:
            # This entire directory has been "done" remove them
            # from the previously seen wallpapers and rewrite
            # the cache file without any of these entries.
            filenames = [f for f in filenames if not f in files]
            availChoices = files
            p = open('priorWalls.txt', 'wb')
            for f in filenames:
                p.write("%s\n"%(f))
            p.close()

        files = availChoices

        while (not done) and tries < 3:
            # Thumbs.db and other stuff can live in the same Folder
            # So try three times to set a wallpaper before giving up.
            try:
                image = random.choice(files)
                filename = image
                img = self.createWallPaperFromFile(filename, monitor)
                monitor.addWallpaper(self.bgImage, img)
                prevList = open('priorWalls.txt', 'ab')
                prevList.write("%s\n"%(filename))
                done = True
            except:
                import traceback; traceback.print_exc()
                print >> sys.stderr, filename, "failed"
                tries += 1
        return done

    def getMonitorDirs(self, monIndex):
        section = 'monitor_%d'%(monIndex)
        # Check for [monitor_0]
        if self.config.has_section(section):
            # check for its own paths section
            if self.config.has_option(section, 'paths'):
                dirs = self.config.get(section, 'paths').split('\n')
        else:
            dirs = self.dirs

        return dirs

    def setWallPaperFromDirList(self):
        """ Given a list of directories choose a directory """
        for monNum, monitor in enumerate(self.monitors):
            imageDir = random.choice(self.getMonitorDirs(monNum))
            status = self.setWallPaperFromFileList(imageDir, monitor)

        self.setWallpaper()

    def getImageDirectories(self):
        # Set global image directories.
        dirs = []
        try:
            dirs = self.config.get('directories', 'paths').split('\n')
        except:
            pass

        if not dirs:
            dirs = self.getDefaultDirs()
        return dirs

    def setWallPaperFromConfigDirs(self):
        self.setWallPaperFromDirList()

    def getConfigFileOptions(self, options):
        configFile = 'pywallpaper.conf'

        if options.configFile:
            configFile = options.configFile

        dirs = options.directories

        self.config = SafeConfigParser()
        self.config.readfp(open(configFile))

        if self.config.has_section('global'):
            self.Blending = self.config.getboolean('global', 'Blending')
            self.BlendRatio = self.config.getfloat('global', 'BlendRatio')
            self.Crop = self.config.getboolean('global', 'Crop')
            self.Fill = self.config.getboolean('global', 'Fill')
            self.Gradient = self.config.getboolean('global', 'Gradient')
            self.PreRotate = self.config.getboolean('global', 'PreRotate')

    def getCommandLineOptions(self):
        parser = OptionParser()
        parser.add_option("-t", "--time", dest="change_time",
                          help = "Change wallpaper time in minutes (0 = change once and exit [default])",
                          default = 0, type = "int")
        parser.add_option("-i", "--image", dest="singleImage", default = None,
                          help = "Set wallpaper to this image and exit (overrides -d)")

        parser.add_option("-d", "--directory", dest="directories", default = [], 
                          action="append", type="string",
                          help = "Add an image directory")

        parser.add_option("-c", "--config", dest="configFile", default = None,
                          help = "path to alternate config file (default <working dir>/pywallpaper.conf)")

        parser.add_option("-w", "--workingdir", dest="cwd", default=".",
                          help = "Working Directory (default .)")

        (options, args) = parser.parse_args()
        return (options, args)

    def go(self):
        options, args = self.getCommandLineOptions()
        self.getConfigFileOptions(options)

        self.dirs = self.getImageDirectories()
        
        if options.cwd and options.cwd != '.':
            os.cwd(cwd)
        if options.singleImage:
            self.setWallPaper(options.singleImage)
            
        elif not options.change_time:
            self.setWallPaperFromConfigDirs()
        else:
            sleepTime = options.change_time * 60.0
            while True:
                self.setWallPaperFromDirList()
                time.sleep(sleepTime)

if __name__ == '__main__':
    d = Desktop()
    d.go()

Sunday, July 18, 2010

Belkin support

Every problem  I submit to Belkin about their wireless routers or WAPs results in the following response. Every single problem is fixed by "reboot the machine."

None of the problem reports submitted had anything to do with ADSL connections.

I don't think I'll ever be buying another Belkin wireless product.

Let us assist you with this issue.                                                                                                  
                                                                                                                                    
In this case, we would suggest you to reset the router to factory settings and re-configure it once and check.                      
                                                                                                                                    
Please follow the steps given below:                                                                                                
- Connect the computer to the "LAN" port on the router and connect the modem to the Internet/"WAN" port, using Ethernet cables.     
- Take a paper clip, insert the paper clip in the reset hole of the router and hold it for 15 seconds.                              
- The power light will flash and then come back "ON" solid, indicating that the router is being restored to factory defaults.       
- The corresponding lights on the front of the router should be lit up.                                                             
- Log on to the router web interface by typing in http://192.168.2.1, in the address bar of your browser.                           
- By default, the password is blank.                                                                                                
- Click on "Connection Type" in the left hand column under "Internet WAN" heading.                                                  
                                                                                                                                    
If the connection type is Dynamic (cable):                                                                                          
                                                                                                                                    
- Choose "Dynamic" and then click on "Next".                                                                                        
- Type in your  Host Name , if your Internet Service Provider has provided it. Else, leave it blank.                                
- Click on "Change WAN MAC Address".                                                                                                
- Click on the button "Clone".                                                                                                      
- Click on "Apply Changes".                                                                                                         
                                                                                                                                    
If the connection type is PPPOE (DSL):                                                                                              
                                                                                                                                    
- Choose "PPPOE" and click on "Next".                                                                                               
- Enter the user name and password given by your Internet Service Provider.                                                         
- Save the settings.                                                                                                                
- Click on the "Home" link at the top of the screen.                                                                                
                                                                                                                                    
If the connection is Static:                                                                                                        
                                                                                                                                    
- Choose "Static" and click on "Next".                                                                                              
- Enter the "IP Address", "Subnet Mask" and "ISP Gateway Address". Click on "Apply Changes".                                        
- It would ask for the "Primary DNS" and "Secondary DNS" information. Enter the required details and click on "Apply Changes".      
                                                                                                                                    
Note: All the required information would be provided by your ISP.                                                                   
                                                                                                                                    
Internet Status should show "Connected" on the top right hand corner of the web page. 
                                              

Wednesday, April 14, 2010

GPH Wiz and Elite

I recently dusted off my misappropriated copy of the newkind source I snarfed while it was available (10 years ago, thank you Mr. Pinder), and ported it to use SDL and then to run on the Wiz (the button mappings are currently a little awkward, but, usable).

I fixed up some long standing bugs in the code (suns are rendered, it doesn't crash randomly due to -ve array indexes), so it gives me something to do when I'm forced to wait (for anything, a compile to finish, for someone to finish shopping d8)

It's running very nicely, it's very playable, I've replaced the scanner with the one from the Archimedes version (I also added the bumper sticker, I need to acquire some decent dice images to add the fluffy dice though). The code let you load one via file, but, that's not quite flexible enough to deal with really changing the scanners. The Archimedes one is about 30px shorter than the original one (a lot when you have 320x240 screen size!), but looks sweet.

I've coverted from PCX-fonts to true-type fonts and made some of the decals transparent. I've removed all the (not-really working) code that tried to deal with different screen resolutions, and have streamlined it to deal with 320x240 (for now). I'm not sold on the "big" font I'm using right now.

I'm now in the process of restructuring the code to make it a little easier to work on, the original code was controlled with globals and it's kind of ugly to try to map js buttons or mouse buttons to mode-specific key presses.


My ToDo List is (in no particular order):
  • Find some .ogg or .mp3 music to replace the 2 MIDIs, the wiz doesn't seem to have timidity or anything that SDL can use to play the midis.
  • Restructure Code to allow nicer event handling.
  • Add an Icon Bar to allow "Screen Changing" with the stylus instead of buttons.
  • Add the extra Archimedes ships.
  • Add convoy, formation, and independent battle logic.
  • Add "trimble" mission.
  • Add fluffy dice (as an option perhaps only at a certain ranking).
  • Add IFS equipment.
  • Convert to OpenGL instead of original 3D.
  • Re-add the screen resolution code (in a better fashion) so I can transfer my saved games back/forth and play at a nice resolution when I want to.

Sunday, April 04, 2010

Windows 7 and UTC: Caveat Emptor

IF you are running your BIOS Clock at UTC,
AND you are running Windows 7 in your local timezone
AND your local timezone is WEST of UTC,
AND ( Daylight Savings (Ends OR Finishes)
OR the year changes )
THEN your machine will lock up
AND will not boot
AND system restore will not work
AND recovery console will not work
UNTIL midnight UTC is reached (because internally some value goes negative (which is very largely positive for unsigned values)).

It locks so hard, even trying to boot to safe mode, that the caps lock light won't even come on.

If you can boot up in a timezone EAST of UTC it comes up OK.