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.

Julius Kavay · Jul 26, 2023 go to post

As others already wrote,

write $order(^$GLOBAL(""))

gives you the first global name accessible from a given namespace. Usually, this will be a percent-global (^%...) but if you want to get the first (or all) global, which resides in a given database, the do the same as above but with extended global access

set dir = "^^c:\databases\mydb\"  // "^^" and "the path to your CACHE/IRIS.dat file"
write $order(^$|dir|GLOBAL(""))
Julius Kavay · Jul 24, 2023 go to post

There are several possibilities, using WinSCP  from Windows, Linux and Samba, etc. But if "using Cache codes" (Objectscript) is a  requirement, then the simplest way is: open a TCP-(server)port on the one end and a TCP-(client)port on the other end, write and read the data, close the connections. Voila. The job is done. I do not see any problem there. OK, maybe you need to open those ports. And do not forget, USB-Sticks exists too ;-))

Julius Kavay · Jul 22, 2023 go to post

Yes, accepts a file too, but as the following test shows, it does not make any difference... a parsing error remains parsing error

USER>set fn="/tmp/mytest.json"

USER>open fn:"nw":1 if $test { use fn write "[0.1, .2]",! close fn write "OK" } else { write "Houston, we have..." }
OK
USER>write {}.%FromJSON(fn)

<THROW>%FromJSON+38^%Library.DynamicAbstractObject.1 *%Exception.General Parsing error 3 Line 1 Offset 7
USER 2e1>

So where is that forgiving Cache/IRIS version?

Julius Kavay · Jul 21, 2023 go to post

Do you have a code snippet for us? Something like

write mylist.%IsA("%ListOfDataTypes") --> 1
set item = mylist.%GetAt(2)
//
// Now the big question: what do you (want to) do with this item?
//
// do you try to lock a global: lock ^myGlobal(item) ?
// do you try to open (a possible locked) Object: set obj=##class(some.class).%OpenId(item [,4]) ?
// something else?
Julius Kavay · Jul 21, 2023 go to post

May I ask, which Cache or IRIS version you use?

USER>write $zv
IRIS for UNIX (Ubuntu Server LTS for x86-64) 2021.2 (Build 649U) Thu Jan 20 2022 08:49:51 EST
USER>write ##class(%DynamicAbstractObject).%FromJSON("[0.1, .2]")

<THROW>%FromJSON+38^%Library.DynamicAbstractObject.1 *%Exception.General Parsing error 3 Line 1 Offset 7
USER 2e1>

As you see, my IRIS is by far not so forgiving... ☹

Julius Kavay · Jul 18, 2023 go to post

Nice, now we know nearly everything, except the most important info: what is the content of pField?

I assume, pObject contains the above JSON, i.e.

set pObject = {"priority": "2",
               "lastmodifieduser": "PORTAL",
               "assignedto": "jdoe01 STAFF",
               ...
               }
               
Julius Kavay · Jul 18, 2023 go to post

I'm not aware of any $ISJSON() or similar named function but you can easily make your own

ClassMethod IsJSON(str)
{
	try { ret:{}.%FromJSON(str) 1 } catch e { ret:e.Code=3 0 throw e }
}

set a="{name:""John Doe"" "
set b="{""name"":""John Doe"" }"

write ##class(some.class).IsJSON(a) --> 0
write ##class(some.class).IsJSON(b) --> 1
write ##class(some.class).IsJSON()  --> <UNDEFINED>zIsJSON+1^...  *str
Julius Kavay · Jul 17, 2023 go to post

Absolutely right. It's more readable,  without stumbling over millions of quotes and parenthesis during constructing (concatenate) the name of that globals ;-) 
I used the "string version" to show him/her, the global can be used even if the name is given as a string.

Julius Kavay · Jul 15, 2023 go to post

As an addition to the above possibilities, you can  ALWAYS use (assumed, you have the rights to access the database where the global lives - this is true for both of the above too) extended global access.

Just one remark, this kind of access is possible but not the recommended way for creating regular classes (databases) rather to occasionally (on demand) access data from other namespace and/or namespaces.

set nsp = "USER"
set myvar = ^|nsp|MyGlobal(1,2,3)

If there is no namespace associated with the database (where the global lives) just use the implicit namespace

set dir = "^^C:\mydatabases\myfolder\"    // win-world, "^^pathToTheDatabase"
set dir = "^^/opt/mydatabases/myfolder/"  // unix-world, 
write ^|dir|myglobal(1,2,3)

// and, of course all other commands and functions
kill ^|dir|myglobal(1)
write $order(^|dir|myglobal(1,2))
set isDef = $data(^|dir|myglobal)
Julius Kavay · Jul 15, 2023 go to post

Indirection is your friend, which of course, works for globals, locals and other things too.

set ^myglobal="This is the root node"
set ^myglobal(12)="A node on level 1"
set ^myglobal(17)="More level 1 node"
set ^myglobal(17,1)="Data on the second level"
set ^myglobal(19,3)="More data on the second level"

; now start to play indirection
set someVariable="^myglobal" // the better way were: set someVariable=$name(^myglobal)

; and get the content of the above global
write @someVariable // --> This is the root node
write @someVariable@(12) // --> A node on level 1
write @someVariable@(17,1) // --> Data on the second level

; the same as above
set myVariable="^myglobal(17)" // Better: set myVariable=$name(^myglobal(17))
write @myVariable // --> More level 1 node
write @myVariable@(1) // Data on second level

; a bit overcomplicated
set string1="^"
set string2="myglobal"

write @(string1_string2_"("_(15+4_","_(1+2))_")") // --> More data on second level

So just (re)read the docu about indirection...

Julius Kavay · Jul 8, 2023 go to post

Somehow I don't understand your problem. If I create a simple class with a %Text property, insert some text data and then query for the word "time" I get it without problem.

Class DC.TextData Extends %Persistent
{
Property Comment As %Text(LANGUAGECLASS = "%Text.English", MAXLEN = 1000);
}

Now some data and the query

USER>d ##class(DC.TextData).%KillExtentData()

USER>s tt=##class(DC.TextData).%New(),tt.Comment="Notice, time is money." w tt.%Save()
1
USER>s tt=##class(DC.TextData).%New(),tt.Comment="It's time for a break." w tt.%Save()
1
USER>s tt=##class(DC.TextData).%New(),tt.Comment="There is no business like show business." w tt.%Save()
1
USER>d $system.SQL.Shell()
SQL Command Line Shell
----------------------------------------------------

The command prefix is currently set to: <<nothing>>.
Enter <command>, 'q' to quit, '?' for help.
[SQL]USER>>select $zversion
5.      select $zversion

Expression_1
IRIS for UNIX (Ubuntu Server LTS for x86-64) 2021.2 (Build 649U) Thu Jan 20 2022 08:49:51 EST

1 Rows(s) Affected
statement prepare time(s)/globals/cmds/disk: 0.0006s/4/140/0ms
          execute time(s)/globals/cmds/disk: 0.0008s/0/394/0ms
                          cached query class: %sqlcq.USER.cls7
---------------------------------------------------------------------------
[SQL]USER>>select * from DC.TextData where Comment %CONTAINS('time')
6.      select * from DC.TextData where Comment %CONTAINS('time')

ID      Comment
1       Notice, time is money.
2       It's time for a break.

2 Rows(s) Affected
statement prepare time(s)/globals/cmds/disk: 0.0005s/4/140/0ms
          execute time(s)/globals/cmds/disk: 0.0043s/30/4,322/0ms
                          cached query class: %sqlcq.USER.cls2
---------------------------------------------------------------------------
[SQL]USER>>quit

USER>
Julius Kavay · Jul 7, 2023 go to post

I know exactly nothing about healthcare, healthcare data, healthcare-classes and objects... sorry. For me it's a simple ObjectScript problem, where you try to do something (probably converting a dynamic object to its string representation - the above error message is known to me for this case). Does such a conversion occurs (somewhere) in your code?

Julius Kavay · Jul 7, 2023 go to post

The error message <METHOD NOT SUPPORTED> says everything.

USER>s obj={"name":"john", "value":65}

USER>w obj.%ToJSON() // --> {"name":"john","value":65}

USER>s obj={"name":"john", "value":65, "dynObj":{"info":"something"} }

USER>w obj.%ToJSON() // --> {"name":"john","value":65,"dynObj":{"info":"something"}}

USER>s obj={"name":"john", "value":65, "dynObj":{"info":"something"}, "cosObj":(##class(%Net.HttpRequest).%New()) }

USER>w obj.%ToJSON() // --> <METHOD NOT SUPPORTED> *%ToJSON,%Net.HttpRequest

So the problem is, you try to "stringify" (JS-speech) a dynamic object, where one of the properties contains a non-dynamic object (%Net.HttpRequest in the above example).

Julius Kavay · Jul 7, 2023 go to post

There are no reserved words for %Contains but there is a requirement on the field (property) type. Excuse me for my arrogance, but instead of reading the documentation everybody thinks, it's cheaper to ask a question in the developer community, to get a ready made solution. So please read this first and if something is not clear, then tell it us what you do not understand and we will help you to understand.

Julius Kavay · Jun 30, 2023 go to post

I have absolutely nothing to do with health and HL7 etc. except I know, they exists but the $length(string,delimiterstring) function will you always tell, how many subfields a string has for a given delimiter string.

write $l("","-") --> 1
write $l("abc-def","-") --> 2
write $l("abc-","-") --> 2
write $l("abc-def-ghi","-") --> 3
etc.
Julius Kavay · Jun 23, 2023 go to post

Maybe there are tools to dump a dynamic object, I don't know, but you can always write your own short method

/// obj: a dynamic object
/// opt: an option, how to display array elements
///      0: just show the index number
///      1: show the parenthesized index
///      2: show index number in a %Get() method
/// tag: optional, the name of the <obj> variable
/// 
ClassMethod DumpJSON(obj, opt = 2, tag = "")
{
	set itr=obj.%GetIterator(), arr=obj.%IsA("%DynamicArray") set:tag]"" tag=tag_"."
	while itr.%GetNext(.key, .val) {
		set:arr key=$case(opt, 2:"%Get("_key_")", 1:"("_key_")", :key)
		if $isobject(val), val.%IsA("%DynamicAbstractObject") {
			do ..DumpJSON(val,opt,tag_key)
		} else { write tag,key,": ",val,! }
	}
}

For ease of use, put it into the %ZLANGC00.mac, for example

%ZLANGC00   ; Command extensions

// Dump a dymanmic object
ZDDUMP(obj,opt,tag) Public { do ##class(your.utility).DumpJSON(obj,.opt,.tag) }

For the data, you mentioned above, the following will be displayed

set metaDynObj={"versionId":"2","security":[{"system":"http://terminol....}

zddump metaDynObj::"metaDynObj"
metaDynObj.versionId: 2
metaDynObj.security.%Get(0).system: http://terminology.hl7.org/CodeSystem/v3-Confidentiality
metaDynObj.security.%Get(0).code: U
metaDynObj.security.%Get(0).display: unrestricted

zddump [11,22,33]
0: 11
1: 22
2: 33

zddump [11,22,33]:1:"x"
x.(0): 11
x.(1): 22
x.(2): 33
Julius Kavay · Jun 21, 2023 go to post

Why do you want to hide CSP files? That would be a mindless task.

Suppose, you encrypt your CSP (into fancy binary data). No browser would understand that! Browsers need plain text data. To hide the code on the server is also meaningless, you can read that CSP in the browser, that's the sense of a webpage .

Julius Kavay · Jun 18, 2023 go to post

For routines (*.int and *.mac)
- first, this is ABSOLUTE necessary, EXPORT your routines (to an file, to source-control-system, etc)
  for example: do $system.OBJ.Export(...)
- compile the routinies (which will be already done)
- delete the *.int and *.mac routinies keeping the *.obj

For classes (*.cls)
- first, this is ABSOLUTE necessary, EXPORT your classes (to an file, to source-control-system, etc)
  for example: do $system.OBJ.Export(...) do $system.OBJ.ExportPackage(...)
- compile the class(es) (which will be already done)
- put the class in deployed mode
  do $system.OBJ.MakeClassDeployed(...)
  
That's all. But DO NOT forget for the export, in elsecase you have to start over with your routines and classes by zero!

Julius Kavay · Jun 12, 2023 go to post

As I started with MUMPS, $H was a few days ahead of 50000, this means, I wrote my first programm (MUMPS V4b on a DEC PDP-11/34) even before ISC was founded. I have never made a direct use of those functions but, if a recall it right, they are used during the installation process (database creation, etc.) .  A quick look into the oldest docs I have (Cache 2.3) says nothing about those functions.

Julius Kavay · Jun 9, 2023 go to post

Correct.
But (in case of need) there is a workaround (assuming, args is an JSON-array of arguments):

kill tmp
set tmp=args.%Size()
for i=1:1:tmp set tmp(i)=args.%Get(i-1)
set resultSet = ##class(%SQL.Statement).%ExecDirect( , sql_whereClause, tmp...)
Julius Kavay · Jun 9, 2023 go to post
kill args
set args($i(args))="arg1"
set args($i(args))="arg2"
set args($i(args))="arg3"
...
set resultSet = ##class(%SQL.Statement).%ExecDirect( , sql_whereClause, args...)
Julius Kavay · Jun 6, 2023 go to post

RemoveDirectoryTree(some_dir) works, if it returns FALSE to you so
- either your Ensemble instance has no rights to delete files and directories
- or you feed RemoveDirrectoryTree() with a filename or with a  nonexistent directory

Try the following:

write FileUnZip,! // this should be an existing DIRECTORY
write ##class(%File).Attribute(FileUnZip),! // this should be 16 (on Windows)
write ##class(%File).RemoveDirectoryTree(FileUnZip),! // 1=removed, 0=not-removed
Julius Kavay · May 23, 2023 go to post

In some way, I wonder about your question. This is a very specific question and a correct and accurate answer can be given by Intersystems only. If you take a look on the articles here, the most of them are about other lanuages, new technologies etc. but none of Cache/IRIS internals. If you look on the questions, very often they start with "I'm new to ISC technologies, need some help". Do you really expect an answer from an newbe? Or you really expect an answer from a Kubernetes, Phyton, Angular etc. developer? On the other hand, you are an Intersystems employee, so why don't ask somebody from the developer department? What about contacting WRC? I would be ashamed to ask such a question here.

Julius Kavay · May 18, 2023 go to post

My solution, assuming that B is originated from A by some number of left or right rotations

ClassMethod RotationRight(a As %String, b As %String) As %Integer
{
    f i=0:1 ret:$e(a_a,$l(a)+1-i,*-i)=b i
}
    
ClassMethod RotationLeft(a As %String, b As %String) As %Integer
{
    f i=0:1 ret:$e(a_a,i+1,$l(a)+i)=b i
}
write ##class(%Dictionary.MethodDefinition).%OpenId("...||Rotate...").Implementation.Size

gives  40 (for RotateRight) and 38 (for RotateLeft).

Julius Kavay · May 18, 2023 go to post

I have no idea, from which error you talk.

ClassMethod MyRequest()
{
	set req = ##class(%Net.HttpRequest).%New()
	set req.Server = "msedgewebdriverstorage.blob.core.windows.net"
	set req.SSLConfiguration="Open"
	set req.Https=1
	do req.Get("/edgewebdriver/?comp=list")
	set rsp=req.HttpResponse
	
	if rsp.StatusCode=200 {
		write "Data Size: ",rsp.Data.Size,!
		write "Dumping the first 256 bytes..." zzdump rsp.Data.Read(256)
		
	} else {
		write "Return Code: ",rsp.StatusCode,!
		write "Resp.Phrase: ",rsp.ReasonPhrase,!
	}
	
	quit rsp
}

The output is just fine... no errors.

do ##class(...).MyRequest() --->

Data Size: 1832857
Dumping the first 256 bytes...
0000: EF BB BF 3C 3F 78 6D 6C 20 76 65 72 73 69 6F 6E         <?xml version
0010: 3D 22 31 2E 30 22 20 65 6E 63 6F 64 69 6E 67 3D         ="1.0" encoding=
0020: 22 75 74 66 2D 38 22 3F 3E 3C 45 6E 75 6D 65 72         "utf-8"?><Enumer
0030: 61 74 69 6F 6E 52 65 73 75 6C 74 73 20 43 6F 6E         ationResults Con
0040: 74 61 69 6E 65 72 4E 61 6D 65 3D 22 68 74 74 70         tainerName="http
0050: 73 3A 2F 2F 6D 73 65 64 67 65 77 65 62 64 72 69         s://msedgewebdri
0060: 76 65 72 73 74 6F 72 61 67 65 2E 62 6C 6F 62 2E         verstorage.blob.
0070: 63 6F 72 65 2E 77 69 6E 64 6F 77 73 2E 6E 65 74         core.windows.net
0080: 2F 65 64 67 65 77 65 62 64 72 69 76 65 72 2F 22         /edgewebdriver/"
0090: 3E 3C 42 6C 6F 62 73 3E 3C 42 6C 6F 62 3E 3C 4E         ><Blobs><Blob><N
00A0: 61 6D 65 3E 31 30 30 2E 30 2E 31 31 35 34 2E 30         ame>100.0.1154.0
00B0: 2F 65 64 67 65 64 72 69 76 65 72 5F 61 72 6D 36         /edgedriver_arm6
00C0: 34 2E 7A 69 70 3C 2F 4E 61 6D 65 3E 3C 55 72 6C         4.zip</Name><Url
00D0: 3E 68 74 74 70 73 3A 2F 2F 6D 73 65 64 67 65 77         >https://msedgew
00E0: 65 62 64 72 69 76 65 72 73 74 6F 72 61 67 65 2E         ebdriverstorage.
00F0: 62 6C 6F 62 2E 63 6F 72 65 2E 77 69 6E 64 6F 77         blob.core.window

You have to work with the Data property of the response object (which is a 1.8MB  stream)

Julius Kavay · May 16, 2023 go to post

For Task2 (hamming distance) and Task5 (double chars) there is also a solution without using a (for, while, etc.) loop .

Julius Kavay · May 16, 2023 go to post

Or just simply

"The problem with computers is, that they always do what we tell them to do and not what we want."

Julius Kavay · May 15, 2023 go to post
Class DC.Samples Extends %RegisteredObject
{

/// partition an array into two subarrays
/// return [[even], [odd]]
ClassMethod Task1a(x As %DynamicArray) As %DynamicArray
{
	set t(0)=[],t(1)=[]
	for i=0:1:x.%Size()-1 do t(x.%Get(i)#2).%Push(x.%Get(i))
	quit [(t(0)),(t(1))]
}

/// partition an array into two subarrays
/// return [[even], [odd]]
ClassMethod Task1b(x As %DynamicArray) As %DynamicArray
{
	set t(0)=[], t(1)=[], i=x.%GetIterator()
	while i.%GetNext(,.v) {  do t(v#2).%Push(v) }
	quit [(t(0)),(t(1))]
}

/// hamming distance of two strings
ClassMethod Task2(x As %String, y As %String) As %Integer
{
	if $l(x)-$l(y) quit "<Error>"	// strings have to be the same length
	set r=0
	for i=1:1:$l(x) set r=$e(x,i)'=$e(y,i)+r
	quit r
}

/// encrypt an string
ClassMethod Task3(x As %String) As %String
{
	quit $tr($re(x),"aeiou","01223")_"aca"
}

/// check a string for identical chars
ClassMethod Task4(x As %String) As %Boolean
{
	quit $tr(x,$e(x))=""
}

/// double chars
ClassMethod Task5(x As %String) As %String
{
	f i=$l(x):-1:1 s $e(x,i)=$e(x,i)_$e(x,i)
	q x
}

}