Julius Kavay · Dec 20, 2021 go to post

A simple

write ##class(%SYS.Namespace).GetPackageDest(yourNsp, yourPackage)

should do the trick

The same goes for globals and routines

write ##class(%SYS.Namespace).GetGlobalDest(yourNsp, yourPackage)

write ##class(%SYS.Namespace).GetRoutineDest(yourNsp, yourPackage)

if yourNsp is not provided, the current Nsp will be used

Julius Kavay · Dec 14, 2021 go to post

Excuse me for my sassy answer, but I'm pretty sure, you' are asking the wrong question. Data can't be stored "case sensitive" (they are stored as they are) but stored data can be processed case sensitive or ignoring the cases, according to ones demand.

So it depends on how your Crystal Reports sees the data.

Julius Kavay · Dec 4, 2021 go to post

Just to put things in right perspektive, those "one letter commands" and "a lot of them in the same line" were neither tempting nor addictive, they were simply necessity!

At the time of the birth of MUMPS (the core of Cache/IRIS/etc.), more then 50 years ago in the second half of 1960es,  memory (which was a real core memory at the time) was rare and expensive and was measured in units of kilobytes! Just to contrast, today's server have the same amount of RAM, but in gigabytes, that's a factor of one million!

As a consequence of memory shortage and because MUMPS of that time was interpreted (i.e. you loaded the sourcecode into memory), one had to utilize each and every possibility to save memory. One of those possibilities were the ability of the language to short each command to one letter and to put as many commads as possible into one line (thereby saving line-ending bytes).

The tools (to save memory) of that (ancient) time were argumentless IFs and ELSES, short (variable-, global- and routine) names, commands with postcondition and sophisticated programming.

Last but not least, if one aims to "modernize" thos old applications, should be keept in mind, especially, if one is not so familiar with the old fashioned style and methods, there will be many unexpected pitfalls.

Sample1: on old printers, the line with "Total..." will be printed "bold-alike"

 write "last item",?15,$j($fn(val,",",2),10),!
 write ?15,"----------",! do  do  do
 . write $c(13),"Total",?15,$j($fn(sum,",",2),10)
 write !!!,"Due date for payment ....",!

Sample2: converting from:

 ; normal flow
 do
 . ; nested
 . ; commands
 ; normal flow

into:

 ; normal flow
 if 1 {
   ; nestd
   ; commands
 }
 ; normal flow

will be in most cases OK, except, if the nested part uses the current value of $STACK:
this is now one less then in case of argumentless DO!

Julius Kavay · Nov 30, 2021 go to post

If you look for those informations from Cache/IRIS then a good starting point is:

do $system.CPU.Dump()

Advantage: you get the same (output) format on Linux and Windows

Julius Kavay · Nov 17, 2021 go to post

According to the above task, "...a string of comma-separated integers ...", inputs like

"3, 5, 7, 8, 10, 12, 14, 16" and / or
"3, 5, 7, 7, 7, 7, -8, -6, -4, -21,-21,-21, 77,77,77,77"

are also valid? Those are all integers too.

Julius Kavay · Nov 13, 2021 go to post

The reason is, the database encryption is not activated - see the last line in your screenshot.

Go to MangementPortal, SystemAdministration --> Encryption. There you can create the encryption keys and activate the encryption.

Julius Kavay · Nov 8, 2021 go to post

I know exactly nothing about HealthShare... so I can just suggest two ways to remove the unwanted characters from a string:

use $zstrip()

set inpData="some wild sequence of characters"
set cleanData = $zstrip(inpData, "*C") // this removes all control characters (0x00-0x1f, 0x7f-0x9f)

the other way is to define a set of valid characters and remove all others

set inpData="some wild sequence of characters"
set validChars = "012...89ABC..Zabc..z..."
set badChars = $translate(inpData, validChars) // remove from input all valid chars, leftover are bad chars
set cleanData = $translate(inpData, badChars) // remove all the bad chars

or just the short version

set cleanData = $translate(inpData, $translate(inpData, validChars))
Julius Kavay · Nov 4, 2021 go to post

Oh, one have to hover over the function name to see, that's a link! Maybe I have to blame my monitor because of the more grayish then bluish color.

Julius Kavay · Nov 4, 2021 go to post

Usually, I solve such problems (it's faster then searching for some funy SQL or other functions) by writing my own function/method/expression, depending on the current requirement. 

ClassMethod TimeZoneToHorolog(tz)
{
   set t=$zdth(tz,3,5), t=t*86400+$p(t,",",2)+($e(tz,20,22)*60+$e(tz,23,24)*60)
   quit t\86400_","_(t#86400)
}

Assuming, tz contains a timezone formatted string like:

2021-11-04T11:10:00+0300
Julius Kavay · Nov 4, 2021 go to post

According to documentation,  the tformat paramer 5 is ignored:

"Specify time in the form "hh:mm:ss+/-hh:mm" (24-hour clock). The time is specified as local time. The following optional suffix may be supplied, but is ignored: a plus (+) or minus (–) suffix followed by the offset of local time from Coordinated Universal Time (UTC). A minus sign (-hh:mm) indicates that the local time is earlier (westward) of the Greenwich meridian by the returned offset number of hours and minutes. A plus sign (+hh:mm) indicates that the local time is later (eastward) of the Greenwich meridian by the returned offset number of hours and minutes."

The same goes for the parameter values 6, 7 and 8

write $zdth("2021-11-04T11:10:00+0100",3,5)  --> 66052,40200
write $zdth("2021-11-04T11:10:00+0200",3,5)  --> 66052,40200
write $zdth("2021-11-04T11:10:00-0100",3,5)  --> 66052,40200
Julius Kavay · Nov 3, 2021 go to post

That part of the question was "out of my viewport". Yes, that's an important point.

Julius Kavay · Nov 3, 2021 go to post

You asked for "cached routines"... the above clear buffer function, as far, as I know, resets the global buffers only, not the routine buffers. Just for completeness. Maybe someone with a more detailed knowledge could me agree or disagre...

Julius Kavay · Nov 3, 2021 go to post

It's a funny request... everybody wants to get a job done as fast as possible, but you want the opposite ;-)

You can clear all buffers, as Vitaliy Serdtsev  suggested, with empty buffers you will get (more or less) constante times but keep in mind, this affects (slows down) all other jobs too!

Just my2cc

Julius Kavay · Oct 30, 2021 go to post

OK, I start with the second question. I'm not aware of a function to see if a specific global is in a buffer or not but there is a routine which shows which globals are using the most buffers:

znspace "%SYS"
do ^GLOBUFF

For the first question: if a global is used continuously, then it will always be in buffer. That's the simple answer. The reality depends on many other factors: the size of the global, the size of the buffer pool, how many other globals are in use, how often is a global used, etc.

To keep a few specific global(s) always in a buffer, there is a simple trick (assuming, your Cache/IRIS installation uses the default setup and you have an unused block size):

1) Goto SystemAdministration-->Configuration-->AdditionalSettings-->Startup: and edit the DBSizesAllowed setting, by checking one of the 16K or the 32K checkboxes

2) Create a new database with the newly enabled block size. This database will hold those few (always needed) globals.

3) Goto SystemAdministration-->Configuration-->SystemConfiguration-->MemoryAndStartup: and allocate (plenty of) memory for the newly created buffersize. Please consider,  after this chanhe, you have to RESTART your system!

4) Copy the global(s) in question into the newly created database:

  merge ^|"^^c:\path_to_new_database\"|GlobalName = ^|"^^c:\path_to_old_database\"|GlobalName

5) Create a Global mapping for the globals in question to the new location.

6) Start working... If everything is OK (which should be) and you are happy, delete the old global data to free up database space:   

kill merge ^|"^^c:\path_to_old_database\"|GlobalName

7) In a standard installation, you have allocated  one buffer pool (with the standard 8KB buffer size). So all your processes faiting to get the needed globals into that buffer pool.

With the above configuration you have two buffer pools, one for the standard 8KB database blocks and one for the new 16KB (or wahtever size you have choosen) database blocks. So you can keep important globals in a separate buffer pool. If you can manage (this will be application dependent) to give this buffer pool the same size as the database itself, the you will have all data (of this database) in the memory all day long.

Julius Kavay · Oct 22, 2021 go to post

I fear  you have to be some kind of a magician, to solve this problem...
You need  two things (a) a time-zone-offset, which is not the problem (it's more or less static) and (b) DST-offset, which is a problem, because there are databases for the past but not for future. Maybe you can put the DST-offset into a global for each of the geographic region you need. And yes, you have to maintain it...

Some starting points:  https://en.wikipedia.org/wiki/Tz_database  and http://web.cs.ucla.edu/~eggert/tz/tz-link.htm. In case you you work with python, take a look at https://pypi.org/project/pytz/

The README file from tz_database says the problem in a nutshell:
"The Time Zone Database (called tz, tzdb or zoneinfo) contains code and data that represent the history of local time for many representative locations around the globe.  It is updated periodically to reflect changes made by political bodies to time zone boundaries, UTC offsets, and daylight-saving rules."

Julius Kavay · Oct 15, 2021 go to post

The question was (see the original post),  why does a command work in a terminal but not in a method. And, as you know, the answer lies in the scoping. I would say, he (@David Hockenbroch) tries to learn and understand the nature of indirection and is not working on a production grade problem.

But maybe I'm wrong... who knows.

Julius Kavay · Oct 15, 2021 go to post

He (@David Hockenbroch) is playing with inderection, using $classmethod() instead of ##class(classname).methodname(...)  does not solve the scoping problem:

ClassMethod testvalidator(class As %String, value As %String) As %Status
{  
  set validator = "sc = $classmethod(class, ""IsValid"", value)"
   write validator,!
   set @validator
   write sc,!
   quit sc
}

The above method gives you the same <UNDEF> error because of non global scoping! By using indirection both variables (validator and sc) must have global scope.

Julius Kavay · Oct 15, 2021 go to post

As @Sergei Shutov pointed out, you can switch off the procdere block by a keyword for the whole class. Additionaly, you can switch on or off the procedure block keyword for a particular  method too. In your case:

class Some.Class  Extends %RegisteredObject
{
/// a procedure block method
ClassMethod ProcBlock()
{
}

/// a nonprocedurblock method
ClassMethod NoProcBlock() [ ProcedureBlock = 0 ]
{
// Caution: All variables have a global scope, hence, they will overwrite variables with the same name, which were created previously. To avoid this, use the NEW command, to protect them (if desired).
}

}
Julius Kavay · Oct 14, 2021 go to post

You have a problem with the scoping!

Indirection has a global scoping, you have to put things with indirection in a global scope:

ClassMethod testvalidator(class As %String, value As %String) As %Status [ PublicList = (validator, sc) ]
{
   new validator, sc
   set validator = "sc = ##class("_class_").IsValid("""_value_""")"
   write validator,!
   set @validator
   write sc,!
   quit sc
}
set result = ##class(...).testvalidator("%Library.Numeric","BLABLA")
do $system.OBJ.DisplayError(result) --> ERROR #7207: Datatype value 'BLABLA' is not a valid number
Julius Kavay · Oct 11, 2021 go to post

According to the task, "...You will receive an integer number and you will return a new number..."

set s=9999999999999999999
write s --> 10000000000000000000
write AddWater(s) --> 1  // which is the expected result

The above method works also for cases, where s contains a string of digits

set a="9999999999999999999"
write a  --> 9999999999999999999
set res=AddWater(s)
write res ---> 999...<165 more nines>...999
write $length(s) --> 19
write $length(res) --> 171  // 19 * 9 = 171

So why do you show those devils?

Julius Kavay · Oct 8, 2021 go to post

Oh, I see right now, we can save one byte...

ClassMethod AddWater(s)
{
   f i=$l(s):-1:1 s t=$e(s,i),$e(s,i)=10**t-1/9*t
   q $tr(s,0)
}
Julius Kavay · Oct 8, 2021 go to post

Check this one...

ClassMethod AddWater(s)
{
   f i=$l(s):-1:1 s t=$e(s,i),$e(s,i)="1E"_t-1/9*t
   q $tr(s,0)
}
Julius Kavay · Oct 7, 2021 go to post

%FromJSON is not a class, it's a method of %DynamicObject and is available in IRIS and for Cache  version 2016.2 and later.

Julius Kavay · Oct 2, 2021 go to post

There is one thing you should check, than this could trigger effects observed by you.
Objects are tracked by reference counts, as long as an objects reference count is greater then one, locks won't be released and the object isn't deleted.

set obj = ##class(Some.Class).%OpenId(id, 4) // the obj's ref count is one
... // more commands
    // now, the application does something like this
set tmp = obj    // obj's ref count is now two!
... // more commands

set obj = "" // the application intents to close the object
             // but the object still exists due to the fact that the ref count is one
             // (the object is still referenced by <tmp>)

There are methods to detect such a situation:
- $system.OBJ.ShowObjects(), lists all objects with reference counts
- $system.OBJ.ShowReferences(obj), list all variables which contains a reference to <obj>

A quick and dirty approach:

set filename = "...some file name"
open filename:"nw":0
if $t { use filename
        do $system.ShowObjects()
        do $system.ShowReferences(obj) 
        close filename
      }
set obj = "" 

Give it a try, maybe your object has multiple references which cause the problem

Julius Kavay · Sep 28, 2021 go to post

I don't know exactly what you mean, maybe you have a example for us?

Something like:

DateFrom: 2021-09-27  DateThru: 2021-09-28
Expected time range:  from ???? thru ????
Julius Kavay · Sep 28, 2021 go to post

The %SYS.Namespace class contains the methods, you are looking for.

write ##class(%SYS.Namespace).GetGlobalDest( [namspace], "global") --> DB where the global lies
write ##class(%SYS.Namespace).GetRoutineDest( [namspace], "routine") --> DB where the routine lies
write ##class(%SYS.Namespace).GetPackageDest( [namspace], "package") --> DB where the package lies