Contacts Cleaner Support Page

March 3rd, 2010

If you are having issues with Contacts Cleaner, or just want to know more about how it works, please visit our users guide at:

http://beavercreekconsulting.com/contacts-cleaner/user-guide.html

We recently made several updates to the FAQ and you will find answers for the most common questions.

Contacts Cleaner Matching Algorithm

March 2nd, 2010

One of the key ingredients of Contacts Cleaner is identification of duplicate contacts.  We have put a lot of effort into the algorithm, and concluded that less is more.

Most folks love Contacts Cleaner.  There are  a lot of really messed up address books out there.  I heard from a customer today who had 13,000 contacts, of which 10,000 were duplicates.  Bummer Dude!  This person needs a simple solution which will fix the mess that is their address book.  Contacts Cleaner to the rescue!

We have settled on a lights out, robust, and repeatable algorithm that will tame the chaos which is your address book.  Contacts Cleaner “just works”.  It will make you address book better without bothering you.  Contacts Cleaner is not perfect, but it is better!

Contacts Cleaner FAQ

March 1st, 2010

I just updated the FAQ for Contacts Cleaner.  I went back through the customer support tickets and extracted common issues to create the new FAQ entries.  If you are having issues with Contacts Cleaner, do check out the FAQ.  Chances are good you’ll find an answer.

Contacts Cleaner 1.0

February 7th, 2010

Beaver Creek Consulting is pleased to announce the release of their new product, Contacts Cleaner.  Contacts Cleaner is a BlackBerry App that removes duplicate contacts from your address book.  Contacts Cleaner is available from BlackBerry App World, as well as popular BlackBerry sites such as CrackBerry and BBGeeks.

PHP PEAR on GoDaddy

May 3rd, 2009

Today I moved the server side components of SimplySchedules.com to my hosting service for the first time.  Yahoo — the launch is getting closer!

The sever side is done in PHP due to the extreme cost effectiveness of hosted LAMP.  I used a few modules from the most excellent PEAR collection.  All good, except when I installed the code at GoDaddy.com, I was missing the PEAR modules.

The PEAR modules are a lot of code, so I was very happy to find this clear and concise blog posting that explained how to install PEAR at GoDaddy.  Basically, you install an installer on your web account and then use a web based front end to install your selected PEAR components.

Scripting Approaches For Java Application Test Automation

April 2nd, 2009

Next week I’m presenting at the Northern Virginia Test Automation Interest Group.  The group’s focus is test automation and I’m talking about how to automate scripting of Java applications with an eye towards testing.

Full, disclosure, I’m a scripting FanBoy; this is an opportunity to talk about exposing scripting interfaces for Java applications so I’m jumping on the opportunity to do so.  It just happens that doing so is a a great route to test automation and I get to talk on and on about scripting.

I’m covering groovy, Rhino, and JavaCC.  The meeting announcement is here.

Clearing and Busting the GWT Hosted Mode Cache

February 1st, 2009

We’ve chosen to use GWT for Beaver Creek Consulting’s latest product (Simply Schedules).  The back end is a REST API with JSON payloads.

I was having trouble with the hosted mode browser.  A list of application objects for a luser are loaded with a request to the server such as:

GET /app/luser/items

The issue is that as the application runs, the list of items on the server changes.  Next time I tried to load the list of items from the server, the hosted browser sees the same URL and decides to use the cached response.

This post on the GWT forum recommended clearing the IE (if you are on windows) cache.  I needed something more permanent as the cache issue is part of the normal operation of the client (this is to say it modifies the items).

The correct answer is to not clear the cache, but to bust the cache.  A little bit of research shows that appending a query parameter with a random number or a timestamp will do the trick.  For the above example, I used the current timestamp:

GET /app/luser/items?cache-buster=1233516109751

The timestamp is generated in “Java” on the client:

String url = "/app/luser/items?cache-buster=" + new java.util.Date().getTime();

It’s quite likely that you don’t even need to name the parameter, just append the time stamp:

GET /app/luser/items?1233516109751

You can have Perl 5 when you peel my cold dead hands off of it.

February 1st, 2009

I started working with Perl in 2000 and along with C++ Perl is the language I cut my teeth on as a professional developer.

5.8 has been my favorite release.   With Perl 6 taking a while to be production ready I’ve been planning on using 5.8 forever.  Well, it turns out forever isn’t that long.  The end of Perl 5.8 has been announced.  The good news is that Perl 5 will continue as Perl 5.10.

Maybe I’ll never upgrade to Perl 6.  Perhaps this point is moot, as I’m using Perl less and less these days.  I’ve been turning to Groovy.

But — when I need something complicated done right now, my goto is Perl 5.

MapQuest Proxy for Jaxer

January 16th, 2009

If you’re a MapQuest developer chances are you’re pretty handy with JavaScript on the client. It’s been the sad case that you leave these skills behind when you switch over to server side programming. Well, happy day, things are changing as support for Server Side JavaScript (SSJS) takes off. With SSJS you can break out your JavaScript Ninja skills on the server side. I’ve been looking at the Jaxer SSJS platform and worked up this example to show off some of the possibilities.

With the MapQuest JavaScript API one can get tiled maps on a page with only client JavaScript. As soon as you use other MapQuest Services such geocoding, routing, or search, you need to supply a proxy on the web server. The proxy is need to allow the MapQuest client library to call home while avoiding the browser’s same-domain security policy.

The example I’m presenting here is an implementation of such a proxy for the Jaxer platform. I think a SSJS proxy is an illuminating and useful example. It’s a useful example since you need a proxy for putting MapQuest and Jaxer together. Also, it’s an illuminating example since it is a typical server side task, fetching data from a different source. The source could be files, in database, RSS feeds, or, as in this case, a server in a different domain. MapQuest (MQ) supplies proxies in common languages such PHP, Java, etc., so this example will also allow comparison of the SSJS implementation to implementations in other languages.

The example consists of two HTML pages, one of which is served to the client and one which runs on the Jaxer server and acts as the proxy.

The Client Side

The client page is a hello world type of example for MapQuest – create a tiled map, geocode an address, and place a Point of Interest marker at the geocoded address. The complete source code for this example is available here. Here’s a screenshot of the client page in action:

The text boxes on the right are a debug log provided the MQ client library that shows interaction between the MQ client library and the proxy. Specifically, the box labeled “Request URL” is address where the MapQuest client library is configured to find the proxy. The Request XML box shows the data the client library is sending, which in this case is a request for geocoding per the MQ API (see the MQ XML Interface Reference). The “Response XML” is the XML returned by the MapQuest geocoding service via the proxy.

Here’s the startMap() method that is called when the client page loads:

<script src="http://btilelog.access.mapquest.com/tilelog/transaction?transaction=script&amp;amp;amp;amp;amp;key=your-MQ-key=true&amp;amp;amp;amp;amp;v=5.3.s&amp;amp;amp;amp;amp;ipkg=controls1" type="text/javascript"></script>
<script src="lib/mapquest/mqcommon.js"></script>
<script src="lib/mapquest/mqutils.js"></script>
<script src="lib/mapquest/mqobjects.js"></script>
<script src="lib/mapquest/mqexec.js"></script>
<script>
var g_proxyServerName = 'localhost';
var g_proxyServerPort = '8000';
var g_proxyServerPath = 'jaxer-mapquest/proxy.html'

var g_serverName = 'geocode.dev.mapquest.com';
var g_serverPort = '80';
var g_serverPath = 'mq';

var g_geoExec = new MQExec(g_serverName, g_serverPath, g_serverPort, g_proxyServerName, g_proxyServerPath, g_proxyServerPort);

function startMap(){
var g_mqMap = new MQA.TileMap(document.getElementById('mapWindow'), 2, new MQA.LatLng(40, -95), "map");

var address = new MQAddress();
address.setCity('Gobles');
address.setState('MI');
address.setCountry('USA');

var gaCollection = new MQLocationCollection("MQGeoAddress");
g_geoExec.geocode(address, gaCollection);
var mqAddress = gaCollection.get(0);

var poi = new MQA.Poi(mqAddress.getMQLatLng());
poi.setInfoTitleHTML('Hello World');
poi.setInfoContentHTML('From Gobles, MI');
g_mqMap.addPoi(poi);
}
</script>

The MQExec object interacts with the proxy. The location of the proxy on localhost is specified as well as the details of the proxied MapQuest server (geocode.dev.mapquest.com). When the MQ client library needs to call home for geocoding services (via g_geoExec.geocode()), it will form a GET or POST with the request details and send the request to http://localhost:8000/jaxer-mapquest/proxy.html.

The Server Side

The sever side proxy is implemented in a page named proxy.html. The page receives the post from the MQ client library, extracts the data, forwards it along to the MQ server, and then returns the MQ response back to the client.

The HTML page, proxy.html, is processed by the Jaxer server. We’ll use a slightly different processing model than the typical Jaxer page lifecycle. In the typical lifecycle a page is parsed on the Jaxer server into a DOM model, scripts that are tagged to be ran on the server are invoked, client side proxies are mixed-in for scripts that are tagged to be proxied, and then the page is serialized and sent off to the client. In this case, we use server side scripts to overwrite the the DOM on the server side prior to the serialization for returning the page to the client.

This is a handy Jaxer technique. Since you set the content type and the response content you can pull stunts like serializing arbitrary JavaScript objects and returning them as JSON to the client. In this case, I’m overwriting the HTML page and returning the content and content type from the map quest server (XML). To me, this technique is the more similar to a J2EE Servlet than the typical Jaxer lifecycle, which feels more like a JSP.

The proxy.html page consist primarily of JavaScript that get executes in the server context. The server side script execution is triggered with a onserverload tag:

<body onserverload="BCC.mqproxy.proxify();">

The proxify() method shows the general steps that the proxy executes:

proxify: function(){
parseClientRequest();
makeMQRequest();
replyToClient();
}

In order to overwrite the page’s DOM with arbitrary content, one calls the Jaxer.Response.setContent() method. In this case, we’ll overwrite the page’s entire DOM with the response and content type obtained from the MQ response. The property Jaxer.response is an instance of Jaxer.Response that points to the current response:

var replyToClient = function(){
Jaxer.response.headers['Content-Type'] = mqResponse.headers['Content-Type'];
Jaxer.response.setContents(mqResponse.text);
}

And that’s all it takes to send back arbitrary content from a Jaxer HTML page.

Before we can reply to the client, this page has to parse the client request and call the server at MapQuest. The following function reads the data posted by the client from Jaxer.request (an instance of Jaxer.Request):

var parseClientRequest = function(){
getMqServerUrlParams();
if (Jaxer.request.method == 'POST') {
getPostData();
}
else {
getUrlParms();
}
};

The MQ client sends the target server, port and path as URL parameters and the getMQServerUrlParams() method picks these off. Jaxer makes the parsed URL available as a property of the request object:

var serverParams = {
sname: '',
sport: '',
spath: ''
};

var getMqServerUrlParams = function(){
logger.debug('getMqServerUrlParams');
for (param in serverParams) {
serverParams[param] = Jaxer.request.parsedUrl.queryParts[param];
logger.debug('getMqServerUrlParams: ' + param + ': ' + serverParams[param]);
}
};

The remainder of the request data comes in as either other URL parameters or as POSTed XML. In the case of XML data, the proxy needs to add a couple of XML elements for a client ID and password. Here’s the routine to get the XML from the request, parse it, modify the DOM and serialize back to XML:


// Fetch the XML form data and add credentials
var getPostData = function(){
logger.debug('getPostData');
logger.debug('getPostData: postdata:          ' + Jaxer.request.postData);

var doc = new DOMParser().parseFromString(Jaxer.request.postData, 'text/xml');
if (doc.documentElement.nodeName == "parsererror") {
throw new Error("People we have an issue: XML parse error");
}
var authenticalNodeList = doc.documentElement.getElementsByTagName("Authentication");
if (authenticalNodeList.length > 0) {
authenticatedRequest = true;
var authenticalNode = authenticalNodeList[0];

// add password
var passwordEl = doc.createElement('Password');
var passwordTextEl = doc.createTextNode(mqPassword);
authenticalNode.appendChild(passwordEl).appendChild(passwordTextEl);

// add client ID
var clientIdEl = doc.createElement('ClientId');
var clientIdTextEl = doc.createTextNode(mqClientId);
authenticalNode.appendChild(clientIdEl).appendChild(clientIdTextEl);
}

// back to a string
postData = new XMLSerializer().serializeToString(doc);
logger.debug('getPostData: fixed up postdata: ' + postData);
};

Notice that there is no cross-browser monkey business to get a parser and serializer. On the server side, Jaxer uses Mozilla so you can count the available features. This example also makes use of the Jaxer.Log facility which lets you write to server side logs and specify the level of logging detail.

The last code snippet show how to place a synchronous server side HTTP request with Jaxer.Web.send(). The URL is assembled and a POST or GET is made per the client request:

var makeMQRequest = function(){
mqUrl = 'http://' + serverParams.sname + ':' + serverParams.sport + '/' + serverParams.spath;
sendOptions.extendedResponse = true;
if (Jaxer.request.method == 'POST') {
if (authenticatedRequest == true) {
mqUrl += '/mqserver.dll?e=5';
}
sendOptions.contentType = 'application/x-www-form-urlencoded';
}
else { // GET
var urlQParams = '';
for (p in urlParams) {
urlQParams += p + '=' + urlParams[p];
}
if (urlParams.length > 0) {
mqUrl += '?' + urlQParams;
}
}
// Call home
mqResponse = Jaxer.Web.send(mqUrl, Jaxer.request.method, postData, sendOptions);
};

Wrap up

This example shows how to proxy web content in other domains using Jaxer. The same basic approach can be used to access other server side resources (files, database, etc).

I’m a big fan of scripting languages, and JavaScript is my current favorite. I’ve been using it not only in web browsers but also as domain specific language in a Business Process Modeling application I’m working with. I’m at the peak of my JavaScript skills, so, I’m really happy to be able to break out JavaScript on the server side.

Perl Syntax Highlighter

December 14th, 2008

SyntaxHighlighter is turning out to be the web standard for displaying source code in blogs. I’ve developed a brush for that most excellent, yet recently neglected language, Perl. This contribution has not yet been included in the SyntaxHighlighter distribution, so I’m also posting the source code here. Enjoy!

I’ve posted the full source code for the brush to the syntaxhighlighter site. This brush is based on a couple of earlier Perl brushes:

http://opticalgarbage.com/sh/js/shBrushPerl.js

http://nevstokes.com/includes/syntax/scripts/shBrushPerl.js


/**
* Perl brush for Code Syntax Highlighter
* by Marty Kube, http://beavercreekconsulting.com/
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, version 3 of the License.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
dp.sh.Brushes.Perl = function()
{
var funcs =
'abs accept alarm atan2 bind binmode chdir chmod chomp chop chown chr ' +
'chroot close closedir connect cos crypt defined delete each endgrent ' +
'endhostent endnetent endprotoent endpwent endservent eof exec exists ' +
'exp fcntl fileno flock fork format formline getc getgrent getgrgid ' +
'getgrnam gethostbyaddr gethostbyname gethostent getlogin getnetbyaddr ' +
'getnetbyname getnetent getpeername getpgrp getppid getpriority ' +
'getprotobyname getprotobynumber getprotoent getpwent getpwnam getpwuid ' +
'getservbyname getservbyport getservent getsockname getsockopt glob ' +
'gmtime grep hex index int ioctl join keys kill lc lcfirst length link ' +
'listen localtime lock log lstat map mkdir msgctl msgget msgrcv msgsnd ' +
'oct open opendir ord pack pipe pop pos print printf prototype push ' +
'quotemeta rand read readdir readline readlink readpipe recv rename ' +
'reset reverse rewinddir rindex rmdir scalar seek seekdir select semctl ' +
'semget semop send setgrent sethostent setnetent setpgrp setpriority ' +
'setprotoent setpwent setservent setsockopt shift shmctl shmget shmread ' +
'shmwrite shutdown sin sleep socket socketpair sort splice split sprintf ' +
'sqrt srand stat study substr symlink syscall sysopen sysread sysseek ' +
'system syswrite tell telldir time times tr truncate uc ucfirst umask ' +
'undef unlink unpack unshift utime values vec wait waitpid warn write';

var keywords =
'bless caller continue dbmclose dbmopen die do dump else elsif eval exit ' +
'for foreach goto if import last local my next no our package redo ref ' +
'require return sub tie tied unless untie until use wantarray while';

this.regexList = [
{ regex: new RegExp('#[^!].*$', 'gm'), css: 'comment' },  // comments
{ regex: new RegExp('^\\s*#!.*$', 'gm'), css: 'preprocessor' }, //shebang
{ regex: dp.sh.RegexLib.DoubleQuotedString, css: 'string' },
{ regex: dp.sh.RegexLib.SingleQuotedString, css: 'string' },
{ regex: new RegExp('(\\$|@|%)\\w+', 'g'), css: 'vars' },
{ regex: new RegExp(this.GetKeywords(funcs), 'gmi'), css: 'func' },
{ regex: new RegExp(this.GetKeywords(keywords), 'gm'), css: 'keyword' }
];

this.CssClass = 'dp-perl';
this.Style =
'.dp-perl .vars { color: #996600; }' +
'.dp-perl .func { color: #006666; }';
}

dp.sh.Brushes.Perl.prototype  = new dp.sh.Highlighter();
dp.sh.Brushes.Perl.Aliases  = ['perl', 'Perl'];