I accomplished something this week. Some tweaks left to do, but at least it is working.
Nook Color
I accomplished something this week. Some tweaks left to do, but at least it is working.
Nook Color
Apparently the blog importer I was using is no longer supported by Facebook, so hopefully this one (NetworkedBlogs) will work. I decided to play around with the layout theme, and added a photo I took of the beautiful Flint Hills area around Emporia, Kansas.
Well, I started out the week attempting to update the rxkinetics.net web app. My plan is to add the ability to change and save settings and pk models, using the localStorage functionality in HTML5. But, localStorage is via JavaScript on the client side (web browser), whereas the web app is ASP.NET server side. And neither the twain shall meet.
Since this is a working site, I had to copy the abpk.aspx to a test page. Then I added a settings page for changing creatinine clearance options, and attempted to save and retrieve the settings and populate the screen.
I wanted to use JSON, because that is what I will need to use when I add local pk model storage. But, after screwing around with JSON for a day and failing, I gave up and put each setting into its’ own row.
Since I’m working in Visual studio 2005, there is no native support for JavaScript, no Intellisense, no syntax checking, no real time debugging. Just blind coding followed
by trial and error. The only debugging I could do was to put alerts at various points within the JavaScript to display the progress.
Then I had no idea where to put the JavaScript, and when to trigger it. Putting the code in head element and triggering the JavaScript on the page onload event did nothing because the page isn’t fully rendered yet. Placing the script in the body “sort of” worked, but the CheckBox.checked value didn’t change. I ended up adding some hidden elements to store the settings so the server side app could read them.
It took three days of beating my head against the wall to figure out this trivial stuff. So, having had enough of this frustration, I switched to working on the Nook Color version of the Android app.
The first problem I ran into was error after unexplained error in Eclipse. It kept showing errors from google tools, which aren’t even used in this app. I eventually figured out that these were red herrings, the real problem was the target platform was not set.
Next problem was the layout editor throwing an XML error on some of the layouts, for no reason whatsoever. Eventually discovered that this is a known bug in the Android layout editor.
Finally I was able to run the app in the emulator, but, as any developer knows there is no substitute for debugging the app on the actual target device.
And that’s when the real nightmare began.
B&N has the Nook Color totally locked down. It will not allow installation of “non-market” apps. Nor does it allow connection to the Android Debug Bridge, and there is no Development setting on the Nook as there is on a standard Android device.
I tried following the cryptic instructions on the Nook developer site to allow ADB access, to no avail.
Then I tried various methods from the internet to soft root it. One suggestion was to attempt to crash the browser by going to certain web site. It said to try it up to twelve times. Good grief, once upon a time google was useful for finding information, now it only brings up page after page of irrelevant useless crap.
Eventually I resorted to rooting the Nook, and, after uninstalling and reinstalling the ADB USB driver umpteen times, I was finally able to connect the Nook to Eclipse and debug the app. I started this at 5 AM and finally, at noon, got the app to run on the Nook.
Since I had copied the layouts from the Android phone version, I’ll need to change all of them, increasing the size and color of all the elements. But at least I can see some light at the end of the tunnel.
As for the web app, I’ll have to mull it over, my brain is just too tired now. I think I’m getting too old for all this switching between languages, my mind is not as agile as it used to be.
Misery
The update parade continues, adding new features to APK and Kinetics. Unfortunately I’ve had to spend a lot of time in the last two years learning and developing Android and web apps. But I’ve resolved to spend more time maintaining these traditional desktop apps, as a result there has been much catching up to do. Most of the new non-database functions were first implemented in Antibiotic Kinetics. It has a much smaller code base, making it easier to add and test new features without worrying about their impact on existing functionality. Although it takes more time to add new features to APK and Kinetics, the kinks have usually been worked out because of this “pre-testing” within the Antibiotic Kinetics code base.
APK 3.5.6 Features added/bugs fixed:
Kinetics 2.3.3 – Features added/bugs fixed:
Because there has been a fundamental change in how APK and Kinetics are accessed, I decided to make some screencasts demonstrating the changes, posting them to youtube.
Video highlights of APK update
Video highlights of Kinetics update
Video highlights of Antibiotic Kinetics update
Sheesh, what a week.
Spent the first day making some improvements to the RxInterventions program:
Then spent the rest of the week simultaneously updating APK and Antibiotic Kinetics. Both programs use the same code base for the calculations, while APK adds database functionality.
For Antibiotic Kinetics and APK added the following calculation related changes:
APK received a complete makeover in version 3.5.4. The most apparent change is the patient database interface. The program now starts with a simple search box. Type in a patient name to find matching records, or press Enter to list all patients. The user cannot add a new patient until record search has been performed. The intent is to cut down on entry of duplicate records for the same patient.
Start screen:
Search results:
MRU drop down:
Complete APK 3.5.4 change listing:
P.S. this new version of WordPress is buggy, the picture upload feature is broken. When I click to add a pic, it blackens the screen and… nothing. Had to add pix via pain-in-the-ass HTML code. Also, the code formatting plug-in does the same thing, blacks out the screen completely without any functionality, so I could not post the Adjust CL to IBW code. Found this on the wordpress forums: I think we can confirm that it is a mistake of the last update of wordpress
I ran some final tests from a USB stick on Vista and Win7, everything worked great. But when I tested it on a virgin XP system, it threw error 713 “MSSTDFMT.DLL is not registered on this computer.” I looked in the project references and noticed that the data formatter dll was listed, so I unchecked it and recompiled. Same error. Closed the IDE, reloaded the project, made sure the dll was no longer referenced in the project. Recompiled, continued to error-out on the test machine.
I remembered playing around with the DataFormat property on one text box on the main form. I had wanted to see if this property could be used for a time formatter, instead of having to use that awful Microsoft date/time control. It wasn’t useful at all, so I deleted the DataFormat property from the text box. But the compiled exe is still looking for the dll. WTF was going on? I finally loaded the form into a text editor and found this:
1 BeginProperty DataFormat2 Type = 13 Format = "HH:MM"4 HaveTrueFalseNull= 05 FirstDayOfWeek = 06 FirstWeekOfYear = 07 LCID = 10338 SubFormatType = 39 EndProperty
Even though I had deleted all reference to this in the IDE, it was still showing up in the form code. I deleted this code block in the text editor, saved the file and recompiled. Finally, it ran without error on all 3 test platforms. Testing completed, I posted the update to the web site. So glad to get this over with, I hate VB and can’t wait to get back to working in Delphi.
Finished updating the help file today. I hadn’t given it a thorough review for 3 years.
Changes since my last blog post:
Here is a screen shot of the MRU (most recently used) list:
And here is a screen shot of the improved EI nomogram:
Next up: more testing, then create installs: MSI for work (yuk) and EXE for others. I hope to update the video tutorials next time I’m off.
Decided to simplify screens even further. All other choices dithered out on patient search screen:
Only 4 icon choices on the patient edit/entry tab:
Summary of changes accomplished so far:
Yet to do:
The Cannabis app looks fantastic on the Mac iOS emulator, but I’ve been doing this long enough to know that you can’t rely on an emulator for software testing. Installation on a physical device is required for a thorough test.
I thought my 2nd generation iPod touch would work for iOS testing, thinking that I would also be able to test the app’s backwards compatibility. But XCode would not connect to the iPod, throwing an error message that XCode did not support iOS v 3.
So, two weeks ago I bought a 4th generation iPod touch with a cracked screen on eBay for $75. It finally came in the mail, in a box without any padding, and miraculously it powered on. I connected it to the Mac, but XCode threw another error, this time saying that it did not support iOS v 5. You’ve got to be kidding me Apple.
One option was to upgrade XCode, but I didn’t want to go that route because I had read that Free Pascal on the Mac had issues with the newest version of XCode.
So, I have spent the last 2 days trying to downgrade the iPod to iOS 4.x. My first attempt to downgrade to 4.3.5 gave the cryptic message “the device isn’t eligible for the requested build”. I then tried to restore it to version 5, and it went into a text display with writing so tiny it was impossible to read. Thought for sure that I had bricked it. I tried multiple times yesterday (and into the night) to download iOS 5, but the storm moving through caused the electricity to shut off 8 times. What a cluster fuck, I eventually gave up.
This morning I was finally able to download iOS 5, but again iTunes gave the message “the device isn’t eligible for the requested build”. WTF Apple? This is the OS that this device came with, how could it be ineligible?
Searches of multiple web sites yielded different suggestions for editing the hosts file. Some said no hash marks, some said a hash mark with no spaces. I tried them all, this one finally worked:
# 74.208.105.171 gs.apple.com
# 74.208.10.249 gs.apple.com
After restoring to iOS 5 and backing up the SHSH blob, I downloaded 4.3.3, put the device into DFU mode, and finally was able to downgrade.
This walled garden approach is exactly why I hate Apple products, they control your device. Every time I use an Apple product I hear the control voice from the Outer Limits: “Do not attempt to adjust the picture. We are controlling transmission. If we wish to make it louder, we will bring up the volume. If we wish to make it softer, we will tune it to a whisper. We will control the horizontal. We will control the vertical. We can roll the image; make it flutter. We can change the focus to a soft blur or sharpen it to crystal clarity. For the next hour, sit quietly and we will control all that you see and hear.”
Anyway, here are a couple of screenshots of the app running on an actual iPod:

One reason I’ve been avoiding working on Kinetics is because it was written in VB classic. At the time I started work on the Kinetics program (1995) I didn’t know any better. Not until I discovered Delphi did the limits of VB become apparent. Although I despise having to find workarounds for its’ shortcomings, I’m not translating 1,245,431 lines of code. No, that’s not a typo, 1,245,431 lines of code (including forms).
Below are some of the more interesting snippets of code that have been added to this version.
One of the first things on my to-do list was a function to prevent a user from completely changing the name in a patient record. The following code works perfectly. Setting the limit of change to 75% should allow one to correct misspellings without completely changing the name:
| Visual Basic | | copy code | | ? |
| 01 | Public Function FuzzyMatch(Fstr As String, Sstr As String) As Single |
| 02 | 'Purpose: Compare two strings and quantify the differences |
| 03 | |
| 04 | Dim L, L1, L2, M, SC, T, R As Integer |
| 05 | |
| 06 | L = 0 |
| 07 | M = 0 |
| 08 | SC = 1 |
| 09 | |
| 10 | L1 = Len(Fstr) |
| 11 | L2 = Len(Sstr) |
| 12 | |
| 13 | Do While L < L1 |
| 14 | L = L + 1 |
| 15 | For T = SC To L1 |
| 16 | If Mid$(Sstr, L, 1) = Mid$(Fstr, T, 1) Then |
| 17 | M = M + 1 |
| 18 | SC = T |
| 19 | T = L1 + 1 |
| 20 | End If |
| 21 | Next T |
| 22 | Loop |
| 23 | |
| 24 | If L1 = 0 Then |
| 25 | FuzzyMatch = 0 |
| 26 | Else |
| 27 | FuzzyMatch = M / L1 |
| 28 | End If |
| 29 | |
| 30 | End Function |
The calling code for the preceding FuzzyMatch function:
| Visual Basic | | copy code | | ? |
| 1 | sngFuzzy = FuzzyMatch(strPtName, .txtName.Text) * 100 |
| 2 | |
| 3 | If sngFuzzy < 75 Then |
| 4 | 'Exit if change too great |
| 5 | .txtName.SetFocus |
| 6 | MsgBoxCenter .hwnd, "Name field has changed by " & Format(100 - sngFuzzy, "##0") & "%", vbExclamation + vbOKOnly, "Edit limit exceeded", .Width, .Height, .Left, .Top |
| 7 | Exit Function |
| 8 | End If |
| 9 |
| Visual Basic | | copy code | | ? |
| 01 | If Not FileExists("\Blank.doc") Then |
| 02 | Dim ba() As Byte |
| 03 | Dim fh As Integer |
| 04 | ba = LoadResData(101, "CUSTOM") |
| 05 | fh = FreeFile |
| 06 | Open gvDataPath & "\Blank.doc" For Binary As fh |
| 07 | Put fh, , ba |
| 08 | Close fh |
| 09 | End If |
| 10 |
The preceding code depends on a function missing in VB classic, to check whether a file already exists:
| Visual Basic | | copy code | | ? |
| 1 | Public Function FileExists(Filename As String) |
| 2 | 'Purpose: Check for file existence |
| 3 | On Error Resume Next |
| 4 | FileExists = (Len(Dir(Filename)) > 0) |
| 5 | End Function |
| 6 |
Finally, there is this function for search and replacing text in a Word doc (have yet to figure out how to call the Printer dialog):
| Visual Basic | | copy code | | ? |
| 01 | Public Sub PrintWordDoc(ModelName As String) |
| 02 | 'Purpose: Word automation for monitoring form |
| 03 | |
| 04 | On Error GoTo PrintWordDoc_Err |
| 05 | |
| 06 | 'Open MS Word in background |
| 07 | Dim WordApp As Object |
| 08 | Set WordApp = CreateObject("Word.Application") |
| 09 | WordApp.Visible = False |
| 10 | |
| 11 | 'Open Template |
| 12 | WordApp.Documents.Open (gvDataPath & "\BlankPK_monitor.doc") |
| 13 | |
| 14 | 'Search and Replace loop |
| 15 | Dim SearchString, ReplaceString As String |
| 16 | Dim I As Integer |
| 17 | For I = 1 To 3 |
| 18 | Select Case I |
| 19 | Case 1 |
| 20 | SearchString = "C_PTNAME" |
| 21 | ReplaceString = frmKinetics.txtName.Text |
| 22 | Case 2 |
| 23 | SearchString = "C_ROOM" |
| 24 | ReplaceString = frmKinetics.txtRmNumber.Text |
| 25 | Case 3 |
| 26 | SearchString = "C_MD" |
| 27 | ReplaceString = frmKinetics.txtPhysician.Text |
| 28 | 'Code truncated here |
| 29 | End Select |
| 30 | |
| 31 | '? WordRange = WordApp.ActiveDocument.Content |
| 32 | |
| 33 | WordApp.Selection.Find.ClearFormatting |
| 34 | WordApp.Selection.Find.Replacement.ClearFormatting |
| 35 | |
| 36 | With WordApp.Selection.Find |
| 37 | .Text = SearchString |
| 38 | .Replacement.Text = ReplaceString |
| 39 | .Forward = True |
| 40 | .Wrap = wdFindContinue |
| 41 | .Format = False |
| 42 | .MatchCase = False |
| 43 | .MatchWholeWord = False |
| 44 | .MatchWildcards = False |
| 45 | .MatchSoundsLike = False |
| 46 | .MatchAllWordForms = False |
| 47 | End With |
| 48 | WordApp.Selection.Find.Execute Replace:=wdReplaceAll |
| 49 | Next |
| 50 | |
| 51 | 'TODO |
| 52 | 'Set printer & NumCopies |
| 53 | |
| 54 | 'Print |
| 55 | 'for I = 1 to NumCopies |
| 56 | WordApp.ActiveDocument.PrintOut |
| 57 | |
| 58 | 'Wait for print before closing Word |
| 59 | While WordApp.BackgroundPrintingStatus > 0 |
| 60 | DoEvents |
| 61 | DoEvents |
| 62 | Sleep (100) |
| 63 | Wend |
| 64 | |
| 65 | 'Close the document without saving |
| 66 | WordApp.ActiveDocument.Close (0) |
| 67 | |
| 68 | 'Quit Word |
| 69 | WordApp.Quit |
| 70 | WordApp = Nothing |
| 71 | |
| 72 | 'Exit before error trap |
| 73 | Exit Sub |
| 74 | |
| 75 | PrintWordDoc_Err: |
| 76 | giTrapItCentralErrorProcessor = TrapItCentralErrorProcessor("ddoc.bas", "PrintWordDoc", CStr(Err), Error$) |
| 77 | If giTrapItCentralErrorProcessor = 1 Then |
| 78 | Resume |
| 79 | ElseIf giTrapItCentralErrorProcessor = 2 Then |
| 80 | Resume Next |
| 81 | Else |
| 82 | Call CleanExit |
| 83 | End |
| 84 | End If |
| 85 | |
| 86 | End Sub |
Some history, a confession, and a re-dedication
Many years ago I designed the Kinetics program to keep a permanent record of patients and consults, realizing the importance of a patient’s history. The database is compact, individual records are very small in order to accommodate a large number of records in a small, easily accessible file. This was the fundamental concept I started with when I wrote the first DOS version 27 years ago.
When Windows 95 came out, text based programs became obsolete overnight. Suddenly everyone wanted icons to click, colorful 3-D dialogs, proportional fonts, and all the other features of a graphical user interface. So, I was asked to develop a Windows version of Kinetics. Work on the program has since consumed a large portion of my life.
Overall the experience has been satisfying, but I’ve never liked the visual database front-end. The data browser paradigm using a VCR style browser control may be visual, but it’s not intuitive. The concept took quite some time for me to understand.
Although I’ve always been dissatisfied with the data browser, I’ve come to accept it over the years, resigned to the fact that it was simply the standard way to create a Windows database front end. All the tutorials and examples in textbooks use the same clunky VCR-style browser control. I expected that all Windows database programs would function in this standard way (most do), and that people would eventually learn the paradigm. After corresponding with users, seeing how they fail to manage their database, it became obvious that most people don’t grasp the concept.
Because of this fundamental misunderstanding by users, Kinetics was never used correctly, people would use the temporary record for consults. They would add a patient without searching first, many patient records were duplicated, some patients (frequent flyers) were saved 6 times. There would even be multiple records for the same patient during the same admission. They used encounter number instead of medical record number, thus losing data integrity as the MRN is permanently associated with that patient.
Over the years I’ve added search features and list functions to give users the ability to navigate the data. I’ve created step-by-step tutorials and recorded demonstration videos for the web site to help users grasp the concept. But I was never able to address the fundamental problem, the counter-intuitive VCR database browser.
My priority is the science, I intended to concentrate on improving the algorithms and equations that analyze the data to give optimal results. But I’m always pulled away from the science in order to work on interface issues, Windows component problems, and workarounds to the clumsy, butt-ugly front-end.
I had all but given up on Kinetics, and focused more of my time on the Antibiotic Kinetics program. Of course, AbPK simply sidesteps the issue by totally eliminating the patient database. Another reason I stopped using Kinetics was because I became frustrated with handwriting monitoring forms and orders. So I programmed Antibiotic Kinetics to automate Word, filling-in and printing the paperwork, freeing me from the busy work so I could think the consult through.
However, karma does eventually catch up to you. I was burned by not having that all important consult history. I had abandoned my fundamental core principle. If I was still using Kinetics, and if it was being used properly, I would have known that we had consulted on this patient before, that he did not tolerate normal doses, and that he required an unusually low dose.
So, there is my confession, and my motivation for finally getting back to work on the Kinetics program. Oftentimes the best ideas come out of adversity.
Below is a peek at the old vs new starting screens.
First, the old way with the clunky VCR navigation, and the displayed temporary record.

The new start screen is yee-haw simple. Search is by MRN or patient name, toggle button to the left of the text box:

Type MRN (or name) and press enter to get a list of matching records. Only after a search is the “Add” button displayed.

Here is a look at the patient data tab after pulling up the record. There are only 5 database buttons to choose from (close, edit, save, cancel, list):

I would appreciate feedback from folks who are using the software, on the off chance that anyone actually reads this crap.
And I still need to work on the science, LOL.