Office: 270.245.1188 Emergency: 270.752.0059
Site Contents

C O M P A N Y

Overview
Advantages — Blade's Edge
Personnel
Contracts & Rates
Contact


S E R V I C E S

Software Engineering
Systems Analysis
Networking & Security
Repairs & Upgrades
Training & Support


P O R T F O L I O

Overview
Landmark Projects
Government Projects
Non-Profit Projects
Development Tools
Scientific & Technical Projects
Support & Business Tools
Consumer Products
Portfolio: Scientific and Technical Projects
 
Jump To:  Overview |  HipSIP |  CatScan / CatStat |  MasterKey |  VBDbImg
 
 

Although it's greatly satisfying to create software used by global corporations and thousands of individuals, many small projects produce equal rewards in very different terms.

We've been blessed to work on a diverse mixture of such small, but uniquely-positioned projects. We summarize two that are of a semi-scientific nature below, followed by a couple of solutions we devised to overcome technical obstacles encountered by other software companies.

Although none of these programs are earth-shakers in any regard, they provided worthy opportunities to obtain unfamiliar domain knowledge, develop new abilities, and apply well-worn skills to previously-unpracticed applications.

 
 
HipSIP
 
Jump To:  Overview |  HipSIP |  CatScan / CatStat |  MasterKey |  VBDbImg
 

I N T R O D U C T I O N

Since 2005, we've been privileged to work intermittently with an embarrassingly-brilliant scientist, R. Andres Ferreyra. A doctor of agricultural and biological engineering, Andres also picked up a masters in agrometeorology and an electrical engineering degree along the way, presumably to satisfy some of his satellite curiosities. ;-)

Among his long-held lesser interests is emerging applications on mobile platforms. To this end, Andres enlisted us to assist in a research project devised to measure human efficiency against an array of highly-varied soft input panels (SIPs).


D E V E L O P M E N T

Andres designed a lineup of SIPs featuring both general purpose and numeric configurations. These designs were translated into bitmaps, and from bitmaps to image maps. Another file was created to host test-values and instructions to the test-subjects and input test values. Because nothing more complicated (and slower, and more difficult to modify) was needed, image maps and test values were expressed as comma-separated values: Andres heartily agrees with us that over-architecting is a cardinal sin.

While Andres was synthesizing the source data, we created HipSIP (Hip as in cool), a simple PocketPC program that presents the series of SIPs and input tests, measures completion times, and tallies errant responses. Because HipSIP is driven from CSVs and bitmaps, Andres was able to continually improve the experiment with no intercession from us once he had the program in his hands.


R E S U L T S   A N D   P O S T - M O R T E M

Through Andres' academic ties, Murray State University bussed fifty or sixty students to a company conference room where we distributed handhelds, issued instructions, and administered the tests. I compiled and surrendered the resulting data to Andres. The results proved several SIPs clearly superior to their companions.

Jason wrote code to replace the standard Windows CE SIPs with these improved incarnations in two company products. Knowing Andres as I do, and in keeping with his scientist-hacker "information should be free" life-mantraI expect he shared his findings with at least some of the mobile manufacturers of the day.

Click Any Image to Enlarge

Click right half of image to move forward
Click left half of image to move backward
Or use LEFT and RIGHT cursor keys






 
 
CatScan / CatStat
 
Jump To:  Overview |  HipSIP |  CatScan / CatStat |  MasterKey |  VBDbImg
 

I N T R O D U C T I O N

The aforementioned R. Andres Ferreyra, acting in a consulting role, had been studying the operations of a local business that encompassed both a sizable fish farm and a processing plant. He outlined two applications to improve efficiency and brought us on board to implement them.

These applications were tentatively named CatStat and CatScan, simply because catfish represented a significant portion of the farm's revenue stream and names with fish in them didn't come to mind as easily or roll off the tongue as smoothly. ;-)


D E V E L O P M E N T

We began developing two distinct programs:

  1. CatStat was built to simulate fish farming. By modifying production variables, harvest count and weight could be predicted. Comparing the various cost vs. yield projections, the farm could maximize profits. Further, by comparing post-season results with pre-season predictions and identifying the reasons for any non-trivial differences, the program could be improved through time.

    Andres' education as an agricultural and biological engineer complemented the farmers' real-world experience perfectly. Jason banged-out the GUI, data layers, and application plumbing while Andres cemented the algorithms, but it wasn't long before the second program demanded priority . . .

  2. CatScan relied on handheld barcode scanners and label printers to track fish from the moment they were extracted from a pond, through every step of the processing plant, to the time they were placed in consumers' hands, whether that be by local delivery or across country via air-mail. This was both to enable the farm to prove to any suspicious customer that its products were processed and delivered in a timely manner and to get ahead of evolving state law that Andres believed would inevitably require such product-traceability.

    RFID tags were considered in place of barcodes, but were ultimately rejected due to a) the immaturity of the technology at the time, b) its greater cost, and c) the potential effects of extreme and rapdily-changing environmental conditions on the tags.

    Other CatScan features included inventory control, QuickBooks integration, and reporting. CatStat was eventually "rolled into" CatScan.


R E S U L T S   A N D   P O S T - M O R T E M

Unfortunately, during the development process, the processing plant was unexpectedly closed and the farming operation sold and downsized. That not every project sees the light of day is simply a fact of programming life.

Still, that doesn't mean that our investment in the project was without its returns. We became familiar with barcode programming and some of the more esoteric aspects of the surrounding technology — and when else will we ever get paid to code a fish-farming simulator? Developers are always excited to learn new technologies, and on that point, we emphatically agree; but learning new businesses is underappreciated, and consistently one of the very best perks of our business.

[Click Image to Enlarge]

 
 
MasterKey
 
Jump To:  Overview |  HipSIP |  CatScan / CatStat |  MasterKey |  VBDbImg

I N T R O D U C T I O N

From Blade Technologies proprietor Jason Purcell:

Another software company, for which I'd already been working, was suffering from crippling problems in one particular, oft-visited area of its flagship application. Support was at its collective wits' end, and pleading for a solution. The app's developers not only failed to identify a solution, but responded to support's cries for salvation by pronouncing the dilemmas irrefutably unsolvable.

Now, since my very earliest days working with other programmers, claiming that something can't be done has been far-and-away the most agitating of developer-birthed irritants — hard evidence, no doubt, of my father's successful indoctrination of his "there's no such thing as can't" mantra.

Once I began hiring developers during my days at Hawkins Research, my aggravation at hearing "It can't be done" only grew. In my decades of experience, I've not once encountered a problem that — appropriated sufficient resources — could not be solved.

Yet, here we had an entire team of developers — five of them — who together determined that the world held no answers for not one, but two distinct quandaries! So of course, I just had to take an unsolicited look at these supposed supernatural monstrosities.


D E V E L O P M E N T

The two bottlenecks, and their solutions:

  1. Symptom: Decrypting thousands upon thousands of records from a database and loading them into a grid required 45–70 seconds on the limited number of relatively-modern systems tested in-house.

    Problem: The developers' insistence on using bloated, third-party database objects and data-bound controls. The backing database engine was a very early version of SQL Server Compact Edition, so conventional database paging wasn't an option. I could have rolled-my-own paging, but all the controls were data-bound and I wanted an overnight solution. I felt there must be a simpler way lurking beneath the surface.

    The developers were using NHibernate data objects because — at least at the time — they generally provided significantly increased performance over intrinsic .NET data objects, in addition to a multitude of extended features. However, I'm sure NHibernate's maker's would've been as surprised as I to learn how their components were being abused in this instance.

    Solution: Dear readers, ignore the question of why thousands of records were being loaded into a grid in a single operation in the first place. [smh, rolls-eyes, face-palms]

    I circumvented NHibernate data objects by writing my own, extremely lightweight version, intended only for this specific programming context. (The app's developers failed to even consider this solution, for with one exception, they were but a few years' out of college and had been irreparably indoctrinated with the "write once, reuse everywhere" fallacy that universities increasingly teach as software gospel.) I set the grid to unbound mode and instead loaded it via a loop that leveraged my custom data object.

  2. Symptom: Using the incremental search feature was painfully slow. As in CHUNK-PAUSE-CHUNK slow.

    Problem: The developers' were using the grid's built-in FIND method, assuming that they couldn't create a faster implementation in managed code.

    Solution: Inside the grid-loading loop, I added each item name/Id descriptor and grid row-index to a hash table. I searched against this hashtable, bypassing the grid's native FIND method, then set the grid's selected record using the associated row-index from the hashtable, and finally set the grid's viewport to make the selected record the first visible row.


R E S U L T S   A N D   P O S T - M O R T E M

MasterKey produced more than a 90-95% reduction in grid-loading times, and roughly a 70-90% reduction in incremental search times, which were more difficult to quantify.

The large variance in search performance is due largely to the row position of the matching record in the grid, as this grid — like most grids — only kept a couple of hundred records in its fast-access cache, so if the matching record's row fell outside of the currently-cached range, wait time was longer. It's possible that factors such as the number of matching records and/or the number of search characters played a much lesser role, but I didn't bother to test this possibility, as what I did made things fast enough.

Was this ground-breaking stuff? Well, certainly not to anyone I grew up coding with, but apparently, it's nothing less than black frakkin' magic — with all the appropriately terrifying and repulsive accoutrement — to today's exclusively-college-educated whippersnappers. and The application team was forced to adopt my code to their program, though I'm sure they were cursing me the entire time for introducing such dirty hacks to their bleached-clean code. ;-)


Sorry, no screenshots
due to non-disclosure agreements
 
 
VBDbImg
 
Jump To:  Overview |  HipSIP |  CatScan / CatStat |  MasterKey |  VBDbImg

I N T R O D U C T I O N

VBDbImg is simply an example program — illustrative code, nothing more. That's why it looks the way it does, with non-graphical, native-only controls and no polish of any kind. Decidedly unshiny.

It shows how to use vanilla Visual Basic to stash an image file into a database, and conversely, to spit a database image into a file, i.e. the time-honored "suck & blow" design pattern. ;-) So why do I include the equivalent of a pop song amongst so many symphonies?

In '96, a old friend and fellow programmer drove an hour to have lunch with me. When he walked into my office, I happened to be working on the inventory area of an application for a used-car dealer, and a PictureBox was displaying an image of some vehicle. He remarked what a pain it was to have to maintain image files in Visual Basic, and what a simple matter it was to use a database for image storage in Delphi.

Of course, I asked what he was talking about, and he informed me that as far as he knew, no one had figured it out, as he hadn't uncovered anything on the sad little digital rag that passed for the Web back then. So, I pulled up AltaVista. (Google wasn't a thing yet. Literally. It didn't exist. And AltaVista wasn't Yahoo yet, either. It was still AltaVista, the Google of our day!) Anyway, my friend was right: No matter how we searched, we found nothing.

Now, I'm sure I wasn't the only one to figure out how to work with database images in VB: From time-to-time, everyone sees an "obvious" solution almost no one else can find no matter how hard they look. (In fact, this was the same guy that within the next year or two wrote a C function I needed for PowerClaim, so what comes around . . .) Yet, of all of us that had discovered the answer, it seems that not a one bothered to share the wealth. Hence, this project.


D E V E L O P M E N T

Like probably every VB3 app, this one uses the Access/Jet database engine. As I was poking around in access, I stumbled upon what was then called a BLOB data type: Binary Large OBject. Now, when I opened this sucker up today, I saw that Access identified my image field as an OLE Object, but back when I created the app, BLOB fields were used to store all kinds of binary data, including OLE Objects. So I think it's the same thing today as it was then. I didn't exactly go digging for nuances on the web since we're talking about twenty-year-old code, so you're welcome to investigate yourself and drop me a line if you want to educate me.

Anyway, the "secret" is to use the AppendChunk() and GetChunk() methods from VB's Recordset.Field object. To store the image, open the file for Binary input, read it in as a byte array, and use AppendChunk() to push it into the field. Reverse the process with GetChunk to push it back out. No more complicated than that. You can see the relevant code in FPrimary.SaveFileToDatabaseRecord() and FPrimary.ExportDatabaseImageToFile().


R E S U L T S   A N D   P O S T - M O R T E M

Besides being upgraded from VB3 to VB6 and switching out the original database images for some slightly newer, higher-res pics, this project is unchanged from '96. It was posted on early versions of the Hawkins Research web site, but was understandably dropped at some point, as it simply wasn't relevant to company business.

This is the way I handled images all the way through VB6: Since the code is succinct and lightning fast and I'd already written it into my personal library, I just never bothered to see if Microsoft ever provided an easier way. Surely they did, but for all you guys and gals charged with maintaining and extending twentieth-century Visual Basic applications, you're welcome!

You can download VBDbImg here.

[Click Image to Enlarge]

 
[Back to Top]