go to post Julius Kavay · Oct 1, 2024 Just in case anyone is upset about "command indirection". Yes, I know the correct term is "argument indirection". It's one of those old habits that never dies...
go to post Julius Kavay · Oct 1, 2024 I assume, you have a routine 'hello' like this hello ; this is my hello-test quit say(arg) write arg,! quit add(x,y) Public { quit x + y } and some variable, set as follows set rou="hello" set say="say", add="add" set a1=5,a2=10, arg="Hello World" set sayall="say^hello(arg)" set addall="$$add^hello(a1,a2)" then you can do things like do @sayall ---> Hello World // command indirection do @say^@(rou)(arg) ---> Hello World // name-indirection do @say^hello(arg) ---> Hello World // name-indirection do say^@(rou)(arg) ---> Hello World // name-indirection do say^hello(arg) ---> Hello World write @addall ---> 15 // command indirection write $$@add^@(rou)(a1,a2) ---> 15 // name-indirection write $$@add^hello(a1,a2) ---> 15 // name-indirection write $$add^@(rou)(a1,a2) ---> 15 // name-indirection write $$add^hello(a1,a2) ---> 15 // Caution, you can't do write @addall + 3 // with "+ 3", the write command is turned into an // expression, and in turn, the indirection is now // a name-indirection. That gives you a SYNTAX error // but you can do write $$@add^@(rou)(a1,a2) + 3 --> 18
go to post Julius Kavay · Sep 23, 2024 See the example class below Class DC.Encoding Extends %RegisteredObject { /// Take an raw stream (i.e. unencoded) and /// output a new, Base64 encoded stream. /// ClassMethod ToBase64(str) { // Base64 encoding means: // you take 3*N characters from the source // and put 4*N characters into the destination. // If the size of the source is not a multiple of 3 then // the last one or two bytes will be padded. // // If you take an N such that 4*N less or equal 32767 // (the max size of a short string) then Cache or IRIS // can work with short strings, which perform (usually) // better than long strings // // N is integer. // // A good value for N is 8190, // so you read 24570 bytes from the source and write 32760 to the destination // // Of course, you can take whatever number up to 910286 // (3 * 910286 = 2730858, 4 * 910286 = 3641144) // set len=8190*3 set flg=1 // this flag instructs $system.Encryption.Base64Encode // not to insert linebreaks at every 76 characters set new=##class(%Stream.GlobalCharacter).%New() do str.Rewind() while 'str.AtEnd { do new.Write($system.Encryption.Base64Encode(str.Read(len),flg)) } quit new } /// Take a Base64 encoded stream /// and decode it to a new stream /// /// The method itself has no information about the decoded data /// hence it assumens binary data, but you, the caller (hopefully) /// knows more about your data and can provide the correct stream /// type for the decoder. /// For exaple a character stream instead of binary. ClassMethod FromBase64(str, new = 0) { // Base64 decoding means: // you take 4*N characters from the source // and put 3*N characters into the destination // // If you take an N such that 4*N less or equal 32767 // (the max size of a short string) then Cache or IRIS // can work with short strings, which perform (usually) // better than long strings // // N is integer. // // A good value for N is 8190, // so you read 24570 bytes from the source and write 32760 to the destination // // Of course, you can take whatever number up to 910286 // (3 * 910286 = 2730858, 4 * 910286 = 3641144) // set len=8190*4 set:'new new=##class(%Stream.GlobalBinary).%New() do str.Rewind() while 'str.AtEnd { do new.Write($system.Encryption.Base64Decode(str.Read(len))) } quit new } ClassMethod Test(file) { set str=##class(%Stream.FileBinary).%New() do str.LinkToFile(file) write str.Size,! set enc=..ToBase64(str) write enc.Size,! set dec=..FromBase64(enc) write dec.Size,! } }
go to post Julius Kavay · Sep 22, 2024 In case, you talk about Cache/IRIS-Classes: Class Example.Test Extends %Persistent { Property BodyText As list Of MyList; } Class Example.MyList Extends %SerialObject { Property Text As list Of %String; } The steps to add data: set test=##class(Example.Test).%New() set list1=##class(Example.MyList).%New() do list1.Text.Insert("red") do list1.Text.Insert("green") do list1.Text.Insert("blue") do test.BodyText.Insert(list1) set list2=##class(Example.MyList).%New() do list2.Text.Insert("Joe") do list2.Text.Insert("Paul") do list2.Text.Insert("Bob") do test.BodyText.Insert(list2) write test.%Save() --> 1 zw ^Example.TestD ^Example.TestD=1 ^Example.TestD(1)=$lb("",$lb($lb($lb($lb("red","green","blue"))),$lb($lb($lb("Joe","Paul","Bob"))))) zso test BodyText(1).Text(1).: red BodyText(1).Text(2).: green BodyText(1).Text(3).: blue BodyText(2).Text(1).: Joe BodyText(2).Text(2).: Paul BodyText(2).Text(3).: Bob
go to post Julius Kavay · Sep 16, 2024 Assuming, your input value is an integer, you have , along with the other solutions, one more: // this works as long as len < 145 // set len = 120 set inp = 12345 write $e(1E120_inp,*-len+1,*) // of course, if the len is shorter than, say 10, // then you can use smaller constans like // set len=10 set inp=9 write $e(1E10_inp,*-len+1,*) A good (or even a bad) side effect of the above solution is, if you get an input value which is LONGER than the length, it will be truncated to the given length
go to post Julius Kavay · Sep 3, 2024 By the way, if you need again and again a local timestamp with decimals, just create a user defined system variable. Make a one line entry into the %ZLANGV00.mac routine: %ZLANGV00 ; User defined (system) variables // Local timestamp with decimals ZLTS() quit $now($ztz-$s($SYSTEM.Util.IsDST():60,1:0)) You can use whatever name you want as long as it starts with Z, contains uppercase chars only and do not conflict with existing names. Use it as a standard $-variable write $zlts, $zdt($zlts,3,1,3) 67086,85681.092746 2024-09-03 23:48:01.092
go to post Julius Kavay · Sep 3, 2024 Together with $now() and timezone adjustment you can have the desired result for time=$h, $now($ztz-$s($SYSTEM.Util.IsDST():60,1:0)) write time,?20,$zdt(time,3,1,3),! // assuming 60 min summertime offset // // you should get an output like thisL 67086,83334 2024-09-03 23:08:54.000 67086,83334.1341026 2024-09-03 23:08:54.134 There is an (old) undocumented function which gives the $h value with several decimal places, unfortunately the recommended replacement is more or less the above solution instead of a simple $zlts (z-local-timestamp).
go to post Julius Kavay · Aug 28, 2024 This is possible, but you have to use it the correct way. $SYSTEM.OBJ is just a shorthand for ##class(%SYSTEM.OBJECT), so the correct syntax for your desire is: job ##class(%SYSTEM.OBJ).Export("yourRoutine.mac","yourPathAndFilename.xml")
go to post Julius Kavay · Aug 22, 2024 in a routine or class, the line ClassMethod ALine() { quit $st($st,"MCODE") } gives you the line quit $st($st,"MCODE") The systemvariable $zname gives you the name of the routine, where you reference $zname and in a classmethod $this gives you the name of the class
go to post Julius Kavay · Aug 13, 2024 We need the source code, so the compiler flag for keeping the source must be on. The 38 char version does the job ClassMethod ascii() [ ProcedureBlock = 0 ] { x n i f i=32:1:126 w:$t(x)'[$c(i) *i } The 34-character version does the job too has a side effect (leaving the variable i with the last value) ClassMethod ascii() [ ProcedureBlock = 0 ] { y f i=32:1:126 w:$t(y)'[$c(i) *i }
go to post Julius Kavay · Aug 9, 2024 It shouldn't be invalid because there are no corresponding constraints. At the beginning, I thought not to participate, because of the problematic specification and example, but now, as I see, I'm not the only one with questions without answers, hence I offer an 38 char solution too (including the hint to compiler flags) and a shorter version with 34 chars, a correkt result but with "a little bit" of side effect.
go to post Julius Kavay · Aug 9, 2024 The problem is, the specification for this task is simple unprecise, and according to my opinion, gives a faulty example. Your exmple code has just a Set command but the task talks about "print out" - hence, I expected to see either a Write "whatever" or at last a Quit "whatever" comand.Also, if we talk about a method signature, I take in account the number of arguments (maybe their types) only and the return type but never their method keywords, as in the solution from Eduard, hence his solution is not only creative but valid too.I think, a fair way to mesure the size of a solution is, if you take the size of the routine which will be executed, and that is the INT routine, which is directly (we neglect the possible compiler optimizations, that's the compilers and not the users credit) compiled into a executable. How I got that code (some generator or via a macro or whatever other method) is actually irrelevant.A very good example for using or not using a method keyword is the "codemode=expression": /// you save that "Quit " but have to write "codemode=expression" /// which is not taken in account by the Implementation.Size ClassMethod Test() [ codemode = expression] { 123 } /// you have to write "Quit " and save the writing of "codemode..." /// The Implementation.Size counts that "quit " ClassMethod Test2() { quit 123 } Whatever you choose, the corresponding INT code is always "quit ..." So the bottom line is, either you should define all constraints and conditions or accept each end every clever solution.
go to post Julius Kavay · Aug 7, 2024 ClassMethod TimeDiff(inpTime = "2024-08-07 17:58:51.563") { set current=$h // or $now(tz-offset) set inpTime=$zdth(inpTime,3) quit current-inpTime*86400+$p(current,",",2)-$p(inpTime,",",2) }
go to post Julius Kavay · Aug 5, 2024 First convert the dynamic array to a Cache List and then the Cache List to Python List - voila the job is done /// Convert a dynamic array to a Cache List /// ClassMethod ArrayToList(arr) { q:'arr.%Size() $lb() s list="", it=arr.%GetIterator() while it,it.%GetNext(.key,.val) { s typ=arr.%GetTypeOf(key) s list=list_$case(typ,"object":$lb(val.%ToJSON()),"array":$lb(..ArrayToList(val)),"null":$lb(),:$lb(val)) } q list }
go to post Julius Kavay · Aug 2, 2024 First, I presume, the Studio lacks such a functionality because usually each nsp contains independent data. As an example, for each of my customers (applications) I have an dedicated namespace (of course, you may say, one can allways have an exeption), and second, if there is no readymade functionality, then make your own. Sometimes it takes longer asking questions or searching the internet then writing a quick-and-dirty "one liner", something like this: // classdefinitions are stored in ^oddDEF, mac-routines in ^rMAC // as said above, quick-and-dirty: // if the SEARCHTERM occurs in %-items, then you will get multiple hits // // the one-liner version k n i ##class(%SYS.Namespace).ListAll(.n) s n="" f s n=$o(n(n)) q:n="" f s="^|n|rMAC","^|n|oddDEF" f s s=$q(@s) q:s="" w:@s_s["SEARCHTERM" s," ",@s,! // for folks with less experience // ClassMethod SearchAllNSP(searchterm) { i ##class(%SYS.Namespace).ListAll(.n) { s n="" f {s n=$o(n(n)) q:n="" f s="^|n|rMAC","^|n|oddDEF" { f s s=$q(@s) q:s="" w:@s_s[searchterm s," ",@s,! } } } } It's up to you to left out all those multiple %-items and to add some formatting... So the bottom line of my answer is: yes, there is a way to search (whatever you want) in one go
go to post Julius Kavay · Jul 29, 2024 set myObj={} if myObj.%Size()=0 { write "This is an empty object" }
go to post Julius Kavay · Jun 23, 2024 Class DC.BigJSON Extends %RegisteredObject { ClassMethod Test(filename) { if ..SaveToFile(..MakeJSON(), filename) { write "Save OK",! write "Size ",##class(%File).GetFileSize(filename),! set input=##class(%File).%New(filename) set sts=input.Open("RS") if sts { set json={}.%FromJSON(input) set iter=json.%GetIterator() while iter.%GetNext(.key, .val) { write "key=",key," size=",$l(val)," data=",$e(val,1,10)_"...",! } } else { write $system.Status.GetOneErrorText(sts),! } } } ClassMethod MakeJSON() { set obj={} set obj.text1=$tr($j("",3600000)," ","a") set obj.text2=$tr($j("",3600000)," ","b") set obj.text3=$tr($j("",3600000)," ","c") quit obj } ClassMethod SaveToFile(obj, filename) { set file=##class(%File).%New(filename) set sts=file.Open("wnu") if sts { do obj.%ToJSON(file) do file.Rewind() use file.Name do file.OutputToDevice() do file.Close() quit 1 } else { quit sts } } } The size shouldn't be a problem USER>do ##class(DC.BigJSON).Test("/tmp/test1.txt") Save OK Size 10800034 key=text1 size=3600000 data=aaaaaaaaaa... key=text2 size=3600000 data=bbbbbbbbbb... key=text3 size=3600000 data=cccccccccc...
go to post Julius Kavay · Jun 22, 2024 The first part (Base 64 encoding is not able to encode ... unicode (2 byte) characters) is correct. The second part (data-->utf8-->base64 and base64-->utf8-->data) is correct only if there is an agreement beetwen the sender and receiver about the double-encoding (utf8+base64). If I was told, I get a base64 encoded file then I expect a file which is only base64 encoded and not a mix of several encodings including base64. A simple way to encode your document could be something like this: ClassMethod Encode(infile, outfile) { // file-binary reads bytes and not characters set str = ##class(%Stream.FileBinary).%New() set str.Filename = infile set len = 24000 // len #3 must be 0 ! set nonl = 1 // no-newline: do not insert CR+LF do str.Rewind() open outfile:"nwu":0 if $test { use outfile while 'str.AtEnd { write $system.Encryption.Base64Encode(str.Read(len),nonl) } close outfile } quit $test }
go to post Julius Kavay · May 30, 2024 Take a look at the classes $system.Security and $system.License, whichever better fulfills your needs