Genii Weblog

Weblog search results for:

Sun 5 Jun 2022, 08:51 PM
Learn to code session on June 6th at 5pm EDT


Making software isn't hard. Making software easy is the really hard part. As our customers and partners know. we work very hard to make our Genii Software products easy and intuitive. But tomorrow (Monday, June 6th at 5pm EDT), I am trying a new challenge. I am holding a Learn-To-Code event in which I will be building a Drag-n-Drop Dominos game using HTML, CSS, and JavaScript. The goal is to have people code along with me, so I need to minimize "cooking show magic" where lots is already prepared for them. Getting the game working was fairly easy, but I am spending much more time simplifying the steps and trying out different approaches to make the code accessible to non-coders and low-coders. If this works out, I will likely do other such events, possibly also throwing in a Notes/Domino Learn-To-Code session here and there.
 
This event is sponsored by the coding bootcamp, Tech Elevator, where I teach people to become full stack web developers. It is a virtual event which means anybody who wants can sign up and join to watch me, though my focus is on motivating Cleveland folks to think about how much fun coding can be.
 
Fri 3 Sep 2021, 08:51 AM
I'm working on a series of posts for next week on the four most common ways to represent a table of values in Notes that do not play nicely with relational databases. There are others, but these four are ones I see routinely when exporting data with Midas Exports or retrieving data with Exciton Boost. (There are also ways that do play nicely, but why talk about them?) My challenge for myself is whether I can use both tools to export or retrieve the data from each in a way that forces them to play nicely with relational databases.
 
In order from most to least common of the four top ways I see to make table data that don't play easily with relational databases:
 
1) Hard-coded table cell fields, every one separate
2) Parallel multi-value fields, one per column
3) Response documents, one per row
4) Tables embedded in rich text
 
Watch this blog for my posts. Also, feel free to leave a comment if you know of other ways to represent table data that don't play nicely with relational databases/techniques.
 
Inline JPEG image
 
Mon 21 Jun 2021, 09:56 PM
 
Inline PNG image
 
I gave a presentation today at Rudi's DominoCamp. Kind of a weird thing presenting in silence for 75 minutes. I was relieved to see the people who started watching seemed to still be there at the end, as there was no way of know while I was presenting. I look forward to getting back to in-person conferences.
 
Slides are here --> Custom Domino Extensions in a Modern AppDev World - DominoCamp 2021 slides <-- though I will likely put them up on Slideshare later as well.
 
For the demos, I put most of the output in slides so you could see it. The source code and make file for the DspLnks64 DSAPI and Daleks ExtMgr are below, though you may need to adjust the makefiles to match the compilers you have set up, or skip it and make the projects in an IDE. (Recommended compilers kept switching between versions.)
 
dsplnks64.dll (version built and used in  demo)
 
ndaleks64.dll (version built and used in  demo)
 
The Node.js demo I desscribed with the invoices is described in full at Down to Business - PDF Invoices from Notes data in Node.
 
Thanks to everybody who attended. Anybody who has questions should feel free to ask, as I am always up for brainstorming about extensions.
 
I will provide a link to the video when it is available.

Tags:

Thu 10 Jun 2021, 09:45 AM
Inline JPEG image
 
 
This is just a simple tip for those upgrading to Notes 12, as I just did. I mentioned on Facebook that I was surprisingly happy with the new workspace look, surprising only because I hated all the recent ones and have used the Textured Workspace until fairly recently. I was surprised that when I was asked for a screenshot like the one above, somebody else showed theirs and it looked quite different, like the one below.
 
Inline JPEG image
 
After being questioned about what I might have done differently, I started looking and found the answer. If you right click on the workspace, there is a Background option. This has been advertised as a way to put a custom background image, but if you are like me and simply aren't sure you want so much blue, you can just set the option to None and you get the lighter screen like me.
 
Inline JPEG image
 
 
 
 
That's it, really. Not a big deal no matter what you choose. I should say, even with the blue background it is better than the Notes 9, 10, or 11 workspaces, so whatever you choose, it feels like a step up. Thanks, HCL.
 

Tags:

Wed 5 May 2021, 05:47 PM
This update on an earlier post shows some of the capability of Midas LSX Version 5.75, released this past week. The goal is an instant little mini-report in a rich text field, based on almost any public REST API. 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", "provider":"https://www.exchangerate-api.com", "documentation":"https://www.exchangerate-api.com/docs/free", "terms_of_use":"https://www.exchangerate-api.com/terms", "time_last_update_unix":1620172951, "time_last_update_utc":"Wed,  05 May 2021 00:02:31 +0000", "time_next_update_unix":1620261101, "time_next_update_utc":"Thu,  06 May 2021 00:31:41 +0000", "time_eol_unix":0, "base_code":"USD", "rates":{"USD":1, "AED":3.67, "AFN":78.37, "ALL":102.81, "AMD":520.88, "ANG":1.79, "AOA":650.5, "ARS":93.66, "AUD":1.3, "AWG":1.79, "AZN":1.7, "BAM":1.62, "BBD":2, "BDT":84.84, "BGN":1.62, "BHD":0.376, "BIF":1950.25, "BMD":1, "BND":1.33, "BOB":6.89, "BRL":5.45, "BSD":1, "BTN":73.91, "BWP":10.93, "BYN":2.57, "BZD":2,  "CAD":1.23,  "CDF":1982.38,  "CHF":0.914,  "CLP":704.64, "CNY":6.48, "COP":3790.25, "CRC":613.73, "CUC":1, "CUP":25.75, "CVE":91.35, "CZK":21.54, "DJF":177.72, "DKK":6.18, "DOP":57.03, "DZD":133.71, "EGP":15.65, "ERN":15, "ETB":42.02, "EUR":0.829, "FJD":2.03, "FKP":0.72, "FOK":6.18, "GBP":0.72, "GEL":3.43, "GGP":0.72, "GHS":5.77, "GIP":0.72, "GMD":51.87, "GNF":9886.02, "GTQ":7.72, "GYD":213.58, "HKD":7.77, "HNL":24.03, "HRK":6.24, "HTG":86.4, "HUF":300.5, "IDR":14451.3, "ILS":3.27, "IMP":0.72, "INR":73.91, "IQD":1455.73, "IRR":41896.5, "ISK":124.59, "JMD":153.18, "JOD":0.709, "JPY":109.33, "KES":107.31, "KGS":84.83, "KHR":4071.34, "KID":1.3, "KMF":407.58, "KRW":1124.57, "KWD":0.3, "KYD":0.833, "KZT":428.31, "LAK":9416.2, "LBP":1507.5, "LKR":196.79, "LRD":171.85, "LSL":14.47, "LYD":4.47, "MAD":8.92, "MDL":17.73, "MGA":3792.33, "MKD":50.8, "MMK":1558.46, "MNT":2844.74, "MOP":8, "MRU":35.96, "MUR":40.28, "MVR":15.42, "MWK":792.93, "MXN":20.24, "MYR":4.12, "MZN":57.47, "NAD":14.47, "NGN":395.55, "NIO":34.94, "NOK":8.32, "NPR":118.26, "NZD":1.4, "OMR":0.384, "PAB":1, "PEN":3.82, "PGK":3.51, "PHP":48.08, "PKR":152.86, "PLN":3.79, "PYG":6503.36, "QAR":3.64, "RON":4.1, "RSD":97.85, "RUB":75, "RWF":984.95, "SAR":3.75, "SBD":7.9, "SCR":14.99, "SDG":378.63, "SEK":8.47, "SGD":1.33, "SHP":0.72, "SLL":10205.78, "SOS":577.27, "SRD":14.12, "SSP":177.64, "STN":20.3, "SYP":1262.9, "SZL":14.47, "THB":31.2, "TJS":11.31, "TMT":3.5, "TND":2.74, "TOP":2.26, "TRY":8.31, "TTD":6.78, "TVD":1.3, "TWD":27.94, "TZS":2315.59, "UAH":27.75, "UGX":3561.65, "UYU":43.84, "UZS":10630.2, "VES":2840459.11, "VND":23031.05, "VUV":107.92, "WST":2.51, "XAF":543.44, "XCD":2.7, "XDR":0.699, "XOF":543.44, "XPF":98.86, "YER":250.25, "ZAR":14.47, "ZMW":22.33}}
 
Even if you don't deal with JSON much, you could probably pick out that the exchange rate with CAD (Canadian dollar) is 1.23. 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 could just use our AppendFieldsWithJSON method to create fields from everything. It would look like this (and goes on and on until ZAR), though this is not current data:
 
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 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' "
 
    ' *** Appends the fields to the form and save
   Call rtchunk.AppendFieldsWithJSON(json_val, props, "TextFont='Bold #004080'""TextFont='-Bold #004080'")
   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, 
 
Request a Midas LSX evaluation license today and give it a try. We'll send you a sample db showing this code with a few variations to give you ideas.
 

Tags:

Thu 29 Apr 2021, 03:18 PM
Inline JPEG image
 
A follow up to Archive a Notes DB off-line in 4 easy steps, this video gives a taste of how powerful and flexible the Archive It! tool is. Along with the archived snapshot, you can save a JSON, XML, or CSV file with some or all of the fields preserved in case a future need arises. In addition, this demo shows how the Midas LSX and the Archive It! db handle more complex forms that might include collapsed sections, embedded views, and much more.
 
Request a Midas LSX evaluation license today and give it a try. We'll send you a link to the Archive It! database with your evaluation.
 
 
 
 

Tags:

Tue 20 Apr 2021, 06:11 PM
Inline PNG image
 
We have a new sample db for our Midas LSX called Archive to Disk.  The idea is that sometimes you have a database you no longer need to use actively, or that you want to give to somebody who won't be using it in Notes/Domino. With no additional coding, you can create an off-line archive that preserves the look and feel of the Notes database, right down to working doclinks, sections, and tabbed tables. Views will be reproduced to access the documents, and a custom launch page created, all in a few easy steps.
 
This uses Midas LSX 5.75, which will be available tomorrow. Midas Export pricing applies. Closed captions will be provided shortly.
 
 
 
 

Tags:

Thu 18 Mar 2021, 11:55 AM
Inline JPEG image
 
There are a lot of ways to write out an exact date and time, but for the sake of international standards, dates in JSON and other interchange formats should be written using ISO 8601. But even that gives us options. The following two dates represent the exact same moment in time, but do they represent the exact same information?
 
"@created""2021-02-22T16:32:19Z"
 
"@created""2021-02-22T11:32:19.53-05:00"
 
While they are considered equivalent, are they? What is the piece of metadata that is lost in the first but not the second? It is the original time zone in which the document was created.
 
Now, this may seem unimportant. In most cases, it probably is unimportant. But if there is one thing I have learned in my years converting data from one format to another, and especially in doing roundtripping or synching of data that must coexist in two different platforms, it is that every detail is precious some of the time or to some of the people. In meeting invites, we see both when the invitation is and what time zone it was created it. If we convert to the first of these two formats and then back, we lose that information, or even if we just pull it out for display elsewhere, we won't have it.
 
Now, I want to be clear that even the second format is risky. A standard JSON parser that recognize dates may turn these both into the same timedate object. But a savvy parser in a system that has the capability to store time zones will store that time zone with the second format. It can't with the first. The detail is simply lost.
 
Addendum: Just a quick follow up to this. In reality, you can't determine the time zone itself from the time offset, but you can calculate the local time in which the time was created. Therefore, we offer an option to use an extended construct for Notes time date item values that gives the time zone as a separate value along with the time and date, e.g., "StartTime": {"zone":"EST", "value":"2021-03-01T10:30:00.00-05:00"}

Tags:

Mon 15 Mar 2021, 10:12 PM
Inline PNG image
 
While Genii Software is best known for our Notes/Domino related coexistence and migration products, we work in other areas as well. But both inside and outside of Notes/Domino, our core business is really data movement. If you have data in some format or encapsulation, and you need it in some other format or encapsulation, that's what we do. Whether you need the data to move for a moment, for the duration of a project, or forever, we help you move it.
 
The challenge for me is usually not the format or system or structure the data is going to, but the format or system or structure the data is coming from. Often older, outdated systems, though certainly not always, I need to understand as much or more about the source as the destination. Which is why I spend time building new design and new data into things like Infopath Forms that are already facing EOL. Because when that data needs to go elsewhere and fit into some other design (whether Microsoft Power Apps or Salesforce Lightning Apps or whatever), we need to be able to understand the data we are likely to see, and the stuff we are less likely to see, but still will because developers will use anything. we need to be prepared for structures allowed in one system but not in another, especially multi-value anything (e.g., repeating tables), as those tend to be implemented differently in different systems.
 
So, I am creating forms that will never be used by anybody but me, all to be ready for you.

Tags:

Wed 3 Mar 2021, 10:57 PM
Inline PNG image
 
 
Barely a week goes by when I don't hear the question "But can you take my Notes data and move it into <Shiny New Thing>?" Sometimes, the question goes the other way around. Either way, the answer is almost certainly yes. When it comes right down to it, one of the things we excel at is moving data around.  Chances are even good we can move from <Shiny New Thing One> to <Even Shinier New Thing Two>. (Companies do like shiny.) Moving data accurately and well is critical whether you want to move your data for a project, for a moment, or forever.
 
We might already have a tool for it. We might need to pull together some different custom tools we have. We might need to use Midas or Exciton or sheer magic. But we can most likely get your data moved, and we can most likely do it with the highest fidelity available. We are not as cheap as that freeware tool you can download from <Shady Website Du Jour>, but we also don't bring the viruses along with us. We might not have the sales team to take you out to a fancy meal before lifting your wallet and dumping it out on the table.
 
We just care about data. We are especially good with Notes data, kind of a speciality of the house, but we are quite adept with other data as well. You might need it in JSON or XML or CSV or HTML, or most likely some combination. Whatever your shiny new thing is, we can help you get your data there, and make sure it shines too when it gets there. The image below includes some of the formats we support, but there are plenty  more that are specialized variants, so don't hesitate to ask. Just know that the answer is probably yes, and that even if it isn't, we can probably turn it into a yes in short order. We're good that way. If you want to ask this question or any others, I can be reached at . I look forward to hearing about the data you need for your shiny new thing.
 
 
Data retrieval, migration, and archiving
 

Tags:

Mon 1 Mar 2021, 03:25 PM
Inline JPEG image
 
This week, I'll hit my blog's 18th birthday. With over nine posts a month on average, I've kept this going far longer than I would have expected. Sometimes, people even seem to read the darn thing.
 
Thanks for reading. Thanks for putting up with the dating advice to my daughter, the nonsensical tales of Mike Midas and Crystal Coex, the endless ponderings, and the incessant self-promotion. Without you, this blog would be totally pointless. So, thanks. On a different blog, I might try to come up with highlights, but the biggest highlight for me is just being here.
 
Fri 19 Feb 2021, 11:44 AM
Yesterday, I wrote a post called Getting the point(s) across with Domino, O365, and Outlook365, but while it is fascinating, it also related to Notes/Domino email which may be a distant memory for some companies. But last night, it occurred to me to try a similar test with Domino mobile and web development, surely a more pressing issue for many companies today who are upgrading Domino applications. I decided to make one change to the content first, which was to make the lists ordered rather than bullets, as it is easier to tell the levels apart.
 
Note: Before I start, I want to acknowledge that part way through writing this post, I started doubting myself, as I was sure nested lists couldn't be this bad. I realized that there are two ways to create nested lists in Notes, and while they may look identical, one renders more reliably than the other. The basic difference is how you create the indents for the list. Suffice it to say, you have no easy way of knowing which technique was chosen, so the rendering can only be considered unreliable.
 
I decided to start with classic Domino web development and move forward in time. I would have included the new AppDev stuff, but it doesn't really render rich text at all. Go figure. Anyway, let's first look at how this looks in the Notes client, and then how it looks retrieved by our Exciton Boost REST API, just to see what it should look like. In each case, take note of what Roman numeral is displayed for C is for Cantaloupe. In the Notes client, it was III.
 
Created in Notes 11.0.1 client
 
Inline JPEG image
 
 
Displayed by Genii Software's Exciton Boost 4.6.1
 
Inline JPEG image
 
 
Displayed by Domino 11.0.1 HTTP (Classic web design)
 
Inline JPEG image
 
 
Displayed by Domino 11.0.1 XPages
 
Inline JPEG image
 
 
Retrieved by Domino 11.0.1 Domino Access Services (retrieved as HTML with ?multipart=false)
 
Inline JPEG image
 
 
Retrieved by Domino 11.0.1 Domino Access Services (retrieved as MIME)
 
Inline JPEG image
 
 
 
Explanation of the two ways to create nested lists
 
Modern method: The current common way to created a nested list is to use either the Indent and Outdent toolbar icons or F8 and Shift-F8 to do the same thing. This will shift both the left margin and first line left margin. See the two middle icons below with the little arrows.
Inline JPEG image
 
But these were not always there as options, and an earlier way to create nested lists was to change margins via the ruler.
 
Older method: The older way to created a nested list was to use the ruler and change the margins. Older rich text, or text created by long time users, may be more likely to have nested lists created this way. If you look at the ruler below, this is the indentation for Granny Smith. Note that only the top margin (the first line) is indented. In Notes rich text, that first line margin is what determines a "new indentation", which is why the ordered lists start over. But for some reason, the different engines that drive Domino don't seem to recognize that simple fact, and treat the nested list as a single list, albeit with different list types.
 
Inline JPEG image
 
 
--> Request an Exciton Boost evaluation license today and give it a try. <--
 

Tags:

Thu 18 Feb 2021, 03:11 PM
When running some tests for a couple of prospective CoexLinks Fidelity customers, I was reminded again of two things.
 
One: Domino email doesn't always render well without help (i.e., CoexLinks Fidelity)
 
Two: Outlook 365 is a weird beast, not matter how much people might want it to be a successor to Notes/Domino.
 
Let's take the following email, written in Notes. 
 
Sent from Notes 11.0.1 client
 
While nested bullet points like this may not be elegant, they are reasonably common in office emails, and were back in 1989 when Lotus Notes 1.0 was released. Notes 1.0 supported nested bullet lists.
 
Inline PNG image
 
 
 
Received in Outlook 365 web client (after rendering by Domino)
 
One of the fundamental ideas of nested bullet points is in that first word, "nested", but sadly, the point has been lost due to the Domino rendering. But worse is yet to come.
 
Inline PNG image
 
 
 
Received in Outlook 365 desktop client (same email)
 
Having already lost the first fundamental idea of nested bullet points, Outlook manages to screw up the second, as in that second word, "bullet". The bullets are mysteriously missing from the email. Absent nesting, indentation, and bullets, the combination of Domino 11 and Outlook 365 has taken this commonplace corporate staple and completely missed the point(s).
 
Inline PNG image
 
 
 
Received in Outlook 365 web client (after rendering by Domino with CoexLinks Fidelity)
 
Fortunately, all is not lost even if you use the unholy combo of Domino and Outlook 365. You just need to add CoexLinks Fidelity to the mix, and badda-bing badda-bang, things get rendered right and displayed right in Office 365 on the web.
 
Inline PNG image
 
 
 
Received in Outlook 365 desktop client (same email)
 
... and, of course, in Outlook 365 desktop client. I hope this gets the point(s) across.
 
Inline PNG image
 
If your company uses Notes mail/Verse, even if it just uses them to pass on programmatic emails to Outlook 365 (or Gmail or whatever), CoexLinks Fidelity fixes the problems that both Domino and Exchange have with email. It's that simple. Use the form below to send yourself a few sample emails and see what I mean. (Email address will not be sold or shared or used for anything but a single follow up to offer an evaluation license.)
 

 

Tags:

Mon 15 Feb 2021, 02:42 PM
Inline JPEG image
 
 
Exciton Boost 4.6.3 was released on our website today. You can find the full release notes online.
 
There are a number of interesting changes in this release, including shortcuts to making more efficient remote procedure calls. You can request an evaluation license today and give it a try, and existing customers can download it as it will work with your current license.

Tags:

Mon 1 Feb 2021, 05:11 PM
Inline PNG image
 
After a delay due to various projects and a product release, I wanted to get back to the demo I described in REST plus RPC: Do the demo backward.
 
If you remember, I showed how to get the data from the view in REST plus RPC: the right data in the right format, and no more. While it would be possible to pull all the data at one time with this demo, it often would not be if there were many more orders or more textual content. Therefore, looking at the basic JavaScript I wrote about in REST plus RPC: building the JavaScript  for RPC, we should assume we might have multiple batches, one for each page of content. By default, that means 20 orders per batch. Since the image above shows that 312 orders are there to be processed, that would be sixteen calls. A developer knowing the data to be returned and the processing to be done might decide to do this in fewer calls or more calls, and thus adjust the page size accordingly.
 
The JSON-RPC commands all have a particular format with a method required and parameters and return id used as needed. But when the fetch is done, the body of the request is always a single, simple JSON string. So, one of the choices to be made that will vary by project is whether to build up the objects as JavaScript objects and use stringify to create the JSON string, or whether to build the JSON string directly. Sometimes one works better, sometimes the other. To show what I mean, look at the JavaScript object for the rtc.appendTable method that creates the outer tabbed table along with its first tab set to the specified state. We could create all the tabs at once, but we don't know which states are represented, so we need to do them one by one. 
 
var tbl = {
           jsonrpc: "2.0", 
           method:  "rtc.appendTable", 
           params:  [1, 
                     1, 
                     "TableWidth=FIT_TO_WINDOW RowDisplay=TABBED TableColorStyle=ALTERNATING_ROWS TableColor=RGB255,191,191 TableBodyColor=RGB127,255,255"
                    ]
          };
 
This is a template, but in order to set the actual tab of the first state as we create the table, we would modify the object to add an additional parameter for the first "column", which is also the first tab of a tabbed table:
 
tbl.params.push("Text='' TabLabel='"+ o.State + "'");
 
After we do this, the object looks like this:
 
var tbl = {
           jsonrpc: "2.0", 
           method:  "rtc.appendTable", 
           params:  [1, 
                     1, 
                     "TableWidth=FIT_TO_WINDOW RowDisplay=TABBED TableColorStyle=ALTERNATING_ROWS TableColor=RGB255,191,191 TableBodyColor=RGB127,255,255",
                     "Text='' TabLabel='AL'"
                    ]
          };
 
If you want to use templates for the calls, they can just be constants, but here is where the downside comes in. In order to use the templates, you have to do a deep copy using either a utility library like lodash, or some clunky code such as:
 
var rowTmpl = {
               jsonrpc: "2.0", 
               method:  "rtc.appendRow", 
               params:  [false, 1]
              };
 
var appendRow = JSON.parse(JSON.stringify(rowTmpl));
appendRow.params.push("Text='' TabLabel='"+ o.State + "'");
 
batchActions.push(appendRow);
batch = JSON.stringify(batchActions);
 
 
It works, but is inelegant at best, and also does a lot of work given that you are converting the eventual object to JSON anyway. So, an alternative would be to built the template as JSON to start with:
 
const rowTmplStart = "{\"jsonrpc\":"2.0", \"method\":\"rtc.appendRow\", \"params\":[false, 1, ";]
const rowTmplEnd = "]}";
 
var appendRow = rowTmplStart+"\"Text='' TabLabel='\""+ o.State + "'\"" + rowTmplEnd;
batch += appendRow;
 
For this demo, I think we are better off using the JSON string, but I wanted to be clear what I was doing, as it is a little less obvious than building an array of objects and stringifying them. Now, we just have to put it all together. I hope to work on that tonight.
 

Tags:

Thu 28 Jan 2021, 12:58 PM
Inline PNG image
Today, Genii Software releases version 4.60 of CoexLinks Migrate, our premier mail migration tool for Domino email databases and archives. Along with a wrap up of various fixes for specialized rendering situations required by individual customers, this version features better control of email layout regions, multibyte character sets in group names, and a performance gain of approximately 20% over the previous version.
 
You only get once change to migrate your data. Do it right.
 
Request an evaluation license today, and see for yourself.
 

Tags:

Mon 25 Jan 2021, 11:28 AM
Inline JPEG image
 
Continuing on from last week's post, we are looking at better ways to retrieve data based on two factors:
 
1) How much data do you need from any given record, and which records do you need it from? If there is related data in another record, can you get it without pulling in loads of stuff you don't need? 
 
2) What format should the data be in? How should it be structured or grouped for maximum usability? While you can certainly write code in your application to reformat or restructure, that adds complexity and room for error on your client.
 
Again using Exciton Boost 4.6 with the Curb Appeal database, we'll examine a couple of additional Fancy Tricks (aka "useful features").
 
 
Fancy trick 3: - Saving preliminary values
This may not sound so fancy, but sometimes the value you want is the result of multiple operations. Rather than passing back all the pieces and doing the processing on the client, which might require multiple requests, we can save the results of a formula or rich text operation into a temporary field, and then use those temporary fields to create the result.
 
On Friday, I posed a challenge called Sorted lists of bullets. In the real estate listings in Curb Appeal, there are usually two, occasionally, three columns of bullet items under the Features heading. These are rich text fields, but all we really care about are the text values for each bullet. In our second Fancy Trick from the first post, I talked about using rich text items as a data source.
 
Inline JPEG image
 
Using that trick, we could get the list of bullets from each of the three rich text fields, Col1, Col2, and Col3. (Imaginative naming, eh?) For this fairly simple example, we could return all three lists as separate arrays, then merge the arrays, then sort, all using JavaScript or whatever language. The item list to retrieve these would look something like this:
 
Col1[BulletList *;$UnformattedText]{A}=bullets1,Col2[BulletList *;$UnformattedText]{A}=bullets2,Col3[BulletList *;$UnformattedText]{A}=bullets3 
 
This would produce three arrays named bullets1, bullets2, and bullets3. But this is where the Fancy Trick comes in. By changing the type string in curly braces from {A} to {AP},  with the P meaning Preliminary, none of the three arrays would appear in the result. Instead, a multi-value temporary text list item would be be added. It uses the name preceded by two dollar signs, e.g., $$bullets1 plus a period plus the chunk property, so the field $$bullets1.UnformattedText is now a Notes text list.
 
Col1[BulletList *;$UnformattedText]{AP}=bullets1,Col2[BulletList *;$UnformattedText]{AP}=bullets2,Col3[BulletList *;$UnformattedText]{AP}=bullets3 
 
As a final step, we can use formula language now that we have simple text list fields, so we add an additional item as 
 
@Sort($$bullets1.UnformattedText:$$bullets2.UnformattedText:$$bullets3.UnformattedText){A}=bulletsSorted 
 
The three text lists get appended together then sorted with @Sort, and the result is a sorted list bullet values returned as bulletsSorted. Since we can use all of Notes formula language, we could done @ReplaceSubstring or @Unique or whatever. The client app simply gets the data it needs in the form and format it needs them.
 
Imagine the following code. Can you see what it would do, and how you might be able to use it while building a web page result?
 
Body[Graphic *;%GraphicWidth]{AP}=widths,@Max($$widths.GraphicWidth)=maxWidth
 
 
Fancy trick 4: - Retrieving related data from other documents and databases
Anyone who has worked with Notes for a while will know that a view cannot do @DbLookups to get related information. If an item number is used but the item name, description, and price are in another database, you can do @DbLookups to retrieve them from inside a document but not from a view. In a typical REST API, you might do one request to get this document's information and then other calls to retrieve related information, but Exciton Boost allows you to use formulas, so you can retrieve related information in your first request. Rather than retrieving lots of data and dealing with it on the client, this also allows highly efficient view operations and caching to empower these lookups. As a simple example from our Curb Appeal database, we could use the following to display the average price of all houses in the current city.
 
City+", "+State{P}=key,@DbLookup("";"";"Listings\\by Location";$$key;2){P}=prices,@Text(@Sum($$prices)/@Elements($$prices);"C")=avg 
 
so, for a listing in Beachwood, OH, you would get
 
{
    "@unid""524C08BF648BE77A85257B8600798F5B",
    "avg""$460628.57"
}
 
Note that I used the previous Fancy Trick twice to save the key and then save the results of the lookup. Also note, when the values do not come from chunk properties but rather from formulas or items, the name is simply preceded by the two dollar signs. This process is very similar to saving variables in any language, but especially in cases where many data points are involved, it saves considerable time and bandwidth.
 
=> Request a free Exciton Boost eval in January, and if you later purchase a license. we'll add in four hours of development assistance, a $700 value. <=
 
If you have found these tricks interesting or intriguing, let me know and I can show more that relate to other parts of the REST API or remote procedure calls.
 

Tags:

Fri 22 Jan 2021, 06:51 PM
Inline JPEG image
 
 
I finally found time to put together two examples of "Fancy tricks" to do with Exciton Boost's REST API, and it is Friday afternoon, so I don't want to post it and have nobody notice. I'll post that Sunday night or Monday morning, but for now, let me leave you with a simple challenge. How would you use Domino Access Services or other HCL code to take the multiple rich text fields above and turn them into a sorted JSON array of strings for all the bullet values? It can obviously be done, but probably not as simply and elegantly as with Exciton. It took me about a minute to write out the request for this and far less than a second to get the following result. I'll show the request along with my post on Monday.
 
{
    "@unid""524C08BF648BE77A85257B8600798F5B",
    "bulletsSorted":
        "Attached parking",
        "Automatic garage door opener",
        "Basement",
        "Bedroom 2 is 15.00 x 14.00",
        "Bedroom 3 is 15.00 x 15.00",
        "Bedroom 4 is 16.00 x 13.00",
        "Central air",
        "Central vacuum",
        "Cul-de-sac location",
        "Dining Room is 15.00 x 14.00",
        "Dishwasher",
        "Eat-in kitchen",
        "Finished basement",
        "Fireplace in great room",
        "Forced air heat",
        "Formal Dining Room",
        "Foyer",
        "Full basement",
        "Garage spaces: 3",
        "Garbage disposal",
        "Great room is 23.00 x 22.00",
        "Great Room",
        "Heating: Gas",
        "Inground pool",
        "Irregular lot",
        "Kitchen is 23.00 x 18.00",
        "Library is 12.00 x 12.00",
        "Lot acreage is: 0.2650",
        "Master bedroom is 18.00 x 15.00",
        "Microwave oven",
        "Office",
        "Office is 16.00 x 15.00",
        "Other Room is 21.00 x 18.00",
        "Oven",
        "Patio",
        "Paved driveway",
        "Porch",
        "Property style: Colonial",
        "Public sewer",
        "Public water",
        "Rec Room is 30.00 x 12.00",
        "Refrigerator",
        "School district: Beachwood CSD",
        "Security system",
        "Smoke alarm",
        "Sun Room",
        "Sun Room is 17.00 x 16.00",
        "Warranty included",
        "Wooded lot",
        "Zoned heat"
    ]
}
 

Tags:

Tue 19 Jan 2021, 09:23 PM
Inline JPEG image
 
At first glance, it may seem like REST APIs are inherently simple. You retrieve the data from a record or collection of records, and then you do your stuff. If you need to create, update records, or delete records, you can do that as well. But when you are building a proper application, there are many other things to consider. Two key factors are:
 
1) How much data do you need from any given record, and which records do you need it from? If there is related data in another record, can you get it without pulling in loads of stuff you don't need? 
 
2) What format should the data be in? How should it be structured or grouped for maximum usability? While you can certainly write code in your application to reformat or restructure, that adds complexity and room for error on your client.
 
Using the Curb Appeal database I showed in Getting data from Domino with Exciton Boost (and companion post with code samples,Data from Domino: nuts and bolts of REST calls), let's look at a few of the "fancy tricks", also known as "useful features" of Exciton Boost 4.6.1 (released today). With Exciton Boost, you can specify exactly which information you need. In the code sample post above, I use the following call:
 
GET /CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B?metadata=false HTTP/1.1
X-Items-List: StreetAddress+", "+City+", "+State=Address,Bdrms,Full=Bathrooms,Half=Half-Baths,Photo[Graphic 1]
 
The resulting JSON is shown below.  Note that we used formula language for the address, but I've shown that before.
Inline JPEG image
 
Fancy trick 1: - Grouping stuff together
If you look up at the original screen capture, you can see that the bathrooms are grouped together. That is because people logically expect full bathrooms and half bathrooms to go together. So, how can we make our JSON, and thus our eventual JavaScript object, reflect this natural grouping? Pretty simple, really. I just change the X-Items-List header to the following (changes shown in Blue).
 
X-Items-List: StreetAddress+", "+City+", "+State=Address,Bdrms,Full=Bathrooms/Full,Half=Bathrooms/Half,Photo[Graphic 1]
 
If successive items are defined with that =group/alias syntax, the result will be grouped in an object named for the group. Now, we get this JSON, and can act on the whole Bathrooms object in our app.
Inline JPEG image
 
Fancy trick 2: - Using rich text as a data source rather than rendering
If you look up at JSON right above the Fancy trick 1 headline, you can see that it is HTML encapsulated in JSON. That is handy if you want to display it, but not if you want to use it as a data object. You could by parsing the HTML, but you shouldn't have to. A similar example is in the columns of bullet points you can see in the top graphic under the title Features. What if you want those bullet points as separate data strings rather than HTML? Exciton Boost makes it easy to define the data structure you want rather forcing you to parse and interpret.
 
We change the reference from Photo[Graphic 1] to Photo[Graphic *] to mean all graphics in the rich text field named Photo. Then, we add in a series of chunk properties related to a graphic, ;$GraphicOffset;$GraphicFormat;%GraphicHeightPX;%GraphicWidthPX. These will all be grouped together. Finally, we add the {A} which makes this an array of objects, one per graphic. If there were no graphics, it would be an empty array.
 
X-Items-List: StreetAddress+", "+City+", "+State=Address,Bdrms,Full=Bathrooms/Full,Half=Bathrooms/Half,Photo[Graphic *;$GraphicOffset;$GraphicFormat;%GraphicHeightPX;%GraphicWidthPX]{A}
 
Since there is only one graphic in this rich text field, the result looks like this:
 
Inline JPEG image
 
We can iterate through the array to get to the objects and their values, but if we don't want to do that, we could simply change the {A} to {O}, and we would get an object with named sub-objects:
 
X-Items-List: StreetAddress+", "+City+", "+State=Address,Bdrms,Full=Bathrooms/Full,Half=Bathrooms/Half,Photo[Graphic *;$GraphicOffset;$GraphicFormat;%GraphicHeightPX;%GraphicWidthPX]{O}
 
Inline JPEG image
 
Now, we could use JSON.parse to get the JavaScript object and refer to Photo.Graphic_1.GraphicHeightPX to get the value 251. As a note, capitalization follows the item definitions, so if you prefer camel case, just make it:
 
X-Items-List: StreetAddress+", "+City+", "+State=address,bdrms,Full=bathrooms/full,Half=bathrooms/half,photo[graphic *;$graphicOffset;$graphicFormat;%graphicHeightPX;%graphicWidthPX]{O}
 
Inline JPEG image
 
Finally, it is worth noting that if only a single property is specified, we don't need objects. If we wanted to get all the bullet items under that Features column. we could use:
 
X-Items-List: StreetAddress+", "+City+", "+State=address,bdrms,Full=bathrooms/full,Half=bathrooms/half,col1[BulletList *;$UnformattedText]{A}=bullets
 
Inline JPEG image
 
=> Request a free Exciton Boost eval in January, and if you later purchase a license. we'll add in four hours of development assistance, a $700 value. <=
 
I will have a couple more Fancy Tricks tomorrow.
 

Tags:

Mon 11 Jan 2021, 10:37 AM
Continuing on the development challenge outlined in REST plus RPC: Do the demo backward and started in REST plus RPC: the right data in the right format, and no more, this post describes how we can build up the JavaScript necessary to invoke a batch of remote procedure calls with the JSON-RPC format. There are multiple ways to send HTTP requests and get back data in JavaScript. I find it easy to understand fetch, so that is what I am using, but it should be easy to translate to jQuery or Ajax or whatever. In this case, the devil is not in the details, but in the broad picture.
 
Note: I am not a JavaScript expert. Some of you will know more than I do, or have different ways to accomplish the task. If you'd like, comment and tell me how I could do differently or better.
 
Remote procedure calls with Exciton Boost use JSON-RPC. I did a Quick primer on JSON-RPC a few months ago if you are want to understand it better, but for our purposes, simply understand that we POST a message with a JSON body in a particular format to call procedure calls, and if an id is specified, we get a return value. There may be an array of methods called sequentially. For example, if I want to get the database title for the ReportIt.nsf database in our proposed demo, I would POST the following:
 
{
  "jsonrpc": "2.0",
  "method": "db.getTitle",
  "params": null,
  "id": 1
}
 
and would get back the JSON payload
 
{
    "jsonrpc""2.0",
    "result""Report It!",
    "id"1
}
 
Now, let's look at a sample JavaScript fetch way of POSTing that. Since I want to show a sequence of calls, I'll also get the default form.
 
const getTitle =  { jsonrpc: "2.0",  
                    method: "db.getTitle",
                    params: null,
                    id: 1
                  };
 
const getForm =   { jsonrpc: "2.0",  
                    method: "db.getDefaultForm",
                    params: null,
                    id: 2
                  };
 
 
function doIt() {
 
var data = [getTitle,getForm];
var stat = 0;
 
fetch('/ReportIt.nsf/api/boost/rpc', {
  method: 'POST', 
  mode: 'same-origin',
  cache: 'no-cache',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(data),
})
.then(response => {stat = response.status; return response.json();})
.then(data => {
if (stat == 200) { 
  document.getElementById("demo").innerHTML = '<h1>'+data[0].result+'</h1>Default form: '+data[1].result;
} else { 
  document.getElementById("demo").innerHTML = '<h1>Status: '+stat+'</h1>'+data[0].error.message;
}});
 
 
};
 
For the crude purposes of this demo, I put a button in HTML that sets the value of a div with id='demo'.
 
<button type="button" style="border-radius: 6px;" onClick="doIt();">Get the database title</button><br>
<p id="demo"></p>
 
When we put this all together on a demo Page element in our database, we get the following. We can build on this for our demo in the next post.
 
Inline GIF image
 
=> Request a free Exciton Boost eval in January, and if you later purchase a license. we'll add in four hours of development assistance, a $700 value. <=
 
 

Tags:

Wed 6 Jan 2021, 12:24 PM
Following up on the promise in yesterday's post, REST plus RPC: Do the demo backward, this post describes our first steps in building the nested tabbed table report demo.
 
My wife works in a preschool, and the first lesson for a successful day is: Rest first (well-rested and well-fed kids are happy kids). Most often, we find the same lesson is true when building apps which may require both the REST API and remote procedure calls: REST first (collect the necessary data, and only that data, in the most usable format).
 
Let's examine the data requirements by looking at a snippet of the table and marking up what data we'll need, some item values and other formulas.
 
Inline JPEG image
 
For those who have been following along, there are direct parallels  from my earlier post, Data from Domino: nuts and bolts of REST calls. That post is a good place to start when thinking about extracting data from any database using Exciton Boost's REST API. It is also a good post for showing many different ways to call the REST API from different languages. In this post, I'll stick to HTTP for clarity.
 
Task 1: Get list of accessible views
Returns a JSON array of objects, one for each view that is included, implicitly (all views) or explicitly (specified views), in the Exciton configuration db and marked as discoverable. Exciton is strict about data security, so views may be accessible but not discoverable. Views not included are inaccessible and will return a 404 error.
 
GET /ReportIt.nsf/api/boost/views HTTP/1.1
Accept: application/json
 
One of the accessible views is (AllOrdersByState) which has a UNID of 8F4CC3794598B864852586540074DE3F. We could access it using the UNID, but since using view names was added in Exciton Boost 4.6.0, we'll do that instead.
 
Task 2: Get view with columns & metadata
Returns a JSON array of objects, one for each document in the view. Each document includes a link to get the document from the documents collection as well as item values for each view column. Note that there are parameters to page through the view if desired.
 
GET /ReportIt.nsf/api/boost/views/(AllOrdersByState) HTTP/1.1
Accept: application/json
 
We get a JSON array of objects like that below. From this, we know we'll need State, City, and Qty, but won't need anything else.
 
Inline JPEG image
 
Task 3: Add selected items to view results 
Going back to the view, the request can include either additional or replacement items for the view columns using an item list via URL or HTTP header. This allows retrieval of any allowed items with the view results, including rendered rich text items.
 
GET /ReportIt.nsf/api/boost/views/(AllOrdersByState)?metadata=false HTTP/1.1
Accept: application/json
X-Items-List: State,City,LastName+", "+FirstName=Saleperson,Unit,Quantity,Color,DeliveryMethod,@Text(Price;"C,")=Price
 
And now we have the data we need in the format we need without the extra baggage. This call is the one REST call that is necessary, though it only returns 20 documents in the view at a time by default. That's a matter for another post as we process the data further
 
Inline JPEG image
 
 
=> Request a free Exciton Boost eval in January, and if you later purchase a license. we'll add in four hours of development assistance, a $700 value. <=
 
 
Continuing reading as I develop the solution. My follow up post, REST plus RPC: building the JavaScript for RPC calls, is now available.

Tags:

Tue 5 Jan 2021, 05:59 PM
I usually wait until I have successfully completed a demo before I post about the results, but that doesn't match well with we actually face in development. Decades ago, we mocked up the final results using Dan Bricklin's Demo or sketched a "UI Design" on a whiteboard. Now, we have more modern techniques, but it's all basically the same idea. Design the goal before trying to achieve. It's a bit risky for a demo, but I thought I'd step through the entire process with you, including any fits and starts. Hence, this series of posts may not be very polished, but I hope they inform how you could proceed. All of these will use Exciton Boost 4.6, and if you are far more motivated than I expect of anyone, you can request an Exciton Boost evaluation license now and I'll post the db and code snippets so you can follow along. Or even tell me how I could should be doing it. Developers seem to love to do that.
 
I should note that I am not overly fond of Agile development or most other methodologies, and tend to go with whatever others are using. For this process, I'm just going seat-of-my-pants. If a formal methodology is important to you, remember what the philosopher on the deserted island said when faced with a cache of canned goods: "First, assume a can opener."
 
Goal: nested tabbed table that displays and works well in both Notes client and web/mobile browser
I decided to start with something familiar to Notes developers, but recognizable in modern web design as well.. Tabbed reports/interfaces were popular in Notes before they were popular on the web, but are now lots of places. (I don't care if you don't like them. Mutter that quietly to yourself, and then come up with something else you'd rather see and suggest it to me. Perhaps it can be my next demo.)
 
Inline PNG image
 
I won't show the web version, as I haven't developed it yet, but imagine it looks and acts basically the same. Our Bricklin's Demo mockup, our rules.
 
Source data
For the iteration of this demo, I'll use a Notes data source/view, as those are familiar to most of you. It also gives me a chance to use the REST API portion of Exciton Boost. There are 312 orders in the database, and a total of 68 nested tables what with all the cities and states.
 
Inline JPEG image
 
Bonus round
For the second iteration, I'm going to use a public REST API which I don't control. Imagine the nested tabbed table as looking kind of like the first. This is a bigger data set, I think, though I admit I haven't even checked carefully. It comes from Open Brewery DB and gives access to a bunch of brew pubs and such in the United States. We'll probably try different parameters as we work, but a sample from Ohio is included below. I don't quite know what I'll do with it, but we can play and you can make suggestions.
 
Inline JPEG image
 
 
=> Request a free Exciton Boost eval in January, and if you later purchase a license. we'll add in four hours of development assistance, a $700 value. <=
 
 
Continuing reading as I develop the solution. My follow up post, REST plus RPC: the right data in the right format, and no more, is now available.
 

Tags:

Tue 5 Jan 2021, 03:24 PM
Inline JPEG image
 
Exciton Boost 4.6.0 was released on our website last week, and you can find the release notes online. We expect to release a few small point releases fairly regularly as we work with increasing numbers of customers and add requested features. Security is paramount, so there are likely to be slight tweaks to the Exciton Configuration template as we make sure we are providing the granular access people need without opening any vulnerabilities. 
 
Recent posts such as Data from Domino: nuts and bolts of REST calls have focused more on the REST API, as that has been the most pressing need identified by customers, but we hope to post some samples showing how the REST API can be complemented by and enhanced by use of the RPC (Remote Procedure Calls) API. Our most recent post on the RPC API is RPC - Empowering the server while retrieving to the client, but while interesting, most real-life uses have involved a combination of REST and RPC, so we'll get a couple of demos showing how they work together.
 
In the past, we have worked very hard to focus on product licenses, but as companies have trimmed developers, we have started doing more services in conjuction with our products when requested, We tend to refer to this as "development assistance" rather than consulting, but we are able to handle any level of work required by pulling in long-term colleagues and collaborators as needed or desired. As much or as little as you need. That's it, and no hard sell.
 
=> Request a free Exciton Boost eval in January, and if you later purchase a license. we'll add in four hours of development assistance, a $700 value. <=

Tags:

Tue 29 Dec 2020, 06:06 PM
Inline JPEG image
 
Exciton Boost 4.6.0 was released on our website today. You can find the release notes online.
 
This is a low key announcement because there probably aren't many reading blog posts about software this close to the New Year, but if you want to get a jump on the competition, you can request an evaluation license today and give it a try.
Wed 23 Dec 2020, 02:00 PM
Inline JPEG image
 
This is intended as a direct reference companion to my post earlier today, Getting data from Domino with Exciton Boost. Here, developers can see the exact requests made with parameters, HTTP headers, etc. in case anything in the video went by too quickly.
 
There are the nine tasks, but in some cases, I show multiple separate requests, as I used more than one in the video to explain different elements. For each request, I show the HTTP method and then one of different ways (e.g., JavaScript's fetch) to show how this code could be called. The second part is merely to get across the wide range of ways you could call Exciton Boost using different technologies. Finally, I include the video again in case you want to see these requests in action and see the results they generate.
 
Intro: Get core services
Returns a JSON array of objects, one for each view that is included, implicitly (all views) or explicitly (specified views), in the Exciton configuration db and marked as discoverable. Exciton is strict about data security, so views may be accessible but not discoverable. Views not included are inaccessible and will return a 404 error.
 
Intro) HTTP

GET /CurbAppeal.nsf/api/boost HTTP/1.1

Intro) cURL

curl --location --request GET '
https://geniisupport.com/CurbAppeal.nsf/api/boost'
 
 
Task 1: Get list of accessible views
Returns a JSON array of objects, one for each view that is included, implicitly (all views) or explicitly (specified views), in the Exciton configuration db and marked as discoverable. Exciton is strict about data security, so views may be accessible but not discoverable. Views not included are inaccessible and will return a 404 error.
 
1) HTTP
 
GET /CurbAppeal.nsf/api/boost/views HTTP/1.1
Accept: application/json
 
1) JavaScript - jQuery
 
var settings = {
  "url": "
https://geniisupport.com/CurbAppeal.nsf/api/boost/views",
  "method": "GET",
  "timeout": 0,
  "headers": {
    "Accept": "application/json"
  },
};

$.ajax(settings).done(function (response) {
  console.log(response);
});
 
 
Task 2: Get view with columns & metadata
Returns a JSON array of objects, one for each document in the view. Each document includes a link to get the document from the documents collection as well as item values for each view column. Note that there are parameters to page through the view if desired.
 
2) HTTP
 
GET /CurbAppeal.nsf/api/boost/views/76CA31CBCB19C70A8525694F0045C657 HTTP/1.1

2) Python - Request
 
import requests

payload={}
headers = {}

response = requests.request("GET", url, headers=headers, data=payload)

print(response.text)

 
Task 3: Get filtered view
Returns a JSON array of objects, a subset of the full view filtered by a key match with the first view column. There are alternative ways to filter the view, but this is easiest.
 
3) HTTP
 
GET /CurbAppeal.nsf/api/boost/views/76CA31CBCB19C70A8525694F0045C657 HTTP/1.1
X-Key-Value: Chagrin Falls, OH

3) JavaScript - Fetch
 
var myHeaders = new Headers();
myHeaders.append("X-Key-Value", "Beachwood, OH");

var requestOptions = {
  method: 'GET',
  headers: myHeaders,
  redirect: 'follow'
};

fetch("
https://geniisupport.com/CurbAppeal.nsf/api/boost/views/76CA31CBCB19C70A8525694F0045C657", requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));

 
Task 4: Get all items from the document
Returns a JSON object containing each item found on the document, or at least all allowed. Items may be explicitly allowed or disallowed in the configuration database, or all may be allowed by default. Some items such as time/date, author and reader fields, and rich text items will be represented by subobjects. Rich text fields are rendered to high fidelity roundtrippable HTML.
 
4) HTTP
 
GET /CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B HTTP/1.1
 
4) Node JS - Request
 
var request = require('request');
var options = {
  'method': 'GET',
  'url': '
https://geniisupport.com/CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B',
  'headers': {
  }
};
request(options, function (error, response) {
  if (error) throw new Error(error);
  console.log(response.body);
});

 
Task 5: Get only selected items
Using an item list via URL or HTTP header, the request determines which items to returns in the JSON object. In addition to actual items, the request may use Notes formula language to create additional items or may use filtering to get subsets of rich text items.
 
5a) HTTP
 
GET /CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B?metadata=false&items=StreetAddress,Bdrms,Full=Bathrooms,Half=Half_Baths,Photo HTTP/1.1
 
5a) JavaScript - XHR

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function() {
  if(this.readyState === 4) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "
https://geniisupport.com/CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B?metadata=false&items=StreetAddress,Bdrms,Full=Bathrooms,Half=Half_Baths,Photo");

xhr.send();

 
5b) HTTP
 
GET /CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B?metadata=false HTTP/1.1
X-Items-List: StreetAddress+", "+City+", "+State=Address,Bdrms,Full=Bathrooms,Half=Half-Baths,Photo[Graphic 1]
 
5b) JavaScript - XHR
 
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function() {
  if(this.readyState === 4) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "
https://geniisupport.com/CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B?metadata=false");
xhr.setRequestHeader("X-Items-List", "StreetAddress+\", \"+City+\", \"+State=Address,Bdrms,Full=Bathrooms,Half=Half-Baths,Photo[Graphic 1]");

xhr.send();

 
Task 6: Add selected items to view results
Going back to the view, the request can include either additional or replacement items for the view columns using an item list via URL or HTTP header. This allows retrieval of any allowed items with the view results, including rendered rich text items.
 
6) HTTP
 
GET /CurbAppeal.nsf/api/boost/views/76CA31CBCB19C70A8525694F0045C657?metadata=false&additems=Col1,Col2 HTTP/1.1
X-Key-Value: Beachwood, OH
 
6) Java - Unirest
 
Unirest.setTimeouts(0, 0);
HttpResponse<String> response = Unirest.get("
https://geniisupport.com/CurbAppeal.nsf/api/boost/views/76CA31CBCB19C70A8525694F0045C657?metadata=false&additems=Col1,Col2")
  .header("X-Key-Value", "Beachwood, OH")
  .asString();

 
Task 7: Get RTItems (as a list, as individual rtitems in JSON, as rendered HTML pages, or rendered HTML fragments)
Explores some of the different ways to retrieve rich text.
 
7a) HTTP
 
GET /CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B/rtitems HTTP/1.1
 
7a) PowerShell - RestMethod
 
$response = Invoke-RestMethod 'https://geniisupport.com/CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B/rtitems' -Method 'GET' -Headers $headers
$response | ConvertTo-Json
 
7b) HTTP
 
GET /CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B/rtitems/Col1 HTTP/1.1
 
7b) PowerShell - RestMethod
 
$response = Invoke-RestMethod 'https://geniisupport.com/CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B/rtitems/Col1' -Method 'GET' -Headers $headers
$response | ConvertTo-Json
 
7c) HTTP
 
GET /CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B/rtitems/Col1 HTTP/1.1
Accept: text/html
 
7c) PowerShell - RestMethod
 
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Accept", "text/html")

$response = Invoke-RestMethod '
https://geniisupport.com/CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B/rtitems/Col1' -Method 'GET' -Headers $headers
$response | ConvertTo-Json
 
7d) HTTP
 
GET /CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B/rtitems/Col1?fragment=true HTTP/1.1
Accept: text/html
 
7d) PowerShell - RestMethod
 
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Accept", "text/html")

$response = Invoke-RestMethod '
https://geniisupport.com/CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B/rtitems/Col1?fragment=true' -Method 'GET' -Headers $headers
$response | ConvertTo-Json

 
Task 8: Get image from rich text (either as an <img> link or as components in a JSON object, either allowing binary retrieval of the image from the server)
Depending on what exactly is needed, different ways to retrieve an image as a link back to the Domino db.
 
8a) HTTP [Image link as HTML fragment]
 
GET /CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B/rtitems/Photo/chunks/Graphic 1?fragment=true HTTP/1.1
Accept: text/html
 
8a) Python - http.client
 
import http.client

conn = http.client.HTTPSConnection("geniisupport.com")
payload = ''
headers = {
  'Accept': 'text/html'
}
conn.request("GET", "/CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B/rtitems/Photo/chunks/Graphic 1?fragment=true", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
 
8b) HTTP [Image components as JSON]
 
GET /CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B/rtitems/Photo/chunks/Graphic 1?metadata=false HTTP/1.1
X-Items-List: Photo[$GraphicOffset]=Offset,Photo[$GraphicFormat]=Fmt,Photo[%GraphicHeightPX]=height,Photo[%GraphicWidthPX]=width
 
8b) Python - http.client
 
import http.client

conn = http.client.HTTPSConnection("geniisupport.com")
payload = ''
headers = {
  'X-Items-List': 'Photo[$GraphicOffset]=Offset,Photo[$GraphicFormat]=Fmt,Photo[%GraphicHeightPX]=height,Photo[%GraphicWidthPX]=width'
}
conn.request("GET", "/CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B/rtitems/Photo/chunks/Graphic 1?metadata=false", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))

 
Task 9: Get image data URI
Retrieves an image as an <img> link with the data URI included, so that the entire image is local. The dataimgs parameter shown can be used for any rich text or document retrieval so that the rendered HTML has the images locally available without any requirement for the Domino image to be accessible.
 
9) HTTP
 
GET /CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B/rtitems/Photo/chunks/Graphic 1?fragment=true&dataimgs=max HTTP/1.1
Accept: text/html
 
9) Shell - wget
 
wget --no-check-certificate --quiet \
  --method GET \
  --timeout=0 \
  --header 'Accept: text/html' \
   '
https://geniisupport.com/CurbAppeal.nsf/api/boost/documents/524C08BF648BE77A85257B8600798F5B/rtitems/Photo/chunks/Graphic 1?fragment=true&dataimgs=max'

 
 
Wed 23 Dec 2020, 11:23 AM
Inline PNG image
 
In my last post, Out of Notes revisited with Exciton, I described a current customer's requirements for getting data from Domino with Exciton Boost's REST API, and promised I'd make a couple of videos showing how to accomplish these specific tasks using our Curb Appeal sample db. This first video takes you through the whole process using POSTMAN, a free development and testing tool popular with mobile/web developers who need to send requests and record responses. In it, I will show the URL endpoints, URL parameters, and HTTP headers used to accomplish each task.
 
Here are the nine tasks, restated slightly to clarify, and with a brief description of what is being demonstrated. (If you would like, you can request an Exciton Boost evaluation license and follow along the steps yourself. I think could provide a Postman collection to work with.) UpdateCheck out the companion blog post with exact requests and sample code.
 
Task 1: Get list of accessible views
Returns a JSON array of objects, one for each view that is included, implicitly (all views) or explicitly (specified views), in the Exciton configuration db and marked as discoverable. Exciton is strict about data security, so views may be accessible but not discoverable. Views not included are inaccesible and will return a 404 error.
 
Task 2: Get view with columns & metadata
Returns a JSON array of objects, one for each document in the view. Each document includes a link to get the document from the documents collection as well as item values for each view column. Note that there are parameters to page through the view if desired.
 
Task 3: Get filtered view
Returns a JSON array of objects, a subset of the full view filtered by a key match with the first view column. There are alternative ways to filter the view, but this is easiest.
 
Task 4: Get all items from the document
Returns a JSON object containing each item found on the document, or at least all allowed. Items may be explicitly allowed or disallowed in the configuration database, or all may be allowed by default. Some items such as time/date, author and reader fields, and rich text items will be represented by subobjects. Rich text fields are rendered to high fidelity roundtrippable HTML.
 
Task 5: Get only selected items
Using an item list via URL or HTTP header, the request determines which items to returns in the JSON object. In addition to actual items, the request may use Notes formula language to create additional items or may use filtering to get subsets of rich text items.
 
Task 6: Add selected items to view results
Going back to the view, the request can include either additional or replacement items for the view columns using an item list via URL or HTTP header. This allows retrieval of any allowed items with the view results, including rendered rich text items.
 
Task 7: Get RTItems (as a list, as individual rtitems in JSON, as rendered HTML pages, or rendered HTML fragments)
Explores some of the different ways to retrieve rich text.
 
Task 8: Get image from rich text (either as an <img> link or as components in a JSON object, either allowing binary retrieval of the image from the server)
Depending on what exactly is needed, different ways to retrieve an image as a link back to the Domino db.
 
Task 9: Get image data URI
Retrieves an image as an <img> link with the data URI included, so that the entire image is local. The dataimgs parameter shown can be used for any rich text or document retrieval so that the rendered HTML has the images locally available without any requirement for the Domino image to be accessible.
 
Note: Accurate closed captions will be provided shortly.
 
 

Tags:

Thu 17 Dec 2020, 11:10 AM
GET request inside POSTMAN
 
Back in 2013, I created a ten part series of blog posts and videos called Out of Notes showing how the Curb Appeal (real estate listings) database with its structured data, computed images, and so forth could be taken from Notes to various formats. Most of those posts are still valid, (though the few with EPUB turned out to be less compelling to many customers). You can still use the Midas LSX to extract data that way, but working with a new Exciton Boost customer made me think about how many challenges they face with a REST API are similar to those I posed with this database. (See bottom of this post for that first video introducing that database and its challenges.)
 
Specific challenges for this Exciton Boost customer include the following (JSON return values unless otherwise indicated):
 
1) (db) GET a list of views configured to be discoverable by the Exciton Configuration database.
2) (view) GET the contents of a specific view from the list using HATEOAS principle. Returned object includes document metadata and column values.
3) (view) GET a filtered set of documents using a primary key. Returned object includes document metadata and column values.
4) (doc) GET all fields from one document.  Returned object includes document metadata and all items, or all allowed items if Exciton Configuration restricts which are accessible. Rich text fields rendered to HTML.
5) (doc) GET subset of items from a document, including mapping of item names and suppression of metadata. Rich text fields rendered to HTML.
6) (view) GET a filtered set of documents using a primary key. Returned object includes subset of items from a document, including mapping of item names and suppression of metadata. Rich text fields rendered to HTML.
7) (rtfield) GET single rich text fields rendered to HTML.
8) (image) GET single image from rich text field as binary
9) (image) GET single image from rich text field as data URI
 
There are lots more things we could do, but these show a number of features of the Exciton Boost REST API. I'll put together a video showing these steps using POSTMAN, then a second video showing how we can take advantage of these in JavaScript. But first, take a quick look at the database from that original 2013 challenge video, and imagine the databases in your domain which include various features like these.
 
Note: Accurate closed captions have been provided, and if English is not your first language, you might want to turn on the auto-translate.
 
  

Tags:

Mon 7 Dec 2020, 04:47 PM
Inline JPEG image
 
 
On Friday, Heiko Voight wrote a post called domino-db, proton and Date/Time values. It makes interesting reading, but the gist of it is that domino-db can be mighty persnickity about dates, and not very respectful of time zones. As an example, Heiko pointed out the two dates below. The invalid one was created using a standard JavaScript function that happens to return milliseconds (3 decimal places) rather than hundredths (two decimal places). Rather than either ignore the extra precision or round it off (worthy of debate which is better), Proton simply chokes on it.
 
'2013-03-01T14:09:01.009Z' // Invalid (too precise)
'2013-03-01T14:09:01.01Z' // Valid
 
 
As it typical with domino-db and Proton, this doesn't just return that it is invalid, it pukes all over the screen. (See above.) Even worse in its own way, the time zone information included in the date was ignored, thus interpreting every date as if it were GMT (nice for Gab and Tim, but not many of the rest of us).
 
Out of curiosity, I checked to see what Exciton Boost 4.5.3 did with these dates. We use a date conversion function that is a bit more flexible. It works properly with any of the following:
 
2013-03-01T14:09:01.009Z
2013-03-01T14:09:01.01Z
2013-03-01T14:09:01.0Z
2013-03-01T14:09:01Z
2013-03T14:09:01.009Z
20130301T14:09:01.009Z
2013-03-01T140901.009Z
20130301T140901.009Z
2013-03-01T14:09:01.009-0400
2013-03-01T14:09:01.009-04
2013-03-01T14:09:01.009-0430
2013-03-01
20130301
 
and quite a few other variations, as it happens, including variants such as:
 
Mon,  7 Dec 2020 15:06:31 -0500
Today
Now
@Adjust(@Today; -1; 0; 0; 0; 0; 0);
 
The key concept is that we should be liberal in what we receive and conservative is what we send. Plus, we shouldn't puke all over. If we do manage to give a date format that is not accepted, such as
 
Mom's birthday
 
we are really okay with a simple invalid request mentioning that the date could not be interpreted. (No, mom, we aren't adding that in 4.5.4.)

Tags:

Thu 3 Dec 2020, 11:49 AM
 
Inline PNG image
 
Two related topics which come up a lot with customers interested in our Exciton Boost  product are authentication and authorization (aka access). The two terms are often used somewhat interchangeably, but they are quite distinct.
 
Here's an overview of some differences between authentication and authorization. This table is adapted from an excellent discussion of the topic on Auth0's website at Authentication and Authorization.
 
Authentication (Domino and/or IAM service)
Authorization (Domino and Exciton Boost)
Determines whether users are who they claim to be
Determines what users can and cannot access
Uses passwords, security questions, 2FA, etc. to validate the user's credentials
Verifies access using access control lists and other policies and rules
Usually done before authorization, or sometimes after a very thin layer authorization (if nobody has access to a server, there's no need to authenticate before determining that).
Usually done after successful authentication. If anonymous access is allowed, authorization is based on what is considered accessible to anyone, often very limited.
Domino session authentication usually relies on a session token in a cookie while IAM uses an ID token plus secret.
Either a session token is passed via HTTP (as cookie) or info is transmitted through an Access Token.
Domino session authentication uses its own NAB or LDAP or whatever, while IAM is governed by an OpenID Connect (OIDC) protocol. (I think. I am not great with these admin details.)
Authorization relies on Domino security first, via a cascading set of factors such as maximum internet access and ACLs. Access using Exciton adds an additional layer of more finely tuned access based on the Exciton Configuration database.
 
Basically, the first step is to prove who you are to Domino. Then, once Domino is convinced you are you, both Domino and Exciton have to decide whether you have sufficient access (authorization) to do what you want to do. Finally, you do it. (All this sounds complicated, but it happens in a blink of the eye.)
 
Domino's ACL is well known. Exciton's access is defined by a configuration database which defines which databases, forms, and views are accessible, and whether they can be used with the REST API or the RPC API. Specific fields on those forms can be defined as accessible or inaccessible (include or exclude field lists). Thus, while Domino Access Services will let you set almost any fields with almost any form, or no form, Exciton Boost makes sure you are only able to create, read, update, and delete fields and documents that you are supposed to.

Tags:

Fri 30 Oct 2020, 12:50 PM
Inline JPEG image
 
 
Slides are here --> DEV103 slides <-- though I will likely put them up on Slideshare later as well.
 
For the demos, I put most of the output in slides so you could see it. The source code and make file for the DspLnks64 DSAPI are below, though you may need to adjust the makefile to match the compilers you have set up, or skip it and make the project in an IDE. (Recommended compilers kept switching between versions.)
dsplnks64.dll (version built and used in  demo)
 
The Node.js demo I showed with the invoices is described in full at Down to Business - PDF Invoices from Notes data in Node.
 
Thanks to everybody who attended. Anybody who has questions should feel free to ask, as I am always up for brainstorming about extensions.
 
I will provide a link to the video when it is available.
 
Update: for those with a login, the video is now available at https://collabsphere.org/ug/sessions.nsf/live.html (Look under DevOps for DEV103). My understanding is that they will eventually be put on Youtube.