Archive for January, 2004

MXNA Performance and Uptime

I know some of you have noticed (since you have sent me email) that MXNA and our weblogs have occasionally been going down, and that the server is often pretty slow. As we accumulate more and more feeds, more archived posts, more traffic, and as more people have started using our ping API so that we pick up their posts in realtime, the server has really suffered. After a little investigation, we discovered that PostgreSQL processes were always to blame whenever the server was in a bad state. I tried installing hot fixes, updated drivers, and even experimented with caching, but PostgreSQL has continued to have problems. Finally, Mike Chambers and I decided to try switching my MySQL, instead, since it is known for it’s superior performance. After about a day of migration work, MXNA is now running MySQL, and it is many times faster than it was. Even the largest queries return almost instantly, and MySQL processes have very little impact on overall system resources. We had opted for PostgreSQL over MySQL initially because:

  1. The PostgreSQL command line interface is better than MySQL’s (out of the box).
  2. PostgreSQL supports more features.
  3. I have always found PostgreSQL’s security and user model to be more intuitive and easier to work with.

In the end, however, performance is our #1 priority, so now I am very happy with MySQL, and with the state of MXNA. We have a couple new features which we have been hesitant to launch because of performance issues which now I believe will be receiving the green light very soon. Stay tuned.

Technology and Car Buying

My wife and I bought a new car last weekend, and I seriously can’t imagine how it was ever done before the Internet and PDAs. We started out researching different models online, reviewing not only what the different manufacturers had to say, but also reading posts from owners of those particular models. Fortunately, all evidence pointed toward the car my wife already wanted, so we drove to a dealership just for a test drive with no intention of buying the car that day. After verifying that we liked the way the car drove, we went home and shifted our focus from browsing to buying. Thanks to edmunds.com (never buy another car without spending a significant amount of time on edmunds.com), we decided on exactly what options we wanted, found out exactly what dealerships’ costs were, and got up to speed on all the new pricing scams (is it really fair for dealerships to pass their advertising costs along to their customers? Hmmm.). We found great interest rates online, and thanks to the interest calculator at cars.com and Microsoft Excel, we were able to model all kinds of pricing scenarios. (I ended up replicating the interest calculator in Flash 5 for my Sony Clie so that I would not have to depend on the financing manager at the dealership to provide me with numbers during negotiations.) By this time, we knew exactly the car we wanted and exactly what we wanted to pay for it.

We spent another half day at a dealership trying to make a deal, but they would not come down far enough. It was an interesting experience since I knew every penny of their costs and all of their tricks to try to artificially inflate the price of the vehicle. The price I was willing to pay had a decent profit built in for them, however they kept claiming that they would be selling the car at a loss if they were to agree to my price. Finally, I took out my spreadsheet and went over it line by line with the manager at which point, he leveled with me and said he simply believed he could sell the car to someone else for more, and that was the bottom line. You can’t argue with that, so we left and executed plan B which was to drive up to Maryland to a dealership with a no-haggle policy which had the exact car we wanted for a very reasonable price. On the way up, we did some additional research on my Clie (connected via GPRS via my cell phone), and put together a game plan for approaching the sales team. It turns out this dealership had a very open policy and was very willing to show you all their costs associated with the car, and even the amount of profit they wanted to make. All their numbers checked out against mine, and we ended up getting the car with additional options for $100 less than what we were offering the first dealership. It turns out I had actually built in more profit in my price than they even wanted to make!

Anyway, I can’t imagine how I could done it without being able to do research via the internet, and without the calculator, browser and interest calculator on my Clie. How did Macromedia technology figure in? Many of the sites I used for research were powered by ColdFusion, all car manufacturers use Flash to give customers a better experience, and the interest calculator I wrote for my Clie was implemented in Flash 5. Now if only the car had a built-in Flash 7 player and an SDK.

Generating Random Numbers in ColdFusion

There was a post last week on cf-talk about random number generation with ColdFusion, and in particular, the use of the randomize() function. The ColdFusion documentation indicates that you should call randomize() before calling rand() in order to ensure highly random numbers (though the same applies to randRange()). The problems are:

  1. The randomize() function only takes in an int. The best way to generate a unique number is by calling getTickCount() which returns a long. The two functions cannot be used together.
  2. If you don’t use a unique number to seed the random number generator, then your results are anything but random. Each time you call rand() or randRange() without reseeding the random number generator, you will get predictable results. In other words, the algorithm for generating random numbers is, ironically enough, predictable, so the only way to get (pseudo) random numbers is by using a unique, dynamic seed. The current time in milliseconds is a perfect choice (and is what gets used by default).

As Sam Neff pointed out on cf-talk, it seems better not to call randomize() in order to allow the ColdFusion server to seed the random number generator with the current time in milliseconds — a long value that cannot otherwise be passed in — and I tend to agree. The problem with this, however, is synchronization since two requests made at the exact same time will cause the same “random” number to be generated. Fortunately, there’s a good solution.

Sam also suggested creating an instance of java.util.Random, storing it in the application scope, and using it to generate your random numbers. It automatically gets seeded with the current time in milliseconds, and will keep returning highly random numbers each time you call it. If you create a new instance of it on each request, you will get fairly random numbers since it will get re-seeded with the current time in milliseconds, however by storing it in your application scope, you can seed it once, then get highly random numbers by calling one of its next methods to get the next pseudorandom, uniformly distributed value from its internal sequence. This sounds like a pretty good solution to me. It also eliminates the possibility of creating two random number generators at the exact same time. If two random number generators using the current time in milliseconds as seeds are instantiated simultaneous, the “random” numbers they generate will be identical. Oops.

In order to make the solution described above a little easier, I threw together a Randomize component which does the following:

  1. Creates a single instance of java.util.Random at the time it’s instantiated and continues to use it for generating additional random numbers. By putting the Random component in some persistent scope, you can ensure that the same instance of Random is being used, and hence your numbers will be highly random.
  2. Allows you to seed the random number generator, and happily accepts ints or longs, which means you can pass in the result of calling getTickCount(). (Just don’t try to pass in a decimal of any kind — it won’t like that.)
  3. Allows you to easily set bounds for your random numbers using the setBounds() and setMax() functions. These can be changed without having to create a new instance of the Randomize component.
  4. Provides a nextBoolean() function for getting back random booleans.

If none of this made much sense to you, the bottom line is that if you need to generate a lot of highly random numbers, create an instance of this component, store it in a persistent scope, and call next() on it whenever you need a random number.

The code is here:

Continue reading…

Pretty Impressed With JEdit

I’ve typically shied away from editors written in Java, however I decided to try out JEdit 4.1 today to see how far it’s come. I must say, I’m pretty impressed. It’s too early to say whether I’ll actually convert, but it’s one of the very few editors with Mac support that I would even consider switching to. It’s responsive, intuitive, and seems to have most if not all the features I need (including column select). Maybe I’ll try it over the weekend and see if I’m still impressed on Monday.

PATH Variable in ColdFusion

I just stumbled across the fact that the ColdFusion variable #path# refers to my system path, which I think is strange. I wonder if the purpose is to assist CFEXECUTE in finding executables. Anyone know? Any other variables like that which are not commonly known? I tried other environment variables, but #path# was the only one defined.

Update:
I should have mentioned that I’m running CFMX 6.1 on OS X with Apache. Anyone seeing this with any other configurations?

Developing Flash Apps for the Sony CLIE (part II)

We’ve been car shopping recently, so I decided to write Loan Star, a loan calculator in Flash 5 for my Sony Clie. I was amazed by how simple and straightforward authoring for the Clie was. By far, the majority of my time was spent getting the amortization and interest formula right as opposed to actually constructing the application. And once it was ready, aside from some minor font issues, I copied the SWF over to my Clie and it looked good and worked perfectly the very first time. As someone who has done mobile development in Java in the past, I found this to be very refreshing.

The biggest hassle (if you can even call it that) was probably transferring the SWF over to the device. SWFs have to be stored on Memory Sticks as opposed to the Clie’s internal media storage, so step one was going out and buying a Memory Stick (I have been contemplating ordering either the 512MB or a 1GB Memory Stick Pro, but since I was in a bit of a rush, I just ran out to Best Buy and bought a 32MB stick). I didn’t buy a Memory Stick reader, however, so I had to transfer the SWF to the stick through my network. Fortunately, the UX50 has built-in WiFi, so I just copied the SWF to a webserver, then downloaded the file and saved it to the Memory Stick. (The UX50 also has built-in Bluetooth which I use extensively, however for some reason, I was not able to transfer the file from my Mac to my Clie via Bluetooth — something I will have to look into further.) The OS knew to put the SWF in the correct directory on the Memory Stick (/PALM/Programs/MMFlash), and the Flash player knew right where to find it. The biggest problem with this particular workflow was that I had to reconnect to the network between each iteration because you automatically get disconnected when switching from the Clie browser to the Flash player. And I had to remember to clear the browser’s cache between iterations, as well, to make sure I wasn’t testing a stale version. Fortunately, thanks to the consistency between the Flash player on the Clie and that on my Mac, there were only a couple of iterations, and all of the issues were purely cosmetic.

Aside from font and processor considerations, and mentally trying to roll back to Flash 5, developing for the Clie was really very simple. It was great to be able to test the calculator right in the Flash IDE without having to use an emulator, or worse, having to constantly copy the bits over to be tested on the actual device. If the application were more extensive, I’m sure I would have run into more issues, or at least architectural considerations, however from what I can tell, developing for the Clie (and devices in general) with platform independent technologies like Java and Flash mostly just requires a little more diligence and attention to resource limitations. And realistic expectations, of course.

I use my Clie on my home wireless network frequently, but yesterday, I got my Clie connecting to the internet through a Bluetooth connection to my phone, which connects via GPRS, so now I am going to look at building a more network-oriented application. If I have time, I might also see how much luck I have getting IBM’s WebSphere Micro Environment JVM running on my Clie, as well. I don’t have high hopes, but being able to write Java applications for my Clie is a very tempting prospect.

If you are considering doing some Flash development for the Clie, step one is to download the the Sony Clie Developer Kit from the Mobile and Devices Developer Center on Macromedia’s site. Feel free to check out the source code for Loan Star, as well, or if you simply want to install it on your Clie, use this URL:

http://www.markme.com/cantrell/flash/loan_star.swf

And just to drive the platform independent point home, here is the finished product:

Flash on My Sony Clie

I just finished building a financial calculator in Flash 5 for my Sony Clie. The Flash player runs very well on the Clie, and I’m getting all kinds of ideas for other apps I can build. Anyway, I’m having a font issue when running the application on the actual device, but once I have that worked out, I’ll post the source and talk about the process of developing for the Clie. It’s certainly much easier than interest formulas and amortization tables, that’s for sure!

Byte Arrays and ColdFusion (Part II)

The function below creates an empty byte array of a specified length in ColdFusion. Why is this useful? You usually need byte arrays for reading from Java InputStreams, so if you are working with Java streams in ColdFusion (trying to embed all your Java code in CFScript so as to not require a jar file installation) the function below will come in very handy:


<cffunction name="getByteArray" access="private" returnType="binary" output="no">
<cfargument name="size" type="numeric" required="true"/>
<cfset var emptyByteArray =
createObject("java", "java.io.ByteArrayOutputStream").init().toByteArray()/>
<cfset var byteClass = emptyByteArray.getClass().getComponentType()/>
<cfset var byteArray =
createObject("java","java.lang.reflect.Array").newInstance(byteClass, arguments.size)/>
<cfreturn byteArray/>
</cffunction>

How Do You Like Your Documentation?

Generally speaking, what format do you like to see documentation in? PDF? FlashPaper? HTML? RTF? Text? Microsoft Word?

Personally, I prefer HTML. I can navigate and find what I need in my browser faster than anywhere else. I almost always have Javadoc in one browser tab and Macromedia LiveDocs open in another. If I need to be able to read documentation offline (on an airplane, for instance, since that’s about the only place I ever go anymore where I’m completely offline), I either save the HTML as a PDF, or preferably, download the HTML to browse locally. HTML prints well enough (although I almost never print anything), loads quickly, can be easily kept up to date, and generally fits into my workflow better than anything else.

In what format would you like to see most or all of the documentation you use on a regular basis, and why? (Don’t forget to take the poll!)

Byte Arrays and ColdFusion

I’m looking for ways to dynamically create byte arrays of indeterminate length in ColdFusion. I have tried this:


sb = createObject("java", "java.lang.StringBuffer");
sb.init(someLength);
byteArray = sb.toString().getBytes();

// and this:

baos = createObject("java", "java.io.ByteArrayOutputStream");
baos.init(someLength);
byteArray = boas.toByteArray();

… but both return byte arrays of 0 length rather than someLength. The only technique I have found that works is this:


function getByteArray(someLength)
{
sb = createObject("java", "java.lang.StringBuffer");
for (i = 0; i lt someLength; i = i + 1)
{
sb.append("_");
}
return sb.toString().getBytes();
}

This works, but as you might expect, it’s not the most efficient technique. Any other ideas?