I bought an HTC Magic a few weeks ago. One of the its coolest thing is the sheer number of apps in the Android Market. There are actually too many and finding the good ones requires lots of searching and testing. These are the ones I use the most so far:
- Wapedia, which greatly optimizes the wikipedia display for mobile devices.
- Pixelpipe, to upload media to Flickr easily.
- QuickDic German, by Thad Hughes (a googler, by the way)
- AnkiOnline. Not actually an app, but a mobile-friendly web site that is always synced with my desktop Anki database. I use it to study german vocabulary while commuting. Pretty cool.
- NewsRob, a Google Reader client (suggested by Cesar from Pinguis Moveis)
Soon I'll hopefully expand this list with an I app I wrote myself, but I've been very lazy lately, so who knows.
Saturday, July 04, 2009
Sunday, June 14, 2009
Sometimes I miss doing Linux end user support work
Last October I set an Ubuntu desktop for Carla's family. We live very far away from them, so it was important that their system was resilient, otherwise it wouldn't last long. They are all beginners in this internet thing, so installing Windows for them would have been a bad idea.
And I was right. Things ran pretty smoothly, we talked via Skype very often, with no signs of virus or crashes. I even found this file in their system:
After many months of usage everything was still working fine, until the computer stopped booting.
Helping them from the phone was a challenge. They had to read the error messages in English for me (and they don't understand this language), while we tried to fix GRUB. In the end I assumed the hard disk was just dead.
I asked my good friend Marcelo Lemos for help and he burned an ISO image of Ubuntu and sent them by mail. I live in Switzerland and it would take ages for the package to get there. The customs in Brazil are a black hole.
The CD got there after a couple days but, of course, since the worst case scenario always apply, the computer was not set to boot via CD-ROM, so we had to fix that - all by phone, while the girls spell each CMOS setup word for me.
Now the Ubuntu Live CD system was finally up, I logged in via a reverse SSH connection (I gave them commands via Gmail that they would run via terminal) and fixed the filesystem errors. But the kernel still showed too many I/O errors from that hard disk. The only safe thing to do was to backup their remaining personal files somewhere while the system is still up, then reinstall everything with a new hard disk.
I needed a safe place to send all their stuff but my amazing friends and former colleagues at RimuHosting do not offer the cheapest disk space plans, unfortunately. So I remembered that a RimuHosting customer once said great things about rsync.net (awesome name, by the way), and I gave them a try.
I ordered a one-year 4Gb quote with them and my account was setup in a few minutes, even before I send them the payment, which is really awesome. I got all login details by mail, and started rsync'ing everything right away. Pretty neat. So it turns out that rsync.net is a decent secure offsite backup service that I strongly recommend so far. They even have servers here in Zürich :-).
The rsync is still running inside a screen(1) session as I write this, and it's going to take a while to finish. I just hope the disk is not too damaged and that it copies the most important files. Otherwise how would they live without the clica-aqui.exe?
So much adrenaline! Only end-user support work gives me that. I miss that a little bit.
NOT!
And I was right. Things ran pretty smoothly, we talked via Skype very often, with no signs of virus or crashes. I even found this file in their system:
clica-aqui.exe (click-here.exe, in Portuguese)
After many months of usage everything was still working fine, until the computer stopped booting.
Helping them from the phone was a challenge. They had to read the error messages in English for me (and they don't understand this language), while we tried to fix GRUB. In the end I assumed the hard disk was just dead.
I asked my good friend Marcelo Lemos for help and he burned an ISO image of Ubuntu and sent them by mail. I live in Switzerland and it would take ages for the package to get there. The customs in Brazil are a black hole.
The CD got there after a couple days but, of course, since the worst case scenario always apply, the computer was not set to boot via CD-ROM, so we had to fix that - all by phone, while the girls spell each CMOS setup word for me.
Now the Ubuntu Live CD system was finally up, I logged in via a reverse SSH connection (I gave them commands via Gmail that they would run via terminal) and fixed the filesystem errors. But the kernel still showed too many I/O errors from that hard disk. The only safe thing to do was to backup their remaining personal files somewhere while the system is still up, then reinstall everything with a new hard disk.
I needed a safe place to send all their stuff but my amazing friends and former colleagues at RimuHosting do not offer the cheapest disk space plans, unfortunately. So I remembered that a RimuHosting customer once said great things about rsync.net (awesome name, by the way), and I gave them a try.
I ordered a one-year 4Gb quote with them and my account was setup in a few minutes, even before I send them the payment, which is really awesome. I got all login details by mail, and started rsync'ing everything right away. Pretty neat. So it turns out that rsync.net is a decent secure offsite backup service that I strongly recommend so far. They even have servers here in Zürich :-).
The rsync is still running inside a screen(1) session as I write this, and it's going to take a while to finish. I just hope the disk is not too damaged and that it copies the most important files. Otherwise how would they live without the clica-aqui.exe?
So much adrenaline! Only end-user support work gives me that. I miss that a little bit.
NOT!
Tuesday, June 09, 2009
Fixed my first bug in C++. PROFIT!
I'm still trying to learn C++ by fixing bugs. Well, the bug I wanted to fix in Ekiga had already being solved upstream (should I be happy or sad?), but I had fun trying to debug it anyway.
Luckily I found another one to fix today. After 1h30m playing around with gdb and adding debug messages everywhere, I fixed a bug in Gnote where preferences were not being set unless you restarted the program.
The biggest challenge was to find out that all code was written already, it just wasn't working. I initially thought I'd have to write the callback methods myself, but then I saw references to "gconf...notify" in the code, which would normally be enough.
Reading the gconf API docs was sufficient for me to find the culprit. 2-liner patch submitted ;-).
Luckily I found another one to fix today. After 1h30m playing around with gdb and adding debug messages everywhere, I fixed a bug in Gnote where preferences were not being set unless you restarted the program.
The biggest challenge was to find out that all code was written already, it just wasn't working. I initially thought I'd have to write the callback methods myself, but then I saw references to "gconf...notify" in the code, which would normally be enough.
Reading the gconf API docs was sufficient for me to find the culprit. 2-liner patch submitted ;-).
Monday, June 08, 2009
Having fun while trying to learn C++
I've been trying to learn C++ lately. I read a few chapters of a few books, but I got tired of just reading so now I am trying to fix bugs in free software out there.
The first step was to install Ubuntu on the Macbook Pro that I use. Second step was to find useful software written in C++ that needs small bugs fixing.
First I tried to fix a bug in gnote, but I wasn't persistent enough and the lead developer fixed the bug himself after many days without any update from me. The lesson learned here is do not just propose a fix a go walkabout. Stick to it until the end.
Now I'm trying to fix an bug in Ekiga. Actually, I think the bug is in the libopal, but I'm not so sure. The symptom is a segmentation fault in SIPHandler::SendRequest() and it only crashes when I set an outbound SIP proxy. Maybe I'm setting an invalid proxy, but well, it shouldn't be crashing.
Let's see how far I'll go this time.
The first step was to install Ubuntu on the Macbook Pro that I use. Second step was to find useful software written in C++ that needs small bugs fixing.
First I tried to fix a bug in gnote, but I wasn't persistent enough and the lead developer fixed the bug himself after many days without any update from me. The lesson learned here is do not just propose a fix a go walkabout. Stick to it until the end.
Now I'm trying to fix an bug in Ekiga. Actually, I think the bug is in the libopal, but I'm not so sure. The symptom is a segmentation fault in SIPHandler::SendRequest() and it only crashes when I set an outbound SIP proxy. Maybe I'm setting an invalid proxy, but well, it shouldn't be crashing.
Let's see how far I'll go this time.
Monday, December 29, 2008
Being naïve about Python object identities, references and sizes.
I'm ashamed of how naïve and ignorant I stand regarding Python stuff. At least this time, I've learned a great lesson about object identities, references and sizes. Hopefully you won't make the same mistake as I did.
Here's what I wanted to do: write an in-memory simplistic log keeper for my application, that would be used as a poor man's brute force protection. The details don't matter much. All this meant is I'd have to keep, say, all the last 10 authentication attempts for all users, for as long as needed, in memory.
I was then a bit worried about memory usage, so I got creative. I'm probably the electrician sysadmin that Tom referred. Sometimes the wires burst in flames when I get creative.
A normal (and sane) person would write something like this:
It's a simple class type object. It would be used this way:
But then I looked at the object names, "client_ip", "auth_result", "auth_timestamp". And I thought: OMG, I'd have one UserLog object instance for each auth event, for each user. I don't want to waste so many precious bytes by keeping these object names in my structure!
So this stupid person had the following reasoning to try and save memory.
Instead of keeping a proper structured and clean "log" object with each log component with their names, I thought I should throw everything inside a list, and use the index numbers to reference to each member. For example:
In order to add mnmemonics for this stupid structure, I'd use some constants that I could use to refer to the indexes. Eg:
Although this hideous code is common for C programmers, it's a deadly sin for Python programmers. What kind of creature would NOT use a dictionary to store this data? That creature is me, Yves, and I ask for your forgiveness.
Of course I should have used a dictionary. A class type object would be even cleaner. So I rewrote that portion of the code.
The truth is the overhead for keeping 1 million instances of the string constant 'client_ip' is not as big as I thought, even when compared to keeping 1 million instances of the integer 2. Why is that?
It's simple. As we know, Python uses references for keeping its objects. We'd have 1 million references to "client_ip", yes, but they all point to exactly the same object: the string constant "client_id" is kept just once in memory, for all our instances.
It's easy to see this happening:
Note how a and b refer to the same object id. One can even compare them by using 'is'.
So although a and b are independent containers, they point to the same string constant, which is only saved once in memory. Interesting, hun? This is called common subexpression elimination and it's a well-known optimization technique for compilers.
Obviously, although we don't have to worry about repeated string constants for the keys in our multiple dictionaries, there's still a storage overhead of using a dictionary compared to using a list to keep objects, but this is also minimal.
Bottom-line: don't bother too much about creating your own "memory efficient" data structure instead of using a good and old dictionary (or similar, such as a class type). It's usually not worth trouble.
Curiously, I noticed the common subexpression elimination does not always happen, and sometimes identical string constants are stored in different places in memory:
Something to discuss in a later post, I guess.
Here's what I wanted to do: write an in-memory simplistic log keeper for my application, that would be used as a poor man's brute force protection. The details don't matter much. All this meant is I'd have to keep, say, all the last 10 authentication attempts for all users, for as long as needed, in memory.
I was then a bit worried about memory usage, so I got creative. I'm probably the electrician sysadmin that Tom referred. Sometimes the wires burst in flames when I get creative.
A normal (and sane) person would write something like this:
UserLog(object):
def __init__(self, auth_result, auth_timestamp, client_ip):
self.auth_result = auth_result
self.auth_timestamp = auth_timestamp
self.client_ip = client_ip
It's a simple class type object. It would be used this way:
lastlog = UserLog(True, 1231700497, '127.0.0.1')
print lastlog.client_ip
But then I looked at the object names, "client_ip", "auth_result", "auth_timestamp". And I thought: OMG, I'd have one UserLog object instance for each auth event, for each user. I don't want to waste so many precious bytes by keeping these object names in my structure!
So this stupid person had the following reasoning to try and save memory.
Instead of keeping a proper structured and clean "log" object with each log component with their names, I thought I should throw everything inside a list, and use the index numbers to reference to each member. For example:
user_logs['yves'] = [False, 1231700497, '10.0.0.33']
In order to add mnmemonics for this stupid structure, I'd use some constants that I could use to refer to the indexes. Eg:
AUTH_TIMESTAMP = 1
for log in user_logs['yves']:
print log[AUTH_TIMESTAMP]
Although this hideous code is common for C programmers, it's a deadly sin for Python programmers. What kind of creature would NOT use a dictionary to store this data? That creature is me, Yves, and I ask for your forgiveness.
Of course I should have used a dictionary. A class type object would be even cleaner. So I rewrote that portion of the code.
The truth is the overhead for keeping 1 million instances of the string constant 'client_ip' is not as big as I thought, even when compared to keeping 1 million instances of the integer 2. Why is that?
It's simple. As we know, Python uses references for keeping its objects. We'd have 1 million references to "client_ip", yes, but they all point to exactly the same object: the string constant "client_id" is kept just once in memory, for all our instances.
It's easy to see this happening:
>>> a = 'gggggggggggggg'
>>> b = 'gggggggggggggg'
>>> c = 'xxxxxxxxxxxxxx'
>>> id(a)
154424848
>>> id(b)
154424848
>>> id(c)
154424888
Note how a and b refer to the same object id. One can even compare them by using 'is'.
above
>>> a is b
True
So although a and b are independent containers, they point to the same string constant, which is only saved once in memory. Interesting, hun? This is called common subexpression elimination and it's a well-known optimization technique for compilers.
Obviously, although we don't have to worry about repeated string constants for the keys in our multiple dictionaries, there's still a storage overhead of using a dictionary compared to using a list to keep objects, but this is also minimal.
Bottom-line: don't bother too much about creating your own "memory efficient" data structure instead of using a good and old dictionary (or similar, such as a class type). It's usually not worth trouble.
Curiously, I noticed the common subexpression elimination does not always happen, and sometimes identical string constants are stored in different places in memory:
>>> a
'my string'
>>> b
'my string'
>>> a is b
False
>>> id(a)
154424808
>>> id(b)
154424928
Something to discuss in a later post, I guess.
Marcadores:
common subexpression elimination,
python
Sunday, November 30, 2008
Sharing the USB 3G serial network of a Mac OS X with a VirtualBox guest machine
When configuring networking on VirtualBox for Mac OS X, I got stuck because it didn't give me the option to use the "Host Interface" option with my ppp0 connection. The ppp0 connection is my "dial-up" Internet connection using a 3G USB modem.
The solution is so obvious, that I'm surprised I couldn't think of it before finding this post on the VirtualBox forum: just use the (amazing) Internet sharing option of the Mac.
- First, configure VirtualBox to use "Host Interface", and pick the "Ethernet" device down below.
- Then, Boot your guest OS (for example, Debian Live, or HaikuOS) and use DHCP to configure the network.
- Finally, configure Internet sharing on the Mac OS X. Just share the "connection from: " .. "To computers using: Ethernet". Wait a few seconds, then force a reload of the DHCP configuration on the guest OS, and it's done!
Now, the trick is how to make the network work on HaikuOS :-).
The solution is so obvious, that I'm surprised I couldn't think of it before finding this post on the VirtualBox forum: just use the (amazing) Internet sharing option of the Mac.
- First, configure VirtualBox to use "Host Interface", and pick the "Ethernet" device down below.
- Then, Boot your guest OS (for example, Debian Live, or HaikuOS) and use DHCP to configure the network.
- Finally, configure Internet sharing on the Mac OS X. Just share the "connection from: " .. "To computers using: Ethernet". Wait a few seconds, then force a reload of the DHCP configuration on the guest OS, and it's done!
Now, the trick is how to make the network work on HaikuOS :-).
Thursday, July 26, 2007
Setting the default locale (language) in TurboGears
The TurboGears documentation only mentions this en passant. It's easy to change the default locale (language) of your TG application.
In your project/controllers.py, in you can add:
I have this in the top namespace of my controllers.py file, not inside the Root class. I'm not sure if this is the prettiest way to make this work, but hey, it works for me. If you have any better suggestion, please leave a comment.
In your project/controllers.py, in you can add:
def locale_pt():
return 'pt'
turbogears.config.update({'i18n.get_locale' : locale_pt})
I have this in the top namespace of my controllers.py file, not inside the Root class. I'm not sure if this is the prettiest way to make this work, but hey, it works for me. If you have any better suggestion, please leave a comment.
Subscribe to:
Posts (Atom)