javahacker.com

The Java Hacker – Peter Jaric's Blog

Meeting Notes #1

I often draw something when I attend meetings at work. It helps me concentrate and it’s fun. I’ll upload some of these drawings here. Here’s the first one:

Fun with JavaScript: count parentheses

Yesterday, I wrote a JavaScript function that returned another function. At one place I wanted to call the returned function immediately, resulting in code looking somewhat like this:

someFunction()()

When seeing that code, I asked myself: would it be possible to count the (pairs of) parentheses? After tinkering a bit, I first came up with (as much whitespace as possible cut away to make it fit into a tweet):

function c(a){function b(){return c(arguments.callee.count)};b.count=1+~~a;return b;}

Then I removed the unnecessary use of arguments.callee:

function c(a){function b(){return c(0-~a)};b.count=0-~a;return b}

Finally I wanted replace the function name c with something looking like a pair of parentheses, and with the help of Mathias Bynens (@mathias) and Gareth Heyes (@garethheyes) I arrived at this:

function ᑕᑐ(a){function b(){return ᑕᑐ(-~a)};b.count=1-~a;return b}ᑕᑐ.count=1;

After running that code, it is now possible to do (this is from the Firebug console):

>>> ᑕᑐ.count
1
>>> ᑕᑐ()().count
3
>>> ᑕᑐ()()()()().count
6

Yes, I know, ᑕᑐ doesn’t really look like parentheses…

Citerus Programming Challenge at JFokus 2011

The company Citerus held a programming competition at the JFokus 2011 developer conference. I was one of the more than 100 contestants. Read more about it at http://www.citerus.se/post/vinnare (in Swedish).

I have included both the winning solution from Carin Lidberg and my own solution below. They are quite different :)

The winning solution:

public class CiterusChallenge {
  static String[] substrings =
    {"TDD", "DDD", "DI", "DO", "OO", "UI",
     "ANT", "CV", "IOC", "LOC", "SU", "VO"};

  public static void main(String[] args) {
    System.out.println(removeSubstringsToTheRight(
        "VOCDIITEIOCRUDOIANTOCSLOIOCVESTAIOCVOLIOCENTSU", 0));
  }

  public static String removeSubstringsToTheRight(String s, int start) {
    int minimum = s.length();
    String result = s;
    for (String substr : substrings) {
      int i = s.indexOf(substr);
      while (i >= 0) {
        if (i + substr.length() > start) {
          String newString = s.substring(0, i) +
                s.substring(i + substr.length());
          newString = removeSubstringsToTheRight(newString, i);
          if (newString.length() < minimum) {
            minimum = newString.length();
            result = newString;
          }
        }
        i = s.indexOf(substr, i + 1);
      }
    }
    return result;
  }
}

And here is my solution. The shortenString method was recursive up to before this version, but I finally made it iterative for performance reasons.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * This class attempts to solve the Citerus JFokus 2011 Challenge
 * (http://www.citerus.se/jfokus).
 *
 * Run this program like this:
 * java Shortener   [ [...]]
 *
 * The example input given in the challenge is:
 *
 * The string we want to shorten:
 * VOCDIITEIOCRUDOIANTOCSLOIOCVESTAIOCVOLIOCENTSU
 * Words that can be removed:
 * TDD, DDD, DI, DO, OO, UI, ANT, CV, IOC, LOC, SU, VO
 *
 * The algorithm basically does an exhaustive search for all possible
 * ways to remove the given words from the input string, but with a few
 * optimizations (all timings based on a few test runs on my computer):
 *
 * 1) Cache
 * Before trying to remove words we check if it is already done for
 * this particular substring. If it is, we just skip it.
 *
 * 2) Divide and conquer
 * The input string might contain characters that can not be removed since
 * they do not exist in any of the words. We can used these characters as
 * delimiters between which we can extract substrings to shorten, one at a
 * time. This optimization can be very effective if the input string has
 * such characters. Compared to the version above, this runs about
 * 35 - 40 times faster on the example input (~2.3ms vs ~85ms).
 *
 * There is at least one more optimization that could be added (in a future
 * version), however it wouldn't have any effect on the example input, since
 * it doesn't meet the requirements:
 *
 * 3) Safely removable words
 * Words that do not overlap with themselves or any other words (DO and OO
 * overlap, IOC and LOC does not) can always be removed directly from a
 * string that is about to be shortened. This is because of that since no
 * other word may remove characters from substrings that match these
 * non-overlapping words (NOWs) the substrings will stay in the string until
 * they are removed by the NOW, even far down in the search tree. Cutting
 * them out directly will make the search tree smaller and the search quicker.
 *
 * Known issues:
 * For large inputs the algorithm will take quite some time.
 * For very large inputs the VM will run out of heap space.
 *
 * CAVEAT:
 * This class does not attempt to be general in any other way than that it
 * accepts different inputs. Specifically, it isn't meant to be subclassed
 * or used from other code and hence it is put in the default package for
 * simplicity. For the same reasons it contains a main method.
 *
 * @author Peter Jaric

 * @version 6
 */
public class Shortener {
  /**
	 * Words that can be removed.
	 */
	private String[] allWords;

	/**
	 * Creates a Shortener that can be run on different input strings
	 * with the given words.
	 *
	 * @param words to remove from strings
	 */
	public Shortener(String[] words) {
		this.allWords = words;
	}

	/**
	 * Finds the shortest string possible by removing this Shortener's words
	 * in the most advantageous order.
	 *
	 * @param input The string to shorten
	 * @return The shortest possible string
	 */
	public String shorten(String input) {
		// Implementation of the divide and conquer optimization follows:

		// Find all possible characters that can be removed by
		// simply concatenating all words
		String possibleChars = "";
		for (String word : allWords) {
			possibleChars += word;
		}

		// Create a (quite ugly) regexp that matches possible removals
		Pattern p = Pattern.compile("[" + possibleChars + "]+");

		// Start matching on the input string
		String todo = input;
		Matcher m = p.matcher(todo);
		String done = "";

		// For each match of possible removals, shorten it and save it
		while (m.find()) {
			// Find the match
			String match = m.group();

			// Add the shortened match together with any possible non-matching
			// stuff before it to what we have done already
			done += todo.substring(0, m.start()) + shortenString(match);

			// Shorten the todo string with what we already have done.
			todo = todo.substring(m.end());

			// Tell the matcher to use the todo string in next iteration
			m.reset(todo);
		}

		// There might be some unmatchable stuff left at the end. Add it
		// if so.
		if (!todo.equals("")) {
			done += todo;
		}

		// End of implementation of the divide and conquer optimization

		return done;
	}

	/**
	 * Finds the shortest string possible by removing this Shortener's words.
	 *
	 * @param input The string to shorten
	 * @return The shortest possible string
	 */
	private String shortenString(String input) {
	  // The list of strings to process, i.e. to
	  // shorten. We are using an ArrayList for
	  // performance reasons.
	  List toProcess = new ArrayList();

    // Set to hold strings that we have added to the list.
    // Note that all strings will go here, even those
    // that can not be shortened further.
	  // This implements the cache optimization.
    HashSet seen = new HashSet();

    // String builder to use for removing words inside strings
    StringBuilder sb = new StringBuilder();

    // Index of the current string to process.
    int marker;

    // Seed the list with the input string
    toProcess.add(input);
    seen.add(input);
    marker = 0;

    // Work through all strings in the queue until all are
    // processed. Shorter strings will be added to the list as we
    // go along.
    while (marker < toProcess.size()) {
      // Get the string to process.
      String current = toProcess.get(marker);
      // Move the marker one step forward.
      marker++;

      // Loop through all ways of shortening the string
      // by removing one of the words.
      for (String word : allWords) {
        // Loop through all matches for the word in the input string, remove
        // the word, and add the result to the list.
        for (int i = current.indexOf(word); i != -1; i = current.indexOf(word, i + 1)) {
          // Remove the word
          sb.append(current.substring(0, i));
          sb.append(current.substring(i + word.length()));
          String shorter = sb.toString();

          // If the shorter string hasn't already been
          // seen, add it to the list.
          if (!seen.contains(shorter)) {
            seen.add(shorter);
            toProcess.add(shorter);
          } 

          // Clear the string builder for the next loop.
          sb.setLength(0);
        }
      }
    }

    // Loop through all strings that have been
    // processed and select the shortest one.
    // Start with the longest one.
    String shortest = input;
    for (String current : seen) {
      if (current.length() < shortest.length()) {
        shortest = current;
      }
    }
    return shortest;
	}

	/**
	 * Main method...
	 */
	public static void main(String[] args) {
		// Check arguments
		if (args.length < 2) {
			System.err.println("Too few arguments.");
			System.exit(1);
		}

		// Extract input string and words from arguments
		String input = args[0];
		String[] words = Arrays.copyOfRange(args, 1, args.length);

		// Create Shortener, shorten string and print result
		Shortener shortener = new Shortener(words);
		String shortest = shortener.shorten(input);
	}
}

Fixing a mistake in auto-opening settings in Chrome

When I was going to open a Spotify link in Google Chrome and the browser asked me if I wanted to open it or not, I checked the “Remember my decision” check box and then clicked “Do not open”, by mistake. And due to Google Chrome’s lack of customization, I could not find where to fix this issue in the options dialog.

But some googling finally led me to this clue. I closed Chrome and opened my LocalState file that I found in C:Users_user_name_AppDataLocalGoogleChromeUser Data (Windows 7). I searched for spotify and found this entry:

 "protocol_handler": {
      "excluded_schemes": {
         "afp": true,
         "data": true,
         "disk": true,
         "disks": true,
         "file": true,
         "hcp": true,
         "javascript": true,
         "mailto": false,
         "ms-help": true,
         "news": false,
         "nntp": true,
         "shell": true,
         "snews": false,
         "spotify": true,
         "vbscript": true,
         "view-source": true,
         "vnd": {
            "ms": {
               "radio": true
            }
         }
      }
   }

I changed the spotify value to false and after reopening Chrome I now can open Spotify links!

Edit settings for screensavers in gnome-screensaver

In newer versions of Ubuntu (and Linuxes) xscreensaver has been replaced with gnome-screensaver. The same screensavers are supported (with some exceptions, I guess), but there is one thing that is lacking: per-screensaver configuration. The author of gnome-screensaver thinks that this is not needed.

There are some ways to get around this, among them: replace gnome-screensaver with xscreensaver (this has some side-effects that may not be desired) or install xscreensaver alongside gnome-screensaver.

If you are comfortable with editing configuration files and reading man pages I would recommend the following way: find and edit the desktop file of each screensaver you want to configure, using the screensaver’s command line options.

Find out where the desktop files are located, read the man page and then edit the desktop file.

Customize Saved Searches in Thunderbird

I use Mozilla Thunderbird exclusively as my email client. One feature Thunderbird offers is Saved Searchs. I use it to create a virtual folder “Unread Mail” that shows all my unread mail that is not junk. To do this I have selected the options “Status isn’t Read” AND “Junk Status isn’t Junk”.

My main use for this folder is to keep mail I haven’t handled yet in view. I mark these mails as unread and take care of them later. Now and then I mark some mails as unread by mistake and they disappear from my virtual folder, which isn’t very good. To fix this I decided to mark all mails I want to keep as starred. Then I wanted to change my virtual folder so that it displays mail that match (“Status isn’t Read” OR “Status is Flagged”) AND “Junk Status isn’t Junk”. This is not possible in Thunderbird’s interface, though. You can only select “Match any of the following” or “Match all of the following”.

I looked around a little in the configuration files (I found them in $HOME/.thunderbird) and found a file virtualFolders.dat! And by simply setting the terms property to the correct value solved my problem, like this:

terms=AND (junk status,isn’t,2) AND (status,isn’t,read) OR (status,is,flagged)

If you want to try something like this, remember to close Thunderbird before you edit the file. And make a backup of virtualFolders.dat first!

Update

When I tried to repeat this on my computer at work, I failed at first. The best way seems to be to create a saved search folder from within Thunderbird that matches the one you want to end up with as much as possible. In my case I made one that matched my desired terms with the exception that the OR was an AND (“Match all of the following”) and then I simply changed that AND to an OR in virtualFolders.dat.

Playing Swedish Scrabble? Boggle?

If you’re playing Scrabble in Swedish with your friends, you will get invaluable help from my friend Jonatan‘s new web application: ordlista.org. There you can check whether a word is valid when playing Scrabble, or just browse through words for fun. It has helped us in numerous Scrabble and Boggle games.

Good gaming!

“Connection problem or invalid MMI code” on Android phone

We have got a new cell phone operator at work and one of their features is that if you prefix a number with the code *150# the call will be charged to a separate bill that will be sent to the employee and not to the employer. This is quite common in Sweden and is of course a good thing, but it doesn’t work on Android (pre 2.1). I use an HTC Tattoo and get this message when calling for example *150#0123456789:

Connection problem or invalid MMI code

In the thread I linked to above, there is a workaround: put a plus sign (+) before the first digit, like so: *+150#0123456789. This gets rid of the error message and allows the call to go through. The number that is called according to the phone has no plus in it: *150#0123456789

Let’s hope this works. Otherwise I might get a call from my boss later on :)

Update:
I mailed Ventelo’s (the operator) support and received this positive answer (translated by me):

Yes, using *+150# will work as well.

Good news, in other words!

Aardvark and answers that do not answer the question

Recently Google announced that they have acquired Aardvark, a service that finds the right person to answer any question you might have. I’ve used it frequently for a little while, and while I think it is a very cool idea and answering questions is quite addictive, I think there is a problem with the quality of the answers to my questions.

It is very common to get answers from people who really do not know the correct answer, but use Google to find something related to the question. I understand that, because it is very tempting to try to answer as many questions as possible, but it isn’t very helpful in the end, because there might be someone more qualified to answer out there.

To raise the quality of answers to my questions I will try to include something in my questions to make casual answerers avoid them. I am thinking of a good phrasing to not sound too arrogant but at the same time fulfill my goal. I think I’ll try something along the lines of “Please only answer if you really do know the answer to this specific question! I have already googled for answers myself. Thanks!!!”

I wonder if that will work or if I from now on will get no answers at all :)

Matching combined results in jQuery – ordered correctly

Today I used the “selector1, selector2, selectorN” selector in jQuery and was confused that, in some cases, when looping over the results I got them in the order of the selectors and not in the order of the elements in the page. I had expected it to work as an OR operator. My code looked like this:

var headers = $('h1,h2,h3', context);
headers.each(function(index) { ... });

First my function was called for all h1s, then for all h2s, etc, regardless of their ordering in the page. Some googling finally led me to this solution: first find all headers and then filter out the ones I need. My first try looked like this:

var headers = $(':header', context).filter('h1,h2,h3');
headers.each(function(index) { ... });

It didn’t work, unfortunately. There was no difference. After some reading I finally produced this less elegant but working solution:

var headers = $(':header', context).filter(function() {
	return $(this).is('h1,h2,h3');
});
headers.each(function(index) { ... });

This gave the desired result. The “:headers” selector was very useful for me this particular time, obviously. It needs to be replaced for the particular set of elements one is looking for of course, and if worst comes to worst, maybe ‘*’ is the only solution, even though it probably will have a bad effect on performance.