I'm sorry to say that this post will be words only. No juicy code or bug ridden demo applications. Hopefully it will give you ideas on how to make use of this concept in your own applications.
Backstory: A customer of ours needed to get mails from Outlook into a Domino CRM web application. The prerequisite was that the users shouldn't need to install the Notes client.
This was presented to me by my boss over a couple of beers. I more or less immediately thought of the great functionality the Domino server has, that you can set up any NSF as the receiver of mails. If you could tag the mail with values inside Outlook, an agent could process the forwarded mails (add Readers/Authors fields based on customer id/etc.).
I started out with a POP3 Gmail account inside Outlook. I went through most of the writable properties of the mail-object, and struck gold. :)
The mail-object has a property called Category. When the mail is received inside Notes, this field is called Keywords. The field seems to be restricted to ASCII characters (or Gmail/Domino converts it to that). Therefore, the values need to be URL-encoded. From my small tests, everything seems to go through the wire. Line break, international characters, etc.
I send the values in a URL parameter pattern, so they're more readable, but formats like XML, CSV and JSON should work just as well. The only restriction I can think of is the ridiculous 32k limit on fields.
To let the user select the customer ID, I use the WebBrowser control inside a dialog in Outlook. The user interface is more or less a view with some DHTML code. When a user click a table row, I add a class on the row so that the user sees which customer is selected. I collect all the values from the selected table row, and put them inside a hidden field (comma separated). When the user clicks OK in the Outlook-dialog, I use VBA to collect the values from the hidden field. A second dialog is used for some custom fields (document type, date and description). That's about it.
Share and enjoy!
Friday, June 5, 2009
Thursday, June 4, 2009
UserCss: Cleaning up the Google Reader interface
I finally had enough with Bloglines. The RSS-robots are extremely slow, the page has a fair amount of downtime, the site has a lot of problems, etc.
I started using Google Reader today. The only thing I didn't like about it was all the clutter. Bloglines wastes little space.
I've known about the posibility for site-specific CSS in Opera for several years, but never had the need for it. This was the perfect occasion to try it out. I used Opera Dragonfly to identify the spots that needed to go/the items that needed to be moved.
This is the result:

(Screenshot from Opera 10 Beta1. Looking forward to being able to have the thumbnails on the left. Not usable as is.)
The stylesheet if you're interested.
In Opera, you're only able to set site-specific CSS per domain. Therefore the above CSS influences all google sites. Opera only stylesheet that doesn't affect (from what little I've tested) other google sites.
I started using Google Reader today. The only thing I didn't like about it was all the clutter. Bloglines wastes little space.
I've known about the posibility for site-specific CSS in Opera for several years, but never had the need for it. This was the perfect occasion to try it out. I used Opera Dragonfly to identify the spots that needed to go/the items that needed to be moved.
This is the result:

(Screenshot from Opera 10 Beta1. Looking forward to being able to have the thumbnails on the left. Not usable as is.)
The stylesheet if you're interested.
In Opera, you're only able to set site-specific CSS per domain. Therefore the above CSS influences all google sites. Opera only stylesheet that doesn't affect (from what little I've tested) other google sites.
Labels:
random tip,
web
Tuesday, May 26, 2009
Conclusive way of testing if content has changed since last FTIndex
The standard way of testing, db.LastModified > db.LastFTIndexed, works great in a production environment. When you're doing performance tuning of an application that updates it's FT-index, it's not so great.
NotesDatabase.LastModified also includes changes to design elements. If you use the above test to fire a NotesDatabase.UpdateFTIndex, then the check, db.LastModified > db.LastFTIndexed, will return true until a document is modified in the db/the FTIndex is updated. Changes to design elements is ignored by the FT-indexing service on the server.
NotesDatabase.UpdateFTIndex is relatively expensive (I would think the more documents in the database -> The more time to check if the FTIndex should be updated). In an application of mine, I use NotesView.FTSearch to find certain content in views (to create HTML menu, etc). I use a class that updates the FT-index before it does the search. On regular pages, there is created two instances of this class. In an application with 200 documents, it takes the server ~130ms to do two calls to NotesDatabase.UpdateFTIndex, when the application is indexed. When I do performance tuning, I do changes to design elements, not content. Therefore the aforementioned test to determine if content has changed is flawed.
This is my so far best alternative to the "standard check". It takes 16ms to do twice in the aforementioned application. A savings of ~115ms.
NotesDatabase.LastModified also includes changes to design elements. If you use the above test to fire a NotesDatabase.UpdateFTIndex, then the check, db.LastModified > db.LastFTIndexed, will return true until a document is modified in the db/the FTIndex is updated. Changes to design elements is ignored by the FT-indexing service on the server.
NotesDatabase.UpdateFTIndex is relatively expensive (I would think the more documents in the database -> The more time to check if the FTIndex should be updated). In an application of mine, I use NotesView.FTSearch to find certain content in views (to create HTML menu, etc). I use a class that updates the FT-index before it does the search. On regular pages, there is created two instances of this class. In an application with 200 documents, it takes the server ~130ms to do two calls to NotesDatabase.UpdateFTIndex, when the application is indexed. When I do performance tuning, I do changes to design elements, not content. Therefore the aforementioned test to determine if content has changed is flawed.
This is my so far best alternative to the "standard check". It takes 16ms to do twice in the aforementioned application. A savings of ~115ms.
Function contentChangedSinceLastFTIndex( db As NotesDatabase ) As Boolean
Dim session As New NotesSession
Dim lastFTIndexed As Variant
lastFTIndexed = db.LastFTIndexed
'First test (least resource-hungry)
If Not ( db.LastModified > lastFTIndexed ) Then
contentChangedSinceLastFTIndex = False
Exit Function
End If
'Conclusive test - test if actual documents (not design elements)
'have been changed since last FTIndex
Dim dateFTIndexed As New NotesDateTime ( lastFTIndexed )
Dim col As NotesDocumentCollection
Set col = db.GetModifiedDocuments( dateFTIndexed )
If col.Count > 0 Then contentChangedSinceLastFTIndex = True
End Function
Labels:
lotusscript,
random tip
Thursday, May 21, 2009
Help get the NotesUI-bugs in Notes 8.5 fixed
If you're having problems working with the NotesUI classes in Notes 8.5, or are planning to upgrade to Notes 8.5.x in the future/have applications that use the NotesUI-classes. Please contact Lotus Support and open a PMR to request inclusion of the fix in an 8.5 FP.
Thanks, Andre for making people aware of this issue.
Thanks, Andre for making people aware of this issue.
Labels:
Lotus Notes
Tuesday, May 19, 2009
Rearrange your Windows taskbar with Taskbar Shuffle
Update: 64-bit version of Taskbar Shuffle. The one on snapfiles/download.com doesn't seem to work with 64-bit Vista. I also found a similar program, Taskix. I haven't tried it, but from what I read on a forum, it works more or less like Taskbar Shuffle.
I recently dropped back from Windows 7 on one of my laptops to Windows XP, due to crackling sounds when playing music off my USB DAC.
One of the Windows 7 features I missed the most was the ability to rearrange the open applications in my taskbar. Thankfully, someone has made an application that lets you do this in earlier versions of Windows, Taskbar Shuffle (I downloaded it from SnapFiles).
At work, I start some applications in a certain order (hour sheet@Notepad++, Lotus Notes, Domino Designer). If Notes crashes and I have open a lot of applications, I often close all other apps, to get the order back. No more of that.
Speaking of useful applications. One of my all time favorite utility applications is Launchy. It lets you launch applications at the blink of an eye. Highly recommended if you prefer your keyboard to your mouse.
Clipboard Recorder is a must when working with code (you can also configure it to keep a history of bitmaps).
For screen capture, I use Gadwin PrintScreen.
At home, avast keeps me safe from viruses, and SUPERAntiSpyware (horrible title) is used to look for spyware.
I recently dropped back from Windows 7 on one of my laptops to Windows XP, due to crackling sounds when playing music off my USB DAC.
One of the Windows 7 features I missed the most was the ability to rearrange the open applications in my taskbar. Thankfully, someone has made an application that lets you do this in earlier versions of Windows, Taskbar Shuffle (I downloaded it from SnapFiles).
At work, I start some applications in a certain order (hour sheet@Notepad++, Lotus Notes, Domino Designer). If Notes crashes and I have open a lot of applications, I often close all other apps, to get the order back. No more of that.
Speaking of useful applications. One of my all time favorite utility applications is Launchy. It lets you launch applications at the blink of an eye. Highly recommended if you prefer your keyboard to your mouse.
Clipboard Recorder is a must when working with code (you can also configure it to keep a history of bitmaps).
For screen capture, I use Gadwin PrintScreen.
At home, avast keeps me safe from viruses, and SUPERAntiSpyware (horrible title) is used to look for spyware.
Labels:
random tip
Friday, May 8, 2009
LotusScript: Case insensitive replace
Recently, I've been working on "cloning" CMS-type applications. To avoid a lot of unnecessary work, I run an agent on the copied CMS that rewrites the UNID of the documents to that of the document in the original CMS, and rewrites local links to point to the cloned application.
Since the urls can be typed in multiple ways, the way to go for the link rewriting is case insensitive replace. This is provided in LotusScript (no need for Java).
The last parameter tells replace that it should do a case insensitive replace.
All the parameters (taken from the documentation)
0 (default): case sensitive, pitch sensitive
1: case insensitive, pitch sensitive
4: case sensitive, pitch insensitive
5: case insensitive, pitch insensitive
Example of pitch difference: e, é, è
The CMS applications in question are web applications, so the body is text/HTML. If you're working on cross platform (Notes/Web) applications, I'd think there would be more work to clone an app (RT-navigation *shudders*).
Since the urls can be typed in multiple ways, the way to go for the link rewriting is case insensitive replace. This is provided in LotusScript (no need for Java).
Replace( htmlBody, webDbNameSource, webDbNameClone, , , 1 )The last parameter tells replace that it should do a case insensitive replace.
All the parameters (taken from the documentation)
0 (default): case sensitive, pitch sensitive
1: case insensitive, pitch sensitive
4: case sensitive, pitch insensitive
5: case insensitive, pitch insensitive
Example of pitch difference: e, é, è
The CMS applications in question are web applications, so the body is text/HTML. If you're working on cross platform (Notes/Web) applications, I'd think there would be more work to clone an app (RT-navigation *shudders*).
Labels:
lotusscript,
random tip