Julius Kavay · Apr 4, 2022 go to post

First, as you alread wrote, changing the collation of an already existing installation is dengerious,
second, as far as I know, the database creation page (of ManagementPortal) offers you "Cache/IRIS-standard" and "Cache/IRIS-standard string" only. Nevertheless, changing to "standard string" only affects the collation and not the display, i.e. string subscripts will be displayed quoted but numeric subscripts are not quoted.

Julius Kavay · Apr 5, 2022 go to post

For us all, the common denominator is Cache/IRIS and we have, as you know, Cache/IRIS for Win, Linux, AIX and MAC platforms. It's nice to know about existing external tools, but for some of us the COS solutions remains as the last resort, especially if those (external) tools do not exists for the OS, one works on (Just My2Cents).

Julius Kavay · Apr 11, 2022 go to post

To help you, help us to help you. This means, show us what you have you already done. So we can you point in the right direction, maybe explain, why your solution dosn't work, etc. It's nothing bad to ask for help. At some point in the time we all were new to Studio and ObjecScript.

Just asking for a solution is like going home from the school and letting the parents make the homework...

So what have you tryed?

Julius Kavay · Apr 11, 2022 go to post

Sergei Shutov's answer is correct. The question was, how to remove a specific character (in this case: double quotes) from a string. Your answer is also correct but he told nothing about quoted strings.

The problem is, we have a question but no explanatory examples. Something like xxxx is the string I have, and
 yyyyy  is the string, I want to get.

Julius Kavay · Apr 12, 2022 go to post

I referred in his answer only the $replace() function without explicit pointing this out. I was upset about the ambiguous question, sorry.

Julius Kavay · Apr 29, 2022 go to post

People call it the reverse mode of $translate().

I saw this kind of usage of $tr() some 20 years ago. If I recall it right, it was mentioned in an article on usenet: comp.lang.mumps.

Julius Kavay · May 8, 2022 go to post

The input variable pInput is an object(reference). You can't save OREFs in a global!

Think about OREFs as memory location (or, if you "speak" C, as a pointer). Trying to save it in a global is the same as saving a C pointer into a file for a later use... Won't work either 

Julius Kavay · May 11, 2022 go to post

The challenge talks about "...rearranging the letters ...", there is no restriction for the ASCII sequence, so this would not work with cyrillic character set :

CMOKBA  (fig tree, russian)
MOCKBA  (Moscow, capital city)

justmy2cents

Julius Kavay · May 15, 2022 go to post

You are right, that's my fault. I didn't read the Notes, just the beginning of the challenge. Sorry.

Julius Kavay · May 16, 2022 go to post
Class DC.Test Extends %RegisteredObject
{
/// Return TRUE if val contains an string
ClassMethod IsString(val) As %Boolean
{
    q $a($lb(val),2)<3
}
/// Return TRUE if val contains a number (int, real or double)
ClassMethod IsNumber(val) As %Boolean
{
    q $a($lb(val),2)>3
}
}

w ##class(DC.Test).IsString("abc") //--> 1
w ##class(DC.Test).IsString("123") //--> 1
w ##class(DC.Test).IsString(123) //--> 0
w ##class(DC.Test).IsNumber(123) //--> 1
w ##class(DC.Test).IsNumber("abc") //--> 0
w ##class(DC.Test).IsNumber("123") //--> 0
w ##class(DC.Test).IsNumber(123_345) //--> 0
w ##class(DC.Test).IsNumber(123+345) //--> 1
w ##class(DC.Test).IsString(123_456) //--> 1
w ##class(DC.Test).IsString(123+456) //--> 0

s x=123, y="123"
w ##class(DC.Test).IsString(x) //--> 0
w ##class(DC.Test).IsString(y) //--> 1

Julius Kavay · May 20, 2022 go to post

Try this one. The idea is, find the state (including the separators), everything before is the city and everything after is the zip code. Then we remove the separator chars (whitespaces, commas and dots).

ClassMethod Disjoin(data, cty, sta, zip)
{
    i $locate(data,"(\s|,|\.)[A-Za-z]{2}(\s|,|\.)",3,,sta) {
        s$lb(cty,zip)=$lfs(data,sta), sta=$$s(sta), cty=$$s(cty), zip=$$s(zip)
        
    } else { s (cty,sta,zip)="" }
    
    q sta]""s(x)	q$zstrip(x,"<>w",",.")
}
Some examples
i ##class(DC.Test).Disjoin("CANTON,TX.,75103",.c,.s,.z) w c,", ",s,", ",z --> CANTON, TX, 75103
i ##class(DC.Test).Disjoin("MILFORD, OH 45150",.c,.s,.z) w c,", ",s,", ",z --> MILFORD, OH, 45150
i ##class(DC.Test).Disjoin("MILFORD OH 45150",.c,.s,.z) w c,", ",s,", ",z --> MILFORD, OH, 45150
i ##class(DC.Test).Disjoin("KANSAS CITY, MO, 12345",.c,.s,.z) w c,", ",s,", ",z --> KANSAS CITY, MO, 12345
i ##class(DC.Test).Disjoin("KANSAS CITY MO, 12345",.c,.s,.z) w c,", ",s,", ",z --> KANSAS CITY, MO, 12345
i ##class(DC.Test).Disjoin("ST. LOUIS MO, 12345",.c,.s,.z) w c,", ",s,", ",z --> ST. LOUIS, MO, 12345
i ##class(DC.Test).Disjoin("  ST. LOUIS MO, 12345",.c,.s,.z) w c,", ",s,", ",z --> ST. LOUIS, MO, 12345

OK, something like this gives a wrong result...
i ##class(DC.Test).Disjoin("   ST. LOUIS MO, 12345",.c,.s,.z) w c,", ",s,", ",z --> , ST, LOUIS MO, 12345
Julius Kavay · May 20, 2022 go to post

Oh, thanks for the hint, I'm aware of that. Actually one should remove the same characters as used in $locate():

if$locate($zstrip(data,"<w",",."), ...)

but the point is, to circumvent such problems, the rule number one in the electronic data processing is: you have to apply for check each and every input (at least) a formal check or you end up with problems like this. So the desired process should be:

read_data --> check_it --> proceed_if_OK_else_back_to_input

The same goes for data during an import process.

Julius Kavay · May 23, 2022 go to post

I was told,  it's illegal to use data structure information, which doesn't were changed in the last 25 years (and after this many years, one could think to have the right given by "customary law" to use it), hence I decided for a more "legal" solution for the above problem - although this solution will work for IRIS (and recent Cache systems) only:

Class DC.Test Extends%RegisteredObject
{

/// Return TRUE if val contains a stringClassMethod IsString2(val) As%Boolean
{
    quit {"a":(val)}.%GetTypeOf("a")="string"
}

/// Return TRUE if val contains a number (int, real or double)ClassMethod IsNumber2(val) As%Boolean
{
    quit {"a":(val)}.%GetTypeOf("a")="number"
}

}
Julius Kavay · May 24, 2022 go to post

From your JSON-String, someone stripped off two chars at the end: "}]"

So if you add those chars, everything will be OK

d##class(%ZEN.Auxiliary.jsonProvider).%ConvertJSONToObject(JSONString3_"}]",,.list)
w list.GetAt(1).sensors.GetAt(1).jobGUID --> 0b955ee7-9a54-4b13-9af1-7019721faeab
 
Julius Kavay · May 24, 2022 go to post

read json <now, Cntrl-V here the above string, press enter>, then

w##class(%ZEN.Auxiliary.jsonProvider).%ConvertJSONToObject(json,,.list1) --> 1w list1 --> 42@%Library.ListOfObjectsw list1.GetAt(1).sensors.GetAt(1).jobGUID --> 0b955ee7-9a54-4b13-9af1-7019721faeab

where is the problem?

Julius Kavay · May 24, 2022 go to post

To get all the jobGUIDs you need two loops:

f i=1:1:list1.Size f j=1:1:list1.GetAt(i).sensors.Size w list1.GetAt(i).sensors.GetAt(j).jobGUID,!
0b955ee7-9a54-4b13-9af1-7019721faeab
8f9e85ab-31e7-4835-8969-6d72d142a2f1
68cea9d3-54cd-43f2-ae37-aaf47ed43e6b
7602764e-8951-451f-9653-ceb84834a1a6
88d2e472-a1e4-40b3-a108-f2d32a2023e5
116f2ac6-da5f-46da-a7c7-92d9eaf98c89
a878e527-f519-4aaa-bf5d-0d65f72de119
be570b14-0555-4b86-ab9f-e37c40c79216
3a13e243-d6ed-4788-98b2-52e9213bee00
54969869-c4f6-43f6-a74a-2a67f9a73fc5
700af7d3-77b3-4a84-ba11-ea49602d6558
18dc3370-c291-468b-af1f-0361d95bb02c
35d0d2e7-1199-4c18-8941-4fff6dbdba1f
8044560c-94d2-4da7-87f5-07328d9e62c1
b636a2f5-d35f-4c82-9646-e09572336e23
9c9a4bf4-e8af-4b8d-9de2-a99cdff150ed
a576d235-6eb6-4312-a1ff-7b1f767b88ce
654cf21e-daad-4a11-b676-86a7bc8a3360
2be4efc8-6616-4bff-87ba-30fe388a1b34
a5374d6c-311c-44d0-8d06-3a31f33dd3a8
955529c5-36be-4f3e-b768-0e3b377804a7
60a7cdb0-499e-4d02-b4d3-06ee58e40481
e84eda78-1491-49af-9e34-d647e817a251
9bcd5fe6-6f05-4482-ad78-612f35c60b41
Julius Kavay · May 24, 2022 go to post

Thanks for the info about the evolution of the LIST functions.

I'm just a developer without any insight information into the internals of LIST functions and, as you wrote, "The changes were carefully done so that working programs that use functions of the form $LISTxxx, $Lx, and $LxS to manipulate $LIST strings will not notice the changes.", hence I do not saw any changes.
OK, there were some enhancements like adding $LV() and $LU() or a third argument to $LTS(), but those changes are not relevant for existing applications.

Regarding the speed gain by using (JSON)array instead of (JSON)object, yes you have right, the array variant is about 5% faster. I just didn't made a speed test for the new solution, the goal was to have a "legal solution" and not an all-time record.

Finally, I'll ask you, why are things like the internal format of $BIT() or $LB() unpublished?
For example, $LB() can't be such a big mystery because a simple ZZDUMP reveals the structure?

There are cases where this information would be (very) helpful. Just to name one, I have a particular case. 

I wrote a simple class, which uses $ZF()-callouts, so the customer can create (i.e. export) data into an excel file (including formatting and colors) as well as read (i.e. import) data from an excel file (again, from *.xls and *.xlsx). The class has methods to read/write individual cells or whole rows or whole columns.

To pass row- and column-data between the application and the callout module, I use $LB().

set exl=##class(%Zu.Library.Excel).%New()
...
// writing datado exl.WriteNum(row,col,value,format)
do exl.WriteRow(row,data) // data is $lb(col1, col2, ...colN)// readingset value=exl.ReadNum(row,col)
set data=exl.ReadRow(row)	// data is $lb(col1, col2, ...colN)
...

To be able to write the corresponding callout module (Windows-DLL as well as Linux-SO), the information about the $LB() structure were esential.
This is just one example. Similar solutions were used for the PDF- and ZIP-callout modules too.
At least for the $LB() it shouldn't be such a big secret, and an official documentation would certainly make more happy customers. But it is not my decision, it must be decided by ISC.

Julius Kavay · May 25, 2022 go to post
...
.SET SC=STREAM.LinkToFile(FILE)   // A
...
...
.do##class(%File).Delete(FILE, .RETURN)  // B

As long you hold your hand on a file (line A), you can't delete the file (line B). You have to do something like

set SC = ""// orkill SC
Julius Kavay · May 25, 2022 go to post

Bye the way, non of Cache/IRIS has an $ZU command but all versions have a bunch of $ZU() functions. So what do you want to do with them?

Julius Kavay · May 26, 2022 go to post

The standard ANSI escape sequenc should be:

write $c(27)_"[42m"_"Your green backround"_$c(27)_"[m"_" and a normal dot."
write $c(27)_"[32m"_"Your green text"_$c(27)_"[m"_" and a normal dot."

Julius Kavay · May 30, 2022 go to post

your exit statement

If (AxVisM1.P0.ToString = "") Then
	Exit While
End If

is to late, this must come after the $ORDER() statement

AxVisM1.Execute("set P0=$o(^ztonMS(""REF"",P0))")
If (AxVisM1.P0.ToString = "") Then
	Exit While
End If
AxVisM1.Execute("s P1=$g(^ztonMS(""REF"",P0))")

The same goes for the next while-loop a few lines below

Julius Kavay · Jun 2, 2022 go to post

A simple method like

ClassMethod ProcData(file = "c:\temp\zipcitystate.csv")
{
    set str=##class(%Stream.FileCharacter).%New()
    do str.LinkToFile(file)
    while 'str.AtEnd {
        set$listbuild(ZIP,CITY,STATE)=$listfromstring(str.ReadLine())
        
        // now you have the individual columns// in ZIP, CITY and STATE variables for further processingwrite"Zip=",ZIP,?12,"City=",CITY,?40,"State=",STATE,!
    }
    
    // depending on the way of your implementation, a "kill str"// would be needed to free up the filekill str
}

to do the job. Then call the method as

do##class(your.class).ProcData()
// ordo##class(your.class).ProcData("path-to-the-file")
Julius Kavay · Jun 4, 2022 go to post

As an ObjectScript routine, remove the "ClassMethod" keyword (which, as the name indicates, belongs to classes. Then either  add a "Public" keyword or you remove the brackets ("{", "}") too, but then all variables will have the same scope:

ProcData(file = "c:\temp\zipcitystate.csv") Public
{
    set str=##class(%Stream.FileCharacter).%New()
    do str.LinkToFile(file)
    while 'str.AtEnd {
        set$listbuild(ZIP,CITY,STATE)=$listfromstring(str.ReadLine())
        
        // now you have the individual columns// in ZIP, CITY and STATE variables for further processingwrite"Zip=",ZIP,?12,"City=",CITY,?40,"State=",STATE,!
    }
    
    // depending on the way of your implementation, a "kill str"// would be needed to free up the filekill str
}

Oh, and to invoke the above procedure just do a:

do ProcData^YourRoutineName()
// ordo ProcData^YourRoutineName("path-to-file")
Julius Kavay · Jun 6, 2022 go to post

It seems, you read the whole PDF into one string thenconverting this to Base64... So there are two "chances to get an error":

- the PDF is longer then the MAXSTRING value (which is 3641144 chars) and

- converting a string to Base64 increases the length of the string by a factor of 1.333 (you get your maxstr here).

The solution is: you read your PDF in chunks, convert this chunks into Base64 and output the converted data into a stream. Due to the nature of Base64, the length of the chunks you read in MUST BE a multiple of 3 (3 input bytes will be converted into 4 output bytes).

Julius Kavay · Jun 7, 2022 go to post

you miss the object reference!

set context.strDocumentEncoded = B64EncodeStream(request.streamPDF)
// ---------------------------^^^^^^^ this should be somethingset context.strDocumentEncoded = ##(your.class).B64EncodeStream(request.streamPDF)

but you have another problems too: your context.strDocument and  context.strDocumentEncoded are currently STRING properties (according to the operation you try to do), which are limitet to a maxlength of 3.47MB!

You have to change both to a STREAM, so you can handle PDFs  larger then ca. 2.6MB (because 2.6 * 4 / 3 ==> 3.46MB, the limit for a string variable).

After you change context.strDocument and context.strDocumentEncoded to a stream properties, you could use this code:

Class DC.Someclass Extends%RegisteredObject
{

Parameter CHUNKSIZE = 2097144;ClassMethod ToBase64(src As%Stream.Object, dst As%Stream.Object) As%Status
{
	i ..#CHUNKSIZE#3=0, src.Rewind(), dst.Rewind() {
		set sts=$$$OKwhile 'src.AtEnd,sts {
			do dst.Write($system.Encryption.Base64Encode(src.Read(..#CHUNKSIZE,.sts),1))
		}
	} else { set sts=$$Error^%apiOBJ(5001,"Chunksize or src/dst-problem") }
	
	quit sts
}

}
if##class(your.class).ToBase64(context.strDocument,context.strDocumentEncoded) write"OK"

It seems, this task will take some time... you have to check, how context.strDocument is populated and  how context.strDocumentEncoded is later in code used. Good luck.

Julius Kavay · Jun 13, 2022 go to post

If you have a (whatever) class with an property like:

Property propName As%Stream.GlobalCharacter;

and you have an instance of that object in a variable obj then a command like the below

write obj.propName --> nn@%Stream.GlobalCharacter

shows you the object reference, which is (formal) an integer number followed by an '@' symbol followed by the name of the class. With other words, what you see is correct.

Julius Kavay · Jun 14, 2022 go to post

Sure, you can check some key points:
- the size of your PDF-file (in bytes) must be the same as the size of the context.strDocument
- the size of the encoded stream must be 1.33 times of the unencoded stream (see below)
- the second parameter of the Base64Encode() method must be set to 1, else you get a stream with line breaks!

set docSize = context.strDocument.Size
set encSize = context.strDocumentEncoded.Size

if -docSize#3+docSize*4/3-encSize { write"Base64 stream has wrong size" }

Your "old" version sent a string, the new version should send a stream - is there everything OK? Just double check all the recent changes.

Julius Kavay · Jun 28, 2022 go to post

First, the correct (or better) way for the above code snipet were:

new$NAMESPACEzn"%SYS"do##class(Config.MapGlobals).Delete(...)
quit

second, one can call routines (and (class)methodes are compiled to rotines) from another namespace by using extended syntax, but in that case such a routine uses the globals (if the routine does a global access) from the CALLING namespace. In Your case this won't work because the Config.MapGlobals uses globals which resides in %SYS namespace and not in the namesspace you are in.