Mustang Acquired

I’ve always wanted a car like this, so when I saw this one pop up on craigslist I just had to go take a look.

The condition of the car was quite overstated.  It was listed as:

  • A Complete Restoration
  • New OEM Convertible Soft top with new hardware
  • New tires ( all 4)
  • Fresh Paint job
  • 351 Winsor V-8 ( hard to find today) 94k original miles
  • C-6 transmission
  • New OEM complete dashboard

However as soon as I got to looking at the car. The truth came out.  The top and tires are new(ish) and the body paint is in fair (but not great/fresh) condition.  The dash was not OEM and it had a piece cut out for a radio which had been glued back in. The transmission has a leak, there is fluid on the undercarriage the floor pans look like swiss cheese and the brakes hardly have any effect at all.  The interior in general would be better if it were altogether missing .

All that being said I was able to talk the seller down to a reasonable price considering and now its my problem.

This should keep me busy for quite a while.

GWT ScrollPanel for Touch Screens

Getting this working is easier than you think. Basically the only tricky bit is that the touch object allows for multiple fingers they are represented in the array ‘touches[]’. Since we are only scrolling we only need to worry about the first finger which is why I use touches[0].screenY. Enjoy.

package com.peterfranza.gwt.mobileui.client.widgets;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.user.client.ui.ScrollPanel;

/**
 *
 * @author peter.franza
 *
 */
public class TouchScrollPanel extends ScrollPanel {

	private int initialTouchX = -1;
	private int initialTouchY = -1;
	private int initialHorizontalOffset;
	private int initialVerticalOffset;
	private boolean moved = false;

	{
		attachTouch(getElement());
	}

	public TouchScrollPanel(VerticalPanel body) {
		super(body);
	}

	private native void attachTouch(JavaScriptObject ele) /*-{
		var ref = this;
		ele.ontouchstart = function(evt){
	  		evt.preventDefault();
	  		ref.@com.peterfranza.gwt.mobileui.client.widgets.TouchScrollPanel::setInitialTouch(II)(evt.touches[0].screenX, evt.touches[0].screenY);
		}
		ele.ontouchmove = function(evt){
	  		evt.preventDefault();
	  		ref.@com.peterfranza.gwt.mobileui.client.widgets.TouchScrollPanel::doScroll(II)(evt.touches[0].screenX, evt.touches[0].screenY);
		}		
		ele.ontouchend = function(evt){
			evt.preventDefault();
			ref.@com.peterfranza.gwt.mobileui.client.widgets.TouchScrollPanel::setEndTouch(II)(evt.pageX, evt.pageY);
		}		
	}-*/;

	private native void fireClick(int x, int y) /*-{
		var theTarget = $doc.elementFromPoint(x, y);
		if (theTarget.nodeType == 3) theTarget = theTarget.parentNode;

		var theEvent = $doc.createEvent('MouseEvents');
		theEvent.initEvent('click', true, true);
		theTarget.dispatchEvent(theEvent);
	}-*/;


	@SuppressWarnings("unused")
	private void setInitialTouch(int x, int y) {
		initialVerticalOffset = getScrollPosition();
		initialHorizontalOffset = getHorizontalScrollPosition();

		initialTouchX = x;
		initialTouchY = y;
		moved = false;

	}

	@SuppressWarnings("unused")
	private void doScroll(int x, int y) {
		if (initialTouchY != -1) {
			moved = true;
			int vDelta = initialTouchY - y;
			int hDelta = initialTouchX - x;
			setScrollPosition(vDelta + initialVerticalOffset);
			setHorizontalScrollPosition(hDelta + initialHorizontalOffset);
		}
	}

	@SuppressWarnings("unused")
	private void setEndTouch(int x, int y) {
		if (!moved) {
			fireClick(x, y);
		}
		initialTouchX = -1;
		initialTouchY = -1;
	}
}

GWT loading remote JSONP XSS

In almost all browsers there is one thing that everybody wants to do, but you just can’t, Load cross site data. That is you can’t unless you are using JSONP. Basically you load the data into its own script tag tell the server you are loading it from to wrap the data in a callback that you have defined. This will fire an event after the data has loaded. Perfect.

I wanted to use it in GWT … now I can.

package com.peterfranza.gwt.cle.client;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.RootPanel;

public class JSONPLoader {

	private LoaderCallback callback;

	public void load(String jsonUrl, LoaderCallback callback) {
		this.callback = callback;
		String callbackString = "jsonLoad_" +
			DOM.createUniqueId().replace("-", "_") + "_callback";
		String url = jsonUrl + (jsonUrl.contains("?") ? "&" : "?")
			+ "_callback=" + callbackString;
		publishCallbackMethod(callbackString);
		Element fr1 = DOM.createElement("script");		
		fr1.setAttribute("src", url);
		RootPanel.get().getElement().appendChild(fr1);

	}

	private native void publishCallbackMethod(String callback) /*-{
		var ptr = this;
  		$wnd[callback] = function(obj) {
  			ptr.@com.peterfranza.gwt.cle.client.JSONPLoader::loadremotedata(Ljava/lang/String;Lcom/google/gwt/core/client/JavaScriptObject;)(callback, obj);
  		};
	}-*/;

	@SuppressWarnings("unused")
	private void loadremotedata(String cbp, JavaScriptObject obj) {
	  callback.onLoad(new JSONObject(obj));
	}

	public interface LoaderCallback {
		void onLoad(JSONObject object);
	}

}

Usage:

JSONPLoader loader = new JSONPLoader();
loader.load("http://pipes.yahoo.com/pipes/pipe.run?_id=CPreCvz42xG4eaOWouNLYQ&_render=json&location=madison&section=mcy", new LoaderCallback() {

	@Override
	public void onLoad(JSONObject object) {
		Window.alert("loaded " + object.size());
	}
});

Notice that the json url does not specify the _callback parameter, this is because it is added by the JSONPLoader class.

Connecting Apache (httpd) To Active Directory

Recently I went through a small effort to connect a subversion repository to active directory. This is a good thing because it means that you no longer will need to manage the usernames and password using the old htpasswd format. The htpasswd is fine for very controlled environments but the passwords it allows you to use are pretty weak and the encryption of the passwords is fairly weak also, so allowing the connection to happen using active directory as the authority is a good thing. Also it keeps you from having to maintain more passwords, and I like that idea.

In your /etc/httpd/conf.d/filename.conf

LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so

LDAPConnectionTimeout 15

LDAPSharedCacheSize 200000
LDAPCacheEntries 1024
LDAPCacheTTL 600
LDAPOpCacheEntries 1024
LDAPOpCacheTTL 600

  <Location /server/cache-info>
   SetHandler ldap-status
  </Location>

  <Location /svn>
    DAV svn
    SVNPath /subversion/repos
    SVNListParentPath on

    AuthzSVNAccessFile /subversion/svnauthorz
    Satisfy Any
    AuthType Basic
    AuthName "Members Only"
    AuthzLDAPAuthoritative off
    AuthBasicProvider ldap
    AuthLDAPBindDN "svn.user@domain.com"
    AuthLDAPBindPassword "svn.user.password"
    AuthLDAPURL "ldap://<ldapserverip>/DC=domain,DC=com?sAMAccountName?sub?(objectClass=user)"
    Require valid-user
 </Location>

However every couple of transactions I would get an error and this message would appear in my error log

/var/log/httpd/error_log

[Fri Apr 30 09:21:46 2010] [warn] [client 192.168.100.105] [22578] auth_ldap authenticate: user peter.franza authentication failed; URI /svnad/projects/ [ldap_search_ext_s() for user failed][Operations error], referer: http://svn/svnad/projects/

The solution was to disable following referers

/etc/openldap/ldap.conf

REFERRALS off

*Note this is in /etc/openldap/ not the ldap.conf in /etc that file is used from pam authentication and not for mod_ldap

Non-blocking UDP datagram replicator

A class that listens to a UDP port and collects all the datagrams and then rebroadcasts those datagrams to other ports. This is useful for several reasons. I use it when stress testing UDP clients because I can subscribe to 1000 client sockets while only really having a single legitimate datasource.

public class Replicator {
	private final AsyncDatagramServer aserver;

	public Replicator(final int port,
			final Collection<DataSinkPoint> endPoints) throws Exception {
		aserver = new AsyncDatagramServer(port,
				new AsyncDatagramServer.AsyncDatagramServerListener() {

			@Override
			public void recieveDatagram(ByteBuffer buffer) {
				try {
					for(final DataSinkPoint d: endPoints) {
						d.send(buffer.duplicate());
					}
				} catch (final Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	private static class AsyncDatagramServer {

		private boolean running = true;

		public AsyncDatagramServer(final int port,
				final AsyncDatagramServerListener listener) throws Exception {

			new Thread(){

				@Override
				public void run() {
					try {
						startSocket(port, listener);
					} catch (final Exception e) {
						throw new RuntimeException(e);
					}
				}

			}.start();

		}

		public interface AsyncDatagramServerListener {
			void recieveDatagram(ByteBuffer buffer);
		}

		public void shutdown() {
			running = false;
		}

		private void startSocket(final int port,
				AsyncDatagramServerListener listener) throws IOException,
				SocketException, ClosedChannelException, Exception {
			DatagramChannel serverChannel = DatagramChannel.open();
			Selector selector = Selector.open();
			DatagramSocket sock = serverChannel.socket();
			sock.setReuseAddress(true);
			sock.bind (new InetSocketAddress (port));
			serverChannel.configureBlocking (false);
			serverChannel.register(selector, SelectionKey.OP_READ);
			ByteBuffer buffer = ByteBuffer.allocate(2048);

			while (running) {
				if(selector.select(500) > 0) {
					processData(listener, selector, buffer);
				}
			}

			selector.close();
			serverChannel.close();
		}

		private void processData(AsyncDatagramServerListener listener,
				Selector selector, ByteBuffer buffer) throws Exception {
			Iterator<SelectionKey> it = selector.selectedKeys().iterator();

			while (it.hasNext()) {
				final SelectionKey key = it.next();

				if (key.isReadable()) {
					DatagramChannel channel =
						(DatagramChannel) key.channel();
					buffer.clear();
					if (channel.receive(buffer) != null) {
						buffer.flip();
						listener.recieveDatagram(buffer.duplicate());
					}
				}
				it.remove();
			}
		}



	}

	public void shutdown() {
		aserver.shutdown();
	}

	public interface DataSinkPoint {
		void send(ByteBuffer buffer) throws IOException;
	}

	private static class DataSinkPointImpl implements DataSinkPoint {
		private final DatagramSocket socket;

		public DataSinkPointImpl(SocketAddress address) throws Exception {
			socket = new DatagramSocket();
			socket.connect(address);
		}

		@Override
		public void send(ByteBuffer buffer) throws IOException {
			socket.send(new DatagramPacket(buffer.array(),
					0, buffer.limit()));
		}

	}

}

Usage:

public static void main(String[] args) throws Exception {
	Collection<DataSinkPoint> endPoints = new ArrayList<DataSinkPoint>();
	for(int i = 4000; i < 5000; i++) {
		endPoints.add(new DataSinkPointImpl(
				new InetSocketAddress("127.0.0.1", i)));
	}

	final Replicator r = new Replicator(3000, endPoints);
	Thread.sleep(5000);
	r.shutdown();
	System.out.println("done.");
}