/system script environment
:foreach item in=[find] do={
:local vname [get $item name]
:local vvalue [get $item value]
:if ($vvalue~"^\\*") do={:set vvalue "ID$vvalue"}
:if ($vvalue~"^(\\(code\\)|;\?\\(eva\?l )") do={:set vvalue "(code)"}
/ip firewall layer7
remove [find where name=$vname]
add name=$vname comment="$vvalue"
:delay 10ms
:execute "/ip firewall layer7 set [find where name=$vname] regexp=[:typeof \$$vname]"
:if ($vvalue="(code)") do={:delay 10ms ; set [find where name=$vname] regexp="code"}
}
/ip firewall layer7
:foreach item in=[find where regexp~"^(array|bool|code|id|ip|ip-prefix|ip6|ip6-prefix|lookup|nil|nothing|num|str|time)\$"] do={
:local vname [get $item name]
:local vvalue [get $item comment]
:local vtype [get $item regexp]
/system script environment
remove [find where name=$vname]
:if ($vtype~"^(array|ip|ip6|num|str|time)\$") do={
:execute ":global $vname [:to$vtype [/ip firewall layer7 get [find where name=$vname] comment]]"
} else={
:if ($vtype~"^(bool|id|ip-prefix|ip6-prefix|lookup|nil|nothing)\$") do={
:if ($vtype="bool") do={:execute ":global $vname [:tobool $vvalue]"}
:if ($vtype="id") do={:execute ":global $vname [:toid $[:pick $vvalue [:find $vvalue "*" -1] [:len $vvalue]]]"}
:if (($vtype="ip-prefix") or \
($vtype="ip6-prefix")) do={:execute ":global $vname [[:parse \":return $vvalue\"]]"}
:if ($vtype="lookup") do={:execute ":global $vname \"\$$vname\""}
:if ($vtype="nil") do={:execute ":global $vname"}
:if ($vtype="nothing") do={:execute ":global $vname [:nothing]"}
} else={
# vtype="code"
:log error "Unknow variable >$vname< of type >$vtype<"
:execute ":global $vname [/ip firewall layer7 get [find where name=$vname] comment]"
}
}
:delay 10ms
}
:if ($vtype = "bool") do={
[[:parse ":global $vname [:to$vtype $[/ip firewall layer7 get [find where name=$vname] regexp]]"]]}
:if ($vvalue = "(function)") do={:set vtype "function" }
When restoring, restoring boolean variables via :execute does not work for me,
all boolean variables are restored as nil (have no values).
I had to insert such a check and restore via :parseCode: Select all:if ($vtype = "bool") do={ [[:parse ":global $vname [:to$vtype $[/ip firewall layer7 get [find where name=$vname] regexp]]"]]}
:if ($vtype="bool") do={:execute ":global $vname [:tobool $vvalue]"}
#
# The function of saving/restoring global environment variables v 01/06/2022
# $1 parameter can take values:
# "save" - saving global variables in /ip firewall layer7
# "recover" - restoring global variables from layer7
# "erase" - cleaning layer7 only ! from global variables
# "print" - printing to the log and terminal of the list of variables located at the time of printing in Layer7
#
:global FuncGlobal do={
:if ([:typeof $0]="lookup") do={
:local count 0
:if (($1="save") or ($1="recover") or ($1="erase") or ($1="print")) do={
:if ($1="save") do={
/system script environment
:foreach item in=[find] do={
:local vname [get $item name]
:local vvalue [get $item value]
/ip firewall layer7
remove [find where name=$vname]
:if (([:typeof [:find [:tostr $vvalue] "(eval " -1]] = "nil") and ([:typeof [:find [:tostr $vvalue] "(evl " -1]] = "nil")) do={
:if ([:find $vvalue "*" -1] = 0) do={:set vvalue "ID$vvalue"}
add name=$vname regex="$vvalue"
:set count ($count+1)
}
:delay 10ms
:execute "/ip firewall layer7 set [find where name=$vname] comment=[:typeof \$$vname]"
}
:log warning ("Function $0 has saved $count variables")
:return $count}
:if ($1="recover") do={
/ip firewall layer7
:foreach item in=[find where comment~"^(array|bool|id|ip|ip-prefix|ip6|ip6-prefix|num|str|time|code|nothing|nil)\$"] do={
:set count ($count+1)
:local vname [get $item name]
:local vvalue [get $item regexp]
:local vtype [get $item comment]
# :if ($vvalue = "(function)") do={:set vtype "function" }
/system script environment
remove [find where name=$vname]
:if ($vtype~"^(array|bool|id|ip|ip6|num|str|time)\$") do={
:if ($vtype = "id") do={
:set vvalue [:pick $vvalue [:find $vvalue "*" -1] [:len $vvalue]]
:execute ":global $vname [:to$vtype $vvalue]"}
:if ($vtype = "bool") do={
[[:parse ":global $vname [:to$vtype $[/ip firewall layer7 get [find where name=$vname] regexp]]"]]
# :if ($vtype="bool") do={:execute ":global $vname [:tobool $vvalue]"}
} else={
:execute ":global $vname [:to$vtype [/ip firewall layer7 get [find where name=$vname] regexp]]"
}
} else={
:if ($vtype~"^(ip-prefix|ip6-prefix|nothing|nil)\$") do={
:if ($vtype~"^(ip-prefix|ip6-prefix)\$") do={:execute ":global $vname [[:parse \":return $vvalue\"]]"}
:if ($vtype="nothing") do={:execute ":global $vname [:nothing]"}
:if ($vtype="nil") do={:execute ":global $vname"}
} else={
:log error "Unknow variable type >$vtype<"
:execute ":global $vname [/ip firewall layer7 get [find where name=$vname] regexp]"
}
}
:delay 10ms;
}
:log warning ("Function $0 restored $count variables")
:return $count}
:if ($1="erase") do={
/ip firewall layer7
:foreach item in=[find where comment~"^(array|bool|id|ip|ip-prefix|ip6|ip6-prefix|num|str|time|code|nothing|nil)\$"] do={remove $item; :set count ($count+1)
}
:log warning ("The repository has been cleared of $count global variables")
:return $count}
:if ($1="print") do={
/ip firewall layer7
:foreach item in=[find where comment~"^(array|bool|id|ip|ip-prefix|ip6|ip6-prefix|num|str|time|code|nothing|nil)\$"] do={
:set count ($count+1)
:local vname [get $item name];
:local vvalue [get $item regexp];
:local vtype [get $item comment];
:put ("$vname "."$vtype "."$vvalue");
:log info ("$vname "."[ $vtype ] "."$vvalue");
}
:log warning ("In Layer7 repository has $count global variables")
:put ("In Layer7 repository has $count global variables")
:return $count}
} else={
:if ([:typeof $1]="nothing") do={:log error ("The function $0 parameter is not set"); :return ("Error $0")}}
:log error ("The function $0 parameter is not valid"); :return ("Error $0");
}
}
# usage examples:
# :log info [$FuncGlobal save]
# :log info [$FuncGlobal recover]
# :log info [$FuncGlobal erase]
# :log info [$FuncGlobal print]
# examples of erroneous usage:
# :log info [$FuncGlobal]
# :log info [$FuncGlobal anovertext]
You try the "new version" if do same error?...
Hi Rex,You try the "new version" if do same error?
EEEEEEEHHHHHHHHHHHHH???????????[…] it is now possible to save/restore the content of a function. Congratulations!
I am going to capture screenshots, just a secondEEEEEEEHHHHHHHHHHHHH???????????[…] it is now possible to save/restore the content of a function. Congratulations!
look at the screenshotsCheck twice.... after reboot....
If the function is
:global f do={ /interface print }
It's normal this:
:put [$f]
(function)
Is just a text "(function)" or another script set again the function correctly...
You are right, some functions are not restored properly. With the last modification you have made now save the functions as "(function)" in the comments.Yes, but the function work?
Is easy copy & paste the "eval / evl" code, but is restored just as string...
on the code is present:
:if ($vvalue~"\\(eval|evl) ") do={:set vvalue "(function)"}
is missing one (another) ( before eval, now the script is fixed
Completely nonsense: if a "virus" has access to the routerboard, it doesn't give a damn about "reading" functions from Layer7,If the Mikrotik developers allow saving the function code in Layer7 and restoring it from there ... this can lead to both good (for example, creating copyright protection) and dangerous consequences (for example, creating virus scripts)
:put [:typeof (>[])]
????????????????????????????????????????????????????????????I found another lost data type:
Return:Code: Select all:put [:typeof (>[])]
op
this data type behaves like code
I found another lost data type:
:global optype (>[:global z "blah"])
$optype
:put $z
# "blah"
:global optype (>[:do {:put "$1"}])
:put [:typeof $optype]
# op
$optype "hmm"
# hmm
:put $optype
# (evl (evl /docommand=;(evl (evl /putmessage=$1))))
:global shortThanToArray (>{})
:put "$shortThanToArray $[:typeof $shortThanToArray] $[:len $shortThanToArray]"
# array 0
Columns: TYPE, COMPLETION, STYLE, OFFSET, PREFERENCE, SHOW
TYPE COMPLETION STYLE OFFSET PREFERENCE SHOW
completion none 2 80 no
completion ( syntax-meta 2 75 no
completion $ syntax-meta 2 75 no
completion [ syntax-meta 2 75 no
completion { syntax-meta 2 75 no
completion " syntax-meta 2 75 no
completion ! syntax-meta 2 75 no
completion - syntax-meta 2 75 no
completion ~ syntax-meta 2 75 no
completion > syntax-meta 2 75 no
completion syntax-meta 2 75 no
completion <value> none 2 -1 no
:put $varWithCodeDataType
or
:put [ :parse "local var" ]
or
:put ( $function->1 )
:put [ /system script environment get [ find name="globalFunction" ] value ]
/environment print
(evl /localname=$var)
{(evl [/local{name=$var}])}
:global arraytest {"a";"b";"c";{"q";"z"}} :put $arraytest :global pointer (>($arraytest->1)) :put $pointer :put [$pointer] :set ($arraytest->1) "x" :put $arraytest :put $pointer :put [$pointer] :set [$pointer] "W" :set pointer "J" :put $arraytest :put $pointer :put [$pointer] :global pointer (>($arraytest->3)) :put $pointer :put [$pointer] :put ([$pointer]->1) :set ([$pointer]->1) "RR" :put $pointer :put [$pointer] :put $arraytest
Anyway to use this data type to write a script that uses mac-telnet to log into another device by MAC address and execute a command?I found another lost data type:
Return:Code: Select all:put [:typeof (>[])]
op
this data type behaves like code
The break is mainly in the regex part. could you please double check? Thanks:if ($vvalue~"^(\(code\)|;\\(eva\?l )") do={:set $vvalue "(code)"};
Hi Rex. The code seams to break in ROS 7.11 stable. for the store script
The break is mainly in the regex part. could you please double check? Thanks:if ($vvalue~"^(\(code\)|;\\(eva\?l )") do={:set $vvalue "(code)"};
Only simple arrays are exported, do not work for array of array and more complex data structure.
with the first documentation of for those resources being published in Scripting - RouterOS - MikroTik Documentation - v. 54 dez. 07, 2023 13:21What's new in 7.13 (2023-Dec-14 09:24):
*) console - added ":serialize" and ":deserialize" commands for converting values to/from JSON;
Yep... I guess you are right.I also thought about using json, but...
...
but hopefully by the time it is removed, it will be possible to use serialize and deserialize using the text field of a script...
:global persist do={
:local varName $1
:local varValue $2
:local varID [/ip firewall layer7-protocol find name="$varName"]
:if ([:typeof $varValue] = "nothing") do={
:if ($varID != "") do={
:set $varValue [/ip firewall layer7-protocol get $varID value-name=regexp]
}
} else={
:if ($varID = "") do={
/ip firewall layer7-protocol add name="$varName" regexp="$varValue"
} else={
/ip firewall layer7-protocol set $varID regexp="$varValue"
}
}
return $varValue
}
:global l7var do={ /ip firewall layer7-protocol :local varName [:tostr $1] :local varNewValue [:tostr $2] :local valuePresent ([:typeof $2] != "nothing") :if ($varName = "") do={ :return [:nothing] } :local varID [find where name=$varName] :if ($delete = "yes") do={ remove $varID ; :return [:nothing] } :if ($valuePresent) do={ :if ([:len $varID] = 0) do={ add name=$varName regexp=$varNewValue :set varID [find where name=$varName] } else={ set $varID regexp=$varNewValue } } :if ([:len $varID] != 0) do={ :return [get $varID regexp] } :return [:nothing] }
FWIW, I adapted a test script for serialize/deserialize, to test using JSON to base64 to L7 FW regex storage (and back). I wasn't trying to replace anything here, more just trying the above approach to see if it even works, since I had a complex array already. And, critically, this will only work in 7.16+ (or maybe even needs 7.17).I also thought about using json, but...
[...]
So, in conclusion, layer7 is certainly not going away anytime soon,
but hopefully by the time it is removed, it will be possible to use serialize and deserialize using the text field of a script...
A possible solution is to convert everything into a base64 array
[...]
{
# an array with most types, including a JSON "float"
:local arr {
"num"=0;
"str"="mystr";
"emptystr"="";
"ip4"=1.1;
"ip6"=1::1;
"prefix4"=1.0.0.1/31;
"prefix6"=1::1/69;
"float"="1.1";
"time"=1s;
"now"=[:timestamp];
"null"=[:nothing];
"list"=(1,2,"three");
"listlist"={(1,2,3);("a","b","c")}
"dict"={"a"=1;"b"="z"};
"dictlist"={{"m"="M"};{"z"="Z"}};
"dictdict"={"b"={"one"=1;"two"=2};"w"={"1"="one";"2"="two"}};
"optype"=(>[:put "echo"]);
"bignum"=[:tonsec [:timestamp]];
"bigneg"=(0-[:tonsec [:timestamp]]);
}
# helpers for test
:local prettyprint do={:put [:serialize to=json options=json.pretty $1]}
:local addtypes do={:local rv $1; :foreach n,a in=$1 do={ :set ($rv->"$n-type") [:typeof $a] }; :return $rv }
:put "\r\narray BEFORE serialization"
$prettyprint [$addtypes $arr]
:put "\r\nconvert to JSON"
:local json [:serialize to=json $arr]
:put "\r\nconvert to base64 for storage as RouterOS string"
:local base64out [:convert to=base64 $json]
$prettyprint $base64out
:put "\r\nsave to base64 JSON as unused L7 FW rule"
:local storename "example-base64-json-to-save-vars"
:local storeid [/ip/firewall/layer7-protocol/find name=$storename]
:if ([:len $storeid]=1) do={
/ip/firewall/layer7-protocol set $storeid regexp=$base64out
} else={
/ip/firewall/layer7-protocol add name=$storename regexp=$base64out
}
:put "\r\nPRETEND you reboot and come back...so wait 3 seconds"
:delay 3s
:put "\r\nsave to base64 JSON as unused L7 FW rule"
:local base64in [/ip/firewall/layer7-protocol get [find name=$storename] regexp]
:put "\r\nif base64, restore it to JSON"
:local newjson [:convert from=base64 $base64in]
:put "\r\nfinally get the array back, with types perserved by :deserialize JSON"
:local arr2 [:deserialize from=json $newjson]
:put "\r\narray AFTER deserialization"
$prettyprint [$addtypes $arr2]
:put "\r\nBONUS: simulate using RESTORED array variables using 'activate-in-context' and 'op' types"
((>[:put "now: $now listlen: $[:len $list] bignum: $bignum prefix6: $prefix6"]) <%% $arr2)
:put "... even though its array, you can use them as normal variables without the -> if you use the <%% to unwrap them"
}
array BEFORE serialization
{
"bigneg": -1738076593889845466,
"bigneg-type": "num",
"bignum": 1738076593889955906,
"bignum-type": "num",
"dict": {
"a": 1,
"b": "z"
},
"dict-type": "array",
"dictdict": {
"b": {
"one": 1,
"two": 2
},
"w": {
"1": "one",
"2": "two"
}
},
"dictdict-type": "array",
"dictlist": [
{
"m": "M"
},
{
"z": "Z"
}
],
"dictlist-type": "array",
"emptystr": "",
"emptystr-type": "str",
"float": 1.100000,
"float-type": "str",
"ip4": "1.0.0.1",
"ip4-type": "ip",
"ip6": "1::1",
"ip6-type": "ip6",
"list": [
1,
2,
"three"
],
"list-type": "array",
"listlist": [
[
1,
2,
3
],
[
"a",
"b",
"c"
]
],
"listlist-type": "array",
"now": "2025-01-28 15:03:13",
"now-type": "time",
"null": null,
"null-type": "nil",
"num": 0,
"num-type": "num",
"optype": "(op)",
"optype-type": "op",
"prefix4": "1.0.0.1/31",
"prefix4-type": "ip-prefix",
"prefix6": "1::/69",
"prefix6-type": "ip6-prefix",
"str": "mystr",
"str-type": "str",
"time": "1970-01-01 00:00:01",
"time-type": "time"
}
convert to JSON
convert to base64 for storage as RouterOS string
"eyJiaWduZWciOi0xNzM4MDc2NTkzODg5ODQ1NDY2LCJiaWdudW0iOjE3MzgwNzY1OTM4ODk5NTU5MDYs
ImRpY3QiOnsiYSI6MSwiYiI6InoifSwiZGljdGRpY3QiOnsiYiI6eyJvbmUiOjEsInR3byI6Mn0sInciO
nsiMSI6Im9uZSIsIjIiOiJ0d28ifX0sImRpY3RsaXN0IjpbeyJtIjoiTSJ9LHsieiI6IloifV0sImVtcH
R5c3RyIjoiIiwiZmxvYXQiOjEuMTAwMDAwLCJpcDQiOiIxLjAuMC4xIiwiaXA2IjoiMTo6MSIsImxpc3Q
iOlsxLDIsInRocmVlIl0sImxpc3RsaXN0IjpbWzEsMiwzXSxbImEiLCJiIiwiYyJdXSwibm93IjoiMjAy
NS0wMS0yOCAxNTowMzoxMyIsIm51bGwiOm51bGwsIm51bSI6MCwib3B0eXBlIjoiKG9wKSIsInByZWZpe
DQiOiIxLjAuMC4xLzMxIiwicHJlZml4NiI6IjE6Oi82OSIsInN0ciI6Im15c3RyIiwidGltZSI6IjE5Nz
AtMDEtMDEgMDA6MDA6MDEifQ=="
save to base64 JSON as unused L7 FW rule
PRETEND you reboot and come back...so wait 5 seconds
save to base64 JSON as unused L7 FW rule
if base64, restore it to JSON
finally get the array back, with types perserved by :deserialize JSON
array AFTER deserialization
{
"bigneg": -1738076593889845466,
"bigneg-type": "num",
"bignum": 1738076593889955906,
"bignum-type": "num",
"dict": {
"a": 1,
"b": "z"
},
"dict-type": "array",
"dictdict": {
"b": {
"one": 1,
"two": 2
},
"w": {
"1": "one",
"2": "two"
}
},
"dictdict-type": "array",
"dictlist": [
{
"m": "M"
},
{
"z": "Z"
}
],
"dictlist-type": "array",
"emptystr": "",
"emptystr-type": "str",
"float": 1.100000,
"float-type": "str",
"ip4": "1.0.0.1",
"ip4-type": "ip",
"ip6": "1::1",
"ip6-type": "ip6",
"list": [
1,
2,
"three"
],
"list-type": "array",
"listlist": [
[
1,
2,
3
],
[
"a",
"b",
"c"
]
],
"listlist-type": "array",
"now": "2025-01-28 15:03:13",
"now-type": "time",
"null": null,
"null-type": "nil",
"num": 0,
"num-type": "num",
"optype": "(op)",
"optype-type": "str",
"prefix4": "1.0.0.1/31",
"prefix4-type": "ip-prefix",
"prefix6": "1::/69",
"prefix6-type": "ip6-prefix",
"str": "mystr",
"str-type": "str",
"time": "1970-01-01 00:00:01",
"time-type": "time"
}
BONUS: simulate using array variables in function using the 'activate-in-context'
with 'op' type
now: 2873w5d15:03:13 listlen: 3 bignum: 1738076593889955906 prefix6: 1::/69
... even though its array, you can use them as normal variables without the -> if
you use the <%% to unwrap them
(>[:put [:typeof [:deserialize from=json [:serialize to=json $1]]]]) <%% "1.1.1.1/0"
# ip-prefix
{ :global globalVars [:toarray ""] :put $globalVars :set ($globalVars->"testArray") [:toarray ""] :set ($globalVars->"testArray"->"value") [:toarray "a,b"] :set ($globalVars->"testArray"->"type") [:typeof ($globalVars->"testArray"->"value")] :set ($globalVars->"testBool") [:toarray ""] :set ($globalVars->"testBool"->"value") true :set ($globalVars->"testBool"->"type") [:typeof ($globalVars->"testBool"->"value")] :set ($globalVars->"testCode") [:toarray ""] :set ($globalVars->"testCode"->"value") [:parse ";"] :set ($globalVars->"testCode"->"type") [:typeof ($globalVars->"testCode"->"value")] :set ($globalVars->"testID") [:toarray ""] :set ($globalVars->"testID"->"value") [:toid *BEEF6] :set ($globalVars->"testID"->"type") [:typeof ($globalVars->"testID"->"value")] :set ($globalVars->"testIP4") [:toarray ""] :set ($globalVars->"testIP4"->"value") 127.0.0.1 :set ($globalVars->"testIP4"->"type") [:typeof ($globalVars->"testIP4"->"value")] :set ($globalVars->"testIP4px") [:toarray ""] :set ($globalVars->"testIP4px"->"value") 192.168.0.0/24 :set ($globalVars->"testIP4px"->"type") [:typeof ($globalVars->"testIP4px"->"value")] :set ($globalVars->"testIP6") [:toarray ""] :set ($globalVars->"testIP6"->"value") 127:0:0::1 :set ($globalVars->"testIP6"->"type") [:typeof ($globalVars->"testIP6"->"value")] :set ($globalVars->"testIP6px") [:toarray ""] :set ($globalVars->"testIP6px"->"value") 192:168:0::0/64 :set ($globalVars->"testIP6px"->"type") [:typeof ($globalVars->"testIP6px"->"value")] :global lookupGen do={:return $0} :set ($globalVars->"testLook") [:toarray ""] :set ($globalVars->"testLook"->"value") [$lookupGen] :set ($globalVars->"testLook"->"type") [:typeof ($globalVars->"testLook"->"value")] :set ($globalVars->"testNil") [:toarray ""] :set ($globalVars->"testNil"->"value") [] :set ($globalVars->"testNil"->"type") [:typeof ($globalVars->"testNil"->"value")] :set ($globalVars->"testNth") [:toarray ""] :set ($globalVars->"testNth"->"value") ; # undefined on purpose for nothing :set ($globalVars->"testNth"->"type") [:typeof ($globalVars->"testNth"->"value")] :set ($globalVars->"testNum") [:toarray ""] :set ($globalVars->"testNum"->"value") -256 :set ($globalVars->"testNum"->"type") [:typeof ($globalVars->"testNum"->"value")] :set ($globalVars->"testOP") [:toarray ""] :set ($globalVars->"testOP"->"value") (>[]) :set ($globalVars->"testOP"->"type") [:typeof ($globalVars->"testOP"->"value")] :set ($globalVars->"testStr") [:toarray ""] :set ($globalVars->"testStr"->"value") [:convert to=base64 "1.1"] :set ($globalVars->"testStr"->"base64") true :set ($globalVars->"testStr"->"type") [:typeof ($globalVars->"testStr"->"value")] :set ($globalVars->"testTime") [:toarray ""] :set ($globalVars->"testTime"->"value") 1w1d1h1m1s :set ($globalVars->"testTime"->"type") [:typeof ($globalVars->"testTime"->"value")] :foreach name,content in=$globalVars do={ :if (($content->"type") = "array") do={ :put ">$name< = >$($content->"type")< >$[:tostr ($content->"value")]< " } else={ :if (($content->"base64") = true) do={ :put ">$name< = >$($content->"type")< >$[:convert from=base64 ($content->"value")]< " } else={ :put ">$name< = >$($content->"type")< >$($content->"value")< " } } } :local json [:serialize to=json options=json.pretty $globalVars] # debug # :put $json :put "\r\nAfter array -> json -> array conversion:\r\n" :global newArr [:deserialize from=json options=json.no-string-conversion $json] :foreach name,content in=$newArr do={ :if (($content->"type") = "array") do={ :put ">$name< = >$($content->"type")< >$[:tostr ($content->"value")]< IMPORTED TYPE: >$[:typeof ($content->"value")]<" } else={ :if (($content->"base64") = true) do={ :put ">$name< = >$($content->"type")< >$[:convert from=base64 ($content->"value")]< IMPORTED TYPE: >$[:typeof ($content->"value")]<" } else={ :put ">$name< = >$($content->"type")< >$($content->"value")< IMPORTED TYPE: >$[:typeof ($content->"value")]<" } } } :put "\r\nNOTES\r\ncode, function, lookup and op are not exportable. Function is also reported as array." :put "Strings are exported and imported on base64 for prevent 7.16.2 and less errors with implicit conversions to json," :put "on importing strings already exist options=json.no-string-conversion that prevents implicit conversions from json" :put "MISSING: apireq, backreference, cmd, exclamation, iterator\r\n" }
My guess is that webfig717+/winbox4 being "done" is the gating item there, I'd imagine they'll re-use those UI components, but those aren't done given the Winbox4 beta threadCould it be related to the MikroTik Devices Controller ?