2011-12-18

How to log out from an AppEngine app only

This blog post explains how to add a logout page to an AppEngine Python application, which will log out of the application only, without logging out of all of Google (e.g. Gmail, Calendar, Picasa, YouTube).

The default AppEngine users.create_logout_url(...) crates a logout URL which would log out from all of Google. To log out from the AppEngine app only, remove the SACSID and ACSID session cookies, which AppEngine has set right after logging in. Here is how to do it in Python:

import Cookie
import os
from google.appengine.api import users
from google.appengine.ext import webapp

class LogoutPage(webapp.RequestHandler):
  def get(self):
    target_url = self.request.referer or '/'
    if os.environ.get('SERVER_SOFTWARE', '').startswith('Development/'):
      self.redirect(users.create_logout_url(target_url))
      return

    # On the production instance, we just remove the session cookie, because
    # redirecting users.create_logout_url(...) would log out of all Google
    # (e.g. Gmail, Google Calendar).
    #
    # It seems that AppEngine is setting the ACSID cookie for http:// ,
    # and the SACSID cookie for https:// . We just unset both below.
    cookie = Cookie.SimpleCookie()
    cookie['ACSID'] = ''
    cookie['ACSID']['expires'] = -86400  # In the past, a day ago.
    self.response.headers.add_header(*cookie.output().split(': ', 1))
    cookie = Cookie.SimpleCookie()
    cookie['SACSID'] = ''
    cookie['SACSID']['expires'] = -86400
    self.response.headers.add_header(*cookie.output().split(': ', 1))
    self.redirect(target_url) 

...

application = webapp.WSGIApplication([..., ('/logout', LogoutPage), ...])
def main():
  run_wsgi_app(application)
if __name__ == '__main__':
  main()

After adding the /logout page as indicated above, offer the logout link like this:

self.response.out.write('<a href="/logout">Logout</a>')

Please note that adding a cookie which expires in the past makes the browser forget about the cookie immediately.

2011-12-11

How to turn off voicemail for Swisscom (.ch) mobiles

This blog post explains how to turn off the voicemail service (named COMBOX) provided (and enabled by default) by the Swiss mobile carrier Swisscom.

According to this PDF, lined from http://www.swisscom.ch/res/mobile/combox/index.htm, dial the following numbers:

  • ##61#
  • ##62#
  • ##67#

2011-11-18

Measure your reaction time using Python

Run this in a terminal window (without the leading $):

$ python -c 'import random, time; time.sleep(2 + 8 * random.random()); \
  print 1; t = time.time(); raw_input(); print time.time() - t'

Press Enter as soon as the number 1 appears. Your reaction time (in seconds) will be printed. For best results, don't do it over an SSH connection. If you can go below .2 second, then you are most probably not human.

2011-11-13

Announcing Portable MariaDB: Small, portable binary MariaDB distribution for Linux

Portable MariaDB is a small, portable binary distribution of the SQL server MariaDB (Monty's fork of MySQL) for Linux i386 (32-bit). Only the mysqld binary and a versatile init script are included. Portable MariaDB can be run by any user in any directory, it doesn't try to access any mysqld data or config files outside its directory. Portable MariaDB can coexist with regular mysqld (MySQL or MariaDB) and other instances of Portable MariaDB on a single machine, as long as they are not configured to listen on the same TCP port. The only dependency of Portable MariaDB is glibc 2.4 (available in Ubuntu Hardy or later).

The most up-to-date documentation of Portable MariaDB is here.

The sources are here.

Why use Portable MariaDB?

  • It's small (not bloated). Fast to dowload, fast to extract, fast to install. Quick size comparison: mariadb-5.2.9-Linux-i686.tar.gz is 144 MB, the corresponding Portable MariaDB .tbz2 is less than 6 MB.
  • It's portable: does not interfere with other MySQL server installations on the same machine.
  • It's self-contained and consistent: copy the database and the configuration in a single directory from one machine to another.

Installation

To run Portable MariaDB, you need a Linux system with glibc 2.4 (e.g. Ubuntu Hardy) or later. 32-bit and 64-bit systems are fine. For 64-bit systems you need the 32-bit compatibility libraries installed. You also need Perl.

  $ cd /tmp  # Or any other with write access.
  $ BASE=https://raw.githubusercontent.com/pts/portable-mariadb/master/release
  $ #OLD: wget -O portable-mariadb.tbz2 $BASE/portable-mariadb-5.2.9.tbz2
  $ wget -O portable-mariadb.tbz2 $BASE/portable-mariadb-5.5.46.tbz2
  $ tar xjvf portable-mariadb.tbz2
  $ chmod 700 /tmp/portable-mariadb  # For security.
  $ /tmp/portable-mariadb/mariadb_init.pl stop-set-root-password

Usage

For security, don't do anything as root.

  $ cd /tmp/portable-mariadb
  $ ./mariadb_init.pl restart
  Connect with: mysql --socket=/tmp/portable-mariadb/mysqld.sock --user=root --database=test --password
  Connect with: mysql --host=127.0.0.1 --user=root --database=test --password

Feel free to take a look at /tmp/portable-mariadb/my.cnf, make modifications, and restart mysqld so that the modifications take effect.

Security

By default, connections are accepted from localhost (Unix domain socket and TCP) only, all MySQL users are refused (except if a password has been set for root above), and root has unrestricted access. Unix permissions (such as the chmod 700 above) are protecting against data theft and manipulation on the file level.

It is strongly recommended to change the password of root to a non-empty, strong password before populating the database.

Java support

Java clients with JDBC (MySQL Connector/J) are fully supported. Please note that Java doesn't support Unix doman socket, so make sure in my.cnf that mysqld listens on a TCP port. Please make sure you have ?characterEncoding=UTF8 specified in your JDBC connection URL, otherwise some non-ASCII, non-Latin-1 characters would be converted to ?.

Unicode support

Just as with MariaDB. All encodings and collations are supported. The latin1 encoding is the default, which can be changed in my.cnf.

Language support

All natural languages (of MariaDB) are supported for error messages. Set the `language' flag in my.cnf accordingly. English is the default.

2011-11-10

How to simply compress a C++ string with LZMA

This blog post explains how to simply compress C++ with LZMA compression, using liblzma.

Use the following functions:

#include <stdlib.h>
#include "lzma.h"
#include <string>

// Level is between 0 (no compression), 9 (slow compression, small output).
std::string CompressWithLzma(const std::string& in, int level) {
  std::string result;
  result.resize(in.size() + (in.size() >> 2) + 128);
  size_t out_pos = 0;
  if (LZMA_OK != lzma_easy_buffer_encode(
      level, LZMA_CHECK_CRC32, NULL,
      reinterpret_cast<uint8_t*>(const_cast<char*>(in.data())), in.size(),
      reinterpret_cast<uint8_t*>(&result[0]), &out_pos, result.size()))
    abort();
  result.resize(out_pos);
  return result;
}

std::string DecompressWithLzma(const std::string& in) {
  static const size_t kMemLimit = 1 << 30;  // 1 GB.
  lzma_stream strm = LZMA_STREAM_INIT;
  std::string result;
  result.resize(8192);
  size_t result_used = 0;
  lzma_ret ret;
  ret = lzma_stream_decoder(&strm, kMemLimit, LZMA_CONCATENATED);
  if (ret != LZMA_OK)
    abort();
  size_t avail0 = result.size();
  strm.next_in = reinterpret_cast<const uint8_t*>(in.data());
  strm.avail_in = in.size();
  strm.next_out = reinterpret_cast<uint8_t*>(&result[0]);
  strm.avail_out = avail0;
  while (true) {
    ret = lzma_code(&strm, strm.avail_in == 0 ? LZMA_FINISH : LZMA_RUN);
    if (ret == LZMA_STREAM_END) {
      result_used += avail0 - strm.avail_out;
      if (0 != strm.avail_in)  // Guaranteed by lzma_stream_decoder().
        abort();
      result.resize(result_used);
      lzma_end(&strm);
      return result;
    }
    if (ret != LZMA_OK)
      abort();
    if (strm.avail_out == 0) {
      result_used += avail0 - strm.avail_out;
      result.resize(result.size() << 1);
      strm.next_out = reinterpret_cast<uint8_t*>(&result[0] + result_used);
      strm.avail_out = avail0 = result.size() - result_used;
    }
  }
}

Please note that in some use cases there may exist a solution which uses less memory.

See the liblzma/container. for documentation of lzma_easy_buffer_encode().

The decompression code was based on xzdec.c in xz-utils.

2011-10-27

Long standby time for Cyanogenmod 7.1 on ZTE Blade phones

This is a testimonial of the Cyanogenmod 7.1 Android spinoff operating system on the ZTE Blade phone.

I've recently installed Cyanogenmod 7.1 to my ZTE Blade. Prevously I had Cyanogenmod 7.0.3 on it, and the battery life was terrible. It didn't last more than 48 hours in standby (3G, mobile data, wifi, GPS, background synchronization switched off, only receiving a few text messages). But after installing 7.1, the battery lasted for 12 days plus 23 hours in standby mode. Awesome! Finally I have a small and cheap Android phone with long battery life.

The phone user interface also feels much snappier now, and 3D games (e.g. Falldown 3D) which lagged and were unplayable with 7.0.3 are fast and playable now.

Unfortunately I wasn't able to upgrade 7.0.3 to 7.1, but I had to wipe the phone (keeping only the SD card contents) before installing 7.1.

2011-10-18

Getting started with IntelliJ to write Android applications on Linux

This blog post gives instructions to get started with Android application development with IntelliJ on Linux.
  1. Install the Java runtime environment (JRE) and the Java compiler (in the JDK). Command to to it on Ubuntu Lucid: sudo apt-get install openjdk-6-jdk . Please note that the JRE without the JDK is not enough, IntelliJ needs the JDK.
  2. You will need about 1.5 GB of free disk space.
  3. Download IntelliJ (either the Ultimate edition or the Community edition; please note that you have to pay for the Ultimate edition after the evaluation period expires) from from. http://www.jetbrains.com/idea/download/ . I've downloaded the file from http://download.jetbrains.com/idea/ideaIU-10.5.2.tar.gz , it was about 160 MB.
  4. Download the Android SDK tools from http://developer.android.com/sdk/ . I've downloaded the file from http://dl.google.com/android/android-sdk_r13-linux_x86.tgz . It was about 160 MB.
  5. If you ever want to connect a real phone via USB, then follow the instructions http://ptspts.blogspot.com/2011/10/how-to-fix-adb-no-permissions-error-on.html do create and install the android.rules udev rule. Please also restart the udev service.
  6. Extract the downloaded archive android-sdk_r13-linux_x86.tgz .
  7. Run the android-sdk-linux_x86/tools/android tool.
  8. On the Available packages tab, find and install the following packages:
    • Android SDK Tools
    • Android SDK Platform-tools
    • Documentation for Android SDK (the latest one)
    • SDK Platform Android 2.2, API 8 (or whichever Android version you are developing for).
    • Samples for SDK API 8 (or whichever Android version you are developing for).
    • Google APIs by Google Inc., Android API 8 (or whichever Android version you are developing for).
    • Android Compatibility package
  9. In the Virtual devices tab, create a virtual device. Use these settings (make sure to enabling snapshots and disabling audio playback and recording):
  10. Start the virtual device, play with it (it's an emulated Android phone), watch how it eats your CPU capacity, and stop it by closing the emulator window.
  11. Please note that the emulator is very slow. It will happily eat 100% even if the virtual device is idle. When you disable sound playback and sound recording, it still eats about 800 MHz (tested on Intel(R) Core(TM)2 Duo CPU P9500 @ 2.53GHz).
  12. A possible bug in the Android emulator: The Launch from snapshot functionality didn't work for me in the emulator, even though the snapshot was present.
  13. In the file ~/Downloads/idea-IU-107.587/bin/idea.sh (the actual filename may depend on where you have downloaded and extracted IntelliJ to), change the line containing OPEN_JDK=$? to OPEN_JDK=1 . This will disable the startup warning.
  14. Start IntelliJ. Enter license data (or choose evaluation), accept the license agreement, just click OK in the Select VCS Integration dialog (or select a superset of the version control systems you are planning to use), unselect all Web/JavaEE plugins (they are not needed for Android development), unselect all the HTML/JavaScript plugins, in the Other plugins dialog select at least these: Android, GenerateToString, Inspection Gadgets, Intention Power Pack, JUnit, Remote Hosts Access, SpellChecker, Structural Search, Task Management, Type Migration; make sure Android is checked; finish the installation.
  15. File / New project. Create project from scratch. Next. Name: afirst. Select type: Android Module. Next. Create source... src. Next. Project JDK / Configure. /usr/lib/jvm/java-6-openjdk . OK. Next. Android SDK: ... . In the top left corner of the window, click +, and select Android SDK. Specify /home/USERNAME/Downloads/android-sdk-linux_x86 (where you have downloaded and extracted the Android SDK to). Select internal JDK: 1.6. OK. Select build target: Android 2.2 (or the Android version of your choice). OK. OK. Now you are back in the Create project wizard, with the Android SDK: selection containing Android 2.2 Platform. Finish.
  16. Wait a few minutes until the project tree afirst appears. Open afirst. Open src. Open com.example. Double click on MyActivity. The MyActivity.java source file appears.
  17. Make sure the virtual device barvirt is running in the Android emulator. Play it safe and restart the emulator.
  18. Stop adb: sudo ~/Downloads/android-sdk-linux_x86/platform-tools/adb kill-server
  19. Restart adb: sudo ~/Downloads/android-sdk-linux_x86/platform-tools/adb devices
  20. In IntelliJ Run / Edit configurations, set up devices and virtual devices like this:
  21. In IntelliJ: Run / Run. Wait a minute. The app should start on the emulator.
  22. Connect your phone with USB debugging enabled (in Settings / Applications / Development). In IntelliJ: Run / Run. Wait a minute. The app should start on the phone.

Typical IntelliJ message for starting the app on the phone:

Waiting for device.
Target device: 1234567890ABCDEF
Uploading file
 local path: /home/pts/IdeaProjects/afirst/out/production/afirst/afirst.apk
 remote path: /data/local/tmp/com.example
Installing com.example
DEVICE SHELL COMMAND: pm install -r "/data/local/tmp/com.example"
pkg: /data/local/tmp/com.example
Success


Launching application: com.example/com.example.MyActivity.
DEVICE SHELL COMMAND: am start -n "com.example/com.example.MyActivity"
Starting: Intent { cmp=com.example/.MyActivity }

Typical IntelliJ message for starting the app on the emulator:

Waiting for device.
Target device: emulator-5554 (barvirt)
Uploading file
 local path: /home/pts/IdeaProjects/afirst/out/production/afirst/afirst.apk
 remote path: /data/local/tmp/com.example
Installing com.example
DEVICE SHELL COMMAND: pm install -r "/data/local/tmp/com.example"
pkg: /data/local/tmp/com.example
Success


Launching application: com.example/com.example.MyActivity.
DEVICE SHELL COMMAND: am start -n "com.example/com.example.MyActivity"
Starting: Intent { cmp=com.example/.MyActivity }

2011-10-06

Named return value optimization in gcc

This blog post demonstrates that GCC 4.1 does Named return value optimization, i.e. it omits creating a temporary object in a function returning an object if all return statements in the function return the same local variable. Example code:

#include <stdio.h>

class C {
 public:
  C() { printf("+\n"); }
  ~C() { printf("-\n"); }
  C(const C&) { printf(":\n"); }
  C& operator=(const C&) { printf("=\n"); }
};

C F(int i) {
  C x;
  if (i > 1) {
    return x;
  } else {
    return x;
  }
}

C G(int i) {
  if (i > 1) {
    C x;
    return x;
  } else {
    C y;
    return y;
  }
}

int main(int argc, char**) {
  F(argc);
  printf("~~~\n");
  G(argc);
  return 0;
}

The output, as expected, even without -O... compiler optimization flags:

$ g++ test_return_object.cc && ./a.out
+
-
~~~
+
:
-
-

2011-10-04

How to initiate and receive voice and video calls from within Gmail?

This blog post explains how to set up Gmail so it will be able to initiate and receive voice and video calls.

  1. Download and install the Google Talk Plugin from here.
  2. Restart your browser, preferably Google Chrome.
  3. Log into gmail in your browser.
  4. In the top right corner click on the cogwheel icon, and then select Mail settings.
  5. In the Chat tab, set up the settings of Voice and video chat.
  6. Click on Verify your settings and make sure it works properly.
  7. Save the settings (Save Changes).
  8. Select a friend in the chat list, open a chat window. In the chat window there will be a phone or camera icon, with which you can start the voice or video chat.

2011-10-02

How to fix the adb no permissions error on Ubuntu Lucid

This blog post explains how to fix the no permissions error the Android Debugger displays when running the adb devices command Linux. The solutions presented here have been tested and found working on Ubuntu Lucid, but they should also work on other Ubuntu and Linux versions as well.

This official help center page has many working and non-working answers to the problem, and many comments. The root cause of the problem is that the current user doesn't have sufficient permissions to access the USB device file created when the phone was connected in USB debug mode.

Killing all running adb server instances with sudo killall adb, disconnecting the phone, reconnecting the phone, and then running sudo adb devices instead (so adb gets run as root) fixes the problem.

Alternatively, it is possible to implement a long-term fix which doesn't require sudo, thus it works with e.g. IntelliJ IDE integration:

  • Create a file named /tmp/android.rules with the following contents (hex vendor numbers were taken from the vendor list page):
    SUBSYSTEM=="usb", ATTRS{idVendor}=="0bb4", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="0e79", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="0502", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="0b05", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="413c", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="0489", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="091e", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="18d1", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="0bb4", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="12d1", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="24e3", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="2116", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="0482", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="17ef", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="1004", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="22b8", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="0409", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="2080", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="0955", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="2257", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="10a9", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="1d4d", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="0471", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="04da", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="05c6", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="1f53", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="04e8", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="04dd", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="0fce", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="0930", MODE="0666"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="19d2", MODE="0666"
  • Run the following commands (without the leading $):
    $ sudo cp /tmp/android.rules /etc/udev/rules.d/51-android.rules
    $ sudo chmod 644   /etc/udev/rules.d/51-android.rules
    $ sudo chown root. /etc/udev/rules.d/51-android.rules
    $ sudo service udev restart
    $ sudo killall adb
  • Disconnect the USB cable between the phone and the computer.
  • Reconnect the phone.
  • Run adb devices to confirm that now it has permission to access the phone.

Please note that it's possible to use , USER="$LOGINNAME" instead of , MODE="0666" in the .rules file, substituting $LOGINNAME for your login name, i.e. what id -nu prints.

2011-09-09

How to install kradview on Ubuntu Lucid

This blog post explains how to install and run kradview on Ubuntu Lucid.

Compiling and installing:

$ sudo apt-get install libqt3-headers kdelibs4-dev
$ wget -O /tmp/kradview-1.1.0.tgz http://www.orcero.org/irbis/kradview/kradview-1.1.0.tgz
$ (cd /tmp && tar xzvf kradview-1.1.0.tgz)
$ cd /tmp/kradview-1.1.0
$ ./configure --without-arts
$ make
$ sudo make install
$ sudo ln -sf ../kde/bin/kradview /usr/local/bin/kradview

Running:

$ kradview

Running with a file preopened:

$ kradview FILENAME

Please note that it might not be necessary to install kradview, because the display utility of ImageMagick may be able to display the image. Installation: $ sudo apt-get install imagemagick . Usage: $ display FILENAME .

2011-08-06

How to set up Skype notifications on Linux to be non-distruptive

This blog post presents my Skype notification setup on Linux. This setup contains no audio notifications and only a few visual notifications which don't disturb my regular work.

In the Skype Options dialog box, select the Chat tab, and set it up like this:

  • When somebody starts a chat with me...: Create a minimised chat window
  • Show emoticons: yes
  • Show animated emoticons: no

In the Skype Options dialog box, select the Notifications tab, and set it up like this:

  • Skype Login: no Enable Event
  • Skype Logout: no Enable Event
  • Skype Login Failed: Enable Event, no sound file
  • Contact Came Online: no Enable Event
  • Contact Went Offline: no Enable Event
  • First Chat Message Received: Enable Event, no sound file, Display pop-up notification
  • Chat Message Received: Enable Event, no sound file, Display pop-up notification
  • Chat Message Sent: no Enable Event

Apply the settings, and close the Options dialog box.

How to set up a compact desktop theme on Ubuntu Lucid

This blog post explains how to set up a compact GNOME desktop theme on Ubuntu Lucid, i.e. such a theme which consumes little screen real estate, leaving space for the contents you work on.

Install and activate the necessary small fonts (FixedSC and Helvetica), as described in this blog post.

Select the FixedSC font in GNOME Terminal.

Run this command (without the $) to install GNOME themes:

$ sudo apt-get install gnome-themes{,-extras,-more,-selected,-ubuntu}

In System / Preferences / Appearance / Theme / Customize, select the following themes:

  • Controls: Simple
  • Window Border: Mist
  • Icons: Mist

Some of the changes take effect immediately, but you may have to restart some applications.

How to set up nicely hinted default fonts on Linux

This blog post explains how to set up a per-user default font configuration under Linux (tested on Ubuntu Lucid), which contains easy-to-read fonts in small sizes and properly hinted rendering.

Install the Microsoft core fonts (e.g. Times New Roman, Arial, Courier New), using the following command (without the $ sign):

$ sudo apt-get install msttcorefonts

Create (or overwrite) the file ~/.fonts.conf with the following contents:

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>

<!-- Accept bitmap fonts -->
  <selectfont>
    <acceptfont>
    <pattern>
      <patelt name="scalable"><bool>false</bool></patelt>
    </pattern>
    </acceptfont>
  </selectfont>

<!--  Enable proper hinting (medium) and disable subpixel rendering (rgba=none)
      for the Microsoft Core fonts (msttcorefonts) with high quality hints.
  --> 
  <match target="font">
    <test name="family"><string>Andale mono</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Arial</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Arial Black</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Comic Sans MS</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Courier New</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Georgia</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Impact</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Times New Roman</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Trebouchet MS</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Verdana</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Webdings</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>

<!--  Just a safe bet: enable proper hinting for the DejaVu font family.
      Bitstream Vera is not shipped on Ubuntu Lucid anymore (but there was a
      package on Ubuntu Hardy).
  --> 
  <match target="font">
    <test name="family"><string>DejaVu Sans</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>DejaVu Sans Mono</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>DejaVu Sans,DejaVu Sans Condensed</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>DejaVu Sans Condensed</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>DejaVu Sans,DejaVu Sans Light</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>DejaVu Sans Light</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>DejaVu Serif</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>DejaVu Serif,DejaVu Serif Condensed</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>DejaVu Serif Condensed</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>

<!-- Set font family preferences for Firefox. Chrome seems to ignore these.
     Please note that /etc/fonts/conf.d/60-latin.conf has more defaults, which
     we don't have to repeat here.
  -->
  <alias><family>serif</family><prefer>
    <family>Times New Roman</family>
  </prefer></alias>
  <alias><family>sans-serif</family><prefer>
    <family>Arial</family>
  </prefer></alias>
  <alias><family>monospace</family><prefer>
    <family>DejaVu Sans Mono</family>
  </prefer></alias>
</fontconfig>

The hintmedium setting above is especially important, because it turns on the proper hinting for Times New Roman etc., which makes these fonts easy to read at small sizes. The default is slight hinting (instead of medium), which is wrong, and it remains wrong (because of a bug) even if you select it at System / Preferences / Appearance / Fonts / Details / Hinting / Medium. The proper way to get the medium hinting is to write a ~/.fonts.conf file, as above.

After changing ~/.fonts.conf log out and back in, or restart all applications for the changes to take effect.

Google Chrome doesn't pay attention to the default fonts specified in ~/.fonts.conf. In Chrome, visit chrome://settings/fonts, and change the defaults to:

  • Standard Font: Times New Roman
  • Serif Font: Times New Roman
  • Sans Serif Font: Arial
  • Fixed-Width Font: DejaVu Sans Mono

You may want to change the window title and dialog box fonts as well. You can do that in System / Preferences / Appearance / Fonts. See this blog post for some crisp (i.e. non-antialiased), small font size defaults. Don't forget to install the FixedSC and Helxetica fonts first, as documented there.

How to set up English search in Google Chrome

This blog post explains how to set up the default search engine to Google in English language in Google Chrome.

By default, if Google is the default search engine in Google Chrome, it returns the search result in the language of the country which is autodetected as the location of the computer. This is bad behavior for most English-speaking travelers, who always want the search results in English, no matter which country they are visiting.

To fix it for yourself, go to chrome://settings/searchEngines in Chrome, and add a new search engine named Google in English, the shortcut (second column) being gg , and the URL being http://www.google.com/search?hl=en&q=%s . Save it, make it the default, and remove all other search engines with Google in their name.

From now on, you can type a search query to the address bar (optionally prefixed by gg and a space), and you will get Google results in English.

Unfortunately the search engine setting is not synchronized between your Google Chrome installations, so you have to configure it manually on each machine and login account.

2011-08-04

How to disable cursor blinking in GNOME applications

This blog post explains how to make the cursor not blink in text input and text area widgets in GNOME applications (including GNOME Terminal). The settings have been tested and found working on Ubuntu Lucid.

Run the following commands (without the leading $) in a terminal window:

$ gconftool-2 --set /desktop/gnome/interface/cursor_blink --type boolean False
$ gconftool-2 --set /apps/gnome-terminal/profiles/Default/cursor_blink --type boolean False
$ gconftool-2 --set /apps/gnome-terminal/profiles/Default/cursor_blink_mode --type string off

Changes take effect immediately, there is no need to restart running applications.

These changes also affect Google Chrome (including the address bar and input fields and textarea fields on the page). However, changes don't take effect within a pages in existing tabs, so you should close them, and create new tabs.

If some cursors still Please see this noblink page to disable blinking in Emacs, XEmacs, GVIM, GTK, Gimp, Qt, LessTif, Mozilla Firefox, Mozilla Thunderbird, Google Chrome, TCL/Tk, Linux console and Microsoft Windows.

How to write hello-world in both Java and C++

This blog post explains hwo to write a hello-world program which compiles in both Java and C++.

The following solution makes use of the language difference that //...\ continues the one-line comment in C++, but not in Java.

//\
class t{public static void main(String[]a){System.out.print/*
#include<stdio.h>
int main(){if(1){return!printf//*/
("Hello, World!\n");}}

2011-06-24

Python 3.2 binaries released in StaticPython for Linux

This blog post is to announce that StaticPython, a binary distribution of Python, has just released Python 3.2 binaries for Linux. (Previously StaticPython contained only Python 2.7 binaries.) Download links for the binaries:

  • python3.2: almost all built-in Python modules, C extensions (including sqlite3) and greenlet
  • stackless3.2: ditto, but with Stackless Python
  • stacklessxl3.2: ditto, and also OpenSSL (with the _ssl and _hashlib modules)

The Python 3.2 binaries of StaticPython can be useful on Linux and FreeBSD systems where Python 3.2 distribution packages are not available, and recompiling from source would be too inconvenient. They can also be used to demo the features of Python 3 for users with a little time and patience, and without a commitment to install it.

2011-06-05

PTetriS/HTML: A minimalistic, but correct Tetris-clone in HTML + JavaScript

This blog post is to announce PTetriS/HTML, a minimalistic, but correct Tetris-clone in HTML + JavaScript. Play PTetriS/HTML here, with a JavaScript-enabled browser.

PTetris/HTML was born to celebrate the coming 10-year anniversary of PTetris, the same Tetris-clone implemented as a Java applet and application. Play PTetriS here, with a Java-enabled browser.

Please note that the PTetriS games are not feature rich (e.g. they don't count the score and they don't show the next brick, and they don't have multiple levels). This is intentional, so they can work as a reference implementation of a correct Tetris game. By correct I mean that the board size is correct, bricks rotate in the correct direction, and the rotation pixel pattern of the bricks is correct (e.g. they don't jump up or down when changing the rotation phase). These properties are copied from the old game FUXOFT's Tetris2 (architecture: ZX Spectrum). There are many Tetris-clones available nowadays which are incorrect.

2011-06-04

How to download a https:// page in Ruby 1.8

This blog post shows an example low-level implementation of downloading a https:// page in Ruby 1.8. The reason why is this blog post was born is that the documentation of the openssl and socket Ruby modules didn't contain a working end-to-end example.

#! /usr/bin/ruby1.8
require 'socket'
require 'openssl'
# Returns a HTTP response header + body.
def download_https(host, port, suburl)
  s = TCPSocket.new('www.gmail.com', 443)
  begin
    ss = OpenSSL::SSL::SSLSocket.new(s)
    begin
      ss.connect
      ss << "GET #{suburl} HTTP/1.0\r\nHost: #{host}:#{port}\r\n\r\n"
      ss.flush
      ss.read
    ensure
      ss.close
    end
  ensure
    s.close
  end
end
p download_https('www.gmail.com', 443, '/')

Please note that this doesn't check the authenticity of the server, i.e. it will happily and silently accept self-signed certificates.

2011-05-19

jtty-builder: easy-to-install JSP web server for Unix

This blog post is an announcement for jtty-builder, an easy-to-install, lightweight webserver with a JSP container for Unix. More specifically, jtty-builder is just a set of shell scripts for Unix which automate downloading and building a lightweight Java web and application server for serving JSP (and Java servlets). The container used is Jtty, which uses Jetty, which uses parts of Apache Tomcat (mostly Jasper). Most steps are automated. There is no need to write configuration files.

See the most recent documentation of jtty-builder here.

To start serving a hello-world JSP page on Unix, do this:

  1. As a shortcut, you can use a prebuilt jttyp.jar instead of building one using jtty-builder. To do that, run the following command, and skip steps 1 to 5 (inclusive):
    $ wget -O jttyp.jar \
        http://pts-mini-gpl.googlecode.com/svn/trunk/jtty-prebuilt/jttyp.jar
  2. Download jtty-builder:
    $ svn co http://pts-mini-gpl.googlecode.com/svn/trunk/jtty-builder
  3. Install java and javac. Example command on Ubuntu Lucid:
    $ sudo apt-get install openjdk-6-jdk
  4. Use jtty-builder to download the sources of Jtty, Jetty and Tomcat:
    (cd jtty-builder && ./download_jttyp.jar)
  5. Use jtty-builder to build jttyp.jar:
    $ (cd jtty-builder && ./build_jttyp.jar)
  6. Copy jttyp.jar to the application directory:
    $ cp jtty-builder/jttyp.jar .
  7. Create your .war file or application directory. A simple example:
    $ mkdir Hello-World
    $ (echo '<html><head><title>JSP Test</title>'
       echo '<%! String message = "Hello, World."; %>'
       echo '</head><body><h2><%= message %></h2>'
       echo '<%= new java.util.Date() %></body></html>') >Hello-World/hi.jsp
    $ mkdir Hello-World/WEB-INF
    $ (echo '<web-app>'
       echo '<display-name>Hello World</display-name>'
       echo '</web-app>') >Hello-World/WEB-INF/web.xml
  8. Start the Java application server running your Hello-World application:
    java -jar jttyp.jar 8765 Hello-World

    (Keep the java application running.)

  9. Try the web page in your web browser by visiting http://127.0.0.1:8765/ Reload it to get the time updated.

    If you modify hi.jsp and reload the page, it gets autmatically recompiled and the new version will run.

See the Jtty project page for more information about using jtty.jar and jttyp.jar for staring Java web applications from the command line.

2011-04-27

How to write a simple echo and chat server in Ruby 1.8

This blog post is an introduction to TCP socket server programming and thread programming in Ruby 1.8. It also illustrates how compact and expressive Ruby code can be. The intended audience is Ruby beginners.

require 'socket'  # TCPServer
ss = TCPServer.new(1233)
loop {
  Thread.start(ss.accept) { |s|
    begin
      while line = s.gets;  # Returns nil on EOF.
        (s << "You wrote: #{line.inspect}\r\n").flush
      end
    rescue
      bt = $!.backtrace * "\n  "
      ($stderr << "error: #{$!.inspect}\n  #{bt}\n").flush
    ensure
      s.close
    end
  }
}

Use telnet 127.0.0.1 1233 to connect to the echo server as a new participant, and then type your chat message(s) terminated by Enter (newline). The echo server sends back each message it receives with the You wrote boilerplate around it. Multiple independent clients can connect to the chat server at a time.

The chat server:

require 'socket'  # TCPServer
require 'thread'  # Queue
ssock = TCPServer.new(1234)
msgs = Queue.new
participants = []
Thread.start {  # Send chat messages to participants.
  while msg = msgs.pop;  # Always true.
    participants.each { |s|
      (s << msg).flush rescue IOError
    }
  end
}
loop {
  Thread.start(ssock.accept) { |sock|
    participants << sock
    begin
      while line = sock.gets;  # Returns nil on EOF.
        msgs << ": #{line.chomp!}\r\n"
      end
    rescue
      bt = $!.backtrace * "\n  "
      ($stderr << "error: #{$!.inspect}\n  #{bt}\n").flush
    ensure
      participants.delete sock
      sock.close
    end
  }
}

Use telnet 127.0.0.1 1234 to connect to the chat server as a new participant, and then type your chat message(s) terminated by Enter (newline). The chat server sends each message (with a colon prepended) to all connected participants.

The Ruby source files above demonstrate the following:

  • how to create a thread
  • how to use thread-local variables (e.g. sock)
  • how to report exceptions in a thread
  • how to ignore IOError
  • how to read a line from a socket
  • how to use the Queue class for synchronization between threads
  • how to clean up using an ensure block
  • how to pass values to a newly created thread

2011-04-09

python-xattr-compat: portable Python module to query and set POSIX extended attributes of files

This blog post is an announcement of python-xattr-compat, a portable Python 2.x module to query and set POSIX extended attributes of files.

python-xattr-compat is a wrapper around the xattr Python package, but if xattr is not available, python-xattr-compat provides compatible replacement implementations (using the dl or ctypes modules) for some systems (currently Linux), so we have a pure Python implementation for extended attribute manipulations.

How it works: Many scripting languages have a syscall function to call arbitrary system calls (like lsetxattr(2)). Python doesn't have syscall built in, but it has the dl and ctypes modules, which let the programmer call functions in any C library, lincluding libc. Since libc on Linux has wrappers for syscall and lsetxattr etc., we can call these to get system-specific extended attribute manipulation without installing non-built-in Python extensions like xattr.

2011-04-03

How to install CyanogenMod onto the ZTE Blade

This blog post explains how I managed to install CyanogenMod to a ZTE Blade phone (both Gen 1 and Gen 2). Please note that there can be multiple solutions, some of them working only on some phone submodels. The solution I give here did work on the model I had.

Pick one of the methods below.

Method one: without rooting the phone (recommended)

This method is recommended, because it is the more straightforward and safer method. Although its description is longer than of method two, doing method one is faster.

You will need a USB cable to connect the phone to a computer and an SD card in the phone.

Instructions:

  1. Make a backup of your data on the phone, this page has some suggestions how (don't use Titanium Backup though, because that needs a rooted phone). You may safely skip this step if you don't have any SMS, phone call log entry, application data, application configuration etc. to save (e.g. because the phone is new and you haven't customized it yet).
  2. Make sure you know your wifi connection credentials (e.g. network name, security type, passphrase).
  3. Make sure you know your Google account name (e-mail address) and password.
  4. On the phone: Settings » Applications » Development » enable USB Debugging.
  5. On the phone: Settings » Applications » enable Unknown sources – Allow installation of non-Market applications
  6. Install the Ask Mr Pigfish application from the Market, run Ask Mr Pigfish, and see it displaying the generation number of your phone (gen1 or gen2). Take a not on paper containing the generation number.
  7. Install the adb and the fastboot tools to your computer. For Linux, see How to install instructions below. For Windows or Mac, see this page. Another download for fastboot is on this page.
  8. The command lines in following instructions are for Linux. Do it similarly on Mac and Windows (e.g. instead of wget, use your browser or download manager to download the file).
  9. Download the ClockworkMod recovery with wget -O /tmp/recovery-clockwork-3.0.1.4-blade.img http://android.d3xt3r01.tk/cyanogen/blade/recovery/recovery-clockwork-3.0.1.4-blade.img
  10. Download the latest version of CyanogenMod from this page. When these instructions were written, the equivalent download command was: wget -O /tmp/update-cm-7.0.0-RC4-Blade-signed.zip http://mirror.cyanogenmod.com/get/update-cm-7.0.0-RC4-Blade-signed.zip
  11. Download the latest version of Google Apps from this page. When these instructions were written, the equivalent download command was: wget -O /tmp/gapps-gb-20110307-signed.zip http://android.d3xt3r01.tk/cyanogen/gapps/gapps-gb-20110307-signed.zip
  12. If already connected, disconnect the phone from the computer.
  13. Remove the SIM card from the phone if you don't have a data plan. This is to prevent the unconfigured CyanogenMod from making expensive data transfers before the wifi is configured. This needs powering off your phone first.
  14. Power the phone back on and wait for it to start up.
  15. Connect the phone to the computer using the USB cable. The phone should display a notification that an USB cable is connected (and possibly another notification that USB debugging is enabled).
  16. Run adb devices on the computer, it should display something like
    List of devices attached 
    Blade-CM7       device
  17. Copy the CyanogenMod ZIP file to the SD card by running adb push /tmp/update-cm-7.0.0-RC4-Blade-signed.zip /sdcard/cm.zip
  18. Copy the Google Apps ZIP file to the SD card by running adb push /tmp/gapps-gb-20110307-signed.zip /sdcard/gapps.zip
  19. To prevent data loss below, make sure the phone is fully charged. You can charge it quickly if you connect it to a wall socket instead of a computer.
  20. If you have a gen1 phone and you want to install CyanogenMod 7.0.1 or later, then upgrade your phone to gen2 by following the How to upgrade a gen1 phone to gen2 and start ClockworkMod recovery below. Otherwise, follow these instructions:
    1. Reboot the phone to fastboot mode by running adb reboot bootloader
    2. Wait for about 20 seconds until the phone reboots into bootloader mode, showing only the green android logo on the screen. (If your phone boots normally a few seconds later, then this method has failed for you, please choose another method to install CyanogenMod to your phone. You may try removing the battery, reinserting the battery, holding the Volume Up key on the phone, and powering on the phone while Volume Up is still held.)
    3. Run fastboot flash recovery /tmp/recovery-clockwork-3.0.1.4-blade.img
    4. Run fastboot reboot
    5. Wait for the phone to start up and detect that the USB cable is connected.
    6. Run adb reboot recovery (this should take about 5 seconds).
    7. Wait for about 5 seconds until the phone reboots into recovery mode, running the ClockworkMod recovery.
  21. Your phone should be running ClockworkMod recovery now. It should display ClockworkMod Recovery v3.0.1.4 (or a larger version number) and a menu below, starting with reboot system now. Use the Volume Up and Volume Down keys to navigate the menu up or down. Navigate to the advanced item, use the Home button to select it. Use the Back button to go back to the main menu.
  22. Select the main menu option Wipe data/factory reset
  23. Select the main menu option Wipe cache partition
  24. Select the main menu option Install zip from sdcard
  25. Select the menu option Choose zip from sdcard
  26. Select cm.zip . This will install CyanogenMod.
  27. Go back to the main menu. Select the main menu option Install zip from sdcard
  28. Select the menu option Choose zip from sdcard
  29. Select gapps.zip . This will install Google Apps.
  30. Go back to the main menu.
  31. Select the main menu option reboot system now
  32. CyanogenMod should be booting now. Configure everything for your needs.
  33. Use the Menu button to configure the wifi first (i.e. below you enter your Google account password).
  34. CyanogenMod might ask you which Google applications to install. If unsure, select all of them. After you make your selection, CyanogenMod will take you the Market page of all these applications. Accept and install them one by one.
  35. If you don't have a data plan, make sure you configure the phone so it won't accidentally make data transfers.
  36. Reinsert the SIM card. This needs powering off your phone first.

How to install adb and fastboot on Linux

# You might need to use anoter package manager for installation:
$ sudo apt-get install wget unzip
$ wget -O /tmp/linux_adb_fastboot.zip \
  http://android.d3xt3r01.tk/cyanogen/tools/linux_adb_fastboot.zip
$ (cd /usr/local/bin && sudo unzip /tmp/linux_adb_fastboot.zip)
$ sudo killall -9 adb
# This starts the daemon. `sudo' is not necessary on some systems.
$ sudo /usr/local/bin/adb devices

How to upgrade a gen1 phone to gen2 and start ClockworkMod recovery

Don't follow these steps unless you are asked to by another step in this howto.

Please note that these instructions apply only to gen1 (1st generation) ZTE Blade models. Doing it on any other phone (i.e. on a gen2 ZTE Blade or any phone other than a ZTE Blade) will most probably make the device useless beyond repair. You can use the Ask Mr Pigfish application (available from the Android Market) to check if you have a gen1 ZTE Blade.

Please note that by following these instructions, not only the configuration and user data, but the operating system will also be removed from the phone. (But the contents of the SD card will remain intact.) To make your (gen2) device useful after these instructions, you should already have an operating system installer ZIP file (e.g. cm.zip above) already on the SD card.

Instructions:

  1. Download the ZIP file Gen1-to-Gen2-TPT-v2.zip from here. The download link can also be found in the section Update to Gen2 Radio of this page.
  2. Unzip the contents of the ZIP file to the SD card, so there should be a folder named image in the root folder of the SD card, and that folder should contain 17 files, from amss.mbn to userdata.img . Make sure that the image folder is in the root folder of the SD card. The easiest way to do this is connecting your phone to the computer using the USB cable, mounting the SD card (using the notification area of the phone), and running a ZIP file extractor on the computer. Disconnect the drive from the computer, and umount the SD card when done.
  3. Make sure the phone is fully charged.
  4. Disconnect the phone from the computer and the charger.
  5. Turn off the phone (by long pressing the power button).
  6. Remove the battery.
  7. Reinsert the battery.
  8. Hold the volume up and menu buttons. Don't release them yet.
  9. (Before doing this, read the next instruction step.) Push the power button to turn the phone on.
  10. Text in green would start appearing on a black background. Release the volume up and menu buttons.
  11. More text in green would start appearing with some indication of progress percentage. Wait for 30 seconds until its done.
  12. The phone boots to ClockworkMod Recovery .

Method two: rooting the phone first

You will need an SD card in the phone.

Outline (see the detailed instructions in the links below):

  1. Make a backup of your data on the phone. (See in method two below.)
  2. Make sure you know your wifi connection credentials (e.g. network name, security type, passphrase).
  3. Make sure you know your Google account name (e-mail address) and password.
  4. Root the phone.
  5. Install the ROM Manager application (from the Android Market).
  6. Install ClockworkMod recovery using the ROM Manager application. (This step needs a rooted phone.)
  7. Download the CyanogenMod update ZIP file (and possibly the Google Apps ZIP file) to the /sdcard.
  8. To prevent data loss below, make sure the phone is fully charged. You can charge it quickly if you connect it to a wall socket instead of a computer.
  9. Remove the SIM card from the phone if you don't have a data plan. This is to prevent the unconfigured CyanogenMod from making expensive data transfers before the wifi is configured. This needs powering off your phone first.
  10. Use the ROM Manager application to start the ClockworkMod recovery.
  11. Within ClockworkMod recovery, wipe the phone.
  12. Within ClockworkMod recovery, install the CyanogenMod update ZIP file (and possibly the Google Apps ZIP file)
  13. Within ClockworkMod recovery, reboot the phone.
  14. CyanogenMod should be booting now. Configure everything for your needs.
  15. If you don't have a data plan, make sure you configure the phone so it won't accidentally make data transfers.
  16. Reinsert the SIM card. This needs powering off your phone first.

All these steps worked for me as explained in detail on the official install CyagnogenMod to ZTE Blade page, except for rooting the phone. That page and also most other web sites instruct the user to reboot the fastboot mode by holding the Volume Up key while powering up the phone. This didn't work for me, because my ZTE Blade had fastboot disabled (so it always booted normally). So I had to find another way to root the phone. The instructions on this page (those containing tinyurl.com/urooted) worked for me. These instructions use a version of the Universal Androot application specialized to the ZTE Blade. Please note that Universal Androot claims that the phone is already rooted — just ignore this message and root it anyway. Please also note that during the installation process you have to re-root the phone using Universal Androot each time you reboot the phone. So if ROM Manager complains that your phone is not rooted, then just run Universal Androot again, and then retry in ROM Manager.

Performance

If the phone feels slow and games are not enjoyable, then tune the performance settings:

  1. Make sure that the latest version of CyanogenMod (at least 7.0.0 without RC in the version number) is installed. Get the newest version of the ZIP file from here. Copy the ZIP file to the (root of the) SD card. Reboot the phone to recovery mode (using adb reboot recovery or the ROM Manager application). In recovery mode, clear the cache and then select the update file (the ZIP file), install it, and reboot the phone.
  2. Make sure that Application / Settings / CyanogenMOD Settings / Performance / Enable surface dithering is off.
  3. In Application / Spare Parts make sure that all animations are disabled.
  4. There seems to be no need for enabling GPU acceleration (debug.sf.hw=1 in /system/build.prop), CyanogenMod seems to be fast without it.

2011-03-25

How to automatically synchronize the shell history between terminal windows

This blog post explains how to automatically synchronize the Unix shell command-line history between multiple shell instances running on the same computer (but possibly different terminal windows), without requiring any manual action (such as running history -w or exiting from the shell) from the user, and also how to make commands be saved to the history file right at the point when the command is executed. The solutions described here work with bash 4.1 (tested with 4.1.5) or newer and zsh (tested with 4.3.4 and 4.3.10), run on Ubuntu Lucid. No attempt was made to synchronize the zsh history and the bash history.

Instructions for zsh

Put (append) this command to your ~/.zshrc and reopen your terminal windows so that the changes take effect:

setopt hist_ignore_dups share_history inc_append_history extended_history

The change takes effect in terminal windows and incoming SSH connections you open from now on. Close your old windows if necessary to avoid confusion. You can also run the source ~/.zshrc to make the change take effect.

Optionally, set your HISTSIZE and SAVEHIST to large enough values, e.g. put HISTSIZE=500000 SAVEHIST=5000000 in your ~/.zshrc.

Once the change took effect, you can start running a command in one terminal window, then just press Enter in another terminal window, then press Up in the other terminal window to get the command running in the other terminal window. Your shell history lines are now synchronized. Synchronization happens whenever you press Enter in a terminal window.

Instructions for bash

Since bash doesn't have the history sharing feature by default, you need to use a helper script for bash. Download it using the following command (without the first $):

$ wget -O ~/merge_history.bash http://raw.github.com/pts/pts-merge-history-bash/master/merge_history.bash

Run

$ touch ~/.merged_bash_history

to signify to the helper script that you want to use the new history feature.

Put (append) this to your ~/.bashrc so the helper script gets loaded at shell startup:

source "$HOME"/merge_history.bash

Optionally, set HISTSIZE and HISTFILESIZE to large enough values, e.g. append the following to your ~/.bashrc:

HISTSIZE=500000 HISTFILESIZE=5000000

The change takes effect in terminal windows and incoming SSH connections you open from now on. Close your old windows if necessary to avoid confusion. You can also run the source command above to make the change take effect.

Once the change took effect, you can start running a command in one terminal window, then just press Enter in another terminal window, then press Up in the other terminal window to get the command running in the other terminal window. Your shell history lines are now synchronized. Synchronization happens whenever you press Enter in a terminal window.

If you want your old shell history to be reused, please copy it any time, and then press Enter:

cp ~/.bash_history ~/.merged_bash_history

Explanation of the bash solution

Bash doesn't have support for manual or automatic synchronization of history files. By default, bash reads the history file ~/.bash_history (can be changed by setting the HISTFILE bash special variable) at startup, adds newly executed commands to its in-memory history buffer, and simply writes (or appends) the contents of the buffer to the history file upon clean exit. With this strategy, commands can be lost for good if the shell is killed with kill -9, or multiple shells are exiting (the last one wins, lines from all previous ones get irrecoverably lost). It's possible to affect this behavior with shopt -s histappend to force appending instead of overwriting, but that's still much less synchronization with command sorting by timestamp. The commands history -w, history -a history -c and history -r can be useful for managing the bash history files, but they may still cause data loss (see above).

To solve these problems, the helper script merge_history.bash above uses the following techniques:

  • It uses HISTTIMEFORMAT bash special variable to make sure timestamps are saved into the history file.
  • It contains a Perl script to merge history files (possibly created by concurrently running bash instances), sorting the results by timestamp and removing duplicates.
  • Before displaying the prompt (using the PROMPT_COMMAND bash special variable) loads the merged history file from disk.
  • When the user presses Enter to run a command, before the command is executed, it saves the in-memory history buffer to a file, and merges that file using the Perl script to the merged history file. It uses trap ... DEBUG (and various black magic trickery) to install its hook before the command is executed. Other solutions for bash history synchronization don't use this technique, so they suffer from the shortcoming of saving the most recently executed command too late (only when it finishes).
merge_history.bash was inspired by the bash preexec emulation script.

Get the most recent version of merge_history.bash from http://raw.github.com/pts/pts-merge-history-bash/master/merge_history.bash . For your studying convenience, here is an outdated copy:

MRG_DONEI=":$SHELLOPTS:"
if test "${MRG_DONEI#*:history:}" != "$PTS_DONEI" &&
   (test "${BASH_VERSION#[5-9].}" != "$BASH_VERSION" ||
    test "${BASH_VERSION#4.[1-9].}" != "$BASH_VERSION") &&
   test "$HOME" &&
   test -f "$HOME/.merged_bash_history"; then

# Merge the timestamped .bash_history files specified in $@ , remove
# duplicates, print the results to stdout.
function _mrg_merge_ts_history() {
  PERL_BADLANG=x perl -wne '
    use integer;
    use strict;
    use vars qw($prefix @lines);
    if (/^#(\d+)\n/) {
      $prefix = sprintf("%030d ", $1);
    } else {
      chomp; $prefix = sprintf("%030d ", time) if !defined $prefix;
      push @lines, "$prefix$_\n"; undef $prefix;
    }
    END {
      my $prev = "";
      for (sort @lines) {
        s@^(\d+) @@; my $ts = $1 + 0; my $cur = "#$ts\n$_";
        print $cur if $cur ne $prev;
        $prev = $cur;
      }
    }
  ' -- "$@"
}

# Read history from $HISTFILE_MRG, 
function _rdh() {
  test "$HISTFILE_MRG" || return
  local HISTFILE="$HISTFILE_MRG"
  # Make `history -w' prefix "$TIMESTAMP\n" to $HISTFILE
  local HISTTIMEFORMAT=' '
  history -c  # Clear the in-memory history.
  history -r  # Append the contents of $HISTFILE to the in-memory history.
}

export -n HISTTIMEFORMAT HISTFILE HISTFILE_MRG
unset HISTFILE  # No history file by default, equivalent to HISTFILE="".
unset HISTTIMEFORMAT
HISTFILE_MRG="$HOME/.merged_bash_history"
history -c  # Discard the current history, whatever it was.

function hook_at_debug() {
  test "$COMP_LINE" && return  # Within the completer.
  trap '' DEBUG  # Uninstall debug trap.
  test "$HISTFILE_MRG" || return
  if : >>"$HISTFILE_MRG"; then
    # Make `history -w' prefix "$TIMESTAMP\n" to $HISTFILE
    local HISTTIMEFORMAT=' '
    # TODO(pts): Don't save if nothing changed (i.e. `history -1` prints
    # the same sequence number as before).
    local TMPDIR="${TMPDIR:-/tmp}"
    local HISTFILE="$TMPDIR/whistory.$UID.$$"
    local MHISTFILE="$TMPDIR/mhistory.$UID.$$"
    history -w  # Write to /tmp/whistory.$$ .
    _mrg_merge_ts_history "$HISTFILE_MRG" "$HISTFILE" >"$MHISTFILE"
    command mv -f -- "$MHISTFILE" "$HISTFILE_MRG"
  fi
}

# Set these both so hook_at_debug gets called in a subshell.
set -o functrace > /dev/null 2>&1
shopt -s extdebug > /dev/null 2>&1

# As a side effect, we install our own debug hook. We wouldn't have to do
# that if bash had support for `preexec' (executed just after a command has
# been read and is about to be executed). in zsh.
PROMPT_COMMAND="trap '' DEBUG; _rdh; trap hook_at_debug DEBUG; $PROMPT_COMMAND"

fi  # End of the file's if guard.
unset MRG_DONEI

2011-02-16

How to dump the full /etc/passwd and /etc/group files when NIS (YP) or LDAP is used

This blog post explains how to dump the flattened version of /etc/passwd and /etc/group files on a Unix system when some user and group entries are stored in a NIS (YP), LDAP or other server.

To dump these fules, run the following commands (not as root, without the leading $).

$ getent group  >/tmp/group
$ getent passwd >/tmp/passwd

The equivalent commands in Perl (use them if getent(1) doesn't work for you):

$ perl -le'$,=":";while(@_=getgrent){$_[3]=~y@ @,@;print@_}'  >/tmp/group
$ perl -le'$,=":";while(@_=getpwent){print@_[0,1,2,3,6,7,8]}' >/tmp/passwd

For NIS (YP) users and groups only, one can use ypcat passwd and ypcat group, respectively.

2011-02-01

How to run Syncless on Linux without installing it?

This blog post explains how to run asynchronous, coroutine-based client and server I/O libraries like Syncless, gevent and Concurrence on Linux without installing them.

On Linux, it's possible to try Syncless without installation, using the StaticPython binary Python distribution, like this:

$ wget -O stacklessco2.7-static \
  https://raw.githubusercontent.com/pts/staticpython/master/release/stacklessco2.7-static
$ chmod +x stacklessco2.7-static
$ ./stacklessco2.7-static
Python 2.7.1 Stackless 3.1b3 060516 (release27-maint, Feb  1 2011, 16:57:16)
[GCC 4.1.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from syncless import coio
>>> coio.sleep(1.5)
(sleeping for 1.5 second)
<object object at 0xf7709490>
>>>

Limitations:

  • This solution requires Linux on x86 (i386) or x86_64 (amd64) architecture. If you have a different Unix system, you have to install Syncless the regular way (e.g. with sudo easy_install syncless).
  • This solution doesn't give you the newest version of Syncless.
  • You can't use Python extensions written in C, except for those compiled into stacklessco2.7-static. See the full list on the StaticPython home page.

Please note that StaticPython can run many other I/O frameworks and libraries, which don't require compiling C extensions. Such libraries include Eventlet, Tornado, Twisted, asyncore and circuits.

2011-01-21

How to implement the C printf function in C++ in a typesafe way?

This blog post explains how to implement the C printf() function in C++ in a typesafe and convenient way.

The most important advantage of the ANSI standard C printf() function are its compactness and expressive power. For example: printf("The %s answer is %05d.\n", "best", 42); means: take the next argument, treat it as a null-terminated string (const char*), and insert it. The format specifier %05d means: take the next argument as a signed integer, pad it with leading zeros to at least 5 digits, and insert it. Please note that printf() is not typesafe: the format specifier has to match the type of the argument. For example, %d wouldn't work for a long long (but %lld would be needed), and %d or %s wouldn't work for a double (but %g would be needed, and %Lg would be needed for a long double). On a mismatch, some compilers would indicate a compile error, others would generate misbehaving (i.e. with undefined behavior) code.

There is no equally expressive message formatting functionality in C++ with a similarly compact syntax. Of course, printf() as it is can be used in C++, but it isn't integrated conveniently with the C++ standard library: e.g. it's not possible to insert an std::string, it's not possible to write to an std::ostream, and it's not possible to append to an existing std::string. C++ streams (e.g. cout << "The " << "best" << " answer is " << 42 << ".\n";) bring type safety (e.g. no matter which integer, floating point or string type 42 and other arguments have, they will be inserted properly), but they don't provide compact and powerful formatting capabilities (e.g. how to specify to pad 42 with zeros to at lest 5 digits).

Would it be possible to combine the compactness and expressive power of printf() with the typesafe behavior of C++ streams? It isn't too hard to create a class named Print and implement an overloaded operator<< so that Print("The %s answer is %05d.\n") << "best" << 42 would work in a typesafe way (raising a run-time error reliably if the type of the argument doesn't match the format specifier, and converting the the size and type of the argument if needed, e.g. %d would work for both int and long long). But is it possible to do it while keeping the original syntax, like this: Printf("The %s answer is %05d.\n", "best", 42);?

Yes, that's possible, using two tricks: overloading operator, (the comma operator), and using a GCC feature of macro expansion with any number of arguments. The macro Printf would expand so that Printf("The %s answer is %05d.\n", "best", 42); expands to (C("The %s answer is %05d.\n"), "best", 42);, which is equivalent to operator,(operator,(C("The %s answer is %05d.\n", "best"), 42);. Here C is a helper class, who has a constructor C(const char* fmt) for the format string, and the relevant const C& operator,(const C&, const char*) and const C& operator,(const C&, int) comma operators are overloaded to do the actual printing, consuming a few more characters in the meantime from the format string, and using that format specifier to format the argument. Type safety is provided by the built-in overloading features of the C++ language (i.e. a different operator, is called based on the type of the argument).

One more trick is needed to get an compile-time error when printing of values of unsupported type is attempted, e.g. class Bad {}; Printf("%s", Bad());. By default, since there is no operator, overridden for the class Bad, the default comma operator is used silently, which is quite useless (compute the first argument, discard it, compute the second argument, return it), and effectively prevents the rest of the arguments from being printed. The solution here is to define template<typename T>void operator,(const C&, T t) { ... }, which would match all types (which are not matched by the non-template version of operator,), and if we write ... so that it produces a type error, then the problem is solved.

The source code of such a typesafe printf() implementation for C++ is available at http://code.google.com/p/pts-mini-gpl/source/browse/#svn/trunk/pts-printf. For the convenience of the programmer, it implements all these:

int Printf(const char* fmt, ...);  // To stdout.
int Printf(FILE*, const char* fmt, ...);
int Printf(std::ostream&, const char* fmt, ...);
int Printf(std::ostringstream&, const char* fmt, ...);
int Printf(std::ofstream&, const char* fmt, ...);
int Printf(std::string*, const char* fmt, ...);  // Append to string.
std::string SPrintf(const char* fmt, ...);

Please note that the implementation is not optimized for speed. Most probably it's not possible to implement a typesafe version of printf() which is also as fast.