In RDMLX, easy, just
#LEN := #STR.CurChars
But in RDML it’s not so easy and for some reason there’s not even a buit-in function to return the length of a string.
So I made this:
Define Field(#W_C256) Type(*CHAR) Length(256)
Define Field(#W_C256_B) Type(*CHAR) Length(256)
Define Field(#W_C1) Type(*CHAR) Length(1)
Define Field(#W_D3_0) Type(*DEC) Length(3) Decimals(0)
Subroutine Name(LENGTH) Parms((#W_C256 *RECEIVED) (#W_D3_0 *RETURNED))
Use Builtin(RIGHT) With_Args(#W_C256) To_Get(#W_C256_B)
Substring Field(#W_C256_B 256 1) Into_Field(#W_C1)
Use Builtin(REVERSE) With_Args(#W_C256) To_Get(#W_C256_B)
Use Builtin(SCANSTRING) With_Args(#W_C256_B #W_C1) To_Get(#W_D3_0)
Change Field(#W_D3_0) To('(256 + 1) - #W_D3_0')
which I then include when necessary.
We are still running on v. 12 and 14.1 (two separate solutions), while waiting for help to upgrade the 12 to 14.2. The upgrade has so far taken almost a month.
So I had to dive back into WAM’s in 12 and added a <svg> element.
Which is then promptly messed up by Lansa, moving the SVG contents out of the element and making the <svg> element empty. Just like I experienced with 14.1.
I made this error and spent a long time trying to spot it:
Select_Sql Fields((#ANTAL 'SUM(ANTAL')) From_Files(TRANS) Where(...)
That is how I learned that the optional SQL source for a field is not validated in the editor or during compilation. Adding the missing end-parenthesis fixed my error:
Select_Sql Fields((#ANTAL 'SUM(ANTAL)')) From_Files(TRANS) Where(...)
Working with CONDCHECK I got confused. The condition check works to mark a field that is filled out incorrectly, but the condition is to be read as “these conditions should be satisfied, if not…”.
Which makes sense; you write the condition that you want satisfied. If it isn’t you get the message.
My problem was that I thought of it in the context of if … then; if this condition is satisfied, I should get the message. Which I now realise was wrong.
I needed this, so here it is for posterity:
In the list BUTLST, I wanted to select the value from the field WCHAR36, on the entry where the value from the field BUTNR matched the mapped field IZBUTNR.
So, in sequence, I wanted
the list BUTLST
the value from the field WCHAR36
on the entry where the value from the field BUTNR
... lxml:list-entries/lxml:entry/lxml:column[@name='BUTNR'][text() ... ]
matched the mapped field IZBUTNR
... = key('field-value', 'IZBUTNR') ...
Completed that is
/lxml:data/lxml:lists/lxml:list[@name='BUTLST']/lxml:list-entries/lxml:entry/lxml:column[@name='BUTNR'][text() = key('field-value', 'IZBUTNR')]/../lxml:column[@name='WCHAR36']
Def_List Name(#BUTLST) Fields(#BUTNR #BUNAVN #WCHAR36) Type(*WORKING) Entrys(*MAX)
Web_Map For(*BOTH) Fields(#IZBUTNR #BUTLST )
I keep forgetting this, cause I do development in other languages and frameworks as well, and nothing in the LANSA editor stops me. But WAM command handlers must not have a name of more than 8 characters.
Or rather, it can and it will work, but then when you try to set it up in the VLF, you, again without warning, enter the more-than-8 character name and lo and behold, you end up with errors on your site.
Instead, a command handler named, for example, CH_FAKKOP, should be referenced in the VLF by the first 8 characters, CH_FAKKO, even though the WAM component is 9 characters.
Edit: This also applies to the WAM name in XSLT, like
<xsl:with-param name="on_change_wrname" select="'UHandleEvent'" />
<xsl:with-param name="on_change_wamname" select="'CH_FAKKO'" />
This is one of those issues that arise from me coming from a different background than what I imagine a typical Lansa developer, indeed a typical i series developer, come from. It is a useful reminder what decimals actually mean.
For example, I have a repository field that is defined like this:
Define Field(#JSN) Type(*SIGNED) Length(4) Decimals(2)
That means, a signed decimal value with 2 digits before the decimal point and 2 digits after the decimal point. In a function, I calculate the value and exchange it back to application calling. In that application, I (unfortunately) have an override, changing the number of decimals.
Override Field(#JSN) Decimals(1)
This was probably done to format the display of the value but where I imagined the value would be passed in a lower level format and then parsed in relation to the definition, this is not what happens.
Instead, the value is still the same 4 digits, but one of those that was after the decimal point is now before the decimal point. The value has been multiplied by 10^1; a value of 0.21 is now 2.1.
Because the override only moved the decimal point.
As someone mentioned a while back on the forum, getting a newline, or indeed any character from a character code, is difficult to find. But it is easy, once you know how:
returns a carriage return in ANSI. I’d probably prefer
(13).AsUnicodeString + (10).AsUnicodeString
as I am primarily targeting the Windows platform.
However, this is a solution for Lansa v. 14, not v. 12, where AsUnicodeString does not exist. In Lansa v. 12 you write
(13).AsByte.AsString + (10).AsByte.AsString
A quick follow-up on .IsValidPassword: The highest entropy of a password that would be accepted by .IsValidPassword(strong) can be calculated like this:
1 upper - 26 characters
1 lower - 26 characters
1 numeric - 10 characters
1 special - 7 characters
4 remaining - 26+26+10+7+1(space) = 70 characters
log2(26+26+10+7)*4+log2(26)*2+log2(10)+log2(7) ~~ 40 bits of entropy
If the requirement was simply 8 characters, the entropy could be
log2(70)*8 ~~ 49 bits of entropy
Entropy is used to calculate how long it would take to crack a password, provided it wasn’t an already know password:
Number of guesses = 2^(entropy - 1)
If we can make 1,500 guesses per second, divide by (1500 * 86400) (86400 is the number of seconds per day):
40 bits of entropy ~ 4,000 days
49 bits of entropy ~ 2.1 million days
What about words? Using words doesn’t necessary increase entropy, as words are part of a finite dictionary. The complete dictionary is somewhere between 100,000 and 200,000 but most people only use 3,000 words.
log2(3000)*4 ~~ 46 bits of entropy ~ 271,000 days
log2(3000)*5 ~~ 58 bits of entropy ~ 1.1 billion days
Using 4 words from your own dictionary would give a stronger password than what .IsValidPassword(strong) accepts, even if those 4 words would not get accepted by that method.
I am not impressed with the Lansa v. 14 SP2 addition of .IsValidPassword (see documentation):
I am sorry. This is completely insufficient and wrong. Also, this is no secret as everyone knows that these rules are insufficient and wrong. Or should know.
So, what are the right rules?
- Long passwords – this equals greater entropy
- Use words that can be remembered – this way the password doesn’t have to be written down or stored digitally
- Do not require use of mixed case and/or special characters – as this lowers entropy