Inspirated

 
 

May 20, 2009

The wonders of modern marketing — get paid $100 for telling time

Filed under: Blog — krkhan @ 4:57 am

A couple of days back, I had to buy a laptop for my dad. Now, deciding one for him was infinitely easier than doing so for myself since the obsession with smaller screens wasn’t playing any role here. In fact, what he ended up liking was a 15.6″ behemoth which, upon comparison, could easily swallow my 12.1″ and 8″ notebooks and still have space left for my cellphone.

The purchase was made at eXtra. Before my dad finalized it though, the salesman asked me if I would like to have the laptop setup with “original Windows Vista, original Anti-Virus software with all the updates, original office and configured with all the drivers for SR 365 only”.

This immediately raised a few points in my head:

  • Dad happens to be as much of a computer guy as I am an electronics’ (although I have some extra credentials, such as scoring a hat-trick of flunking performances at the university in a single course related to electronics). I really didn’t want him to be bothered with all the “Windows Genuine Advantage” pile of crap later on.
  • I would be saved the trouble of downloading, installing, cracking, patching and updating a “clean” Windows installation — regardless of the fact that I find it quite amusing whenever someone refers to a Windows installation as “clean”.
  • Around $100 would be a good bargain considering retail prices of all the softwares mentioned.

Then, a few counter-points:

  • Until that moment, I had been totally oblivious to Compaq laptops coming without having any pre-installed operating system. In fact, that’s one of the reasons why I myself had settled for an OS-less Fujitsu-Siemens notebook few years ago, which gave me very handsome physical as well as technical specs for the cash I spent. Back then, I was also pleasantly surprised when my Linux From Scratch system got migrated to the new machine using only bash, netcat and tar; making it usable on the very day of notebook’s acquisition.
  • I harbor a particular distrust for salesmen who speak too fast.

The counter-points outweighed the originals, and I decided to go with an empty laptop. Got home, downloaded and burned a cracked copy of XP SP3, only to find out that the laptop wasn’t empty at all. It already had a working Vista & Co. on it which only required setting up the initial time and localization settings. Immediately, I recalled other unsuspecting customers at the counter who did pay the extra charges for getting their laptops “ready”.

Fortunately for my dad, my time-telling prowess wasn’t as valuable as the salesman’s so I didn’t ask him $100 for it. Unfortunately, he’ll now have to cope with Vista.

“Windows: Microsoft’s tax on computing neophytes.”

Tags: , , , , , , ,

May 17, 2009

Inbox Stats v1.0 — Because graphs speak louder than numbers

Filed under: Blog — krkhan @ 4:00 am

Inbox Stats v1.0

Changelog:

  • As can be seen from the screenshot above, graphs can be turned on through the options menu. Implementing them resulted in two useful modules:
    • scrolledcanvas: Provides a derived Canvas class which has built-in support for scrolling oversizes images.
    • roundedrectangle: Provides functions for drawing rectangles with rounded corners on a Canvas or Image. Optionally, text can be given which will be prettily centered (and truncated upon requirement) in the drawn shapes.
  • More minor code enhancements and bugfixes.

You can find both the modules and the application itself here. All code is released under the PSF license so feel free to use it any way you want. Oh, and if you still haven’t figured out why anyone would be interested in the SMS stats in the first place, here’s a little quote for you:

“Statistics are like a bikini. What they reveal is suggestive, but what they conceal is vital.”

Tags: , , , , , , , , , , , ,

May 14, 2009

User-defined iterators in Python

Filed under: Blog — krkhan @ 5:19 am

Iterable classes are one of the features which make Python code more readable. Simply put, they let you iterate over a container a la:

1
2
for s in ("Spam", "Eggs"):
	print s

Here, s iterates over the tuple printing the words one by one.:

Spam
Eggs

Now comes the interesting part: How do I make my own classes iterable? The official Python Tutorial gives a working example for how to do it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Reverse:
	"Iterator for looping over a sequence backwards"
	def __init__(self, data):
		self.data = data
		self.index = len(data)
 
	def __iter__(self):
		return self
 
	def next(self):
		if self.index == 0:
			raise StopIteration
		self.index = self.index - 1
		return self.data[self.index]
 
value = Reverse('spam')
for char in value:
		print char

Output:

m
a
p
s

The example appeared perfectly fine to a beginner like me. However, since I’m just kinda twisted in the head, I added a new line in the for loop:

16
17
18
19
value = Reverse('spam')
for char in value:
	if char in value:
		print char

Which resulted in the (quite unexpected) output:

 

That’s it. Nothing. Even though the code should make perfect sense and does work in case of built-in types. For example:

1
2
3
4
tup = ("Spam", "Eggs")
for s in tup:
	if s in tup: 
		print s

So daisy-ly gives:

Spam
Eggs

The culprit in case of tutorial’s example for user-defined iterators? After toying around the code sample a little, here’s what I pinned down:

  • On the nested lines where another iterator is required, the Reverse class is supposed to return instance of an iterator which would define the next() method for returning successive values.
  • Since the Reverse class returns only itself in this scenario, the self.index variable is shared among iterators of the Reverse('spam').
  • As a result, Reverse.next() raises the StopIteration in the nested condition.

Once I understood the underlying problem, some further head-scratching and a can of malted drink resulted in the solutions:

  • Return a copy for the iterative functions instead of the instance itself:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    import copy
     
    class Reverse:
    	"Iterator for looping over a sequence backwards"
    	def __init__(self, data):
    		self.data = data
    		self.index = len(data)
     
    	def __iter__(self):
    		return copy.copy(self)
     
    	def next(self):
    		if self.index == 0:
    			raise StopIteration
    		self.index = self.index - 1
    		return self.data[self.index]
     
    value = Reverse('spam')
    for char in value:
    	if char in value:
    		print char

    Pro: Less strain on the programmer, only a couple of extra lines of code are needed.
    Con: copying the instance can be expensive in case of larger containers.

  • Use another class:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    class Reverse:
    	"Iterator for looping over a sequence backwards"
    	def __init__(self, data):
    		self.data = data
     
    	def __iter__(self):
    		return ReverseIter(self)
     
    class ReverseIter:
    	def __init__(self, inst):
    		self.inst = inst
    		self.index = len(self.inst.data)
     
    	def next(self):
    		if self.index == 0:
    			raise StopIteration
    		self.index = self.index - 1
    		return self.inst.data[self.index]
     
    value = Reverse('spam')
    for char in value:
    	if char in value:
    		print char

    Pro: Since the whole container is not copied, only the index is unique among iterators — less burden on the memory.
    Con: Not everyone likes defining new classes.

Both solutions worked equally well and resulted in the same output (the expected one this time):

m
a
p
s

The choice of either solution is solely dependent on the programmer’s preference. As a side note, after equating Python programming with carnal activities in few of my previous posts, I’m gonna take it to the next step and finally tag this post accordingly.

Tags: , , , , , , , , , ,

May 12, 2009

SMS Inbox statistics for Series 60 mobile phones v0.2

Filed under: Blog — krkhan @ 7:04 pm

Update: New version

Improvements in the new version:

  • Previous version hung up while calculating the statistics. The new version dispatches a thread for the dirty work and keeps the user interface responsive with a “Processing” notification.
  • Contact stats are sorted in descending order by the number of messages per each contact.
  • Code improvements for making it more “Pythonic”.

inboxstats.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# -*- coding: utf-8 -*-
"""Script for printing trivial statistics about inbox, such as:
	Number of texts
	Number of unique contacts who sent the texts
	Number of texts sent by respective contacts
"""
 
__author__ = "Kamran Riaz Khan"
__email__ = "krkhan@inspirated.com"
__version__ = "0.2"
__copyright__ = "Copyright (c) 2009 Kamran Riaz Khan"
__license__ = "Python"
__status__ = "Production"
 
import appuifw, e32, inbox, thread
 
def exit_key_handler():
	"Release app_lock."
	app_lock.signal()
 
def parse_inbox_stats(stats):
	"""Parse the inbox statistics,
	Updates the stats dictionary with:
		sms-count : Number of texts
		sms-contacts: List of tuples with following pairs:
			Name of contact, Number of corresponding
			(ordered according to decreasing number of texts)"""
	curr_inbox = inbox.Inbox()
	messages = curr_inbox.sms_messages()
	contacts = {}
 
	for i in messages:
		address = curr_inbox.address(i)
		if contacts.has_key(address):
			contacts[address] = contacts[address] + 1
		else:
			contacts[address] = 1
 
	contacts = contacts.items()
	contacts.sort(lambda x, y: cmp(x[1], y[1]))
	contacts.reverse()
 
	stats["sms-count"] = len(messages)
	stats["sms-contacts"] = contacts
 
def print_inbox_stats(content, stats):
	"""Print inbox stats in the content Text field,
	Remembers the cursor position of Text before the call
	and points at it again after updating the content."""
	pos = content.get_pos()
 
	statsmap = [
		(u"SMS Count", unicode(stats["sms-count"])),
		(u"Unique Contacts", unicode(len(stats["sms-contacts"]))),
		(u"", u"")
		]
 
	statsmap += [(k, unicode(v)) for k, v in stats["sms-contacts"]]
 
	for i in statsmap:
		content.style = appuifw.STYLE_BOLD
		content.add(i[0] + (i[0] and u": " or u""))
		content.style = 0
		content.add(i[1] + u"n")
 
	content.set_pos(pos)
 
if __name__ == "__main__":
	content = appuifw.Text()
	appuifw.app.title = u'Inbox Stats'
	appuifw.app.body = content
	appuifw.app.exit_key_handler = exit_key_handler
 
	stats = {}
	t = thread.start_new_thread(parse_inbox_stats, (stats,))
 
	content.style = appuifw.STYLE_ITALIC
	content.add(u"Processing text messages...n")
	thread.ao_waittid(t)
	content.add(u"Done!nn")
	content.style = 0
 
	print_inbox_stats(content, stats)
 
	app_lock = e32.Ao_lock()
	app_lock.wait()

Inbox Stats v0.2 Screenshot

Tags: , , , , , , , , , , ,

May 10, 2009

SMS Inbox statistics for Series 60 mobile phones

Filed under: Blog — krkhan @ 8:03 pm

Update: New version

Self-indulgence is what I do best. It usually results in me trying to figure out random statistics about my personal life; e.g., graphs about which hours of day I’m mostly awake on and pie-charts about my bathroom habits. Such stuff doesn’t only make me feel more important than I actually am, but also polishes my fundamental math skills which were lost while trying to calculate average number of viruses a Windows user is hit by on an yearly basis.

Texting is what I do second best. Combine the two of my most productive practices and the need emerges of having a way to produce useless statistics about my cell phone’s inbox. This is where PyS60 comes to the rescue. In my previous post I praised Python’s s** appeal. Here’s the demonstration:

  • Total time spent with Python: Less than a week
  • Total time spent with PyS60: Less than a minute
  • Total time spent with Symbian development: Less than never

And still, even a total n00b like me could easily accomplish what he wanted to, using only the library reference manual and 70 lines of understandable code:

inboxstats.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
"""Script for printing trivial statistics about inbox, such as:
	Number of texts
	Number of unique contacts who sent the texts
	Number of texts sent by respective contacts
"""
 
__author__ = "Kamran Riaz Khan <krkhan@inspirated.com>"
__version__ = "$Revision: 0.1 $"
__date__ = "$Date: 2009/05/10 15:30:00 $"
__copyright__ = "Copyright (c) 2009 Kamran Riaz Khan"
__license__ = "Python"
 
import appuifw
import e32
import inbox
 
def exit_key_handler():
	"Release app_lock."
	app_lock.signal()
 
def inbox_stats():
	"""Parse the inbox statistics,
	Returns the dictionary:
		sms-count : Number of texts
		sms-contacts: Dictionary with the pairs:
			contact-name : Number of texts from contact"""
	cur_inbox = inbox.Inbox()
	messages = cur_inbox.sms_messages()
	contacts = {}
 
	for i in messages:
		address = cur_inbox.address(i)
		if contacts.has_key(address):
			contacts[address] = contacts[address] + 1
		else:
			contacts[address] = 1
 
	return {
		"sms-count" :  len(messages),
		"sms-contacts" :  contacts
		}
 
if __name__ == "__main__":
	content = appuifw.Text()
	appuifw.app.title = u'Inbox Stats'
	appuifw.app.body = content
	appuifw.app.exit_key_handler = exit_key_handler
 
	stats = inbox_stats()
	statsmap = (
		(u"SMS Count", unicode(stats["sms-count"])),
		(u"Unique Contacts", unicode(len(stats["sms-contacts"]))),
		)
 
	for i in statsmap:
		content.style = appuifw.STYLE_BOLD
		content.add(i[0] + u": ")
		content.style = 0
		content.add(i[1] + u"n")
 
	content.add(u"n")
	for k, v in stats["sms-contacts"].iteritems():
		content.style = appuifw.STYLE_BOLD
		content.add(k + u": ")
		content.style = 0
		content.add(unicode(v) + u"n")
 
	app_lock = e32.Ao_lock()
	app_lock.wait()

Which gives me:

Inbox Stats Screenshot

Tags: , , , , , , , , , , ,

May 9, 2009

Python for Series 60: Reinvent the ophidian addiction on mobile phones

Filed under: Blog — krkhan @ 9:31 pm

Remember the good old days when playing Snakes on mobile used to be about the most productive thing you could do in a classroom? Well, those days are back, but this time taking guise of another fun reptilian phenomenon: Python for Series 60. If you need to develop/prototype applications on Series 60 devices while having some real fun, you might find PyS60 to be the best thing Nokia did since 1100.

In past, I have tried demystifying the beast known as Symbian development. Truth be told, I really ended up wishing that I had never attempted to do so in the first place. The whole development process was:

  • Extremely bloated: You need about a supercomputer to crunch out one innocent little SIS file without waiting for eons.
  • Error prone: Put the SDKs in a non-standard path and you’re foobar-ed.
  • Intimidatingly cryptic: For a beginner (and by beginner I mean beginner to Symbian, C++ experience apparently proves to be of no help over here), reading Symbian C++ is more or less like reading Perl. Especially since the humor that has developed over the decades resembling Perl code to line noise doesn’t lose any of its appeal here either.

For example, to create a simple notification which would read “Spam and eggs”, I would need to spend about 8 hours downloading, configuring, compiling, comprehending, troubleshooting the development tools. Further 4 for trying to understand how to accomplish something so simple in Symbian code. Granted, such painful development procedures might be required in some scenarios (e.g., where speed is a factor or where masochistic programmers prevail); in PyS60, producing the notification was as simple as:

Python for S60 on Nokia N72

import appuifw
appuifw.note(u"Spam and eggs", "info")

A mammoth two lines of code which I can easily understand without even referring to a book — I feel so cheap.

Tags: , , , , , ,

May 6, 2009

Breaking the ISP shackles on Huawei SmartAX MT 882

Filed under: Blog — krkhan @ 10:56 am

What does an ISP do when it needs to sell a customized router? Well, if they’re smart, they go for a Chinese product; re-brand it as their own, slap stupid restrictions on it and then shove the whole thing down the customers’ throats.

Last year, when I came to Saudi Arabia on vacation, I got ADSL installed on my phone-line. As mentioned above, a Huawei SmartAX MT 882 was provided by the ISP. Interestingly, it came not only with a re-branded appearance, but also with a customized firmware which purged all Huawei logos and references from the administration interface. As a side note, switching from a Linksys WAG200G (which I had back in Pakistan) to the Huawei thing was more or less like transitioning from GIMP/Photoshop to MS Paint. For example, even though I had UPnP enabled on the goddamned Chinese weapon, it never worked. Leaving me no alternative but to forward the ports manually.

Back to the topic, the device worked halfway decently. That is, until I came back during these vacations and bought the ADSL service from a different ISP. As soon as I popped up the configuration interface to type in the ADSL credentials, I was hit with this:

Huawei SmartAX MT882 Configuration Interface

See any issues? The username is already tied to the older ISP. My new username is something like “[a-number-I-can't-remember]@1024.nesma.net.sa“. The configuration interface only allows me to type in the [number-I-can't-remember] part, effectively allowing usernames only of the format: “[a-number-I-can't-remember]@1024.afaqe2e.com“. Because of the old ISP’s stupid attempt at monopolizing sales, I apparently needed to buy another router to work with the new username.

Hell, no. If I had actually went ahead and bought another router for this reason alone, I might’ve as well stopped calling myself a geek. Looking for a fix, the first thought that naturally occurred to me was to try and flash the firmware. Again, firmware flashing for such crippled devices isn’t any less of a b**** either. Curiously, I opened up the source of the interface webpage. Apart from a total mess of tag-soup the likes of which I had only ever seen in FrontPage websites, I spotted this:

<input type="hidden" size="30" maxlength="63" name="pppuser" value="51252403762@1024.afaqe2e.com">
<input type="text" name="pppuser_prefix" size="20" maxlength="35" value="51252403762">
@<input type="text" name="rate" size="5" maxlength="15" value="1024">.afaqe2e.com

Er.. a hidden input field that basically contains the whole username. What for? I had and still have no idea. Nevertheless, it gave me a clue that the "afaqe2e.com" part is not hard-coded in the customized firmware. That is, if I could only manage to somehow input the new username unmodified in the router, it should still work.

Bling.

  • Backup the router configuration.
  • Open it in a text editor.
  • Search for the username.
  • Change it.
  • Save the file and “restore” it through the administrative interface.
  • Restart the device, and stick a middle finger to the monopolizing ISP’s.
  • Pat yourself on the back for being the William Wallace of home internet gateways.
Tags: , , , , , , , , , , , , ,

May 3, 2009

“All methods in Python are effectively virtual”

Filed under: Blog — krkhan @ 8:07 pm

Dive Into Python really is one of the best programming books I have ever laid my hands on. Short, concise and to-the-point. The somewhat unorthodox approach of presenting an alien-looking program at the start of each chapter and then gradually building towards making it comprehensible is extraordinarily captivating. With that said, here’s an excerpt from the chapter introducing Python’s object orientation framework:

Guido, the original author of Python, explains method overriding this way: “Derived classes may override methods of their base classes. Because methods have no special privileges when calling other methods of the same object, a method of a base class that calls another method defined in the same base class, may in fact end up calling a method of a derived class that overrides it. (For C++ programmers: all methods in Python are effectively virtual.)” If that doesn’t make sense to you (it confuses the hell out of me), feel free to ignore it. I just thought I’d pass it along.

If you were able to comprehend the full meaning of that paragraph in a single go, you’re probably (a) Guido van Rossum himself (b) Don Knuth (c) Pinnochio.

Neither of which happens to be my identity, so it took me a few dozen re-reads to grasp the idea. It brought back memories of an interesting question that I used to ask students while I was working as a teacher’s assistant for the C++ course: “What is a virtual function?” The answer always involved pointers and polymorphism; completely ignoring any impact virtual functions would be having on inheritance in referential/non-pointer scenarios. (Considering that most of the C++ books never attempt to portray the difference either, I didn’t blame the students much.) Confused again? Here’s some more food for thought: Python does not even have pointers, so what do these perpetually virtual functions really entail in its universe? Let’s make everything peachy with a nice example.

Consider a Base class in C++ which defines three functions:

  • hello()
  • hello_non_virtual()
  • hello_virtual()

The first function, i.e., hello() calls the latter two (hello_non_virtual() and hello_virtual()). Now, we inherit a Derived class from the Base, and override the functions:

  • hello_non_virtual()
  • hello_virtual()

Note that the hello() function is not defined in the Derived class. Now, what happens when someone calls Derived::hello()? The answer:

Mechanism of virtual function invocation

Since Derived::hello() does not exist, Base::hello() is called instead. Which, in turn, calls hello_non_virtual() and hello_virtual(). For the non-virtual function call, the Base::hello_non_virtual() function is executed. For the virtual function call, the overridden Derived::hello_virtual() is called instead.

Here’s the test code for C++:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
 
using namespace std;
 
class Base {
public:
	void hello()
	{
		cout&lt;&lt;"Hello called from Base"&lt;<endl; hello_non_virtual();="" hello_virtual();="" }="" void="" hello_non_virtual()="" {="" cout<<"hello="" called="" from="" non-virtual="" base="" function"<<endl;="" virtual="" hello_virtual()="" };="" class="" derived="" :="" public="" public:="" int="" main()="" d;="" d.hello();="" return="" 0;="" <="" pre="">
 
And its output:
 
 
<blockquote>
Hello called from Base
Hello called from non-virtual Base function
Hello called from virtual Derived function
</blockquote>
 
 
 
Similarly, a Python program to illustrate the statement <em>"all methods in Python are effectively virtual"</em>:
 
 
<pre lang="python" line="1">class Base:
	def hello(self):
		print "Hello called from Base"
 
		self.hello_virtual()
 
	def hello_virtual(self):
		print "Hello called from virtual Base function"
 
class Derived(Base):
	def hello_virtual(self):
		print "Hello called from virtual Derived function"
 
d = Derived()
d.hello()

Output:

Hello called from Base
Hello called from virtual Derived function

I hope this clears up the always-virtual concept for other Python newcomers as well. As far as my experience with the language itself is concerned, Python is s**; simple as that. Mere two days after picking up my first Python book for reading, I have fallen in love with its elegance, simplicity and overall highly addictive nature.

Tags: , , , , , , , , , , , , ,

May 1, 2009

The mindbogglingly low shutdown time of Windows 7

Filed under: Blog — krkhan @ 10:10 am

This is it. Windows 7 has hit the nail right on its head. While going through BBC’s utterly crap article hyping the new Release Candidate, I spotted this absolute gold of a quote:

Many beta testers of Windows 7 have reported that it is faster than Vista, especially in terms of start-up and shutdown sequence of the computer.

Mr Curran said that the Microsoft Windows team had been poring over every aspect of the operating system to make improvements.

“We were able to shave 400 milliseconds off the shutdown time by slightly trimming the WAV file shutdown music.”

“It’s indicative of really the level and detail and scrutiny on Windows 7.”

No other operating system in the world can have claims over this ground-breaking innovation for reducing shutdown times. I mean, it took more than a decade of research and real-world feedback for Microsoft to finally declare that chopping shutdown music will reduce the — gasp! — shutdown time as well. Who knows, maybe Windows 8 will blow everyone out of the water by discarding each and every sound found in the previous versions. We’re living in a wonderful age of technological revolution.

Tags: , , , , , , , ,