Use MySQL with Erlang

If you want to get your manager to try out Erlang, but they are hesitant (probably an understatement) you might be able to get some leverage if you use a relational database rather than mnesia. So, here's a quick sample of how to connect to and query a MySQL database.

First, you'll need to install the MySQL ODBC driver if you haven't already. You can find it at http://dev.mysql.com/downloads/connector/odbc/5.1.html. Then you'll need a database to connect to and a table to query. Here's the SQL script I used to create my test database:

CREATE DATABASE `test`;

CREATE TABLE `test`.`test_table`
(
  `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  `first_name` VARCHAR(45) NOT NULL,
  `last_name` VARCHAR(45) NOT NULL,
  PRIMARY KEY (`id`)
)
ENGINE = InnoDB;

INSERT INTO `test`.`test_table`
(
  `first_name`,
  `last_name`
)
VALUES
(
  'Matt',
  'Williamson'
),
(
  'Matt',
  'Williamson2'
),
(
  'Matt',
  'Williamson3'
);

And here's the code to connect and query in erlang:

application:start(odbc).
ConnString = "Driver={MySQL ODBC 5.1 Driver};Server=localhost;Database=test; User=root;Password=ace152;Option=3;".
{ok, Conn} = odbc:connect(ConnString, []).
Results = odbc:sql_query(Conn, "SELECT * FROM test_table").

This is what my interactive session looks like:

Erlang (BEAM) emulator version 5.5.5 [async-threads:0]

Eshell V5.5.5  (abort with ^G)
1> application:start(odbc).
ok
2> ConnString = "Driver={MySQL ODBC 5.1 Driver};Server=localhost;Database=test;
User=root;Password=ace152;Option=3;"
.
"Driver={MySQL ODBC 5.1 Driver};Server=localhost;Database=test; User=root;Passwo
rd=ace152;Option=3;"

3> {ok, Conn} = odbc:connect(ConnString, []).
{ok,<0.39.0>}
4> Results = odbc:sql_query(Conn, "SELECT * FROM test_table").
{selected,["id","first_name","last_name"],
          [{1,"matt","williamson"},
           {2,"matt","williamson2"},
           {3,"matt","williamson3"}]}
5>

It's that simple. Post a comment if you want more samples or description.

Erlang docs: http://www.erlang.org/doc/apps/odbc/index.html

New iPhone Apps

I hit the App Store last night to find a new game in the number one spot that I hadn't seen before. It's called Space Deadbeef (as in the hex number). It's a side-scroller with amazing graphics and a great interface-- and it's free! This game is very fun and it's impossible to duplicate this interface on any other platform because it makes extensive use of the multi-touch screen. Personally, I use three fingers to target all of the enemies rapidly and it is very satisfying. It makes me feel like a robot, but in a good way.

In other news, Microsoft released an app called SeaDragon on the App Store. Yes, it is a bit strange seeing as they are supposedly planning to create their own app store (http://tech.slashdot.org/tech/08/11/08/2225250.shtml). This app allows you to view images at different resolutions using pinch-and-zoom a la Google Maps. Seems like Microsoft is as original as ever. http://gizmodo.com/5109658/seadragon-mobile-microsofts-first-ever-iphone...

I've attached three pics of the game, but they are crappy res because I took them with my cell phone so they don't do much justice.

[iPhone/Shooter] SPACE DEADBEEF from Masaaan K on Vimeo.

Superb Erlang Web App Tutorial

I came across the most impressive Erlang tutorial I have seen yet. Check it out. Now.

http://www.vimeo.com/2007411

Duplicate an Object in Flash

I'm working on a tile editor in Flash CS4 and opted to use the TileList class for the palette. Once a swatch is selected, I need to create a copy of that swatch and attach it to the stage. I wasn't quite sure how polymorphism in AS3 worked but I ended up with this little snippet:

var mySwatchClass:Class = mySwatch.source.constructor;
var newTile = new mySwatchClass();

Let me know if it helps!

Add your location to iPod/iPhone Wifi Location Service

iPod TouchI recently got an iPod Touch and it is the best gadget I've ever had. One of the features of the powerful little machine is the location service. This service uses the wifi radio to listen for wifi beacons, the signal an access point sends out every second or two to let clients know the AP is there. When you refresh your list of wireless networks, it gathers these signals to make the list. Anyway, the utility of this feature is actually quite extensive. You can use it to find nearby restaurants, movie showtimes, and make getting directions a breeze. Unfortunately in my home area, there is no coverage.

I began searching and found an article on MacRumors that mentioned Apple uses a company called Skyhook to provide their database of AP MAC addresses and their coordinates http://www.macrumors.com/2008/01/23/skyhooks-wi-fi-location-technology-f.... Skyhook, according to their website, keeps a database of MAC addresses and associates them with their GPS location. Using this database is claimed to be accurate within 10-20 Meters.

After visiting Skyhook's website, I found the form where you can add your Wifi Access Point to their database. The page is at http://www.skyhookwireless.com/howitworks/submit_ap.php. Unfortunately it can take up to a few weeks to have the data updated with all of their partners. I will repost here if it ends up working for me.

P. S. If you can't find your MAC address, this article might help http://getsatisfaction.com/skyhookwireless/topics/how_do_i_find_the_mac_....

UPDATE 12/22/2008
It worked! Now when I push the current location icon in Google Maps it centers right on my street. Now any other urban residents like myself can find where they are!

Google Maps Circle Overlay

This was another feature that should have been simple, but just wasn't. This Google Maps extension allows you to use circle overlays. It is really a GPolygon with 45 points, but it looks like a circle. Here is a sample. You can download the source here.

js/gmaps.CircleOverlay.js:

// This file adds a new circle overlay to GMaps2
// it is really a many-pointed polygon, but look smooth enough to be a circle.
var CircleOverlay = function(latLng, radius, strokeColor, strokeWidth, strokeOpacity, fillColor, fillOpacity) {
    this.latLng = latLng;
    this.radius = radius;
    this.strokeColor = strokeColor;
    this.strokeWidth = strokeWidth;
    this.strokeOpacity = strokeOpacity;
    this.fillColor = fillColor;
    this.fillOpacity = fillOpacity;
}

// Implements GOverlay interface
CircleOverlay.prototype = GOverlay;

CircleOverlay.prototype.initialize = function(map) {
    this.map = map;
}

CircleOverlay.prototype.clear = function() {
    if(this.polygon != null && this.map != null) {
        this.map.removeOverlay(this.polygon);
    }
}

// Calculate all the points and draw them
CircleOverlay.prototype.redraw = function(force) {
    var d2r = Math.PI / 180;
    circleLatLngs = new Array();
    var circleLat = this.radius * 0.014483;  // Convert statute miles into degrees latitude
    var circleLng = circleLat / Math.cos(this.latLng.lat() * d2r);
    var numPoints = 40;
   
    // 2PI = 360 degrees, +1 so that the end points meet
    for (var i = 0; i < numPoints + 1; i++) {
        var theta = Math.PI * (i / (numPoints / 2));
        var vertexLat = this.latLng.lat() + (circleLat * Math.sin(theta));
        var vertexLng = this.latLng.lng() + (circleLng * Math.cos(theta));
        var vertextLatLng = new GLatLng(vertexLat, vertexLng);
        circleLatLngs.push(vertextLatLng);
    }
   
    this.clear();
    this.polygon = new GPolygon(circleLatLngs, this.strokeColor, this.strokeWidth, this.strokeOpacity, this.fillColor, this.fillOpacity);
    this.map.addOverlay(this.polygon);
}

CircleOverlay.prototype.remove = function() {
    this.clear();
}

CircleOverlay.prototype.containsLatLng = function(latLng) {
    // Polygon Point in poly
    if(this.polygon.containsLatLng) {
        return this.polygon.containsLatLng(latLng);
    }
}

CircleOverlay.prototype.setRadius = function(radius) {
    this.radius = radius;
}

CircleOverlay.prototype.setLatLng = function(latLng) {
    this.latLng = latLng;
}

circle.html:

<html>
<head>
    <title>GMaps Circle Test</title>
    <script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=ABQIAAAAOzwQ7Lh4CqiMto5Mx5BruhS-xyZmcPPoBCehH0LrfEv4pktlHxSKTILYLRlghp_oPDcwTo3STVXADg" type="text/javascript"></script>
    <script src="js/gmaps.CircleOverlay.js" type="text/javascript"></script>
    <script type="text/javascript">
    var circle = null;
    var circleRadius = 50; // Miles
    var map = null;
    var isCompatible = GBrowserIsCompatible();
   
    //<![CDATA[
    function load() {
        if (isCompatible) {
            // Create Map
            map = new GMap2(document.getElementById("map"));
            map.setCenter(new GLatLng(42, -74), 6);

            // Add controls
            map.addControl(new GLargeMapControl());
            map.addControl(new GMapTypeControl());
           
            // Create and add the circle
            circle = new CircleOverlay(map.getCenter(), circleRadius, "#336699", 1, 1, '#336699', 0.25);
            map.addOverlay(circle);
        }
    }
    //]]>
    </script>
</head>
<body onload="load()" onunload="GUnload()">
    <div id="map" style="width: 400px; height: 300px; border: 1px solid #666666;"></div>
</body>
</html>

Check if a polygon contains a coordinate in Google Maps

At work, I've been tasked with a neat little project where a user can select a list of users represented by markers on a Google map by editing a polygon to surround the markers with. However, to my dismay, I could not find any methods in the API to see if a polygon contains a coordinate. I also had a hard time finding an algorithm so that I could implement it.

First I tried the winding number algorithm (http://en.wikipedia.org/wiki/Point_in_polygon) but failed. I didn't put too much time into it since it is so CPU-intesive anyway. Then I came across an article on MSDN (http://msdn.microsoft.com/en-us/library/cc451895.aspx) which I adopted into Javascript. I extended the GPolygon class with a new method called containsLatLng, just like the GLatLngBounds class. The difference is that the method in the GLatLngBounds class will only get the 4 coordinates of the bounding box, which are the farthest points in the polygon, and see if the coordinate lies within that box. My method, however, does true collision detection to see if the point lies within any shape polygon with as many sides as you want. It worked out perfectly.

Without any further ado, here is the code [js/gmaps.polygon.containsLatLng.js]:

// Create polygon method for collision detection
GPolygon.prototype.containsLatLng = function(latLng) {
    // Do simple calculation so we don't do more CPU-intensive calcs for obvious misses
    var bounds = this.getBounds();
   
    if(!bounds.containsLatLng(latLng)) {
        return false;
    }
   
    var numPoints = this.getVertexCount();
    var inPoly = false;
    var i;
    var j = numPoints-1;
   
    for(var i=0; i < numPoints; i++) {
        var vertex1 = this.getVertex(i);
        var vertex2 = this.getVertex(j);
       
        if (vertex1.lng() < latLng.lng() && vertex2.lng() >= latLng.lng() || vertex2.lng() < latLng.lng() && vertex1.lng() >= latLng.lng())  {
            if (vertex1.lat() + (latLng.lng() - vertex1.lng()) / (vertex2.lng() - vertex1.lng()) * (vertex2.lat() - vertex1.lat()) < latLng.lat()) {
                inPoly = !inPoly;
            }
        }
       
        j = i;
    }
   
    return inPoly;
};

And here is the sample usage [index.htm]:

<html>
<head>
    <title>GIS Test</title>
    <script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=ABQIAAAAOzwQ7Lh4CqiMto5Mx5BruhRP7uQ16ovEZegyAfeetOdXUUHv1xQhaNqllcioqRUJo6b7JhhTgJZNyw" type="text/javascript"></script>
    <script src="js/gmaps.polygon.containsLatLng.js" type="text/javascript"></script>
    <script type="text/javascript">
    var isEditing = false;
    var polygon = null;
    var map = null;
    var isCompatible = GBrowserIsCompatible();
    var markers = [];
    var iconIncluded = 'http://maps.google.com/mapfiles/dd-start.png';
    var iconExcluded = 'http://maps.google.com/mapfiles/dd-end.png';
       
        function editClick() {
                isEditing = !isEditing;
                       
                if(isEditing && polygon != null) {
                        document.getElementById('edit_button').innerHTML = 'Stop Editing';
                        document.getElementById('help').innerHTML = 'Click to add points to your selection.';
                        document.getElementById('reset_button').disabled = 'disabled';
                        polygon.enableDrawing();
                } else {
                        document.getElementById('edit_button').innerHTML = 'Edit Selection';
                        document.getElementById('reset_button').disabled = '';
                        document.getElementById('help').innerHTML = 'Click "Edit Selection" to select users.';
                        polygon.disableEditing();
                }
        }
       
        // Update all markers with in poly status
        function updatePoints() {
                for(var i in markers) {
                        var marker = markers[i];
                        var point = marker.getLatLng();
                        var inPoly = polygon.containsLatLng(point);
                       
                        if(inPoly) {
                                marker.setImage(iconIncluded);
                        } else {
                                marker.setImage(iconExcluded);
                        }
                }
        }
       
        function resetPolygon() {
                if(polygon != null) {
                        map.removeOverlay(polygon);
                }
               
                polygon = new GPolygon([], "#000000", 1, 1, "#336699", 0.3);
                map.addOverlay(polygon);
               
                GEvent.addListener(polygon, "lineupdated", function() {
                        setTimeout(updatePoints, 50);
                });
               
                GEvent.addListener(polygon, "endline", function() {
                        setTimeout(editClick, 50);
                });
               
                updatePoints();
        }

    //<![CDATA[
    function load() {
        if (isCompatible) {
            // Create Map
            map = new GMap2(document.getElementById("map"));
            map.setCenter(new GLatLng(40, -90), 3);

            // Add controls
            map.addControl(new GLargeMapControl());
            map.addControl(new GMapTypeControl());

            // Create Selection Polygon
            var latlng = map.getCenter();
            var width = 20;
            var height = 12;
            var lat = latlng.lat();
            var lng = latlng.lng();
            var x1 = lng - width / 2;
            var y1 = lat - height / 2;
            var x2 = lng + width / 2;
            var y2 = lat + height / 2;
                       
                        resetPolygon();

            // Add 10 markers to the map at random locations
            var bounds = map.getBounds();
            var southWest = bounds.getSouthWest();
            var northEast = bounds.getNorthEast();
            var lngSpan = northEast.lng() - southWest.lng();
            var latSpan = northEast.lat() - southWest.lat();

            for (var i = 0; i < 100; i++) {
                var point = new GLatLng(southWest.lat() + latSpan * Math.random(), southWest.lng() + lngSpan * Math.random());
                var marker = new GMarker(point, {bouncy: true, title: "Customer " + i, autoPan: false});
                map.addOverlay(marker);
                marker.bindInfoWindowHtml("This is customer info " + i);
                markers.push(marker);
            }
           
            updatePoints();
        }
    }
    //]]>
    </script>
</head>
<body onload="load()" onunload="GUnload()">
    <div>
        <span><button id="edit_button" onclick="editClick()" type="button">Edit Selection</button></span>
        <span><button id="reset_button" onclick="resetPolygon()" type="button">Reset Selection</button></span>
        <span id="help" style="color: #666;">Click "Begin Editing" to select users.</span>
    </div>
    <hr />
    <div id="map" style="width: 640; height: 480; border:1px solid #333;"></div>
</body>
</html>

Sample: http://dawsdesign.com/Samples/GIS/
Download: http://dawsdesign.com/Samples/GIS/GIS.zip

Functional Programming =:= Secure Programming?

Here is a great article that describes an interesting perspective of functional programming. The author over at Tech Republic describes how functional programming is often more secure than imperative languages without even trying.

Here's the link http://blogs.techrepublic.com.com/security/?p=567

Erlang gen_server OTP Demo

This is a short video I put together. It shows how to use emacs to generate an Erlang gen_server to greet a client. It also demonstrates Erlang's hot code-loading capabilities.

Erlang/OTP gen_server demo from Matt Williamson on Vimeo.

Really high quality at http://dawsdesign.com/video/video-gen_server_demo

Syndicate content