The difference between Label and Label

Looking for a control to do some specific thing, I landed upon label. Then I started looking for alternatives to do the very specific thing I was looking for and so I found … label. Not the same though.

PRIM_LABL (Label) and PRIM_SLAB (Label) are obviously different. There are a few properties and I believe methods that are missing in one but the documentation does not explain a use case for one or the other, nor why one should choose one (or the other).

I believe the Lansa documentation is severely lacking.

Keyed collections and getting the key

I fear this will be my “Carthago delenda est“: Furthermore, I believe the Lansa documentation is severely lacking.

Case in point, today, using Visual Lansa 14.1 and the online and up-to-date documentation, I wanted to use a keyed collection. I wanted to use this in a way where I can later loop through the collection getting keys and values.

Now, had I started on 7.60.1 FOR Parameters I might have guessed this earlier, but I didn’t. I started on Keyed Collection (PRIM_KCOL). Silly me.

It does tell me how to define a keys collection but in a roundabout way. So the definition goes like this

#PRIM_COL

Like:

Define_Com Class(#PRIM_KCOL<#PRIM_VAR #CHAR512>) Name(#COL1)

which defines a collection #COL1 with keys of type #CHAR512 and values of the variant type, #PRIM_VAR. You have to use repository fields as the key type for some reason, but there is no such requirement for the key value.

Now, #COL1.ItemCount can tell me how many pairs of keys and values are in the collection but there is no way to use this to iterate through the collection.

Since I had not started on the FOR page I tried this:

For Each(#COL1_VAL) In(#COL1)
#COL1_KEY := #COL1.KeyOf<#COL1_VAL>
...
Endfor

which actually works. I did however suspect that it could have some form of performance issues and also would only work consistently if all values were unique.

But wild and semi-random searching of the documentation lead me to the poorly demonstrated Key parameter for the For loop:

For Each(#COL1_VAL) in(#COL1) Key(#COL1_KEY)

This works.

I have also tried to find the documentation on the different assignment operators. I know what +=, -=, *= and /= does, but apparently I don’t know what := does since sometimes I need to use <=:

#VAR_OBJ <= #COL1<#COL1_KEY>
...
#COL1_VAL := #COL1<#COL1_KEY>.String
...
#COL1_VAL := #VAR_OBJ.String

I am guessing <= passes a reference while := assigns a value.

Furthermore, I believe the Lansa documentation is severely lacking.

ModalResult

I will swear that the documentation does not contain any information about what happens when you assign a value to the ModalResult property of a form. In fact, ModalResult is a property of push buttons (PRIM_PHBN), but when a button is pushed, the ModalResult is supposed to be migrated to the form as well.

This became apparent when I had a form with a reusable that tried to catch invalid input when the user clicked on a button. Unfortunately, the reusable sent a signal to an event which then set the ModalResult property, closing the form no matter what I tried to do.

It turns out that assigning a value to ModalResult closes the modal form immediately.

Evtroutine Handling(ÆPHBN_1.Click)
  If Cond(...)
    ...
  Else
    #COM_OWNER.ModalResult := OK
  Endif
Endroutine

 

AsInteger and AsNumber

There’s a special place somewhere for whoever thought of this. The intrinsic functions AsInteger and AsNumber work in very different ways and I believe they are so badly named that this “feature” is a bug.

Anyway, that is how it is in RDMLX.

So.

Which of these functions can be used to convert the content of a string to a numeric value? Like the string “53”?

Yes, it is a naughty example, because if you run both of these on Windows you get the same result, 53.

#STR := "53"
#NUM := #STR.AsNumber /* returns 53 */
#INT := #STR.AsInteger /* returns 53 */

But that is a trick. On IBM i I would have needed to use “242” to get the same value from both functions because

AsInteger returns the character code of the first character in the string

True, that will be an integer, but the name of the function is terrible.

The reason the code above gives the same result is that the character code for “5” in ASCII (Windows) is 53, while the character code for “2” in EBCDIC (IBM i) is 242.

It does not matter how long the string is, AsInteger will only look at the first character.

But really, it should have been called something with CharCode.

Having said that:

As long as I don’t care about character codes, it is AsNumber I need to use.

V.14.1 still crashes on invalid XSLT

The bug I wrote about some time ago with invalid XSLT still exists in v.14.1

That time it was missing the <tbody> in a <table>. This time it was an <input> inside a <tr>. Obviously wrong, I know, but apparently whichever version it was written in back in 2010/2011 allowed it and today, when I wanted to do an edit, the editor crashed.

The <input> was moved to the <td> within the <tr>.

And this is why some people hate Javascript

Working on our VLF application, I ran into a problem for our Microsoft Edge users: If the command handler window was expanded (the draggable bar pulled upwards) beyond a certain point, only the filter window contracted. Not the instance list and thereby effectively nor the command handler window.

The problem comes from resizing of the table cells, the function VF_SY001_PRIVATE_SizeInstanceList_Height in VF_XXNNN.js.

So I chose to overwrite the function in an additional javascript file, if the user is in Edge:

window.setTimeout(function() {
if (window.navigator.userAgent.indexOf("Edge") > -1) {
var func = VF_SY001_PRIVATE_SizeInstanceList_Height;
VF_SY001_PRIVATE_SizeInstanceList_Height = function(sHeight) {
func(sHeight);
let nHeight = parseInt(sHeight);
nHeight = nHeight + 24;
nHeight = "" + nHeight + "px";
document.getElementById("VF_UM011_Container").style.height = nHeight;
};
}
}, 1000);

I set the func variable to the original function, overwrite the function to call the original plus some extra code. Now I just need it tested by others.

Lansa Editor still rewrites my code

A follow-up to the other post from last year, I have now experienced this in a new and disturbing way.

I realize that this code is not pretty but it was just a quick job that I would fix later. In this case, I added some javascript that would append an HTML element with an attribute. The javascript used double-pings (“) and the attribute would then use pings (‘):

2017-02-14_090415

Unfortunately, when checking in the changes the Lansa Editor changed the pings to double-pings, rendering my code buggy.

Switching technology services

I have now had the help from Lansa support for a very specific problem. We have a number of solutions, some of which use the XHTML technology service, some the PPC_XHTML technology service.

None of these solutions use more than one technology service.

PPC_XHTML is no longer supported by Lansa so when we upgraded to v.14 this presented a problem. Support found a way to make it work and we continued, making only minor adjustments to the code.

Now we have been upgraded to v.14.1 and something broke in the process.

It can still be made to work but we can only have either XHTML or PPC_XHTML working at the same time. Due to a deadline we will live with that for a short time and then we will start the migration of the PPC_XHTML solutions.

The work-around is this:

Getting XHTML to work: Use Tools -> Import to import the v.14.1. weblets. Done.

Getting PPC_XHTML to work: Use Tools -> Import to import the old v.12 weblets. Check out the specific design weblets made for our solution. Check out the WAM that we need to work with. Done.

So, not bad but not optimal either. That is of course the problem using a technology that is no longer supported.

An example of the JSM HashService

The documentation for some of the functionality in Lansa is sparse, at best. The HashService in Lansa Integrator is one such area (documentation currently here), so here is an example I have that works:

It is important to read up on cryptography first and a short and good guide can be found here.

Define Field(#JSMXHDLE1) Type(*CHAR) Length(4)
Define Field(#JSMXSTS) Type(*CHAR) Length(20)
Define Field(#JSMXMSG) Type(*CHAR) Length(512)
Define Field(#JSMXCMD) Type(*CHAR) Length(512)
* WVALUE is the value to be hashed
Define Field(#WVALUE) Type(*CHAR) Length(255)
* WHASH is the hash returned
Define Field(#WHASH) Type(*CHAR) Length(64)
* WSALT is the salt for the hashing
Define Field(#WSALT) Type(*CHAR) Length(64)
* WINPUT is the value sent to the hashing function = WVALUE + WSALT
Define Field(#WINPUT) Type(*CHAR) Length(319)
* Open service
Use Builtin(JSMX_OPEN) To_Get(#JSMXSTS #JSMXMSG #JSMXHDLE1)
Execute Subroutine(CHECK) With_Parms(#JSMXSTS #JSMXMSG)
* Load service
#JSMXCMD := 'SERVICE_LOAD SERVICE(HashService) TRACE(*YES)'
Use Builtin(JSMX_COMMAND) With_Args(#JSMXHDLE1 #JSMXCMD) To_Get(#JSMXSTS #JSMXMSG)
Execute Subroutine(CHECK) With_Parms(#JSMXSTS #JSMXMSG)
* Set
* * WVALUE
* * WSALT
* See https://crackstation.net/hashing-security.htm
* WSALT should be unique for each WVALUE
* WSALT should be at least as long as the result value
* - for SHA-256 that is 256 bits
#WINPUT := #WVALUE + #WSALT
#JSMXCMD := 'HASH FIELD(WINPUT) DIGEST(SHA256) SERVICE_EXCHANGE(*FIELD)'
Use Builtin(JSMX_COMMAND) With_Args(#JSMXHDLE1 #JSMXCMD) To_Get(#JSMXSTS #JSMXMSG)
Execute Subroutine(CHECK) With_Parms(#JSMXSTS #JSMXMSG)
#WHASH := #JSMXMSG
* Unload service
Use Builtin(JSMX_COMMAND) With_Args(#JSMXHDLE1 'SERVICE_UNLOAD') To_Get(#JSMXSTS #JSMXMSG)
Execute Subroutine(CHECK) With_Parms(#JSMXSTS #JSMXMSG)
* Close service
Use Builtin(JSMX_CLOSE) With_Args(#JSMXHDLE1) To_Get(#JSMXSTS #JSMXMSG)
Execute Subroutine(CHECK) With_Parms(#JSMXSTS #JSMXMSG)
* Check routine
Subroutine Name(CHECK) Parms((#JSMXSTS *RECEIVED) (#JSMXMSG *RECEIVED))
If Cond('#JSMXSTS *NE OK')
Use Builtin(JSMX_CLOSE) With_Args(#JSMXHDLE1) To_Get(#JSMXSTS #JSMXMSG)
Menu Msgtxt('Java service error has occured')
Endif
Endroutine

In this example I have chosen SHA256 which I believe is OK. Avoid MD2 and MD5 if possible, as collisions has already been found, and as SHA1 has a theoretically attack described I would avoid that one as well, even if it is default for the HashService. SHA384 appears to also be supported and could be used.

The HMAC algorithms would be even better but there I ran into a problem. I am running on Lansa v. 14, I think that the documentation is for v. 14 SP1, and there is no HMAC parameter in the HashService on my machine. Also in the documentation, there are the CONVERT and CREATE commands, the last of which should give me a good random unique salt, but the are not present on my machine.

Anyway, the code above works.

Old application and new(-ish) browser

Back in a web application built using Visual Lansa v. 12.5 and using the technology service PPC_XHTML, I got the task of getting it to work on a new unit. It was – unsurprisingly – a PDA application and the new “PDA” would be a modern, fast and capable android unit.

The application was built for an Internet Explorer for the handheld units and on an Android it is logical to look at Chrome.

To my surprise very little had to be done to get it to look nice. CSS media queries and a tiny bit at that and I was practically done.

However, one of the WAMs had an auto-submit when the user made a change to the selection in a radio and in Chrome 54 for Android, that resulted in a request with the old value being sent. The radio button was updated but as the request contained the old value, the response was “wrong”. The problem was that the request body was being constructed, on the click event, before the radio button change had taken effect.

The fix was rather simple – I inserted a bit of javascript using jQuery:

$("input#RADIOBUTTON1").mousedown(function() {
   $("input[name=RADIOGROUP]").val($(this).val());
});
$("input#RADIOBUTTON2").mousedown(function() {
   $("input[name=RADIOGROUP]").val($(this).val());
});

This way, as the mousedown event fires before the click event (remember, a click event is combination of a mousedown and a mouseup on the same element), the radio button was updated before the request body was constructed.

Unfortunately the final unit turns out to run a browser built on Chromium 52. And there is a bit difference for the web application.

I have not solved it yet – we might be able to get the units with a newer browser – but I needed to test it on my own machine. And getting an old Chrome/Chromium does take some steps.

First of all, you can’t really get an old Chrome. But Chromium should be good enough.

I found the guide on the Chromium website but I will repeat it here, just it case:

And then I could confirm that the issue exists in Chromium 52. Now I could just find the cause in the change logs.

Update: I think I managed to “fix” my problem. The browser was built using the system component WebView on Android. WebView, which uses Chromium and will be using Chrome on Android 7, can be updated using the Google Play Store and after doing that, it now runs on Chromium 55 and our web application works as intended.