Monday, February 28, 2011

pancake syrup

When I am making pancakes, sometimes I like to have brown sugar syrup with them, it is also much cheaper to make pancake syrup from scratch than to buy it from the grocery store.

mix 1 cup brown sugar
and 2 cups water

boil for 25 minutes.

add vanilla.

That's all there is to that one.

Monday, February 21, 2011

console input in java

I wrote up a sample of nice and clean console input with validation, and repeated prompting on invalid inputs.

package org.yi.happy.console;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class DemoInput {
    /**
     * A demo of prompting for and reading validated data from standard input.
     */
    public static void main(String[] args) {
        try {
            /*
             * get a usable line reader.
             */
            BufferedReader in = new BufferedReader(new InputStreamReader(
                    System.in));

            /*
             * the result of the read loop
             */
            String word = null;
            /*
             * keep going until we get what we want
             */
            while (true) {
                /*
                 * ask the question
                 */
                System.out.print("enter a word: ");
                /*
                 * get the answer
                 */
                String line = in.readLine();
                /*
                 * is the answer what we want?
                 */
                if (line.matches("\\w+")) {
                    /*
                     * save the answer and done
                     */
                    word = line;
                    break;
                } else {
                    /*
                     * report a bad answer and repeat
                     */
                    System.out.println("that does not look like a word: "
                            + line);
                    continue;
                }
            }

            /*
             * the result of the read loop
             */
            double number = 0;
            /*
             * keep going until we get what we want
             */
            while (true) {
                /*
                 * ask the question
                 */
                System.out.print("enter a number: ");
                /*
                 * get the answer
                 */
                String line = in.readLine();
                /*
                 * parse the answer
                 */
                try {
                    number = Double.parseDouble(line);

                    /*
                     * range checks can go here (on failure do a continue, on
                     * accept do a break)
                     */

                    /*
                     * it was good, done
                     */
                    break;
                } catch (NumberFormatException e) {
                    /*
                     * it was not good, report the bad answer and repeat
                     */
                    System.out.println("that does not look like a number: "
                            + line);
                    continue;
                }
            }

            /*
             * if we get here we have two good answers.
             */

            /*
             * do something using the input
             */
            System.out.println("the word was " + word + " and the number was "
                    + number);

        } catch (IOException e) {
            /*
             * there was an error, so display it and give up
             */
            e.printStackTrace();
        }

    }
}

I don't think I can make it any simpler and still repeat the prompting for input until valid input is given. If there were many inputs being done I could break the logic out into an instance of the template pattern.

Sunday, February 20, 2011

all sub-sets of a set in java

I was offered the challenge to find all the sub-sets of a set, represented as an ordered list, using java.

I know a list isn't really a set, but it is the same idea in the end, since the elements are not repeated, also the non-recursive implementation I came up with would work equally well with sets as lists.

I started with a recursive implementation, and later found a non-recursive implementation with the same output.

First I made some tests to show what was going to happen.

package org.yi.happy.subset;

import static org.junit.Assert.assertEquals;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.junit.Test;

public class FindSubsetsTest {
    @Test
    public void testFindAll() {
        List<Integer> in = Arrays.asList(0,1,2,3);
        
        List<List<Integer>> have = FindSubsets.findAll(in);
        
        List<List<Integer>> want = new ArrayList<List<Integer>>();
        want.add(new ArrayList<Integer>());
        want.add(Arrays.asList(3));
        want.add(Arrays.asList(2));
        want.add(Arrays.asList(2, 3));
        want.add(Arrays.asList(1));
        want.add(Arrays.asList(1, 3));
        want.add(Arrays.asList(1, 2));
        want.add(Arrays.asList(1, 2, 3));
        want.add(Arrays.asList(0));
        want.add(Arrays.asList(0, 3));
        want.add(Arrays.asList(0, 2));
        want.add(Arrays.asList(0, 2, 3));
        want.add(Arrays.asList(0, 1));
        want.add(Arrays.asList(0, 1, 3));
        want.add(Arrays.asList(0, 1, 2));
        want.add(Arrays.asList(0, 1, 2, 3));

        assertEquals(want, have);
    }

    @Test
    public void testFindAllFlat() {
        List<Integer> in = Arrays.asList(0, 1, 2, 3);

        List<List<Integer>> have = FindSubsets.findAllFlat(in);

        List<List<Integer>> want = new ArrayList<List<Integer>>();
        want.add(new ArrayList<Integer>());
        want.add(Arrays.asList(3));
        want.add(Arrays.asList(2));
        want.add(Arrays.asList(2, 3));
        want.add(Arrays.asList(1));
        want.add(Arrays.asList(1, 3));
        want.add(Arrays.asList(1, 2));
        want.add(Arrays.asList(1, 2, 3));
        want.add(Arrays.asList(0));
        want.add(Arrays.asList(0, 3));
        want.add(Arrays.asList(0, 2));
        want.add(Arrays.asList(0, 2, 3));
        want.add(Arrays.asList(0, 1));
        want.add(Arrays.asList(0, 1, 3));
        want.add(Arrays.asList(0, 1, 2));
        want.add(Arrays.asList(0, 1, 2, 3));

        assertEquals(want, have);
    }
}

And the implementation, with implementation notes in it.

package org.yi.happy.subset;

import java.util.ArrayList;
import java.util.List;


public class FindSubsets {

    /**
     * Find all the subsets of in, recursively.
     * 
     * @param <T>
     *            the type of item items in the set.
     * @param in
     *            the set to get subsets off.
     * @return the list of subsets of in. The order is the same as doing binary
     *         counting with the least significant digit on the right.
     */
    public static <T> List<List<T>> findAll(List<T> in) {
        /*
         * we can do this recursively, we either exclude or include the first
         * item, and join all the deeper subsets to it.
         */

        if (in.size() == 0) {
            /*
             * the base case is just the empty set.
             */
            List<List<T>> out = new ArrayList<List<T>>();
            out.add(new ArrayList<T>());
            return out;
        }

        List<List<T>> out = new ArrayList<List<T>>();

        T first = in.get(0);
        List<List<T>> rest = findAll(in.subList(1, in.size()));

        /*
         * first all the sets excluding the first item
         */
        for (List<T> r : rest) {
            out.add(r);
        }

        /*
         * next all the sets including the first item
         */
        for (List<T> r : rest) {
            List<T> s = new ArrayList<T>();
            s.add(first);
            s.addAll(r);
            out.add(s);
        }

        return out;
    }

    /**
     * Find all the subsets of in, non-recursively.
     * 
     * @param <T>
     *            the type of item items in the set.
     * @param in
     *            the set to get subsets off.
     * @return the list of subsets of in.
     */
    public static <T> List<List<T>> findAllFlat(List<T> in) {
        List<List<T>> out = new ArrayList<List<T>>();
        out.add(new ArrayList<T>());

        for (T i : in) {
            List<List<T>> next = new ArrayList<List<T>>();
            for (List<T> j : out) {
                next.add(j);

                List<T> k = new ArrayList<T>(j);
                k.add(i);
                next.add(k);
            }
            out = next;
        }

        return out;
    }

}

It was not much harder than counting binary to make this list, I gave up on adding the restriction where the resulting lists of lists should be sorted.

Sunday, February 6, 2011

HTTP subversion access

The objective is restore the subversion repository URL space from my old web site. This will require making some subversion repositories available over HTTP using Apache 2.2. Authentication is required only for updates. Access to the repositories should be configured in the virtual host, and not globally.

The environment for the directions is Ubuntu 10.10 (Maverick Meerkat) Desktop freshly installed and updates done.

This example is for exposing multiple repositories under /svn in the URL space of a virtual host.

Install apache with the subversion module, and subversion:
sudo apt-get install apache2 libapache2-svn subversion

Make a home for the physical subversion repositories.
sudo mkdir /var/svn

And create a few repositories accessable to the web server:
sudo svnadmin create /var/svn/repos
sudo chown -R www-data:www-data /var/svn/repos
sudo svnadmin create /var/svn/repos2
sudo chown -R www-data:www-data /var/svn/repos2

create some users for authenticaton
sudo touch /var/svn/passwd
sudo htpasswd -bm /var/svn/passwd user1 pass1
sudo htpasswd -bm /var/svn/passwd user2 pass2

create the access control file /var/svn/access
[repos:/]
user1 = rw
* = r

[repos2:/]
user1 = rw
user2 = r
* =

Create a virtual host by creating /etc/apache2/sites-available/demo.local:
<VirtualHost *:80>
ServerName demo.local
ErrorLog ${APACHE_LOG_DIR}/demo.local-error.log
CustomLog ${APACHE_LOG_DIR}/demo.local-access.log combined

<Location /svn>
DAV svn
SVNParentPath /var/svn
SVNAutoVersioning On
AuthzSVNAccessFile /var/svn/access
Satisfy Any
Require valid-user
AuthType Basic
AuthName "Subversion repository"
AuthUserFile /var/svn/passwd
</Location>

</VirtualHost>

enable the virtual host
sudo a2ensite demo.local
sudo /etc/init.d/apache2 reload

At this point the repositories are available on the web server, and can be mounted using WebDAV. Extra details are in the SVN red book.

better mp4 conversion

Since I am using a Mac, it is sometimes good to convert videos that the stock player can not play into a format that it can play, for instance wmv to mp4, since wmv files can not be played by quicktime or the finder preview, VLC plays them instead.

Today I was looking at quality settings and found a tip on setting the output quality in ffmpeg.

My new script that converts all the files given on the command line to mp4 format is
#!/bin/bash
[ "$1" ] || {
  echo use: $0 file...
  exit 0
}

for file in "$@"; do
  ffmpeg -i "$file" -acodec libfaac -vcodec mpeg4 -qmax 8 "$file.mp4"
done

Lower numbers for -qmax are higher quality and larger file sizes.

Friday, February 4, 2011

minimal asterisk install

The objective is to do as little as possible to setup an asterisk server running and be able to accept a call from a sip client. The sip client is running on the same network as the server.

The environment is Ubuntu 10.10 (Maverick Meerkat) Desktop freshly installed and updates done.

Firstly, install asterisk:
sudo apt-get install asterisk
being in Canada my telephone country code is 1

Second, add a demo sip device by adding these lines to /etc/asterisk/sip.conf:
[user-01]
type=friend
context=demo
secret=test
qualify=yes
host=dynamic

Finally, reload the sip configuration
sudo asterisk -rx ‘sip reload’

Now you can connect with a sip client, such as Telephone for Mac

the settings in this example are:
Domain: test-server.local
User Name: user-01
Password: test

Dial s or 1000 to activate the demo.