Notes and Domino v12 is here!

HCL Software is launching the new version of the collaboration platform HCL Domino on June 7, together with the latest version of the meeting platform Sametime. If you already are a customer with entitlement to the products, you can already download them from FlexNet today.

Some of the new features in Domino v12:

  • Support for storing DAOS files in Amazon S3, to offload your own servers
  • Active directory password sync
  • Two-factor authentication and additional enhancements to internet security
  • New mobile capabilities
  • New icons and view list styling options
  • Hide fields or view columns on devices with lower resolution
  • Bootstrap 4 for XPages
  • Support for formula language in DQL queries
  • Aggregate document collections (e.g. from a search) across Domino databases
  • Button in Administrator client to find all groups a user belongs to
  • Enhancements to mail-in databases

And much more. Find out at the launch!

It is not only the Domino server and the Notes client that is being launched. The latest version of HCL’s no-code/low-code development tool Domino Volt is also available, as is a new version of the AppDev Pack that allows node.js developers to work directly with data stored in the Domino NoSQL-database. But wait, there is more!

A very exciting product HCL will present at the launch is Nomad Web, a client for Domino built for the browser with no downloads or plugins required. The client is written in Web Assembly, so it runs native in modern browsers. It can execute formulas and Lotusscript code, everything you can do in the regular client can be done (with a few exceptions like XPages). There has even been new classes added to Lotusscript to access hardware common in mobile devices and laptops, e.g. the camera and GPS. Nomad for iOS and Android has already been released, but with this zero footprint web client it is incredibly easy to deploy existing Domino application without having to convert them to true web applications. They will simply work as-is. This is truly an impressive engineering feat by HCL.

If you haven’t done it yet, sign up for the launch of the new Domino and Sametime on June 7.

0 Comments

Keep up with COVID-19 though Domino!

Are you are suddenly sitting at home with nothing to do, due to the corona virus COVID-19? You can’t go to the gym. You can’t go to your favorite computer store to browse all the latest hardware and plan for your next water-cooled build. You can’t go out to eat.

But what you can do is to try out some of the new functionality in HCL Notes and Domino. Today I started a little project where I try to incorporate a number of the latest and coolest functions in a simple but useful application. I hope to be able to create several blog posts about this project over the next few days.

I came up with the idea for this app when someone sent me a link to a web page where information about COVID-19 is aggregated from all US states. I thought it was a neat page, but then I noticed that they have a public API where the numbers are served up. Now things started to become much more interesting! This is what the JSON data looks like:

[
  {
    "state": "AK",
    "positive": 6,
    "negative": 400,
    "pending": null,
    "death": null,
    "total": 406,
    "lastUpdateEt": "3/18 16:30",
    "checkTimeEt": "3/19 15:12"
  },{
    "state": "AL",
    "positive": 68,
    "negative": 28,
    "pending": null,
    "death": 0,
    "total": 96,
    "lastUpdateEt": "3/19 10:45",
    "checkTimeEt": "3/19 15:15"
  },{
    "state": "AR",
    "positive": 46,
    "negative": 310,
    "pending": 113,
    "death": null,
    "total": 469,
    "lastUpdateEt": "3/19 11:23",
    "checkTimeEt": "3/19 15:16"
  },{
    "state": "AS",
    "positive": 0,
    "negative": null,
    "pending": null,
    "death": 0,
    "total": 0,
    "lastUpdateEt": "3/14 00:00",
    "checkTimeEt": "3/19 16:18"
  },{
    "state": "AZ",
    "positive": 44,
    "negative": 175,
    "pending": 130,
    "death": 0,
    "total": 349,
    "lastUpdateEt": "3/19 00:00",
    "checkTimeEt": "3/19 15:18"
  },{
    "state": "CA",
    "positive": 924,
    "negative": 8787,
    "pending": null,
    "death": 18,
    "total": 9711,
    "lastUpdateEt": "3/19 14:25",
    "checkTimeEt": "3/19 15:20"
  }
...

So what could I do with this data? Why not bring it into a Domino database to start with, and then retrieve the data on a schedule, say every hour?

We should then be able to chart the data for each state over time. In order to not store the same data over and over again, I want to check if the data has been modified since the last time the agent ran. I will just use the lastUpdateEt date and time stamp in combination with the state abbreviation to perform a lookup. If I get any result(s) back, the data was already stored.

So how do you read the JSON from the API? In the past I would have used my own HTTP Request class, but this is not needed anymore. This is thanks to the NotesHTTPRequest class, first introduced in Domino 10 and then improved in Domino 11. In Domino 11 the wizards at HCL in Chelmsford added classes to parse JSON. The NotesJSONNavigator is the base of the parser, then you use NotesJSONArray, NotesJSONObject and NotesJSONElement to traverse through a JSON payload. When you get the hang of it, this is much easier than it maybe sounds at first.

So let’s take a look at my code. This is a scheduled agent, running once an hour:

%REM
  Agent Retrieve Data
  Created Mar 19, 2020 by Karl-Henry Martinsson/DBS
%END REM

Option Public
Option Declare

Sub Initialize
  Dim session As New NotesSession
  Dim db As NotesDatabase
  Dim view As NotesView
  Dim http As NotesHTTPRequest
  Dim json As NotesJSONNavigator
  Dim element As NotesJSONElement
  Dim stateArray As NotesJSONArray
  Dim state As NotesJSONObject
  Dim response As Variant
  Dim url As String

  Set db = session.CurrentDatabase
  Set view = db.GetView("LookupExisting")
  Call view.Refresh()

  Set http = session.CreateHTTPRequest()
  url = "https://covidtracking.com/api/states"
  response = http.get(url)
  Set json = session.CreateJSONNavigator(response)
  Set element = json.GetFirstElement()
  Do Until element Is Nothing
    Set state = element.Value
    Call processState(state, db, view)
    Set element = json.GetNextElement()
  Loop
End Sub

Function processState(state As NotesJSONObject, db As NotesDatabase, view As NotesView)
  Dim doc As NotesDocument
  Dim col As NotesViewEntryCollection
  Dim values List As String 
  Dim element As NotesJSONElement
  Dim key As String
  Dim value As String
  Dim stateName As String
  Dim lastUpdate As String 

  Set doc = New NotesDocument(db)
  doc.Form = "StateData"
  Set element = state.GetFirstElement()
  Do Until element Is Nothing 
    key = element.Name
    value = element.Value
    If key="state" Then
      stateName = value
    End If
    If Right$(key,2)="Et" Then
      lastUpdate = Format$(CDat(value),"mm/dd/yyyy hh:nn AM/PM")
      Call doc.ReplaceItemValue("lastUpdated", lastUpdate)
    Else 
      Call doc.ReplaceItemValue(key, value)	
    End If
    Set element = state.GetNextElement()
  Loop
  Set col = view.GetAllEntriesByKey(stateName+"^"+lastUpdate)
  If col.count=0 Then
    Call doc.Save(True,False)
  End If
End Function

This is all the code you need. Yes, I am serious. You can now consume any data on the web, served up by any system with a REST API, straight into Domino, with just a few lines for code.

The NotesHTTPRequest is very straight forward, so there is not much to say about it. But the classes used to parse JSON may need some explanation.
You start with the NotesJSONNavigator. You then use the value property of the NotesJSONElement class to get a value, an array or an object. The array or object is put into a NotesJSONArray or NotesJSONObject object, and you can then traverse down into the JSON structure. This is very powerful and useful, we have all been asking IBM for this functionality for many years. Now HCL delivers!

I created a hidden view for the lookup to avoid the same data stored multiple times. It only contains one (sorted) column, which is used by the lookup:

That is pretty much it.

I also created a view to display the data:

Soon we will do something more fun with the data. I will just let the scheduled agent run for a while and build up my database first. Keep your eyes open for the next post about this project!

4 Comments

Run Notes applications on iPad!

IBM and HCL has released an amazing product, IBM Domino Apps for iPad. They have been showing early versions at IBM Think and other events for the last year, but now it is here, and you can download it in the Apple App Store!

I have seen earlier versions of the product, and I have to say that the developers at HCL did an excellent job. Your existing Notes applications can now run right out of the box with full fidelity and functionality, including formula language and Lotusscript, with no changes needed.

Even features like replication to a local database and working offline works. It is simply a full Notes application client for the iPad.

This is something that people have been asking IBM to develop for at least a decade. And finally we have it available.

There is a version for Android in the works as well, but no official release date has been set for it yet.

So what does this mean? It means that not only can you run your current applications on an iPad, you can develop new applications specifically for tablets. The applications can be styled to work better on tablets, for example larger fonts and buttons. HCL even added some tablet specific functions, like camera integration, to the core Notes functionality.

There are a couple of limitations in the first versions, most notable that there is no support for the mail template, and no support for Xpages in the Notes client.

If you are using Notes and have users with iPads, install IBM Domino Apps for iPad and be prepared to be amazed!

0 Comments

#DominoForever – Release Day

Finally it is here, the new version of IBM Domino. After the world premiere yesterday in Frankfurt, the world-wide launch is taking place today.

The focus in this release is on application development and administration. Features like self-healing of databases and increase of the maximum database size to 256 GB are among the most popular with administrators, while developers have a number of exciting additions.

The two most talked about features are the new Domino Query Language and node.js integration with Domino. Domino Query Language has been written from the bottom up to be fast, and the demonstrations I have seen confirms this. It is fast, very fast! And it can handle searches that would not only take a long time to create in earlier versions of Domino, but would take forever to run. Now the result comes back in a second, or even less. This really blew my mind when I first saw it earlier this year. John Curtis, the engineer that pretty much single handed wrote this code, did an amazing job, fully on par with when Damien Katz rewrote the formula language in ND6 and increased the performance several times over.

The second big feature of Domino 10 is the integration with node.js through the domino-db connector. It will be delivered in a separate application development pack, which will enter beta this week. This is a slight disappointment, I had been hoping this functionality would be available at the launch. But I rather wait the time that is needed for IBM and HCL to make it a fully stable product, instead of rushing something unfinished to the market.

Another product announced today was Notes for iPad, which makes it possible to run existing Notes applications unmodified on an iPad. All the functions we know and love are supported, like replication, offline access to applications, Lotusscript, Formula language, and more.

To support mobile Notes applications, there are enhancements in Lotusscript, for example camera and GPS support. Lotusscript has also been extended with other new classes, for HTTP requests and JSON parsing directly in native Lotusscript. No need to call Java or system API:s anymore!

HCL has done an amazing job in a short time, and Domino is on its way to become a very powerful and extendable platform for modern web development. A company can now not only deploy their existing business applications on iPads, they can also hire young developers who have experience of node.js and modern frameworks/libraries like Angular and React, and have them develop new solutions that can access existing data in Domino databases. Why use Mongo DB for data storage, when you have the much more secure Domino server available?

Domino 10 is not the end point. Domino 11 will be out next year, and IBM/HCL have committed to a long future for Domino. Forget #domino2025, now it is #DominoForever!

If you were not able to attend any of the launch events, here is the live stream from Frankfurt :

https://m.facebook.com/story.php?story_fbid=310707186390803&id=111720058922703

1 Comment

Six Days Left…

I have finished the slides for my presentation at CollabSphere in Ann Arbor next week. I just have a little more code to add to demo database, and perhaps throw in a bonus or two…

My session will be next Wednesday (July 24) at 9am in Grande III.  There are still a few seats available for CollabSphere 2018. The cost is only $100 for 3 days of presentations, workshops, and networking, This is great value for the money!
Don’t miss the latest from IBM and HCL on Notes and Domino 10, Nomad and probably a surprise or two.

 

 

1 Comment

I’ve Seen Things You People Wouldn’t Believe…

This last week about 50 other specially invited people visited HCL America in Chelmsford, MA for a tour of their Collaboration Workflow Platforms (CWP) office. I was one of the lucky ones, and for two days we got to meet many of the engineers at HCL and see what they were working on around Notes and Domino. There are some parts that are under NDA, but I will talk about what I am allowed to mention.

We got to play with the latest build of Notes 10, compiled that same morning. It included some of the new Lotusscript classes we have heard about before, like the NotesHTTPRequest class and NoteJSONParser class. That functionality had just been added in right before our visit (it is not available in the private beta that was released a few weeks ago), but when I tested it (yes, we got to play with the code right there!) it worked perfectly.

This is a testament to the skills of the HCL developers. Most of them came over from IBM, and you probably know many by name. But there were also new-hires, and HCL is looking to fill many more positions in the US. The investments HCL is doing in this is impressive, and the whole atmosphere was extremely positive and filled with excitement.

We were split up into smaller groups and were treated to a number of very interactive presentations of the directions taken in different areas. The biggest focus was on application development, and with the addition of support for node.s to the platform and the new classes in Lotusscript, the engineers were visibly excited to be able to show off what they have accomplished.

The HCL developers have the right to be excited and proud. We were treated to two major announcements. The first one is a new extremely fast query language called DGQF (Domino General Query Facility). It is not an add-on, but part of the core code. It will be available in Notes/Domino 10, and can be called from everywhere, using Lotusscript, Java, Formula, and Javascript. Initially the searches can be made only in one database at a time, but in the future there will be support for multi-database searches.
At CollabSphere 2018 in just over a week, there will be presentations on DGQF. If you have’t registered yet, do it now. You don’t want to miss this!

The second announcement is under NDA for now, but I would expect for something exciting to be announced at CollabSphere, as well as at later conferences like ICON UK in September.

So stay updated by attending user group conferences during the fall, leading up to the release of Domino 10 at some day in some month, who may or may not contain a 10. I am very excited about the future of Notes and Domino!

 

0 Comments

Come see me at CollabSphere 2018!


I will be presenting my session Elementary – Consume Watson Services using Node-RED and Domino 10 at CollabSphere 2018, taking place in Ann Arbor, MI inn just a little over a month (July 23-23). If you haven’t registered yet, hurry up! This amazing conference that Richard Moy have been arranging for 10 years now will be full of news and sessions about Domino 10. If you are a developer, you should be very excited. There are a large number of session focusing on everything from classic Lotusscript and the new improvements coming in Domino 10 to sessions about Node.js and how it is supported in Domino 10. There are even introductions to Node.js and Node-RED, and how you can use them in your Domino environment as well as making yourself more marketable.

In addition to all the technical sessons you also have networking and social events. Don’t miss out on this great and inexpensive ($75) conference!

0 Comments

Domino 10 and Beyond – my thoughts

It has now been a little over a month since IBM announced the new direction of IBM Notes, Domino, Verse and Sametime. I have been thinking through what I think this means for the product and the ecosystem of third-party tools and business partners. Some people view the move of development from IBM to HCL Technologies as an abandonment of the product family. But that is not how I see it.

IBM has, despite their size, limited resources to dedicate to development of the Domino family of products. They have new products and services they are trying to bring to market, and by having HCL take over the development and add more resources, this is a win both for IBM and for Notes/Domino.

With more developers dedicated to the product, I expect to see more frequent updates and new features added quicker than we have been used to the last 5-6 years. The product management and future direction of the platform is still managed by IBM, but with more non-IBM resources at their hands I hope the product managers will be able to push harder for the addition of new technology and updates, bringing Domino back to a first class development platform.

Domino was an outstanding product, but for the last 6-8 years the innovation mostly stopped. New technologies were not added at the pace they were adapted by the rest of the world, and the support for new protocols like TLS 1.2 was lagging. IBM also but on Dojo as the framework for XPages, while the rest of the world mostly went to jQuery.

But if IBM allows HCL to update some aging parts and add new functions, requested by the community, I can see this being a great platform. And IBM says they will listen to the community and the users. Starting this month, IBM is bringing the Domino 2025 Jam to four cities in North America: Toronto on 12/8, Dublin (Ohio) on 12/13, Chicago on 12/14 and Dallas on 12/15. here will also be several events in Europe as well as a virtual Jam sometime in the future.

At the Domino 2025 Jam developers and users will be able to suggest what features they find important, what needs to be fixed, and where they want to see the product go in the future. I don’t think the Jam will have a huge impact on the upcoming Domino 10 release next year, but it may help IBM prioritize where to put their effort. Where I see the Domino 2025 Jam being helpful is in the longer timeframe, especially if it is repeated every 12 to 18 months to verify that the product direction is still what the market is looking for.

I also would like to see IBM addressing at least the most requested changes on IdeaJam.

Let me describe some of the functions and features I want to see in an upcoming version of IBM Domino.

Javascript Everywhere

For the last 20+ years we have mainly been using Lotusscript, both in the client and for agents on the server. It is a powerful language, but if you have been working with other more modern languages (Lotusscript is based on Visual Basic) there are many limitations and functions you are missing.

I would like to see Javascript made into a fully supported language everywhere. Both in the client and on the server. Add support for jQuery, to make it easy to address elements, and create a Javascript API to complement the Lotusscript functions.

In addition to making it easier to create and parse JSON (used in and by most web applications today), it would open up the product to new developers who may come from a more traditional web development background.

I would love to see Lotusscript get a modernization, but I doubt that will happen. In order to improve Lotusscript, a quite lot of changes are needed. Instead I think the future improvements should be on the Javascript API side.

External API

Any modern product needs a public API so other tools and applications can integrate with it. I would like to see support in Domino for LoopBack, like IBM is doing in LiveGrid. When you create a view, there would be a matching API created to create, read, update and delete documents, as well as list all records, perform searches, etc.

But there should also be additional more specialized API:s available, perhaps the most common functions should be exposed as API calls out of the box.

Integration with External Services

Notes and Domino also needs integration with external services, e.g IBM Watson, Mongo DB or Node-RED. Why not support for IFFTT? Expose the calendar as a Google Calendar feed. But also make it easy to connect external services to Notes and Domino. Make it easy to use Oauth 2.0 to login to a Domino-hosted service and vice versa.

New Domino Designer

Unlink Domino Designer from the Notes client. Create a Eclipse plug-in (and make sure it stays updated to work with new versions of Eclipse). This will help new developers to start working with Domino, using tools they are already familiar with. The goal should be that someone familiar with Javascript should be able to open Eclipse and start writing code for Domino, and the only thing they need to learn is the Domino Object Model.

Add ready-to-use web components/plugins, so the developer can easily add for example a name-lookup into Domino Directory or a date/time selector. Support CSS frameworks like Bootstrap, and make it easy to modify the look of the applications.

Notes Client

The Notes client makes it easy to quickly build applications. You get a lot of the core functionality of the applications “for free”, like views, forms, etc. But you are also limited in how the application looks. You can change the look of views somewhat by selecting background colors, fonts and a few other attributes. On forms you can select between two different looks for some of the fields, while other fields can not be modified at all. What I would like to see is a way to easily restyle everything by using CSS. Then you can make the forms and views look much more modern. Let the developer create “themes”, a set of CSS rules and perhaps images that can be applied to new applications in seconds. These themes could be published online, for other developers to use.

These are just some of the ideas I have for improvements to Domino. What are you ideas?

5 Comments

My MWLUG presentation: Elementary!

Yesterday I presented at MWLUG, and I want to share my presentation with both the ones attending and anyone who was not able to be there. I am posting two version, one with just the slides, and one with speaker notes, where I tried to capture the content, if not the exact verbiage of the session.

I hope to be able to post the demo database with the code later this week or early next week.

 

1 Comment

My presentation at MWLUG

Tomorrow, August 8, you are welcome to attend my presentation “Elementary!” at MWLUG 2017. In about 45 minutes I will show how to easily incorporate Watson functionality in your own applications, both on the web and in your Notes client applications.

I will be using Node-RED and IBM BlueMix to do this, and I think many will be surprised how easy it is, and how little code is needed. For example I will implement translation from English to Spanish with two (2) lines of server side code. To call this from the web you just need another handful of lines.

I hope to see you tomorrow at 5pm!

0 Comments

IBM Connect 2017 – I will be speaking in San Francisco

I will be speaking at IBM Connect in San Francisco now in February. Rob Novak has resurrected “The Great Code Giveaway” and asked me to present it together with him. Who would turn down that opportunity? So some time between February 21 and 23 you can see Rob and me on stage at Moscone West. The exact time and location has not been announced yet.

I hope to see you in San Francisco and that you will find our presentation and code useful!

1 Comment

Updated MailNotification class – Now with HTML email support and web links

I have updated my MailNotification class with some additional functionality I needed at work. Since our mail system now is Outlook/Exchange, and therefore the Notes doc links don’t work anymore, I am in the process of converting all my email notifications into HTML email. The doc links are now made into HTML links, pointing to a notes:// or http:// address.

I simply added a new class, HTMLmail. It is based on the old NotesMail class, but I override a few functions that are different. This makes it very easy to update the emails I am generating in my Lotusscript agents, in most cases I only have to replace NotesMail with HTMLmail in the declaration and instantiation:

Dim maildoc As HTMLMail
Set maildoc = New HTMLMail()

When I had doc links in the email I also had to modify the code where I generate it. The method takes three arguments: the NotesDocument to link to, the Alt/Title attribute for the link (to be displayed when hovering over the link) and the text of the link:

Call maildoc.AppendDocLink(doc,"Click to open",doc.ClaimNumber(0))

In order to generate the links I created a Link class, where you can set what protocol you want to use (“notes” or “http”) you want the link to use, you can change the port from the default of 80, and you can even force the link to point to a different server. I use this class in the AppendDocLink method in the HTMLmail class.

Here is a short code sample, it is just a function to create a mail notification for an insurance claim. The claim document is passed to the function and a mail is sent to the adjuster and his/her manager.

Sub SendNotification(doc as NotesDocument)
	'*** Create a new object and set the sender, recipients and subject
	Set maildoc = New HTMLMail()
	maildoc.Principal = |"System Notification" <noreply@example.com>|
	Call maildoc.AddMailTo(doc.GetItemvalue("Adjuster")(0))
	Call maildoc.AddMailCC(GetManagerName(doc.GetItemValue("Adjuster")(0)))
	maildoc.Subject = "30 DAY ALERT - " & doc.GetItemValue("ClaimNumber")(0)
	'*** Build body content, including a link to the document
	Call maildoc.AppendText("Claim number ")
	Call maildoc.AppendDocLink(doc,"Click to open",doc.GetItemValue("ClaimNumber")(0))
	Call maildoc.AppendText(" was received on ")
	Call maildoc.AppendText(Format$(doc.GetItemValue("Received_Date")(0),"mm/dd/yyyy") & ". ")
	Call maildoc.AppendText("This claim has been opened for 30 days. ")
	Call maildoc.AppendText("Please confirm all appropriate actions has been performed.")
	Call maildoc.AddNewLine(2)
	'*** Add no-reply notification to the end and send the email
	maildoc.NoReply = True   
	Call maildoc.Send()
	'*** Flag the NotesDocument as processed and save it to avoid duplicate notifications
	doc.Warning30daySent = "Yes"
	Call doc.Save(True,True)
End Sub

That’s pretty much it.  Enjoy the code, and as usual I do not guarantee anything. Use on your own risk, as always. If you like this code and use it, let me know.

Option Public
Option Declare

Class NotesMail
	Public maildoc As NotesDocument 
	Public body As NotesRichTextItem
	Private p_subject As String
	Private p_sendto List As String
	Private p_copyto List As String
	Private p_blindcopyto List As String
	Private p_principal As String
	Public NoReply As Boolean 
	Public mailbox As NotesDatabase
	
	Public Sub New()
		Dim session As New NotesSession
		Dim mailservername As String
		' We must use mail.box on current server.
		mailservername = session.Currentdatabase.Server
		' Using mail.box directly is unsupported, but is the
		' only way to make the mail look like it is actually
		' sent from another address, in our case the principal.
		Set mailbox = New NotesDatabase(mailservername,"mail.box")
		If mailbox.Isopen = False Then
			Print "mail.box on " & mailservername & " could not be opened"
			Exit Sub
		End If
		Set me.maildoc = New NotesDocument(mailbox)
		Call me.maildoc.ReplaceItemValue("Form","Memo")
		'Set me.body = New NotesRichTextItem(maildoc,"Body")
		Call CreateBody()
		me.p_subject = ""
		me.p_principal = ""
		' Empty lists for addresses
		Erase me.p_sendto
		Erase me.p_copyto
		Erase me.p_blindcopyto
		me.NoReply = False	' Default is not to add a disclaimer to the end
	End Sub
	
	Private Sub CreateBody()
		Set me.body = New NotesRichTextItem(maildoc,"Body")
	End Sub
	
	Public Property Set Subject As String
		me.p_subject = FullTrim(Subject)
	End Property
	
	Public Property Get Subject As String
		Subject = me.p_subject
	End Property
	
	Public Property Set Principal As String
		me.p_principal = FullTrim(Principal)
	End Property
	
	Public Property Get Principal As String
		Principal = me.p_principal
	End Property

	'*** Recipient address (mailto) functions
	Public Property Set MailTo As String
		me.p_sendto(FullTrim(MailTo)) = FullTrim(MailTo)
	End Property
	
	Public Property Get MailTo As String	' Get the first address only
		ForAll mto In me.p_sendto
			MailTo = mto	
			Exit ForAll
		End ForAll
	End Property
	
	Public Property Set SendTo As String	' Alias for MailTo
		MailTo = SendTo
	End Property
	
	Public Property Get SendTo As String	' Alias for MailTo
		SendTo = MailTo	
	End Property
	
	Public Sub AddMailTo(address As String)	' Additional address
		me.p_sendto(address) = address
	End Sub
	
	Public Sub RemoveMailTo(address As String)	' Remove address from list
		Erase me.p_sendto(address)
	End Sub

	' *** Functions for CC address
	Public Property Set MailCC As String
		me.p_copyto(FullTrim(MailCC)) = FullTrim(MailCC)
	End Property
	
	Public Property Get MailCC As String	' Get the first address only
		ForAll mcc In me.p_copyto
			MailCC = mcc	
			Exit ForAll
		End ForAll
	End Property
	
	Public Sub AddMailCC(address As String)
		me.p_copyto(address) = address
	End Sub

	Public Sub RemoveMailCC(address As String)
		Erase me.p_copyto(address)
	End Sub
	
	' *** Functions for BCC address 
	Public Sub AddMailBCC(address As String)
		me.p_blindcopyto(address) = address
	End Sub
	
	Public Property Set MailBCC As String
		me.p_blindcopyto(FullTrim(MailBCC)) = FullTrim(MailBCC)
	End Property
	
	Public Property Get MailBCC As String	' Get the first address only
		ForAll bcc In me.p_blindcopyto
			MailBCC = bcc	
			Exit ForAll
		End ForAll
	End Property
	
	Public Sub RemoveMailBCC(address As String)
		Erase me.p_blindcopyto(address)
	End Sub
	
	' *** Functions for email body 
	Public Sub AppendText(bodytext As String)
		Call me.body.AppendText(bodytext)	
	End Sub
	
	Public Sub AppendDocLink(doc As NotesDocument, comment As String, linktext As String)
		If FullTrim(linktext) = "" Then
			Call me.body.AppendDocLink(doc, comment)	
		Else
			Call me.body.AppendDocLink(doc, comment, linktext)	
		End If
	End Sub
	
	Public Sub AppendNewLine(cnt As Integer)
		Call me.body.AddNewline(cnt)	
	End Sub
	
	Public Sub AddNewLine(cnt As Integer)
		Call me.body.AddNewline(cnt)	
	End Sub
	
	Public Sub AttachFile(filename As String)
		Call me.body.EmbedObject(1454,"",filename)	
	End Sub
	
	' *** Send the mail
	Public Sub Send()
		Dim session As New NotesSession 
		Dim richStyle As NotesRichTextStyle 
		Dim recipients As String 
		If me.subject<,>,"" Then
			maildoc.Subject = me.subject
		End If
		recipients = ""
		If ListItemCount(me.p_sendto)>,0 Then
			maildoc.SendTo = ListToArray(me.p_sendto)
			recipients = recipients + Join(ListToArray(me.p_sendto),"~") + "~"
		End If
		If ListItemCount(me.p_copyto)>,0 Then
			maildoc.CopyTo = ListToArray(me.p_copyto)
			recipients = recipients + Join(ListToArray(me.p_copyto),"~") + "~"
		End If
		If ListItemCount(me.p_blindcopyto)>,0 Then
			maildoc.BlindCopyTo = ListToArray(me.p_blindcopyto)
			recipients = recipients + Join(ListToArray(me.p_blindcopyto),"~") + "~"
		End If
		maildoc.Recipients = FullTrim(Split(recipients,"~")) 
		If me.p_principal<,>,"" Then
			Call maildoc.ReplaceItemValue("Principal", me.p_principal)
			' If principal is set, we want to fix so mail looks like
			' it is coming from that address, need to set these fields
			Call maildoc.ReplaceItemValue("From", me.p_principal)
			Call maildoc.ReplaceItemValue("Sender", me.p_principal)
			Call maildoc.ReplaceItemValue("ReplyTo", me.p_principal)
			Call maildoc.ReplaceItemValue("SMTPOriginator", me.p_principal)
		End If
		' If NoReply is set, append some red text... 
		If NoReply = True Then
			Set richStyle = session.CreateRichTextStyle
			richStyle.NotesFont = 4
			richStyle.NotesColor = 2
			richStyle.Bold = True	
			Call me.body.AppendStyle(richStyle)
			Call me.body.AddNewLine(1)	
			Call me.body.AppendText("*** DO NOT REPLY TO THE SENDER OF THIS MESSAGE! ***")	
			Call me.body.AddNewLine(1)	
			Call me.body.AppendText("*** IT IS AN AUTOMATED SYSTEM MAIL ***")	
		End If
		On Error Resume Next
		'Call maildoc.CopyItem(body, "Body")
		If me.p_principal<,>,"" Then
			Call maildoc.Save(True,False)	' Save in mail.box
		Else
			Call maildoc.Send(False)			' Send mail normally
		End If
	End Sub
	
	
	' *** Private functions called from within the class ***
	
	' *** Convert list to array
	Private Function ListToArray(textlist As Variant) As Variant
		Dim i As Integer 
		Dim temparray() As String
		ReDim temparray(0) As String 
		ForAll t In textlist
			temparray(UBound(temparray)) = t
			ReDim Preserve temparray(UBound(temparray)+1) As String
		End ForAll
		ListToArray = FullTrim(temparray)
	End Function
	
	' *** Count items in a list
	Private Function ListItemCount(textlist As Variant) As Integer
		Dim cnt As Integer
		cnt = 0
		ForAll t In textlist
			cnt = cnt + 1
		End ForAll
		ListItemCount = cnt
	End Function

End Class


%REM
	Class HTMLMail
	Description: Inherits from NotesMail class, implements additional functions
%END REM
Class HTMLMail As NotesMail
	Private session As NotesSession 
	Private mimebody As NotesMIMEEntity 
	Private header As NotesMIMEHeader 
	Private stream As NotesStream
	Private p_server As String
	Private p_protocol As String
	Private p_port As Integer
	Public LinkServerOnly As Boolean
		
	%REM
		Sub CreateBody
		Description: Override body creation with HTML body
	%END REM
	Private Sub CreateBody()
		Dim db As NotesDatabase 
		Set session = New NotesSession()
		Set db = session.CurrentDatabase 
		Set stream = session.CreateStream 
		session.ConvertMIME = False ' Do not convert MIME to rich text 
		Set me.mimebody = maildoc.CreateMIMEEntity
		Call stream.writetext(|<,HTML>,|)
		Call stream.writetext(|<,head>,|)
		Call stream.writetext(|<,/head>,|)
		Call stream.writetext(|<,body>,|)
		Call stream.writetext(|<,div style="font-family: Calibri,Arial; font-size:12pt;">,|)
		me.p_protocol = "notes"
		me.p_port = 80
		LinkServerOnly = False
	End Sub
	
	Public Sub AppendText(bodytext As String)
		Call me.stream.writetext(bodytext)	
	End Sub
	
	Public Sub AddNewLine(cnt As Integer)
		Dim i As Integer
		For i = 1 To cnt
			Call me.stream.writetext("<,br>,")
		Next 
	End Sub

	Public Sub AppendNewLine(cnt As Integer)
		Dim i As Integer
		For i = 1 To cnt
			Call me.stream.writetext("<,br>,")
		Next 
	End Sub

	Public Sub SetLinkServer(server As String)
		Me.p_server = server
	End Sub
	
	Public Sub SetLinkProtocol(protocol As String)
		Me.p_protocol = protocol
	End Sub

	Public Sub SetLinkPort(port As Integer)
		Me.p_port = port
	End Sub
	
	Public Sub AppendDocLink(doc As NotesDocument, comment As String, linktext As String)
		Dim html As String
		Dim link As Link
		Set link = New Link(doc)
		Call link.SetProtocol(Me.p_protocol)
		Call link.SetPort(Me.p_port)
		If Me.p_server<,>,"" Then
			Call link.SetServer(p_server)
		End If
		link.ServerOnly = LinkServerOnly
		html = |<,a href="| & link.URL() + |"|
		If FullTrim(linktext)<,>,"" Then
			html = html + | title="| + comment + |" alt="| + comment + |"|					
		End If
		html = html + ">," + linktext + "<,/a>,"
		Call AppendText(html)
	End Sub
	
	Sub AddNoReplyNotification()
		Call me.stream.writetext(|<,div style="font-family: consolas, courier; font-size: 10pt; color:#FF0000; margin-top: 25px; margin-bottom: 25px;">,|)
		Call me.stream.writetext("***************************************************<,br>,")	
		Call me.stream.writetext("*** DO NOT REPLY TO THE SENDER OF THIS MESSAGE! ***<,br>,")	
		Call me.stream.writetext("***   IT IS AN AUTOMATED SYSTEM MAIL FROM LNP   ***<,br>,")	
		Call me.stream.writetext("***************************************************<,br>,")
		Call me.stream.writetext("<,/div>,")
		If me.p_principal = "" Then
			me.p_principal = |"Do Not Reply" <,noreply@deep-south.com>,|
		End If
	End Sub
	
	' *** Send the mail
	Public Sub Send()
		Dim doc As NotesDocument 
		Dim recipients As String

		maildoc.Form = "Memo" 
		'*** If NoReply is set, append some red text... 
		If NoReply = True Then
		'	Call stream.writetext(|<,p>,<,font color="red">,|)
		'	Call stream.writetext("*** DO NOT REPLY TO THE SENDER OF THIS MESSAGE! ***<,br>,")	
		'	Call stream.writetext("*** IT IS AN AUTOMATED SYSTEM MAIL ***")
		'	Call stream.writetext("<,/font>,<,/p>,")
			Call AddNoReplyNotification()	
		End If
	 	'*** Add HTML for end of email
		Call stream.writetext(|<,/div>,|) 
		Call stream.writetext(|<,/body>,|) 
		Call stream.writetext(|<,/html>,|) 
		Call mimebody.SetContentFromText(stream, "text/HTML;charset=UTF-8", ENC_IDENTITY_7BIT) 
 
		If me.subject<,>,"" Then
			maildoc.Subject = me.subject
		End If
		recipients = ""
		If ListItemCount(me.p_sendto)>,0 Then
			maildoc.SendTo = ListToArray(me.p_sendto)
			recipients = recipients + Join(ListToArray(me.p_sendto),"~") + "~"
		End If
		If ListItemCount(me.p_copyto)>,0 Then
			maildoc.CopyTo = ListToArray(me.p_copyto)
			recipients = recipients + Join(ListToArray(me.p_copyto),"~") + "~"
		End If
		If ListItemCount(me.p_blindcopyto)>,0 Then
			maildoc.BlindCopyTo = ListToArray(me.p_blindcopyto)
			recipients = recipients + Join(ListToArray(me.p_blindcopyto),"~") + "~"
		End If
		maildoc.Recipients = FullTrim(Split(recipients,"~")) 
		If me.p_principal<,>,"" Then
			Call maildoc.ReplaceItemValue("Principal", me.p_principal)
			' If principal is set, we want to fix so mail looks like
			' it is coming from that address, need to set these fields
			Call maildoc.ReplaceItemValue("From", me.p_principal)
			Call maildoc.ReplaceItemValue("Sender", me.p_principal)
			Call maildoc.ReplaceItemValue("ReplyTo", me.p_principal)
			Call maildoc.ReplaceItemValue("SMTPOriginator", me.p_principal)
		End If
		On Error Resume Next
		If me.p_principal<,>,"" Then
			Call maildoc.Save(True,False)	' Save in mail.box
		Else
			Call maildoc.Send(False)			' Send mail normally
		End If
		session.ConvertMIME = True ' Restore conversion - very important 
	End Sub

End Class


%REM
	Class Link
	Description: Class for Doc Link functionality
%END REM
Class Link
	Private p_protocol As String
	Private p_server As String
	Private p_domain As String
	Private p_port As Integer
	Private p_dbpath As String
	Private p_docunid As String
	Private p_Action As String 
	Private p_doc As NotesDocument
	Private p_db As NotesDataBase
	Public ServerOnly As Boolean
	
	%REM
		Sub New
		Description: Constructor
	%END REM
	Public Sub New(doc As NotesDocument) 
		Dim server As NotesName
		Set p_doc = doc
		Set p_db = doc.Parentdatabase
		Set server = New NotesName(p_db.Server)
		Call SetServer(server.Common)
		Call SetPort(80)
		Call SetProtocol("notes") 	'Set as default
		ServerOnly = False
		p_domain = GetDomain()
		p_dbpath = doc.Parentdatabase.Filepath
		p_docunid = doc.UniversalID
		p_action = "OpenDocument"
	End Sub
	
	%REM
		Sub SetProtocol
		Description: Set the protocol to use (notes:, http:, https:)
	%END REM
	Public Sub SetProtocol(protocol As String)
		Dim tmp As String
		'*** Remove any : or /
		tmp = Replace(protocol,":","")
		tmp = Replace(tmp,"/","")
		p_protocol = LCase(tmp) + ":"
		If Not p_db Is Nothing Then
			tmp = GetDomain()
			Call SetDomain(tmp)
		End if
	End Sub
	
	%REM
		Sub SetAction
		Description: Set the action, e.g. ?OpenDocument
	%END REM
	Public Sub SetAction(action As String)
		Dim tmp As String
		'*** Remove any ? if already there
		tmp = Replace(action,"?","")
		p_action = "?" + tmp
	End Sub
	
	%REM
		Sub SetServer
		Description: Override server name if we want another server
		Do not specify the Notes domain or Internet domain name!
	%END REM
	Public Sub SetServer(servername)
		p_server = servername
	End Sub

	Public Function GetDomain() As String 
		Dim tmp As String
		Dim startpos As Integer
		Dim endpos As Integer  
		If p_protocol = "notes:" Then
			tmp = p_db.NotesURL
		Else
			tmp = p_db.HttpURL
		End If
		startpos = InStr(tmp,"://")+3
		endpos = InStr(startpos,tmp,"/")
		If endpos>,startpos Then
			tmp = Mid$(tmp,startpos, endpos-startpos)
		Else
			tmp = "deep-south.com"
		End If
		GetDomain = tmp
	End Function
	
	%REM
		Sub SetDomain
		Description:Set the domain part of the URL, e.g. @Deep-South or .deep-south.com 
	%END REM
	Public Sub SetDomain(domain As String)
		p_domain = domain
	End Sub
	
	%REM
		Sub SetPort
		Description: Set the port number, e.g. 80 or 3000
	%END REM
	Public Sub SetPort(portnumber As Integer)
		p_port = portnumber
	End Sub
	
	%REM
		Function URL
		Description: Get the URL for the document
	%END REM
	Public Function URL() As String
		Dim tmp As String 
		tmp = p_protocol & "//" 
		If p_protocol<,>,"notes:" Then
			tmp = tmp & p_server 
			If ServerOnly = False Then
				tmp = tmp & "."
			End if 
		End If
		If ServerOnly = False Then
			tmp = tmp & p_domain
		End If
		If p_protocol<,>,"notes:" Then
			If p_port <,>, 80 Then
				tmp = tmp & ":" & p_port  
			End If
		End If
		tmp = tmp & "/" & p_dbpath & "/0/" & p_docunid & "?" & p_action
		tmp = Replace(tmp,Chr$(92),"/")	'Replace \ with / for URL
		URL = tmp
	End Function
	
End Class
2 Comments

MWLUG in Austin – I will be presenting again

I have been selected to present at MWLUG in Austin on August 17-19. My presentation will be kind of part two of my presentation last year in Atlanta. It will focus less on the basics and go more into the fun and more advanced stuff. Kind of an extended version of my Connect 2016 presentation.

The title is “Think Outside The Box – Part 2”, and I will discuss and show how you can build a modern web front-end using standard techniques like Javascript/jQuery and frameworks like Bootstrap and jQuery Mobile and have it work against a Domino backend. I will demonstrate how to easily read data from and write data to the Domino database, and how to consume data using free plugins like BootstrapTable and FullCalendar.

I will also discuss the difference between JSON and JSONP and why the latter usually is better when building this type of integration. You will leave with a sample database containing the source code all the demos I will be showing as well as Lotusscript script libraries with classes I built to easily build agents that will interact with the website.

The idea is that you should be able to attend my session in Austin even if you haven’t seen any previous presentation. I will assume you have basic web design skills (HTML, CSS and a working understanding of Javascript) but you don’t have to be an expert at all. I also recommend some Lotusscript knowledge, as I will be providing all attendees with plenty of code to bring home and start using yourself.

I hope to see you in Austin in August! If you haven’t registered yet, go ahead and do it now! There are still seats left.

0 Comments

My Connect 2016 presentation & demo database

Connect2016_DemoDesignAs I promised, I would post my IBM Connect 2016 presentation on my blog.

Presentation (PDF): {link} 

Demo database (ZIP): {link}

You can also find the presentation on SlideShare.net.

To the right you see the database design, you want to look in the Agent section for the agents and in the Pages section for the HTML pages.

Note: You need to sign the database with an ID that have the proper rights. Otherwise the code will not work.

Enjoy!

 

6 Comments

Free Code – Clean groups in Domino Directory

The other day I had to clean up the groups in our Domino Directory. Many groups still contained names of terminated users, they had not been cleaned/maintained properly. We also removed some groups over time, but some of them were still listed as members of other groups.

So I wrote a small Lotuscript agent to perform this cleanup. I am posting it below in case someone needs it. As always: no guarantees, use at your own risk, etc.

Update: As some commenters pointed out, there are some issues with the code. First of all, I was using a view my company added to name.nsf. The view PeopleByFirstName has the following selection formula: SELECT Type = “Person” & TerminationDate=””
The field TerminationDate is one we added to the person document. This field is either blank (for current employees) or contains the date they were terminated (and then they are filtered out of most views).

Also as Christian points out, any groups that contains external users would be clenaed out. In the past when I worked at a company that used mail groups with external users, those groups were kept in a separate (secondary) Domino Directory, names_ext.nsf. So this is something to keep in mind if you choose to use this code.

Finally I have updated the code with a few more lines. It will now ignore server groups, and also get a list of all servers and make sure they are included as group members when the groups are processed.

Thanks for pointing out the problems with the code!

 

Dim session As New NotesSession
Dim db As NotesDatabase
Dim view As NotesView
Dim doc As NotesDocument
Dim userNames List As String
Dim groupNames List As String
Dim serverNames List As String
Dim groups List As NotesDocument
Dim tmp As String
Dim tmpname As NotesName
	
Set db = New NotesDatabasesession.CurrentDatabase.Server,"names.nsf")
'*** Get all existing groups and put in a list
Set view = db.getView("Groups")
Set doc = view.GetFirstDocument()
Do Until doc Is Nothing
    Set groups(doc.UniversalID) = doc
    tmp = doc.GetItemValue("ListName")(0)
    groupNames(tmp) = tmp
    Set doc = view.GetNextDocument(doc)	
Loop

'*** Get all active users and put in a list
Set view = db.getView("PeopleByFirstName")
Set doc = view.GetFirstDocument()
Do Until doc Is Nothing
    tmp = doc.GetItemValue("FullName")(0)
    Set tmpname = New NotesName(tmp)
    userNames(tmpname.Common) = tmpname.Common
    Set doc = view.GetNextDocument(doc)	
Loop

'*** Get all servers and put in a list
Set view = db.getView("Servers")
Set doc = view.GetFirstDocument()
Do Until doc Is Nothing
    tmp = doc.GetItemValue("ServerName")(0)
    Set tmpname = New NotesName(tmp)
    serverNames(tmpsname.Common) = tmpname.Common
    Set doc = view.GetNextDocument(doc) 
Loop	
'*** Loop though list of groups and process each one
ForAll g In groups
    '*** Check that not server group
    If g.GetItemValue("GroupType")(0)<>"4" Then  
        tmp = ""
        '*** Store existing list of group members in a backup field
        Call g.ReplaceItemValue("MembersBackup",g.GetItemValue("Members")) 
        '*** Loop through all members of the group
        ForAll m In g.GetItemValue("Members")
            Set tmpname = New NotesName(m)
            '*** If the name is an existing group or an active user, add to list
            If IsElement(userNames(tmpname.Common)) _
            Or IsElement(groupNames(tmpname.Common)) _
            Or IsElement(serverNames(tmpname.Common))Then
                tmp = tmp + tmpname.Canonical + ";"
            End If
        End ForAll
        '*** Write list back to members field
        Call g.ReplaceItemValue("Members", FullTrim(Split(tmp,";")))
        Call g.Save(True,False)
    End If
End ForAll
MsgBox "Done!"

 

8 Comments

Calling a Notes web agent from another server using JSONP

In my MWLUG presentation (as well as in a couple of entries on this blog) I talk about how you can access Domino data from a regular webpage using jQuery and a Lotusscript agent returning data as JSON. The issue with this solution is that the web page must be on the same web application path as the Domino agent. You can’t do what’s known as cross-domain Ajax.

For example if the Domino server is domino.texasswede.com but you have the webpage hosted at www.texasswede.com, it will not work. The security in Javascript does not allow calls across servers like that. There is however an easy solution, and it is called JSONP. What you do is to return not JSON but a call-back function with the JSON data as the argument.

So instead of returning this:

{ "firstName":"Karl-Henry", "lastname":"Martinsson","email":"texasswede@gmail.com" }

you would have the Lotuscript agent return this:

personCallBack({ "firstName":"Karl-Henry", "lastname":"Martinsson","email":"texasswede@gmail.com" })

Let’s assume we call the agent GetPersonData.jsonp.  On the calling side (in the jQuery code) you would then use this code:

$.ajax({
    url : "http://domino.texasswede.com/database.nsf/GetPersonData.jsonp?OpenAgent",
    dataType:"jsonp"
});

Finally you write the Javascript call-back function that will accept the data:

function personCallBack(data) {
    $("#firstName").html(data["firstName"]);
    $("#lastName").html(data["lastName"]);
    $("#emailAddress").html(data["email"]);
}

You can of course make this as advanced as you like but this is the basics. I have updated the JSON class I use for stuff like this to include a method to return JSONP. The new function is called SendJSONPToBrowser() and takes a string with the name of the call-back function as argument, for example like this:

Call json.SendJSONPToBrowser("personCallBack")

Below is the updated class (if you downloaded my sample database from MWLUG you have the older version of it). Enjoy!

 

%REM
	Library Class.JSON by Karl-Henry Martinsson
	Created Oct 9, 2014 - Initial version
	Updated Nov 6, 2015 - Added JSONP support
	Description: Class to generate simple JSON from values
%END REM

Option Public
Option Declare

Class JSONdata
	Private p_json List As String
	
	Public Sub New()
		'*** Set default value(s)
		me.p_json("ajaxstatus") = ""
	End Sub
	
	%REM
		Property Set success
		Description: Set success to true or false
	%END REM
	Public Property Set success As Boolean
		If me.success Then 
			Call me.SetValue("ajaxstatus","success")
		Else
			Call me.SetValue("ajaxstatus","error")
		End If
	End Property
	
	%REM
		Property Get success
		Description: Not really used...
	%END REM
	Public Property Get success As Boolean
		If me.p_json("ajaxstatus") = |"success"| Then
			me.success = True
		Else
			me.success = False
		End If
	End Property
	
	%REM
		Sub SetMsg
		Description: Set msg item
	%END REM
	Public Sub SetMsg(message As String)
		Call me.SetValue("msg",message)
	End Sub
	
	Public Sub SetErrorMsg(message As String)
		Call me.SetValue("errormsg",message)
		me.success = False
	End Sub
	
	Public Sub SetValue(itemname As String, value As String)
		Dim tmp As String
		Dim delimiter As String
		'*** Check for quote (double and single) and fix value if needed
		tmp = Replace(value,Chr$(13),"<br>")
		tmp = FullTrim(Replace(tmp,Chr$(10),""))
		If InStr(tmp,|"|)>0 Then
			If InStr(tmp,|'|)>0 Then
				tmp = Replace(tmp,|"|,|"|)
				delimiter = |"|
			Else
				delimiter = |'|
			End If
		Else
			delimiter = |"|
		End If
		'*** Store value with delimiter in list
		me.p_json(itemname) = delimiter & tmp & delimiter
	End Sub
	
	Public Sub SetData(itemname As String, value As String)
		'*** Store value in list
		me.p_json(itemname) = value
	End Sub
	
	%REM
		Function GetJSON
		Description: Return a JSON object as text
	%END REM
	Function GetJSON As String
		Dim json As String
		'*** Opening curly braces + CR
		json = "{" + Chr$(13)
		'*** Loop through all list elements and build JSON
		ForAll j In me.p_json
			json = json + |"| + ListTag(j) + |":| + j + "," + Chr$(13)
		End ForAll
		'*** Remove the comma after the last item
		json = Left$(json,Len(json)-2) + Chr$(13)
		'*** Add closing curly bracket and return JSON
		json = json + "}"
		GetJSON = json 
	End Function
	
	%REM
		Sub SendToBrowser
		Description: Print JSON to browser, with correct MIME type
	%END REM
	Public Sub SendToBrowser()
		'*** MIME Header to tell browser what kind of data we will return (JSON).
		'*** See http://www.ietf.org/rfc/rfc4627.txt
		Print "content-type: application/json"
		Print me.GetJSON
	End Sub
	
	%REM
		Sub SendJSONPToBrowser
		Description: Print JSON to browser, with correct MIME type
	%END REM
	Public Sub SendJSONPToBrowser(callbackFunction As String)
		'*** MIME Header to tell browser what kind of data we will return (Javascript).
		'*** See http://www.rfc-editor.org/rfc/rfc4329.txt
		Print "content-type: application/javascript"
		Print callbackFunction + "(" + me.GetJSON + ")"
	End Sub
	
End Class

 

0 Comments

MWLUG in Atlanta – I will be presenting!

It is less than 7 weeks left until MWLUG, the Midwest Lotus User Group conference. This year the conference takes place in Atlanta, between August 19 and 21. During the three days there will be over 40 technical session and workshops on collaboration, receptions and networking opportunities, as well as access to experts of IBM solutions, both from IBM and other companies. The topics includes application development, system administration, best practices, customer buisness cases and innovation/future plans by IBM. Breakfast and lunch is included for two days as well. And all this for the cost of only $50 per person! The event takes place at Ritz-Carlton in downtown Atlanta. There is a block of rooms reserved at a special conference rate of $149.00 per night.

One of the sessions will also mark my personal debute as a speaker at a conference. I will present “Break out of the box – Integrate existing Domino data with modern websites” where I will talk about how to integrate websites built either within Domino or on other platforms with backend data that resides in a Domino database. I will talk about how you can build a modern looking website using tools like jQuery and Bootstrap and seamlessly integrate them with existing data on your trusty Domino server using JSON and Ajax. I will also provide plenty of example code ready for you to bring home and start playing with.

A number of IBM Champions will be presenting, as well as IBMers and other industry experts. So no matter your interest, I am sure you will find plenty of good sessions. I am sure I will have a hard time picking which sessions to attend!

So what are you waiting for? Go to http://www.mwlug.com and register! See you there!

 

1 Comment

Code – Get date range as years, months and days

There is a question in the IBM DeveloperWorks forum for Notes/Domino 8 about how to calculate the number of years, months and days between two dates. Then the poster wanted to calculate the sum of two such date ranges and return that as years, months and days as well.

Since the lack of formatting in the forum makes it hard to read the code, I decided to simply post it here on my blog. As always, there are several ways to write the code. One could for example use Mod (a very under-used function that many developers don’t even know about) to help calculate the number of years, months and days.

I also include a function I use to calculate the number of business days between two dates. This could be used to calculate how long a ticket has been open in a help desk system, where you usually don’t want to include Saturday and Sunday in the count.
Simply change diffOne = Days(startDate,endDate) to diffOne = BusinessDays(startDate,endDate).

Enjoy!

Option Public
Option Declare

Type Components
	yearCount As Integer
	monthCount As Integer
	dayCount As Integer	
End Type

Sub Initialize
	'*** Declare variable for componentized date 
	Dim compOne As Components
	Dim compTwo As Components
	Dim compSum As Components
	'*** Declare variables for day difference count
	Dim diffOne As Integer
	Dim diffTwo As Integer 
	'*** Declare start and end date variables
	Dim startDate As String
	Dim endDate As String
	
	'*** First date range
	startDate = "01/01/2011"
	endDate = "03/02/2013"
	diffOne = Days(startDate,endDate)
	Call DayCountToComponents(diffOne, compOne)
	MsgBox compOne.yearCount & " years " & _
	compOne.monthCount & " months " & compOne.dayCount & " days"
	
	'*** Second date range	
	startDate = "04/03/2012"
	endDate = "08/17/2015"
	diffTwo = Days(startDate,endDate)
	Call DayCountToComponents(diffTwo, compTwo)
	MsgBox compTwo.yearCount & " years " & _
	compTwo.monthCount & " months " & compTwo.dayCount & " days"
	
	'*** Sum of first and second date range
	Call DayCountToComponents(diffOne + diffTwo, compSum)
	MsgBox compSum.yearCount & " years " & _
	compSum.monthCount & " months " & compSum.dayCount & " days"
End Sub


%REM
	Function DayCountToComponents
	Description: Convert day count to years, month and days
%END REM
Function DayCountToComponents(dayCount As Integer,components As Components) As Boolean
	Dim daysLeft As Integer
	On Error GoTo errHandler
	components.yearCount = Int(dayCount/365)
	daysLeft = dayCount - components.yearCount * 365
	components.monthCount = Int(daysLeft/30)
	daysLeft = dayCount - (components.yearCount * 365) - (components.monthCount * 30) 
	components.dayCount = daysLeft
	'*** Return
	DayCountToComponents = True
exitFunction:
	Exit Function
errHandler:
	DayCountToComponents = True
	Resume exitFunction	
End Function

%REM
	Function Days
	Description: Get the number of days between two dates
%END REM
Function Days(startDate As Variant,endDate As Variant) As Integer
	Days = Int(CDbl(CDat(endDate))-CDbl(CDat(startDate)))
End Function

%REM
	Function BusinessDays
	Description: Get the number of business days (Monday-Friday) between two dates
%END REM
Function BusinessDays(startDate As Variant,endDate As Variant) As Integer
	Dim startDT As NotesDateTime
	Dim endDT As NotesDateTime
	Dim cnt As Integer 
	On Error GoTo errHandler
	Set startDT = New NotesDateTime(startDate)
	Set endDT = New NotesDateTime(endDate)
	cnt = 0
	Do Until CDbl(startDT.Lslocaltime) > CDbl(endDT.Lslocaltime)
		If Weekday(startDT.Lslocaltime)<7 Then
			If Weekday(startDT.Lslocaltime)>1 Then
				cnt = cnt + 1
			End If	
		End If
		Call startDT.Adjustday(1, True)  
	Loop 
	BusinessDays = cnt
exitFunction:
	Exit Function
errHandler:
	BusinessDays = 0
	Resume exitFunction	
End Function

 

1 Comment

End of content

No more pages to load