Ben Langhinrichs

Photograph of Ben Langhinrichs

E-mail address - Ben Langhinrichs






July, 2020
SMTWTFS
   01 02 03 04
05 06 07 08 09 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Search the weblog





























Genii Weblog


Civility in critiquing the ideas of others is no vice. Rudeness in defending your own ideas is no virtue.


Thu 9 Jul 2020, 11:33 AM
This is a follow up to my post, From REST to Notes db in two seconds. In that, we use the results of a call to a public REST API to created a form, fields, view, and documents. Cool, but often you just want to create an instant little mini-report in a rich text field. Let's start at the end this time. There is a nifty REST API to retrieve foreign exchange rates. You call it at https://open.exchangerate-api.com/v6/latest. An example is today's results, which are 
 
{"result":"success","documentation":"https://www.exchangerate-api.com/docs/free","terms_of_use":"https://www.exchangerate-api.com/terms","time_last_update_unix":1594253195,"time_last_update_utc":"Thu, 09 Jul 2020 00:06:35 +0000","time_next_update_unix":1594340705,"time_next_update_utc":"Fri, 10 Jul 2020 00:25:05 +0000","time_eol_unix":0,"base_code":"USD","rates":{"USD":1,"AED":3.67,"ARS":70.88,"AUD":1.44,"BGN":1.73,"BRL":5.36,"BSD":1,"CAD":1.36,"CHF":0.94,"CLP":791.55,"CNY":7.01,"COP":3608.55,"CZK":23.69,"DKK":6.6,"DOP":58.2,"EGP":15.98,"EUR":0.885,"FJD":2.16,"GBP":0.796,"GTQ":7.7,"HKD":7.75,"HRK":6.68,"HUF":314.67,"IDR":14199.6,"ILS":3.45,"INR":74.99,"ISK":139.34,"JPY":107.48,"KRW":1196.48,"KZT":409.22,"MXN":22.72,"MYR":4.27,"NOK":9.44,"NZD":1.53,"PAB":1,"PEN":3.53,"PHP":49.53,"PKR":166.43,"PLN":3.96,"PYG":6615.67,"RON":4.29,"RUB":71.27,"SAR":3.75,"SEK":9.22,"SGD":1.39,"THB":31.23,"TRY":6.86,"TWD":29.42,"UAH":26.85,"UYU":43.29,"ZAR":17}}
 
Even if you don't deal with JSON much, you could probably pick out that the exchange rate with CAD (Canadian dollar) is 1.36. We could certainly use the new JSON classes in Notes to traverse the JSON, find the values and build a report, but our Midas LSX is all about maximizing what you can do while minimizing the effort to do it. So, my business users want a snapshot of four specific exchange rates. I decided to present them like this:
 
Inline JPEG image
But how did I get from the JSON returned to this table? As a practical matter, I first just used our AppendFieldsWithJSON method to create fields from everything. It looked like this (and goes on and on until ZAR):
 
Inline JPEG image
 
You can see that when our method hits an object inside the object (this one called rates), it presents the values like this. But I wanted the rates presented more nicely, so I switched the properties of the AppendFieldsWithJSON to start down at the rates object (by setting ChildOf='rates'), and specify it as a vertical table inside a single tabbed table with a label. That looked like this:
 
Inline JPEG image
 
This is close, but I only want my four currencies, and I think the background should be green. Oh, and I'd like the labels to reflect the commonly used names for these currencies. So, I change the properties string a bit to include a comma-delimited list of the items I want and the way I want them to appear.
 
props = "AsTable='vertical' AsObjectArray='yes' ChildOf='rates' Items='AUD=Australian Dollar,CAD=Canadian Dollar,EUR=Euro,JPY=Japanese Yen' "
 
After a bit more tweaking of the color and tab label, I get my final code:
 
Sub Initialize
   DimAs New NotesSession
   Dim db As NotesDatabase
   Dim doc As NotesDocument
   Dim http As NotesHTTPRequest
   Dim gs As New Geniisession
   Dim rtitem As New Geniirtitem
   Dim rtchunk As Geniirtchunk
   Dim props As String
   Dim col1props As String
   Dim col2props As String
   Dim json_val As String 
 
   Set db = s.CurrentDatabase
   Set doc = New NotesDocument(db)
   doc.Form = "JournalEntry"
   doc.Subject = "Exchange rate data as of "+CStr(Now)
 
   ' *** Create the rich text item, overwriting it if it already exists
   Call rtitem.CreateBackend(doc.Handle, "Body"True)
 
   ' *** Add the title, and make everything Verdana to look better
   Call rtitem.DefineFont("Verdana")
   Set rtchunk = rtitem.DefineChunk("Everything")
   rtchunk.Font = "Plain 10pt Verdana"
   Call rtchunk.AppendTable(11"RowDisplay='Tabbed' TabFont='12pt Bold Verdana' BorderEffects='Drop_Shadow' TableWidth='Fixed' ", _
   "Text='' Width='3in' CellColor='RGB127,255,127' TabLabel='FX Rates with US Dollar'")
   Call rtchunk.ZoomIn("Table 1; Row 1; Inside column 1")
 
   ' *** Retrieve the JSON to use
   Set http = s.CreateHTTPRequest()
   http.PreferStrings = True
   json_val = CStr(http.get("https://open.exchangerate-api.com/v6/latest"))
 
   props = "AsTable='vertical' AsObjectArray='yes' ChildOf='rates' Items='AUD=Australian Dollar,CAD=Canadian Dollar,EUR=Euro,JPY=Japanese Yen' "
   col1props = "Text='' TextFont='Bold #004080'"      
   col2props = "Text='' TextFont='-Bold #004080'"      
 
    ' *** Appends the fields to the form and save
   Call rtchunk.AppendFieldsWithJSON(json_val, props, col1props, col2props)
   Call rtitem.Save()    
End Sub
 
and when I run that, I am back to the beginning. This could be the entire rich text field, or you could have an agent just drop it in where you want in an existing rich text. 
Inline JPEG image
A lot of power with a small amount of code, and it is easy enough to tweak and change and run again so you can design and create your look without spending a ton of time designing and creating your code. That's the Midas LSX advantage,

Copyright 2020 Genii Software Ltd.

Fri 29 May 2020, 04:22 PM
Inline JPEG image
 
 
I've noticed a couple of people in very different conversations talk about the idea of "round tripping" data, moving it from Notes rich text to HTML or MIME and then bringing it back. Often, this is described more specifically as moving it from "Domino to Mongo DB" or from Notes to SharePoint or simply from "the client to the web". Fundamentally, these all mean more-or-less the same thing. The internal format is Notes rich text. The "external" format is HTML or MIME, and even the MIME is really just HTML packaged differently.
 
In both conversations where it was mentioned, round tripping was treated as if it were a special case, unusual and not of interest to most Notes/Domino users.
 
This is simply not true. Round tripping happens every day, and it happens without any special coding or effort. Two of the simplest examples:
 
1) Send an email to a colleague outside of your domain. After that person replies, reply back. You've gone from rich text to MIME to rich text (again) to MIME (again). Two round trips.
 
2) Staying entirely in a Notes client, any version including Notes 11, saving a document with a rich text field set to "Store contents as HTML and MIME". Then, open it up to read it. For bonus points, make a change and save it, then open it again. You've gone from rich text to MIME to rich text to MIME to rich text again.
 
But so what? Obviously, Notes allows you to store content as HTML and MIME, so it must understand it. Right? 
 
Watch the video. All I do is save three documents with rich text fields stored as HTML and MIME, then reopen them. That's it. Watch the chaos which ensues. Then, tune in next week as I start to show the different ways Genii Software has found to make that round trip more pleasant and productive. Because we could all use a pleasant round trip right about now.
 
 
(I skipped the audio on this, but the captions should tell you what you need to know. I used HCL Notes 11.0 for this demo.)
 
 
 
 

Copyright 2020 Genii Software Ltd.

Tags:

Tue 19 May 2020, 02:16 PM
Inline JPEG image
 
When creating videos and demos and blog posts, I always have to ask myself how long is long enough and how long is too long. But the question turns out to be a trick, because there are no unladen users. Everybody is too busy, too distracted, and too absorbed with their own issues. Unladen means not carrying a load. If you only focus on users who are not carrying a load, you are focusing on nobody at all.
 
Having said that, people probably do have a need for your software or services or whatever. Year after year, people buy our software, so we're clearly not only focused on the unladen. The difficulty then is knowing what load they are carrying, and how your software or services or whatever can lighten that load, or make it more productive or profitable.
 
So, while I strongly believe in brevity and most of my videos are 3 minutes or shorter, the real question: how you can get and keep the attention of a laden user? Clickbait headlines and dimmicks are good for getting attention, and lousy for keeping it. Information dense articles and videos are good for the thoroughly engaged, and lousy at engaging. Storytelling is fairly effective, but your story has to hit the mark quite closely, as distracted users often won't extrapolate to their own issues if the one being solved is not very, very close to a match.
 
Do you have ways you get and keep attention? If you do, how long do you assume the attention span will hold out? Obviously, the more your offering is exactly what people will need, the more likely they are to stay around to hear the pitch, but what do you do when they don't recognize that it is exactly what they need?

Copyright 2020 Genii Software Ltd.

Thu 7 May 2020, 10:50 AM
Idea: HCL should update documentation of Domino limits
 
For years, I maintained a fairly popular Domino limits feature on our website. (It is still there, and people still access it, but I have made it more difficult to find as I couldn't figure out how to reference changes made in the "fixpack years", when limits could change in a fixpack.) I could update it for Notes/Domino 10 and 11, but why not vote for this idea and convince HCL to do it properly?
 
Note: This is not my idea. I just saw it, and think it is worth supporting.
 
Click on the idea above or this link to head over to vote for it.

Copyright 2020 Genii Software Ltd.

Wed 29 Apr 2020, 03:03 PM
Inline GIF image
St Augustine famously said, though probably in Latin, "When in Rome, do as the Romans do." Yet my previous post, Down to Business - PDF invoices from Notes data with Node, violates that spirit in a fairly major way. Now, the post is still well worth a read and contains a demo that is absolutely relevant, but the script is a bit like reading a sex scene in a book by a priest. You know what is happening, but you're not convinced the author really does.
 
JavaScript isn't written that way. JavaScript doesn't generally operate that way. Sure, it works, but not in a way that would speak to anybody coming from the modern world of JavaScript or Node.js development. It does look a lot like LotusScript, but if we want to widen the range of developers who work with Notes/Domino, we need to reach beyond the relatively few LotusScript developers still out there and appeal to the vastly wider ocean of JavaScript developers. My earlier post, A bigger boat: meeting developers where they are, adds one element of that by allowing parameters to be passed as an object. But it is still fairly old-fashioned synchronous blocking code. Do this. Then do that. While this, do that other. The main JavaScript loop runs in a single thread, so unless you spin off functions, while it is off doing a function, everything waits. That is not good when you should also be processing mouse movements, etc.
 
In short, we need to go asynchronous. We need Promises. Not ordinary promises, like "I will remember to take the trash out on trash day, but JavaScript Promises, which are more like, "I will come back with a result that either resolves this function or rejects it due to error."
 
So, back to the drawing board with Exciton Power. Here is the same basic script I showed in  Down to Business - PDF invoices from Notes data with Node, generating the exact same invoices, but now using the asynchronous (and default) mode for Exciton Power. It some a bit more error trapping and uses slightly different class names (e.g., ExcitonCollection rather than GCollection). All methods are asynchronous and return promises. It is still mostly imperative code and still pseudo-synchronous in that it uses an async / await model familiar to JavaScript developers. It should be fairly clear to hardcore LotusScript developers as well, but let's face it, we old dogs do have to try and learn a few new tricks. Mostly, it does the job without blocking the main event loop, so Node.js can get on with its business, though a more truly asynchronous model will be coming for times when you might handle multiple documents at the same time by spinning off different threads. But for now, at least we can pass as Roman wannabes if not full-fledged Romans. Che buon'idea!
 
Note: I am not a JavaScript expert by any means, and welcome any suggestions about how to improve this and make it feel more natural to JavaScript developers.
 
// *** Initiate a session
const session = require('./build/debug/ExcitonPower');
const { createInvoice } = require("./createInvoice.js");
 
// *** Create a collection and add a view to it
const coll = session.useCollection();
 
let invoiceStarted = false;
 
// *** Cycle through the view, looking for invoices and their line item response documents
coll.addByView({server: "", filePath: "AcroBatsCRM.nsf", viewname: "Customers"}).then(async doccount => {
  console.log("Added "+doccount+" documents from Customers view");
  try {
    let doc = await coll.getFirstDoc({items: "CompanyName,InvNo,Contact,Address,City,State"})
    let docobj;
    if (doc != null) docobj = JSON.parse(doc);
 
    let count = 0;
    let total = 0.0
    let invoiceStarted = false;
    while (doc !== null) {
      if (docobj'@form' == "Invoice") {
        invoice = {InvNo: docobj.InvNo, filename: docobj.CompanyName+" - "+docobj.InvNo+".pdf", shipping: docobj, items: []};
        invoice.subtotal = 0.0;
        invoice.paid = 0.0;
 
        invoiceStarted = true;
        total = 0.0;
        count = 0;
        } 
      else if (docobj'@form' == "Line Item" && invoiceStarted) {
        count++;
        doc = await coll.getDocByUNID({unid: doc, items: "ItemNo,Qty,Price,Total,@DbLookup(\"\":\"\"; \"\":\"AcroBatsPRD.nsf\"; \"Products\"; ItemNo; \"ItemDesc\")=ItemDesc"});
        docobj = JSON.parse(doc);
        invoice.items.push(docobj);
        total += docobj.Total;
        invoice.subtotal = total;
        invoice.paid = 0.0;
        }
 
      if ((doc = await coll.getNextDoc({unid: doc, items: "CompanyName,InvNo,Contact,Address,City,State"})) != null)
        docobj = JSON.parse(doc);
 
      if (doc == null || (invoiceStarted && docobj'@form' != "Line Item")) {
        invoice.subtotal = total;
        invoice.paid = 0.0;
        createInvoice(invoice);
        console.log("Created invoice as "+invoice.filename+" for $"+total); 
        invoiceStarted = false;
        }
      }
    }
  catch(err) {
    console.log("Error: "+err.message);
    }
  }).catch(function(err){console.log("Error: "+err.message)});
 
console.log("Completed!");
 

Copyright 2020 Genii Software Ltd.

Tags:

Mon 27 Apr 2020, 08:44 AM
Inline JPEG image
 
I've had various customers ask what exactly is in Notes 11, especially for those who are just gradually getting back on maintenance after being lapsed for a while. Mat Newman gives a rundown.
 
 
 

Copyright 2020 Genii Software Ltd.

Tags: