Julius Kavay · Oct 16, 2023 go to post

Your example shows https but you try a http connection.   Is this a mistake or a typo?

Julius Kavay · Oct 7, 2023 go to post

Is my assumption correct, you use for the property "PrijsAkCatVm" an own data type (Asci.Getal) instead of %Numeric, in order to be able to use some extra parameters like HINT, VIEW, VISIBLE etc.
Is that correct? If yes, then there is a much simpler solution where neither  MS nor SQL won't stumble over it. The catchword is PropertyClass.

/// Create a new Cache class.
/// Define here all the extra parameter you need.
///
Class Extra.Props
{
    Parameter HINT;
    Parameter VIEW = 1;
    Parameter VISIBLE = 1;
    Parameter VOLGORDE;
    // etc.
}

/// then take your Cache Table, add the above defined class
/// to your Cache Table, complete the property definitions with
/// the appropriate parameters - Done.
///
Class Your.CacheTable Extends %Persistent [ PropertyClass = Extra.Props ]
{
   Property PrijsAkCatVm As %Numeric (CAPTION="...", "HINT=...", etc.); 
}

Now you can use the above defined (extra) parameters in each and every property  in this class.

Julius Kavay · Sep 25, 2023 go to post

Usually, you get a <COMMAND> error, if you call a (class)method as an expression but the called method does not provide a value 

Method SomethingErr()
{
    write "Hello"
}

Method SomethingOk()
{
    quit "Hello"
}


do ..SomethingErr() // this is OK
do ..SomethingOK()  // this is OK
write ..SomethingErr() // gives a <COMMAND> error
write ..SomethingOK()  // is OK
Julius Kavay · Sep 25, 2023 go to post

As an addition to the above said

set mydir="C:\dir1\dir2\newdir"
//
// creates newdir ONLY if dir1 and dir2 exists
write ##class(%File).CreateDirectory(mydir)

// creates newdir and, IF NECESSARY, the intermediate directories dir2 and dir1 too
write ##class(%File).CreateDirectoryChain(mydir)
Julius Kavay · Sep 13, 2023 go to post

There are two aspects of the question,
a) how to get the old property value of a modified property and
b) what happens, if one still opens the same object in the SAME PROCESS once again.

For a) the answer is already given by either using the GetStored() method or cloning the object. In cases, where an old propvalue is needed, I prefer the object cloning, especially if the base object contains embedded objects.
Of course, if the application uses the %Reload() method, then the %OnReload() callback method should do the same as %OnOpen() does.

Class DC.Data Extends %Persistent
{
Property Name As %String;
Property Addr As DataAddr;
Property oldObj As Data [ ReadOnly, Transient ];
Method %OnOpen() As %Status [ Private, ServerOnly = 1 ]
{
    set r%oldObj=..%ConstructClone(1)  // do a deep clone
    do ..%SetModified(0)               // clear modified state
    Quit $$$OK
}
}

Class DC.DataAddr Extends %SerialObject
{
Property Street As %String;
Property City As %String;
}

kill
set obj=##class(DC.Data).%New(),obj.Name="Joe"
set obj.Addr.Street="Abbey Rd. 123", obj.Addr.City="London"
write obj.%Save() --> 1

kill
set obj=##class(DC.Data).%OpenId(1)

set obj.Name="Paul"
write obj.Name --> Paul
write obj.oldObj.Name --> Joe

set obj.Addr.City="London East"
write obj.Addr.City --> London East
write obj.oldObj.Addr.City --> London

For b), it was said, that a second open (of the same object) returns the same OID. This is true. But there is one more thing. That second open doesn't even trys to get that object from the database but just keeps a lookout in the memory. This means two things (assuming no locks are used)
1) if the object was modified by another process, you "open the old version" already in the memory of your process, and
2) nevertheless that an other process deletes that object, your proces will open a nonexisting object...

Seq  Process-A                                  Process-B
-------------------------------------------------------------------------
 1   set obj1=##class(DC.Data).%OpenId(1)
 2                                              do ##class(DC.Data).%DeleteId(1)
 3   write ##class(DC.Data).%ExistsId(1) --> 0
 4   set obj2=##class(DC.Data).%OpenId(1)
 5   write obj1=obj2 --> 1
 

As a consequence of the above, I have learned not to use a simple open:

set obj=##class(Some.Class).%OpenId(oid)

but a more secure open, by invalidating a possible old instance:

set obj="", obj=##class(Some.Class).%OpenId(oid)
Julius Kavay · Aug 21, 2023 go to post

Nice, the first part of the problem (or project, if you wish) is solved. What about a "side project", not pinging all but the active VPNs only? Use the netstat command to get all the established connections

/// Execute an arbitrary OS command and return the command output
ClassMethod OSCmd(cmd, ByRef ans)
{
    kill ans
    open cmd:"QR":10
    set old=$system.Process.SetZEOF(1), ans=0
    if $test {
        use cmd
        for {read line quit:$zeof  set ans($increment(ans))=line}
        close cmd
    }
    quit ans
}

Of course, you have to take into account OS specific differences and access rights

do ##class(your.classname).OSCmd("ping google.com", .ans) zw ans
ans=11
ans(1)=""
ans(2)="Pinging google.com [142.250.185.174] with 32 bytes of data:"
ans(3)="Reply from 142.250.185.174: bytes=32 time=21ms TTL=114"
ans(4)="Reply from 142.250.185.174: bytes=32 time=27ms TTL=114"
ans(5)="Reply from 142.250.185.174: bytes=32 time=19ms TTL=114"
ans(6)="Reply from 142.250.185.174: bytes=32 time=18ms TTL=114"
ans(7)=""
ans(8)="Ping statistics for 142.250.185.174:"
ans(9)="    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),"
ans(10)="Approximate round trip times in milli-seconds:"
ans(11)=""

do ##class(your.classname).OSCmd("netstat -ano | findstr ""ESTABLISHED""", .ans) zw ans
ans=6
ans(1)="  TCP    127.0.0.1:23           127.0.0.1:50814        ESTABLISHED     8272"
ans(2)="  TCP    127.0.0.1:23           127.0.0.1:60874        ESTABLISHED     2872"
ans(3)="  TCP    127.0.0.1:23           127.0.0.1:63199        ESTABLISHED     8272"
ans(4)="  TCP    127.0.0.1:1972         127.0.0.1:49436        ESTABLISHED     2404"
ans(5)="  TCP    127.0.0.1:1972         127.0.0.1:51840        ESTABLISHED     2404"
ans(6)="  TCP    127.0.0.1:1972         127.0.0.1:54330        ESTABLISHED     2404"

Now you can analyse and process the command output...

Also, see this post too.

Julius Kavay · Aug 17, 2023 go to post

Some remarks:

 // on Linux, it's a good idea to limit the ping count
 set cmnd="ping -c 3 "_host
 
 // if $zeof isn't alway on, as on my systems the case is
 // we need two more lines
 set cmd="..."
 set old=$system.Process.SetZEOF(1)  // turn $ZEOF on
 open cmd...
 ...
 close cmd
 do $system.Process.SetZEOF(old)     // reset to old state
Julius Kavay · Aug 17, 2023 go to post

Four short lines of Objectscript code


ClassMethod Ping(host)
{
	set cmd="ping "_host
	open cmd:"QR":10
	for {use cmd read ans quit:$zeof  use 0 write ans,!}
	close cmd
}

// some test
do ##class(your.class).Ping("google.com")

Pinging google.com [142.250.185.110] with 32 bytes of data:
Reply from 142.250.185.110: bytes=32 time=25ms TTL=114
Reply from 142.250.185.110: bytes=32 time=26ms TTL=114
Reply from 142.250.185.110: bytes=32 time=19ms TTL=114
Reply from 142.250.185.110: bytes=32 time=19ms TTL=114

Ping statistics for 142.250.185.110:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 19ms, Maximum = 26ms, Average = 22ms

Julius Kavay · Aug 9, 2023 go to post

Using a two digit year in 2023 is the same as wishing to get a Y2K problem again. Probably it will be now the Y2.1K issue.

Julius Kavay · Aug 5, 2023 go to post

Nice, and where are those 4 byte floating point data? Do you have some information about that record?

Julius Kavay · Aug 5, 2023 go to post

also, you could try the 

$SCONVERT(s,format,endian,position)

function (Format: F4)

Julius Kavay · Aug 5, 2023 go to post

Instead of ZW RECORD (which only gives an ASCII rubbish) please give some examples as hex-dump (ZZDUMP RECORD or something similar). A few values together with hex-dump.

Julius Kavay · Aug 4, 2023 go to post

Merely you have to "open" the article to get those tags into top position. If you just browse (see the screenshot) over the articles: (a) you have to scroll down and (b) a tag name could have but must not have the same meaning as an acronym. In my opinion, an acronym should always be explained after the first usage - either you write it out or you insert a link or whatever...  

Julius Kavay · Aug 4, 2023 go to post

By the way, you can also "shorten" a given node and start over...

// from the above example,
// name = ^A("TEST1","TEST2", ... "TEST10")
// now we take that global with the first two subscripts
set name = $name(@name,2)
// and add new subscripts
set name = $name(@name@(3333,4444))
set @name = "new data"

Try it and then ZWRITE ^A  to see the effect

Julius Kavay · Aug 4, 2023 go to post
set name = $name(^A)
for i=1:1:10 { set name = $name(@name@("TEST"_i)) }
set @name=""
Julius Kavay · Aug 4, 2023 go to post

I assume, we are talking about ObjectScript? Then you got in the main method a <SYNTAX> error because "calling" is not a command keyword. So what are you really doing? We don't need the whole main method, the line with the call would be enough. By the way, a method name like "this_method" is not a valid name except if you place it in (double)quotes.  Something, which is formal correct, looks like this:

Method "this_MainMethod"()
{
    do ..SecondMethod()
}

Method SecondMethod()
{
    // ...
}
Julius Kavay · Aug 3, 2023 go to post

I just saw now, I published the next to last version instead of the last... sorry. I end up 53 bytes. This "s_0" was a work-around for not to use $g(z) by getting at least one loop for case, someone calls the method with an empty string

ClassMethod IsValid(s)
{
	f{s c=$a(s,$i(i))+1 ret:$i(z,c=42-(c=41))>0!'c 'z}
}
Julius Kavay · Aug 3, 2023 go to post

After I put all the solutions in a pot, salting them with some own ideas then filtering, I got a really nice solution with 55 bytes. Works for all the examples given by @Eduard.Lebedyuk.

The best idea-donors where, among others, @Stuart Strickland and @Lorenzo Scalese, thank you.

ClassMethod IsValid(s)
{
	f{s c=$a(s_0,$i(i))+1 ret:$i(z,c=42-(c=41))>0!'c 'z}
}
Julius Kavay · Aug 3, 2023 go to post

Two more bytes and the problem is solved:

Property refDate As %Date [InitialExpression = {$piece($horolog,",",1)}];
//.............................................^......................^
Julius Kavay · Aug 3, 2023 go to post

If my aging brain me do not misleads, you could save two more bytes

 g:"()"'[$c(c)  // instead of this (13 bytes)
 g:c=41-c+40    // use this        (11 bytes)
 
Julius Kavay · Aug 3, 2023 go to post

I hope, this change does not affect the way I use (some of the) mnemonics - am I right?

Class My.Mnemonics Extends %RegisteredObject
{
/// Set-/Reset mnemonic routine
ClassMethod SetMnemonics(rou={$zname}) [ ProcedureBlock = 0 ]
{
    set old=##class(%Device).GetMnemonicRoutine()
    use $i::"^"_rou
    quit old
    
MA(x)	write "This is MA "_x quit
MB()	write "This is MB" quit
}
}


// for example:
set old=##class(My.Mnemonics).SetMnemonics()
write /ma(123)
do ##class(MyMnemonics).SetMnemonics(old)
Julius Kavay · Jul 28, 2023 go to post

OK, one can short down those 20 bytes into 17 and we end up with 64 bytes.

ClassMethod IsValid(x)
{
1	s z=x,x=$replace($tr(x,$tr(x,"()")),"()","") g 1:x'=z q x=""
}

Again, speed wasn't asked

Julius Kavay · Jul 28, 2023 go to post

OK, I start with 47 chars... unfortunately, I have to add 20 chars more for that (stupid) extra requirement of ignoring characters like {, [, <, etc. therefore end up with 67 chars

ClassMethod IsHalfValid(x)
{
1	s z=x,x=$replace(x,"()","") g 1:x'=z q x=""
}

ClassMethod IsFullValid(x)
{
1	s z=x,x=$replace($zstrip(x,"*e",,"()"),"()","") g 1:x'=z q x=""
}

Speed was'n asked...

Julius Kavay · Jul 27, 2023 go to post

In the mean time the answer is already given by Mr Maslennikov and others, but to shorten your runtime,  you could also try a "variablenless" loop, maybe this gives you some seconds more... The emphasis is on "maybe".

// if you have null-subscripts enabled
if $d(^YYY(""))!1 for i=0:1 {quit:$order(@$zr)=""} write i

// if null-subscripts are not enabled
if $d(^YYY(-9E18))!1 for i=0:1 {quit:$order(@$zr)=""} write i

// of course, you can do that on any arbitrary level too
if $d(^YYY(1,2,3,""))!1 for i=0:1 {...} write i

// the value of -9E19 ist just for explanation, use a value suitable for your needs

May I ask for the background, why do you need that node count? 

Julius Kavay · Jul 27, 2023 go to post

Caution,  backward $order() is always slower than forward $order(). If you need the last (hopefully few) entries, than it's OK to use a backward-$O() but running (counting) from the bottom to the top over several millions of nodes is definitely not an effective run.