I have made several callouts but never a callin (with userlogin), like you trying to do.
You wrote, you have several instances (Cache and IRIS) installed, presumably on the same hardware respective OS. Take a look in one of your Cache installation: <InstallDirectory>\dev\Cache\callin\
There are three files worth to study: sampcallin.c, sampcallint.c and shdir.c
The callin mechanism does not needs IPs and ports. To find out if anything has changed as a result of switching from Cache to IRIS, please contact WRC.

 Put your variables into parentheses, i.e. 

 return {"value1":(val1), "value2":(val2)}
Julius Kavay · Oct 31, 2025 go to post

JavaScript uses underscores as separators in (big)number literals.

<script>alert(1_234);</script> displays 1234
<script>alert(12_345_678_901_234_567_890_123n);</script>  displays 12345678901234567890123

Maybe there is a quirk/problem in VS terminal...

Julius Kavay · Sep 28, 2025 go to post

Oh yes, you are able to create an instance of

Class Your.Page Extends %CSP.Page
{
Property Name As %String [ InitialExpression = "Joe" ];
}

class because the inheritance goes as follows:
Your.Page <-- %CSP.Page <-- %Library.Base <-- %Library.SystemBase
and the %Library.SystemBase donates you the %New() method.

Julius Kavay · Sep 28, 2025 go to post

My guess is, because abstract classes (%CSP.Page is an abstract class) can't be instantiated, your subclass lacks the generator methos for property initialisation.

But there is a simple solution:

Class Your.Page Extends (%RegisteredObject, %CSP.Page)
{
Property Name As %String [ InitialExpression = "Joe" ];
}

Well, the world is right again

set page=##class(Your.Page).%New()
write page.Name --> Joe
Julius Kavay · Aug 18, 2025 go to post

Ha ha ha 😂, that's a big mistake. Those are old functions (for even older applications, maintained for backward compatibility only)  in the mean time all replaced by the $list...() functions.

Julius Kavay · Jul 20, 2025 go to post

You have a status (or error code), OK, now take that code and make it more readable:

set code=<put here your code>
write $system.Status.GetErrorText(code)

I think, it will be some kind of authentication issue...

Julius Kavay · Jul 7, 2025 go to post

In SystemManagementPortal goto:

SystemAdministration --> Configuration --> AdditionalSettings --> StartupSettings: JobServers

Julius Kavay · Jun 8, 2025 go to post

First, measuring execution times on modern operating systems where multiple processes run in parallel (on multiple CPUs) is challenging. The following demo application assigns a value to a variable in four different ways:
– in a single method
– in two methods, both in the same class
– in two methods where one method code is in an inherited class, and
– in two methods where one method is in a different class

As expected, the first is the fastest (keyword: loop unrolling) and the last is the slowest, the other two take about the same time.

Class DC.Times Extends (%RegisteredObject, TimesAbstract)
{
ClassMethod ShowTimes()
{
	while $zh#1 {} set t1=$zh for i=1:1:1E6 { do ..Complete() } set t1=$zh-t1
	while $zh#1 {} set t2=$zh for i=1:1:1E6 { do ..OneClass() } set t2=$zh-t2
	while $zh#1 {} set t3=$zh for i=1:1:1E6 { do ..InhClass() } set t3=$zh-t3
	while $zh#1 {} set t4=$zh for i=1:1:1E6 { do ..TwoClass() } set t4=$zh-t4
	write $j(t1,9,5), $j(t2,9,5), $j(t3,9,5), $j(t4,9,5),!
}
/// The complete application is carried out in one method
ClassMethod Complete()
{
	set x=12345
	set y=12345
}
/// The entire application is done in the same class, but with different methods
/// Both methods are local (OneClass + LocTask)
ClassMethod OneClass()
{
	set x=..LocTask()
	set y=..LocTask()
}
/// The entire application is done in the same class, but with different methods
/// One method is local (InhClass) the other is inherited (InhTask)
ClassMethod InhClass()
{
	set x=..InhTask()
	set y=..InhTask()
}
/// The entire application uses two methods in two different classes
ClassMethod TwoClass()
{
	set x=##class(DC.Times2).ExtTask()
	set y=##class(DC.Times2).ExtTask()
}
/// As an "application" we simply return a constant value
ClassMethod LocTask(val)
{
	quit 12345
}
}

Class DC.Times2 Extends %RegisteredObject
{
/// As an "application" we simply return a constant value
ClassMethod ExtTask(val)
{
	quit 12345
}
}

Class DC.TimesAbstract [ Abstract ]
{
/// As an "application" we simply return a constant value
ClassMethod InhTask(val)
{
	quit 12345
}
}

Some time values

USER>

USER>f i=1:1:3 d ##class(DC.Times).ShowTimes()
  0.10833  0.19660  0.19649  0.22001
  0.10837  0.19657  0.19608  0.22000
  0.10826  0.19661  0.19603  0.21992

USER>

USER>f i=1:1:3 d ##class(DC.Times).ShowTimes()
  0.10998  0.19711  0.19643  0.22006
  0.10830  0.19657  0.19624  0.22013
  0.10822  0.19684  0.19628  0.22139

USER>

USER>w $zv
IRIS for UNIX (Ubuntu Server 22.04 LTS for x86-64) 2025.1 (Build 225_1U) Fri May 16 2025 12:18:04 EDT
USER>

Second, the choice of development method (use of include files, class inheritance, multiple classes, a large method in an even larger class, etc.) depends on other factors such as maintainability, runtime priority, etc.

Julius Kavay · May 21, 2025 go to post

It's not a permission issue!
A simple check tells you:

write ##class(%SYS.Namespace).GetRoutineDest(,"%Test") --> ^/opt/isc/icindy/mgr/irislib/

a routine named %Test will bes stored in the "irislib" database.
Now, if you take a look at the irislib database, you will see, it's a READONLY database, hence you get the <PROTECT> error. A readonly means read only, even for the Superuser!

If you absolutely need to name that routine with %-something (except %Z* and %z*) than:
- 1) remove the readonly flag from the database in question
  2) save your routine
  3) turn on the readonly flag
  4) for every change in that routine repeat the abowe game: 1), 2) and 3)
- and don't forget to make a copy of your %-something routine
  because each IRIS update REMOVES ALL %-routines except those %Z* and %z*
  

Julius Kavay · May 14, 2025 go to post

Despite the misleading error message, the solution (with the help of WRC) is:  IRIS  native API requires a %Developer role

Julius Kavay · Feb 10, 2025 go to post

Before you start reading, set the lineterminator property to the desired value

 do myStream.Rewind()
 set myStream.LineTerminator=$c(13,10)  // or $c(10)
 
 // or more general
 set myStream.LineTerminator=$case($zversion(1), 2:$c(13,10), 3:$c(10), :"")
 
 // now start reading
 set line = myStream.ReadLine()
 ...
 ...
Julius Kavay · Feb 7, 2025 go to post

And do not forget, if the application has/uses parts of "older code" then the so called "naked syntax" may also be a issue (of course not, if you just want to know the name of the global).

Classmethod Test()
{
  kill ^myGlobal
  kill ^yourGlobal
  set ^myGlobal(2)="some data"
  do ..moreData("data1")
  set ^yourGlobal(3)="other data"
  do ..moreData("data2")
  
  // Now, the globals look like
  //
  // ^myGlobal(2)="some data"
  // ^myGlobal(9)="data1"
  //
  // ^yourGlobal(3)="other data"
  // ^yourGlobal(9)="data2"
}

ClassMethod moreData(data)
{
  set ^(9)=data	
}

Beside all the "nice" combinations of direct sets, indirections, naked synates etc. do not forget, your application may call routinies/methods which are in deployed mode (third party APIs and utilities - hopefully with  documentation)

Julius Kavay · Feb 4, 2025 go to post

With the help of a standard editor only - that will be a difficult and cumbersome task, for example, in the below snippet try to find the "^Test" global (not the routine ^Test):

 set value = ^Test  // take a value from the global ^Test
 do ^Test           // call the routine ^Test
 
 // a more complex case
 //
 set ref = "^Test"      // in this case you are lucky
 set ref = "^" _ "Test" // this could be a stumbling stone
 // few lines later
 set value = @ref  // get the value of ^Test global
 do @ref           // call the routine ^Test

You will need some kind of an "intelligent" editor which can make a difference between a call (do) like operation and a "get-value" like operation. The one I know of (but I have never used it, so I don't know how good it works) is the RE/parser of GJS. Asking Google is a good starting point.

Julius Kavay · Jan 17, 2025 go to post

This is the rare case where the statement “RTFM” leads you down the wrong path or, better said, reading the documentation confuses you more than informs.

So you have to change your viewpoint. And that depends on, what do you do.
If you work with ObjectScript (and of course, with objects) then your first citation "Case-sensitive: variable names..." holds.

But if you are more that SQL guy, who day in, day out busy with Updates, Inserts and Selects, then you will say, "No, no, my table and field names aren't case sensitive".

And now we sit in the middle of those two worlds, where a case sensitive Objectscript meets a case insensitive SQL world.

So what is the status quo?

All the (persistent) classes can be seen (and used) as SQL tables, but this freedom has its price (or, better, its consequence): you must be aware, that the two worlds (ObjectScript and SQL) do not use the same case-rule.

An ObjecScript class Test.Person can be named in SQL as Test.Person, as TEST.Person, as TEST.PERSON or even as TeSt.PeRsOn.

To de-escalate the resulting confusion, the following rule was added:

It's forbidden to have two ObjectScript classes, which have the same spelling but (somewhere) a different case (the Studio wizard checks this). I hope, this helps a bit...

Julius Kavay · Oct 6, 2024 go to post

Indirection has its rule:  Indirection works with PUBLIC variables,
i.e. the variable, you address, mustbe a public variable, in your case the <arg> variable.
This is due to compatibility with old applications,
developed before the introduction of the block structure.
  
You have two options

instead of using argument indirection (what you currently do),
use name indirection for label and routinname, see method Test1()

@lab and @(rou)  because label- and routine-names are not variables.

If you want to keep argument indirection, just tell your class, that certain variables were PUBLIC
see method Test2()

In your example, you got a wrong result because, by chance the variable <arg> was defined in the terminal session with the same value as in methode code, see method Test3()


ClassMethod Test1()
{
    s arg="argument-1"
    s lab="say", rou="hello"
    d @lab^@(rou)(arg)
}

ClassMethod Test2() [ PublicList = arg ]
{
	s arg = "argument-2"
	s routine = "say^hello(arg)"
	d @routine
}

ClassMethod Test3()
{
	s routine = "say^hello(arg)"
	d @routine
}

Now some tests in a terminal

kill   // we kill all local variables
do ##class(your.class).Test1() ---> argument-1

kill
do ##class(your.class).Test2() ---> argument-2

kill
do ##class(your.class).Test3() ---> <UNDEF> *arg ==> missing arg

kill
set arg="surprise"
do ##class(your.class).Test3() ---> surprise

// you can prove things the other way too

set arg="my-value"  // variables, defined in a terminal session are public
do ##class(your.class).Test1() ---> argument-1
write arg --> my-value  // arg wasn't overwritten!

do ##class(your.class).Test2() ---> argument-2
write arg --> argument-2  // arg IS OVERWRITTEN

Method Test3() shows, indirection works with public variables

Julius Kavay · Sep 23, 2024 go to post

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,!
}

}
Julius Kavay · Sep 22, 2024 go to post

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

Julius Kavay · Sep 16, 2024 go to post

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

Julius Kavay · Aug 22, 2024 go to post

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

Julius Kavay · Aug 7, 2024 go to post
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)
}
Julius Kavay · Aug 5, 2024 go to post

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
}
Julius Kavay · Aug 2, 2024 go to post

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

Julius Kavay · Jun 23, 2024 go to post
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...

Julius Kavay · Jun 22, 2024 go to post

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
}
Julius Kavay · May 13, 2024 go to post

If your system does not support JSON (i.e. pre 2016.2?) then give this "dirty trick" a try:

- add a zero-width-space character to your numbers
- create the output stream
- remove the zero-width-space characters

Instead of the zero-width-space you can use any other character too, which does not appear in your data (binary data should be base64 encoded).

ClassMethod WithQuotes()
{
	set zwsp = $c(8203) // zero-width-space
	set obj = ##class(%ZEN.proxyObject).%New()
	
	set obj.ID = 1234_zwsp
	set obj.Number=123.45_zwsp
	
	if ##class(%ZEN.Auxiliary.jsonArrayProvider).%WriteJSONStreamFromObject(.tmp,obj) {
  		set json=##class(%Stream.TmpBinary).%New()
		do tmp.Rewind()
		while 'tmp.AtEnd { do json.Write($tr(tmp.Read(32000),zwsp)) }
	}
	
	do json.Rewind()
	write json.Read(json.Size)
}