Not a function
-
I now have multiple
IndexOutOfBoundsException
errors. I believe it's a consequence of changing the metadata function syntax by inserting['data']
before.get
. However, the metadata function syntax check did not return an error. Even if the error is due to the new['data']
Mango syntax, I'm not clear on how to fix the problem, since deleting['data']
to match the Mango scripting documentation will just revert back to thenot a function
error in the metadata script.ERROR 2018-07-11T20:59:00,003 (com.serotonin.m2m2.meta.MetaPointLocatorRT.execute:321) - Index: 1, Size: 1 java.lang.IndexOutOfBoundsException: Index: 1, Size: 1 at java.util.ArrayList.rangeCheck(ArrayList.java:653) ~[?:1.8.0_131] at java.util.ArrayList.get(ArrayList.java:429) ~[?:1.8.0_131] at jdk.nashorn.internal.scripts.Script$Recompilation$23961$30$\^eval\_.__scriptExecutor__(<eval>:2) ~[?:?] at jdk.nashorn.internal.scripts.Script$23926$\^eval\_.:program(<eval>:213) ~[?:?] at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:637) ~[nashorn.jar:?] at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:494) ~[nashorn.jar:?] at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:393) ~[nashorn.jar:?] at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:449) ~[nashorn.jar:?] at jdk.nashorn.api.scripting.NashornScriptEngine.access$200(NashornScriptEngine.java:73) ~[nashorn.jar:?] at jdk.nashorn.api.scripting.NashornScriptEngine$3.eval(NashornScriptEngine.java:510) ~[nashorn.jar:?] at javax.script.CompiledScript.eval(CompiledScript.java:92) ~[?:1.8.0_131] at com.serotonin.m2m2.rt.script.CompiledScriptExecutor.execute(CompiledScriptExecutor.java:89) ~[mango-3.4.4.jar:?] at com.serotonin.m2m2.meta.JavaScriptPointLocatorRT.executeImpl(JavaScriptPointLocatorRT.java:84) ~[meta-ds-3.4.0.jar:?] at com.serotonin.m2m2.meta.MetaPointLocatorRT.execute(MetaPointLocatorRT.java:310) [meta-ds-3.4.0.jar:?] at com.serotonin.m2m2.meta.MetaPointLocatorRT$ScheduledUpdateTimeout.run(MetaPointLocatorRT.java:212) [meta-ds-3.4.0.jar:?] at com.serotonin.timer.Task.runTask(Task.java:179) [mango-3.4.4.jar:?] at com.serotonin.timer.TaskWrapper.run(TaskWrapper.java:23) [mango-3.4.4.jar:?] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_131] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_131] at java.lang.Thread.run(Thread.java:748) [?:1.8.0_131]
Can someone please shed more light on this new Mango syntax? Where is it documented? Thanks.
-
@Pedro @mihairosu I can confirm that the
.get()
method was removed from the starts and runtimes wrapper for the scripting context in Mango v3.4.0, it was listed in the release notes. However I am not sure why this change was made, I have asked the other developers to look at this.@pedro said in Not a function:
After changing the syntax, the metadata javascript editor now issues the following warning: ['data'] is better written in dot notation
How would I write this in 'dot notation?' Will the "Mango Java Script" help page be changed to illustrate the new syntax?
Dot notation means writing this
object.data
rather thanobject['data']
, they are 100% equivalent, the former is just more succinct.@pedro said in Not a function:
I now have multiple IndexOutOfBoundsException errors. I believe it's a consequence of changing the metadata function syntax by inserting
Yes its definitely caused by this change, previously the
.get(true)
method would loop over the list of starts and runtimes and return the starts and runtimes object for the value true. The object returned by.data
now is a list which you would have to iterate over yourself.What does appear to work more like the previous behavior is something like this -
if (OverVLimit.past(HOUR, 1).startsAndRuntime[true].proportion > 0) return 1;
-
@jared-wiltshire said in Not a function:
I can confirm that the .get() method was removed from the starts and runtimes wrapper for the scripting context in Mango v3.4.0, it was listed in the release notes.
Thanks, Jared. I did not see any mention of
.get()
removal in the release notes, including the meta release notes. Perhaps I looked in the wrong place. Can you please provide a link to those release notes so that I can read it in context?What does appear to work more like the previous behavior is something like this -
if (OverVLimit.past(HOUR, 1).startsAndRuntime[true].proportion > 0) return 1;
Thanks. I just tried that, and this is the result:
Script error: TypeError: Cannot get property "proportion" of null in at line number 5 in at line number 5
So it seems that in addition to finding and deleting get() from all my scripts, I need to figure out the equivalent syntax for each , and then check for null before proceeding with the intended use, then test each script. Then I have to figure out the syntax for other .get() functions, and check multiple combinations of data to make sure each new code still works. This is quite a hassle, as I have 25 .get() calls to find among 337 metadata scripts.
The removal of
.get()
is clearly breaking many scripts. I'm looking forward to hearing why.get()
was removed. If it can be put back in and released in the next week or so, I may be better off waiting for the new release rather than changing, debugging, and testing all those scripts. Since the Mango Java Script online documentation still shows .get(), I have some hope that this functionality will be restored in the next release. When do you reckon the next release will be? I also have to weigh this against a version rollback.Thanks.
-
@jared-wiltshire said in Not a function:
startsAndRuntime
I found it under the core release notes:
Removing get(object) and get(DataValue) from StartsAndRuntimeList javascript wrapper so these methods are no longer available and should never have been used
Still wondering why the abrupt removal. I hope the documentation is changed to illustrate what to use instead.
-
Pedro,
We removed that method because it was ambiguous as it required java to cast the argument to a Mango DataValue. This could be dangerous as Javascript has no concept of Integer vs. Double and supplying a 1.0 vs a 1 to the get() method could result in a failure on the backend.
The new way to get the same information as described above will require you to check for null as if that state has not occurred in that period there will be no proportion member on a null object.
The documentation will be updated and put out in our next release which should be in a week or two.
-
@terrypacker Thanks for the clarification.
I'm sure users would be grateful if there were a couple of different examples of the new usage in the context help, including a warning about the potential to return null. It seems that any calls where
.proportion
or.percentage
returned a 0 will now fail, and must be preceded by a check for null before the method is called. -
@Pedro we will add a new method for the next release that can be used like this:
(OverVLimit.past(HOUR, 1).startsAndRuntime[true].proportion
which will return a 0 percentage/proportion instead of null for convenience.
-
@terrypacker Thanks, that would be handy. Currently I have to add three lines of code to each .proportion or .percentage call. Some of the scripts run only at the end of the month, so with luck I'll be able to upgrade before the end of the month and edit those scripts before the month is up. Now I'm editing the scripts that run every minute.
-
@Pedro after further discussion we will NOT be adding a method to avoid a null result. Take the example of a multistate point that has 3 states 1,2,3. If you request the time spent in state 4, you should get a null result. I believe you could use the Global Scripts module to define a method you can call in one line to achieve the non-null result of 0.
-
@terrypacker Okay, thanks for the forewarning.
-
@pedro said in Not a function:
I have to add three lines of code to each .proportion or .percentage call.
One line, probably more readable to put a function in a global script though.
if ((OverVLimit.past(HOUR, 1).startsAndRuntime[true] || {proportion: 0}).proportion > 0)
-
After even further discussion we will be adding the get() function back in. It will work for multistate and binary points to get the StartsAndRuntime object for that state, and it will return a 0 starts, 0 proportion, 0 runtime object for states that did not occur. To check if a state is present in a statistics object, therefore, one can check that (if they feel it is distinct to their scripts' logic) by
.past(HOUR, 1).startsAndRuntime[true] == null
Sorry for any inconvenience this caused.
Edit: Here is the example from the JavaScript help internal to Mango,
var stats = b.past(MONTH, 2); var sar = stats.get(false).proportion; //get the proportion of time in false whether or not false occurred var stateNotNull = stats.getStartsAndRuntime().containsKey(false); //see if false occurred
and here is the help page's example, https://help.infiniteautomation.com/about-mango-java-script/
return b.past(MONTH, 2).get(false).proportion;