Category Archives: Old Blog Post
Texas Law H.B. 2003
A new Texas law that took effect September 1, 2009. H.B. 2003 says a person commits a third degree felony if the person posts one or more messages on a social networking site with the intent to harm, defraud, intimidate or threaten another person.
The same thing goes for instant messaging, it is now illegal to pretend to be someone else in an IM, trying to defraud or intimidate someone.
Strange problem with views
I been having a strange problem with a particular view in one of my Notes applications.
The view displays main documents andchild (response)documents.
The problem is thatthe child documents are not sorting correctly, as you can see in the following screenshot:
The child documents are created using several different forms, and I have a hidden column in the view intended to sort the documents in a particular order based on the form.
The first column isjust displaying the claim number (09PSITXnnnnnnn, etc). It is sorted but not categorized. It is set to show a twistie when expandable. The column is very narrow, so it will only show the custom twistie I am using.
The second column is the one I use for sorting. The column formula is as follows:
@If(Form="Coverage Verification";1; Form="QuickStrikeSheet";2; Form="Expense Sheet";3; Form="Attachments";4; Form="Time Sheet";5; Form="Legal Summary";6; Form="Diary";7; Form="Log";8; Form="Negotiation Summary";9; Form="LargeLossNoticeReport";10;@Left(Form;4)="frm_";11;@Left(Form;10)="MailMerged";12;99 );
The column is hidden and sorted ascending.
Following this column I have a handful more, but they are all for the main document, showing additional info, creating the colored background based on status, etc.
Below is the design, with the non-sortable view selected.
It seems like the response documents are being displayed in some other sort order. It does not seem to be consistent with the order they are created, though.
Anyone can figure this out? I am using Domino Designer 7.0.2.
Please mail me at khm@deep-south.com if you can’t comment here.
I would have asked the question on twitter or used SameTime and the BleedYellow community server, but my network admin is blocking pretty much everything. Especially twitter, as he think the only use for twitter is to see what Ashton Kutcher is doing…
Update: If I move the hidden sortedcolumn to the left, before the categorized column, the sorting is correct but then the users can’t jump quickly to a particular claim number by doing a view search (just start typing in a claim number).
Lotus Notes 8.5.1 – Now with free Designer!
Notes client performance
Watch the two screencam videos linked below. They are each about 10-15 seconds long.
Exactly the same code, running on the same computer, against the same server.
I am able to reproduce the results are reproduced every time I test.
I don’t have Notes 8.x on this system, as our plans currently are to eventually move all our users to Notes 7…
And I don’t see Notes 8.x being deployed in a near future here.
Update: I just used TeamStudio Profiler to time the process. In Notes 5 it took 3.8 seconds, in Notes 7 it took 0.8 seconds. The main difference was in calling a db.GetView(). I then wrote some code that just call that function 8 times, each time to a different view. It took 2.4 seconds in Notes 5 and 0.17 seconds in Notes 7, again according to Profiler.
More fun with lists
After Kathy Brown wrote about lists earlier today, I thought I would share another example of how they can be used. Back in April I shared some code showing how to get latitude and longitude for an address, by calling Google’s GeoCode REST service.
Today I will show how easy it is to use that class together with a list…
First, let’s revisit the GeoCode class. I made some minor modifications, so I will post the latest version here:
Class GeoData Private GeoString As String Public street As String Public city As String Public zip As String Public state As String Public latitude As String Public longitude As String Public Sub New(streetStr As String, cityStr As String, stateStr As String, zipStr As String) Dim httpObject As Variant Dim mapsKey As String Dim mapsURL As String Dim address As String Dim retries As Integer Dim httpURL As String Dim returncode As String Dim coordinates As String Dim ret As Integer Dim xmladdress As String Dim addarray As Variant retries = 0 Set httpObject = CreateObject("MSXML2.ServerXMLHTTP") mapsKey = "your_googleAPI_key" mapsUrl = "http://maps.google.com/maps/geo?q=" address = streetStr & ", " & cityStr & ", " & stateStr & " " & zipStr httpURL = mapsURL & address & "&output=xml&key=" & mapsKey ' Use output=CSV for CVS file Do If retries>1 Then Sleep 1 ' After the two first calls, introduce a 1 second delay betwen each additional call End If retries = retries + 1 Call httpObject.open("GET", httpURL, False) Call httpObject.send() GeoString = Left$(httpObject.responseText,16000) returncode = GetGeoValue("code") If retries >= 10 Then returncode = "500" ' Fake other failure after 10 attempts End If Loop Until returncode <> "620" If returncode = "200" Then coordinates = GetGeoValue("coordinates") latitude = Left$(coordinates, Instr(coordinates,",")-1) longitude = Mid$(coordinates, Len (latitude)+2, Instr(Len(latitude)+2,coordinates,",")-Len(latitude)-2) street =GetGeoValue("ThoroughfareName") zip = GetGeoValue("PostalCodeNumber") city = GetGeoValue("LocalityName") state = GetGeoValue("AdministrativeAreaName") xmladdress = GetGeoValue("address") If city = "" Then If state <> "" Then addarray = R5split(xmladdress,", ") city = addarray(1) zip = Right$(addarray(2),5) End If End If If Ucase(state)<>Ucase(stateStr) Then ' Different state? ret = Msgbox("The address returned seems to be very different" & Chr$(13) & _ "from the one submitted." & Chr$(13) & _ "The address returned is:" & Chr$(13) & Chr$(13) & _ street & Chr$(13) & city & ", " & state & " " & zip & Chr$(13) & Chr$(13) & _ "Do you want to use this address?",4+32,"WARNING") If ret = 7 Then street = streetStr zip = zipStr city = cityStr state = stateStr End If End If If street = "" Then Msgbox "The street address could not be verified." & Chr$(13) & _ "Existing value will be saved." & Chr$(13) & _ "Please verify that address is correct.",,"Street Not Verified" street = streetStr End If If city = "" Then Msgbox "The city could not be verified." & Chr$(13) & _ "Existing value will be saved." & Chr$(13) & _ "Please verify that address is correct.",,"City Not Verified" city = cityStr End If Else If returncode = "602" Then Msgbox "No corresponding geographic location found"_ ,,"Google GeoCode Error 602" Elseif returncode = "603" Then Msgbox "The geocode cannot be returned due to legal or contractual reasons." _ ,,"Google GeoCode Error 602" End If ' Return original value to avoid overwriting... street = streetStr zip = zipStr city = cityStr state = stateStr End If End Sub Public Function Accuracy() As Integer Dim startpos As Long Dim endpos As Long If IsValid = False Then Accuracy = 0 Exit Function End If startpos = Instr(Lcase(GeoString),|accuracy="|) + 10 endpos = Instr(startpos, Lcase(GeoString), |"|) If endpos < startpos Then Accuracy = 0 Else Accuracy = Cint(Fulltrim(Mid$(GeoString,startpos, endpos - startpos))) End If End Function Public Function HasAddInfo(address As String) As Integer If Instr(Lcase(address),"apt")>0 Then HasAddInfo = True Elseif Instr(Lcase(address),"apartment ")>0 Then HasAddInfo = True Elseif Instr(Lcase(address),"suite ")>0 Then HasAddInfo = True Elseif Instr(Lcase(address),"ste ")>0 Then HasAddInfo = True Elseif Instr(Lcase(address)," #")>0 Then HasAddInfo = True Elseif Instr(Lcase(address),", ")>0 Then HasAddInfo = True Else HasAddInfo = False End If End Function Public Function Compare(str1 As String, str2 As String) As Integer End Function Public Function IsValid() As Integer If GeoString = "" Then IsValid = False Else IsValid = True End If End Function Public Function GetGeoValue(tag As String) As String Dim startpos As Long Dim endpos As Long Dim tempstring As String If GeoString = "" Then GetGeoValue = "" Exit Function End If startpos = Instr(Lcase(GeoString),"<" & Lcase(tag) & ">") + Len(tag) endpos = Instr(startpos, Lcase(GeoString), "</"+Lcase(tag) & ">") If endpos < startpos Then GetGeoValue = "" Else tempstring = Fulltrim(Mid$(GeoString,startpos+2, endpos - startpos - 2)) GetGeoValue = Fulltrim(R5strReplace(tempstring,"&","&")) End If End Function Private Function R5strReplace(mystring As String, search As String, replacewith As String) As String Dim source As String source = mystring While Instr(source, search) > 0 source = Left$(source, Instr(source, search) - 1) + replacewith + _ Right$(source, Len(source) - Instr(source, search) - Len(search) + 1) Wend R5strReplace = source End Function Private Function R5split(strSource As String, strItemDelim As String) As Variant Dim astrReturn() As String ' The array to return Dim intElement As Integer ' The array element currently being set Dim z_intItemCount As Integer ' The total number of elements for the array Dim z_intStartOfItem As Integer ' The start position of the item in the source string. Dim z_intEndOfItem As Integer ' The end position of the item in the source string. Dim z_strCurItem As String ' The currently parsed item Dim z_strRemaining As String ' The remaining string to cycle through Dim z_strStartOfItemBack As String ' The rest of the string, from the start of the item on back. z_strRemaining = strSource ' Cycle through the source string and get a count of elements: While (Not z_strRemaining = "") z_intStartOfItem = Instr(1, z_strRemaining, strItemDelim) If (z_intStartOfItem <> 0) Then z_intItemCount = z_intItemCount + 1 z_strRemaining = Mid(z_strRemaining, z_intStartOfItem + Len(strItemDelim), Len(z_strRemaining)) Else z_intItemCount = z_intItemCount + 1 z_strRemaining = "" End If Wend ' Size the return array so that it can hold all of the elements: Redim astrReturn(z_intItemCount - 1) ' Reset the holder to the value of the source string: z_strRemaining = strSource ' Cycle through the source list, parsing the string into individual array elements: While (Not z_strRemaining = "") For intElement = 0 To Ubound(astrReturn) ' Find the end of the current element: z_intEndOfItem = Instr(1, z_strRemaining, strItemDelim) ' If there is still an item delimiter in the string, parse ' out the item, otherwise assume the remaining text is the ' last item: If (z_intEndOfItem <> 0) Then z_strCurItem = Mid(z_strRemaining, 1, z_intEndOfItem - 1) astrReturn(intElement) = z_strCurItem z_strRemaining = Mid(z_strRemaining, z_intEndOfItem + Len(strItemDelim), _ Len(z_strRemaining)) Else astrReturn(intElement) = z_strRemaining z_strRemaining = "" End If Next Wend ' Return the split array to the caller: R5split = astrReturn End Function End Class
provided by Julian Robichaux at nsftools.com.
Below is a simple code sample that will read all person documents from the NAB, get address information for each person, create a list of GeoData objects, then loop through the list and retrieve data out of it.
Of course it could have been done all in the first loop, but I am splitting it up for demonstration purposes.
Sub ProcessDocs Dim db As New NotesDatabase("dsCorp/Deep-South","names.nsf") Dim view As NotesView Dim doc As NotesDocument Dim geodata As GeoData Dim street As String Dim city As String Dim state As String Dim zip As String Dim uind As strring ' Loop though all person documents Set view = db.GetView("People") Set doc = view.GetFirstDocument() Do While doc Is Not Nothing ' Read address from person documents street = doc.OfficeStreetAddress(0) city = doc.OfficeCity(0) state = doc.OfficeState(0) zip = doc.OfficeZIP(0) If street<>"" Then ' Make sure we have an address unid = doc.UniversalID ' Person document unid, used as list tag ' Create a new list item, with unid as list tag and a GeoData object stored Set geodata(unid) = New GeoData(street, city, state, zip) End If Set doc = view.GetNextDocument(doc) Loop ' Now we will look through the list and get docs again Forall g In geodata ' Get the person document again based on list tag Set doc = db.GetDocumentByUNID( Listtag(g) ) ' Write latitude and longitude to person document doc.OfficeLatitude = g.Latitude doc.OfficeLongitude = g.Longitude Call doc.Save(True,True) End Forall End Sub
provided by Julian Robichaux at nsftools.com.
Simple Mail Notification Class
I have a function I wrote way back to generate mail notification out of my program. But in many cases it had to be modified for each use. Yesterday I decided to write simple class instead, and here is the result. I will post it at OpenNTF.org soon as well.
This is how you use the class:
Set mailnotification = New MailNotification()
mailnotification.SendTo="texasswede@gmail.com"
mailnotification.Subject = "Test email fron Notes"
mailnotification.Principal = "System X "
Call mailnotification.body.AppendText( "This is some text in the body field. " )
Call mailnotification.body.AppendText( "And some more." )
Call mailnotification.body.AddNewLine( 1 )
Call mailnotification.body.AppendText( "Docclink: " )
Call mailnotification.body.AppendDocLink( doc, "Click to open" )
Call mailnotification.body.AddNewLine( 2 )
Call mailnotification.Send()
Easy, huh?
And here is the class itself. I store it in a script library called Class.MailNotification… Enjoy!
Class MailNotification Public maildoc As NotesDocument Public body As NotesRichTextItem Public subject As String Public sendto As String Public copyto As String Public bccto As String Public principal As String Public Sub New() Dim session As New NotesSession Set maildoc = New NotesDocument(session.CurrentDatabase) Call maildoc.ReplaceItemValue("Form","Memo") Set body = New NotesRichTextItem(maildoc,"Body") subject = "" sendto = "" copyto = "" bccto = "" principal = "" End Sub Public Sub Send() If subject<>"" Then maildoc.Subject = subject End If If sendto<>"" Then maildoc.SendTo = sendto End If If copyto<>"" Then maildoc.CopyTo = copyto End If If bccto<>"" Then maildoc.BlindCopyTo= bccto End If If principal<>"" Then maildoc.Principal = principal End If Call maildoc.Send(True) End Sub End Class
Lotus knows… the Power of One
Or perhaps the title of this post should be "Lotus should know". The story below is inspired by several suggestions at the Lotus Knows IdeaJam, including this one.
Thisis a true story of how one person in 6 months got a whole department to change from one word processor to another, without even involving the IT department.
In early 1993, I started working as a journalist at Computer Sweden, the Swedish edition of ComputerWorld. I had previously worked at Microsoft (in 1988-1990), and then I worked as a programmer for 2 years. At that workplace we used Microsoft Word and Excel. So I was very used to Word.
At Computer Sweden, they used WordPerfect 5.1 (if I recall correctly). When writing, they used special markup for QuarkXPress, to set headlines, body text, etc. I did not like WordPerfect, and was not used to it, so I loaded Word on my computer and started working. After a few weeks I decided to make life easier by developing a Normal.dot template so I could format the text in a WYSIWYG way, and then have a macro to create the QuarkXPress markup when I was done. I also added code to copy the resulting file to tne network share where the editors could get to it.
Some other users saw it, got Word installed and started using my macro. Within 6 months of me starting, the editor-in-chief demanded that everyone switched to Word and used my macro. WordPerfect was out from that magazine. Soon other magazines followed, and several started using the same macro. Later I modified it to generate HTML, upload the resulting file to teh web server and edit the homepage to include a link to the new story.
Not one dollar spent in sales calls/visits, direct marketing or anything from Microsoft, just one user showing how a different tool could do things faster and better. I am sure a similar macro and template could have been done in WordPerfect. But I knew Word, soI built it there.
Imagine tech-savy students coming out in the workplaces, loading their computers with "Lotus Notes Personal Edition", "Domino Designer Personal Edition" and connecting to a public demo server provided by IBM, and then develop some useful and good looking applications for their new employer in a day or two…Web-enabled and/or Notes client access in one easy-to-use environment.
OpenNTF – free hosting of projects?
During IamLUGlast week, John Head talked about some really exciting new things that are in the planning stage at OpenNTF. Nathan T Freeman teased a little bit about it the other day as well.
What the plan is (and as Nathan said, it is not set in stone it will happen) is that OpenNTF will offer free development hosting. When you create your project, you get a question if you want it hosted. If you select "yes", a VMware server is being setup, Linux and Domino installed, your ID file being created and sent to you within a few minutes. I think John said 120 seconds…
I think this is really exciting, it will let everyone start playing with Xpages and other technologies without the need for your own 8.5.x server. I know that I am excited about testing this! From what I hear, IBM donated an open-ended server license for this to happen.
Free legal e-books!
A couple of months ago, I stumbled on a series of booksat Barnes & Noble. Since I am interested in history, they caught my eye. The first book is named 1632, the second one 1633, and they are parts of a series calledthe 1632 series or "Ring of Fire". Yesterday I happend to stumble on more information about the books, and found out it is a whole series of books, e-books, etc. Many of the books are available as free legal downloads at the publisher Baen Bookswebsite, through the Baen Free Library.
From Wikipedia (slightly edited for length:
The fictional town of Grantville, West Virginia and its power plant are displaced in space-time. A hemispherical section of land about three miles in radius measured from the town center is transported back in time from April of 2000 to May of 1631. The town is thrust into the middle of the Thirty Years’ War, in the German province of Thuringia in the Thuringer Wald, near the fictional German free city of Badenburg.
Grantville, led by Mike Stearns, president of the local United Mine Workers of America (UMWA), must cope with the town’s space-time dislocation, the surrounding raging war, language barriers, and numerous social and political issues, including class conflict, witchcraft, feminism, the reformation and the counter-reformation, among many other factors. One complication is a compounding of the food shortage when the town is flooded by refugees from the war. The 1631 locals experience a culture shock when exposed to the mores of contemporary American society, including modern dress, sexual liberation, and boisterous American-style politics.
Grantville struggles to survive while trying to maintain technology sundered from twenty-first century resources. Throughout 1631, Grantville manages to establish itself locally by forming the nascent New United States of Europe (NUS) with several local cities even as war rages around them. King Gustavus Adolphus rapidly moves the war theater to Franconia and Bavaria, just south of Grantville. This leads to the creation of the Confederated Principalities of Europe (CPoE).
I just downloaded 1632 and will start reading it tonight. If it is good, I might just go ahead and buy the books. I think this kind of publishing is great, you get to read some, see if you like it, then buy the books and support the authors.