My Feed Notifier application has out-grown my blog. Today I registered feed-notifier.com to host the app now that version 2.0 is nearing completion. Check it out!
My Feed Notifier application has out-grown my blog. Today I registered feed-notifier.com to host the app now that version 2.0 is nearing completion. Check it out!
I’ve cleaned up some code, changed the tab appearance of the options dialog, and have added controls for configuring the pop-ups. Here’s how we’re looking now…

Feed Notifier 2.0
I’ve started the settings dialog for Feed Notifier 2.0. It will have three tabs:
So far I’ve got the Feeds tab implemented. I wrote the code in a hurry, so it needs some cleaning up. But here it is…

Feed Notifier 2.0 - Feed Configuration
Work on version 2.0 of the Feed Notifier is coming along smoothly. Now I’d like to show off the new dialogs for adding feeds to the notifier. It’s now been broken up into a 2-step process.

Add Feed: Step 1

Add Feed: Step 2
Things worth noting:
My Feed Notifier application has been a relative success. It’s the only app I’ve created that continues to get hundreds of downloads every month, just by people finding it on my blog from search engines. I’ve also received dozens of feature requests and have some ideas of my own. So, I’ve been wanting to create version 2 of this simple but useful application and I’ve finally started just that. For starters, the system tray pop-ups are getting a revamped look and feel, including user-selectable themes. Here’s a sneak peek at my work in progress…

Feed Notifier 2.0 - Sneak Peek
Some things to note about the new pop-up design:
I’m writing most of the code from scratch, so it may take some time before this release is available. I’ll keep you posted.
Dumbest UI decision ever.
For those who haven’t noticed, the Google homepage (not iGoogle and not the Firefox start page, etc. but the real actual homepage at google.com) does a fade-in effect, showing only the logo, search bar and search buttons until the user moves the mouse, revealing everything else that used to always be visible upon page load.
Supposedly they did this to create less clutter and be more minimalistic, since most people visiting the page are just going to type in their search and hit enter. Supposedly they also did tons of internal testing and randomized public testing. Well, I think it’s retarded and annoying and a user experience failure.
The bottom line is that this change adds no benefit and is more likely to degrade the user experience.
Reminds me of this Onion video, except this time it’s Google and not Apple:
Apple Introduces Revolutionary New Laptop With No Keyboard
See also:
http://googleblog.blogspot.com/2009/12/now-you-see-it-now-you-dont.html
My co-worker showed me a neat little app that showed snowflakes falling on the Windows desktop. The snow would pile up on windows, and the snow didn’t draw on top of other windows, only the desktop wallpaper.
I wondered how I could accomplish this using wxPython. wx has a ScreenDC, but this draws on the entire screen, over windows and all. I wanted to draw under windows but over the desktop.
The solution I came up with isn’t cross platform, but it works. The idea is to use ctypes to invoke some win32 API’s to find the appropriate window to draw on. The next important thing is knowing about the function wxWindow::AssociateHandle. You can associate a window with any system-wide HWND and the wxWindow will start acting upon that window instead.
On windows, the control we want to draw on can be found with Spy++ and it’s hierarchy is:
SysListView32 is the control that shows all the desktop icons. To get a handle to this control, we use the win32 functions GetDesktopWindow and FindWindowEx.
The following function finds a window from the specified name hierarchy.
def find_window(parent, names): if not names: return parent name = unicode(names[0]) child = 0 while True: child = ctypes.windll.user32.FindWindowExW(parent, child, name, 0) if not child: return 0 result = find_window(child, names[1:]) if result: return result
We use it like this:
desktop = ctypes.windll.user32.GetDesktopWindow() handle = 0 handle = handle or find_window(desktop, ['Progman', 'SHELLDLL_DefView', 'SysListView32']) handle = handle or find_window(desktop, ['WorkerW', 'SHELLDLL_DefView', 'SysListView32'])
On Windows 7 (and maybe Vista too), Progman is replaced by WorkerW, so we have to try both hierarchies and use the first match we find.
Then we just create a dummy window and associate it with the handle we found with find_window.
self.AssociateHandle(handle)
After that, a WindowDC can be used to draw on the desktop wallpaper. The usual flicker-reducing techniques can’t really be used as we aren’t getting paint events. Instead, what I did was invalidate small regions of the desktop with RefreshRect, followed by Update and then finally drawing the next frame. Like this:
dc = wx.WindowDC(self) for flake in self.flakes: self.RefreshRect(flake.rect) self.Update() flake.update() flake.draw(dc) dc.Destroy()
I called my snowflake implementation wxSnow, and you can get it here:
http://www.michaelfogleman.com/wxsnow-snow-falling-on-your-windows-desktop/
Testing embedding videos on my blog. This was taken with my new camera, which is awesome! Be sure to watch the HD version!
Jayda & Pretzel from Michael Fogleman on Vimeo.
I wrote a Python module for generating Tiny URL- and bit.ly-like URLs. I see people in the programming community asking how to do this all the time. Some of the suggestions on how to implement it are dumb. Here’s my approach. I posted it as a recipe here: http://code.activestate.com/recipes/576918/
A bit-shuffling approach is used to avoid generating consecutive, predictable URLs. However, the algorithm is deterministic and will guarantee that no collisions will occur.
The URL alphabet is fully customizable and may contain any number of characters. By default, digits, upper- and lower-case letters are used, with some removed to avoid confusion between characters like o, O and 0. The default alphabet is shuffled and has a prime number of characters to further improve the results of the algorithm.
The block size specifies how many bits will be shuffled. The lower BLOCK_SIZE bits are reversed. Any bits higher than BLOCK_SIZE will remain as is. BLOCK_SIZE of 0 will leave all bits unaffected and the algorithm will simply be converting your integer to a different base.
The intended use is that incrementing, consecutive integers will be used as keys to generate the short URLs. For example, when creating a new URL, the unique integer ID assigned by a database could be used to generate the URL by using this module. Or a simple counter may be used. As long as the same integer is not used twice, the same short URL will not be generated twice.
The module supports both encoding and decoding of URLs. The min_length parameter allows you to pad the URL if you want it to be a specific length.
Sample Usage: >>> import short_url >>> url = short_url.encode_url(12) >>> print url LhKA >>> key = short_url.decode_url(url) >>> print key 12
Use the functions in the top-level of the module to use the default encoder. Otherwise, you may create your own UrlEncoder object and use its encode_url and decode_url methods.
Here’s the code!
DEFAULT_ALPHABET = 'JedR8LNFY2j6MrhkBSADUyfP5amuH9xQCX4VqbgpsGtnW7vc3TwKE' DEFAULT_BLOCK_SIZE = 22 class UrlEncoder(object): def __init__(self, alphabet=DEFAULT_ALPHABET, block_size=DEFAULT_BLOCK_SIZE): self.alphabet = alphabet self.block_size = block_size self.mask = (1 << block_size) - 1 self.mapping = range(block_size) self.mapping.reverse() def encode_url(self, n, min_length=0): return self.enbase(self.encode(n), min_length) def decode_url(self, n): return self.decode(self.debase(n)) def encode(self, n): return (n & ~self.mask) | self._encode(n & self.mask) def _encode(self, n): result = 0 for i, b in enumerate(self.mapping): if n & (1 << i): result |= (1 << b) return result def decode(self, n): return (n & ~self.mask) | self._decode(n & self.mask) def _decode(self, n): result = 0 for i, b in enumerate(self.mapping): if n & (1 << b): result |= (1 << i) return result def enbase(self, x, min_length=0): result = self._enbase(x) padding = self.alphabet[0] * (min_length - len(result)) return '%s%s' % (padding, result) def _enbase(self, x): n = len(self.alphabet) if x < n: return self.alphabet[x] return enbase(x/n) + self.alphabet[x%n] def debase(self, x): n = len(self.alphabet) result = 0 for i, c in enumerate(reversed(x)): result += self.alphabet.index(c) * (n**i) return result DEFAULT_ENCODER = UrlEncoder() def encode(n): return DEFAULT_ENCODER.encode(n) def decode(n): return DEFAULT_ENCODER.decode(n) def enbase(n, min_length=0): return DEFAULT_ENCODER.enbase(n, min_length) def debase(n): return DEFAULT_ENCODER.debase(n) def encode_url(n, min_length=0): return DEFAULT_ENCODER.encode_url(n, min_length) def decode_url(n): return DEFAULT_ENCODER.decode_url(n) if __name__ == '__main__': for a in range(0, 200000, 37): b = encode(a) c = enbase(b) d = debase(c) e = decode(d) assert a == e assert b == d c = (' ' * (7 - len(c))) + c print '%6d %12d %s %12d %6d' % (a, b, c, d, e)
I’ve updated the Feed Notifier application with one new feature and one bug fix. A “Dismiss All” feature allows you to clear the popup queue so that the popups will stop until more new ones come in. I also finally tracked down the cause of a bug that caused the app to crash on shutdown/logout. Yay. The new installer has been uploaded.